2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
40 #include <pulse/i18n.h>
41 #include <pulse/pulseaudio.h>
42 #include <pulse/rtclock.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/sndfile-util.h>
48 #include <pulsecore/core-util.h>
50 #define TIME_EVENT_USEC 50000
52 #define CLEAR_LINE "\x1B[K"
54 static enum { RECORD
, PLAYBACK
} mode
= PLAYBACK
;
56 static pa_context
*context
= NULL
;
57 static pa_stream
*stream
= NULL
;
58 static pa_mainloop_api
*mainloop_api
= NULL
;
60 static void *buffer
= NULL
;
61 static size_t buffer_length
= 0, buffer_index
= 0;
63 static pa_io_event
* stdio_event
= NULL
;
65 static pa_proplist
*proplist
= NULL
;
66 static char *device
= NULL
;
68 static SNDFILE
* sndfile
= NULL
;
70 static pa_bool_t verbose
= FALSE
;
71 static pa_volume_t volume
= PA_VOLUME_NORM
;
72 static pa_bool_t volume_is_set
= FALSE
;
74 static pa_sample_spec sample_spec
= {
75 .format
= PA_SAMPLE_S16LE
,
79 static pa_bool_t sample_spec_set
= FALSE
;
81 static pa_channel_map channel_map
;
82 static pa_bool_t channel_map_set
= FALSE
;
84 static sf_count_t (*readf_function
)(SNDFILE
*_sndfile
, void *ptr
, sf_count_t frames
) = NULL
;
85 static sf_count_t (*writef_function
)(SNDFILE
*_sndfile
, const void *ptr
, sf_count_t frames
) = NULL
;
87 static pa_stream_flags_t flags
= 0;
89 static size_t latency
= 0, process_time
= 0;
90 static int32_t latency_msec
= 0, process_time_msec
= 0;
92 static pa_bool_t raw
= TRUE
;
93 static int file_format
= -1;
95 /* A shortcut for terminating the application */
96 static void quit(int ret
) {
97 pa_assert(mainloop_api
);
98 mainloop_api
->quit(mainloop_api
, ret
);
101 /* Connection draining complete */
102 static void context_drain_complete(pa_context
*c
, void *userdata
) {
103 pa_context_disconnect(c
);
106 /* Stream draining complete */
107 static void stream_drain_complete(pa_stream
*s
, int success
, void *userdata
) {
110 pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context
)));
115 pa_log(_("Playback stream drained."));
117 pa_stream_disconnect(stream
);
118 pa_stream_unref(stream
);
121 if (!pa_context_drain(context
, context_drain_complete
, NULL
))
122 pa_context_disconnect(context
);
125 pa_log(_("Draining connection to server."));
130 static void start_drain(void) {
135 pa_stream_set_write_callback(stream
, NULL
, NULL
);
137 if (!(o
= pa_stream_drain(stream
, stream_drain_complete
, NULL
))) {
138 pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context
)));
143 pa_operation_unref(o
);
148 /* Write some data to the stream */
149 static void do_stream_write(size_t length
) {
153 if (!buffer
|| !buffer_length
)
157 if (l
> buffer_length
)
160 if (pa_stream_write(stream
, (uint8_t*) buffer
+ buffer_index
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0) {
161 pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
169 if (!buffer_length
) {
172 buffer_index
= buffer_length
= 0;
176 /* This is called whenever new data may be written to the stream */
177 static void stream_write_callback(pa_stream
*s
, size_t length
, void *userdata
) {
179 pa_assert(length
> 0);
185 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_INPUT
);
190 do_stream_write(length
);
199 size_t data_length
= length
;
201 if (pa_stream_begin_write(s
, &data
, &data_length
) < 0) {
202 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
207 if (readf_function
) {
208 size_t k
= pa_frame_size(&sample_spec
);
210 if ((bytes
= readf_function(sndfile
, data
, (sf_count_t
) (data_length
/k
))) > 0)
211 bytes
*= (sf_count_t
) k
;
214 bytes
= sf_read_raw(sndfile
, data
, (sf_count_t
) data_length
);
217 pa_stream_write(s
, data
, (size_t) bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
219 pa_stream_cancel_write(s
);
222 if (bytes
< (sf_count_t
) data_length
) {
227 /* Request fulfilled */
228 if ((size_t) bytes
>= length
)
236 /* This is called whenever new data may is available */
237 static void stream_read_callback(pa_stream
*s
, size_t length
, void *userdata
) {
240 pa_assert(length
> 0);
246 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_OUTPUT
);
248 while (pa_stream_readable_size(s
) > 0) {
251 if (pa_stream_peek(s
, &data
, &length
) < 0) {
252 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
258 pa_assert(length
> 0);
261 buffer
= pa_xrealloc(buffer
, buffer_length
+ length
);
262 memcpy((uint8_t*) buffer
+ buffer_length
, data
, length
);
263 buffer_length
+= length
;
265 buffer
= pa_xmalloc(length
);
266 memcpy(buffer
, data
, length
);
267 buffer_length
= length
;
277 while (pa_stream_readable_size(s
) > 0) {
281 if (pa_stream_peek(s
, &data
, &length
) < 0) {
282 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
288 pa_assert(length
> 0);
290 if (writef_function
) {
291 size_t k
= pa_frame_size(&sample_spec
);
293 if ((bytes
= writef_function(sndfile
, data
, (sf_count_t
) (length
/k
))) > 0)
294 bytes
*= (sf_count_t
) k
;
297 bytes
= sf_write_raw(sndfile
, data
, (sf_count_t
) length
);
299 if (bytes
< (sf_count_t
) length
)
307 /* This routine is called whenever the stream state changes */
308 static void stream_state_callback(pa_stream
*s
, void *userdata
) {
311 switch (pa_stream_get_state(s
)) {
312 case PA_STREAM_CREATING
:
313 case PA_STREAM_TERMINATED
:
316 case PA_STREAM_READY
:
319 const pa_buffer_attr
*a
;
320 char cmt
[PA_CHANNEL_MAP_SNPRINT_MAX
], sst
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
322 pa_log(_("Stream successfully created."));
324 if (!(a
= pa_stream_get_buffer_attr(s
)))
325 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
328 if (mode
== PLAYBACK
)
329 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a
->maxlength
, a
->tlength
, a
->prebuf
, a
->minreq
);
331 pa_assert(mode
== RECORD
);
332 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a
->maxlength
, a
->fragsize
);
336 pa_log(_("Using sample spec '%s', channel map '%s'."),
337 pa_sample_spec_snprint(sst
, sizeof(sst
), pa_stream_get_sample_spec(s
)),
338 pa_channel_map_snprint(cmt
, sizeof(cmt
), pa_stream_get_channel_map(s
)));
340 pa_log(_("Connected to device %s (%u, %ssuspended)."),
341 pa_stream_get_device_name(s
),
342 pa_stream_get_device_index(s
),
343 pa_stream_is_suspended(s
) ? "" : "not ");
348 case PA_STREAM_FAILED
:
350 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
355 static void stream_suspended_callback(pa_stream
*s
, void *userdata
) {
359 if (pa_stream_is_suspended(s
))
360 pa_log(_("Stream device suspended.%s"), CLEAR_LINE
);
362 pa_log(_("Stream device resumed.%s"), CLEAR_LINE
);
366 static void stream_underflow_callback(pa_stream
*s
, void *userdata
) {
370 pa_log(_("Stream underrun.%s"), CLEAR_LINE
);
373 static void stream_overflow_callback(pa_stream
*s
, void *userdata
) {
377 pa_log(_("Stream overrun.%s"), CLEAR_LINE
);
380 static void stream_started_callback(pa_stream
*s
, void *userdata
) {
384 pa_log(_("Stream started.%s"), CLEAR_LINE
);
387 static void stream_moved_callback(pa_stream
*s
, void *userdata
) {
391 pa_log(_("Stream moved to device %s (%u, %ssuspended).%s"), pa_stream_get_device_name(s
), pa_stream_get_device_index(s
), pa_stream_is_suspended(s
) ? "" : _("not "), CLEAR_LINE
);
394 static void stream_buffer_attr_callback(pa_stream
*s
, void *userdata
) {
398 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE
);
401 static void stream_event_callback(pa_stream
*s
, const char *name
, pa_proplist
*pl
, void *userdata
) {
408 t
= pa_proplist_to_string_sep(pl
, ", ");
409 pa_log("Got event '%s', properties '%s'", name
, t
);
413 /* This is called whenever the context status changes */
414 static void context_state_callback(pa_context
*c
, void *userdata
) {
417 switch (pa_context_get_state(c
)) {
418 case PA_CONTEXT_CONNECTING
:
419 case PA_CONTEXT_AUTHORIZING
:
420 case PA_CONTEXT_SETTING_NAME
:
423 case PA_CONTEXT_READY
: {
424 pa_buffer_attr buffer_attr
;
430 pa_log(_("Connection established.%s"), CLEAR_LINE
);
432 if (!(stream
= pa_stream_new_with_proplist(c
, NULL
, &sample_spec
, &channel_map
, proplist
))) {
433 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c
)));
437 pa_stream_set_state_callback(stream
, stream_state_callback
, NULL
);
438 pa_stream_set_write_callback(stream
, stream_write_callback
, NULL
);
439 pa_stream_set_read_callback(stream
, stream_read_callback
, NULL
);
440 pa_stream_set_suspended_callback(stream
, stream_suspended_callback
, NULL
);
441 pa_stream_set_moved_callback(stream
, stream_moved_callback
, NULL
);
442 pa_stream_set_underflow_callback(stream
, stream_underflow_callback
, NULL
);
443 pa_stream_set_overflow_callback(stream
, stream_overflow_callback
, NULL
);
444 pa_stream_set_started_callback(stream
, stream_started_callback
, NULL
);
445 pa_stream_set_event_callback(stream
, stream_event_callback
, NULL
);
446 pa_stream_set_buffer_attr_callback(stream
, stream_buffer_attr_callback
, NULL
);
448 pa_zero(buffer_attr
);
449 buffer_attr
.maxlength
= (uint32_t) -1;
450 buffer_attr
.prebuf
= (uint32_t) -1;
452 if (latency_msec
> 0) {
453 buffer_attr
.fragsize
= buffer_attr
.tlength
= pa_usec_to_bytes(latency_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
454 flags
|= PA_STREAM_ADJUST_LATENCY
;
455 } else if (latency
> 0) {
456 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) latency
;
457 flags
|= PA_STREAM_ADJUST_LATENCY
;
459 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) -1;
461 if (process_time_msec
> 0) {
462 buffer_attr
.minreq
= pa_usec_to_bytes(process_time_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
463 } else if (process_time
> 0)
464 buffer_attr
.minreq
= (uint32_t) process_time
;
466 buffer_attr
.minreq
= (uint32_t) -1;
468 if (mode
== PLAYBACK
) {
470 if (pa_stream_connect_playback(stream
, device
, &buffer_attr
, flags
, volume_is_set
? pa_cvolume_set(&cv
, sample_spec
.channels
, volume
) : NULL
, NULL
) < 0) {
471 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c
)));
476 if (pa_stream_connect_record(stream
, device
, &buffer_attr
, flags
) < 0) {
477 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c
)));
485 case PA_CONTEXT_TERMINATED
:
489 case PA_CONTEXT_FAILED
:
491 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c
)));
502 /* New data on STDIN **/
503 static void stdin_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
507 pa_assert(a
== mainloop_api
);
509 pa_assert(stdio_event
== e
);
512 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
516 if (!stream
|| pa_stream_get_state(stream
) != PA_STREAM_READY
|| !(l
= w
= pa_stream_writable_size(stream
)))
519 buffer
= pa_xmalloc(l
);
521 if ((r
= read(fd
, buffer
, l
)) <= 0) {
524 pa_log(_("Got EOF."));
529 pa_log(_("read() failed: %s"), strerror(errno
));
533 mainloop_api
->io_free(stdio_event
);
538 buffer_length
= (uint32_t) r
;
545 /* Some data may be written to STDOUT */
546 static void stdout_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
549 pa_assert(a
== mainloop_api
);
551 pa_assert(stdio_event
== e
);
554 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
558 pa_assert(buffer_length
);
560 if ((r
= write(fd
, (uint8_t*) buffer
+buffer_index
, buffer_length
)) <= 0) {
561 pa_log(_("write() failed: %s"), strerror(errno
));
564 mainloop_api
->io_free(stdio_event
);
569 buffer_length
-= (uint32_t) r
;
570 buffer_index
+= (uint32_t) r
;
572 if (!buffer_length
) {
575 buffer_length
= buffer_index
= 0;
579 /* UNIX signal to quit recieved */
580 static void exit_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
582 pa_log(_("Got signal, exiting."));
586 /* Show the current latency */
587 static void stream_update_timing_callback(pa_stream
*s
, int success
, void *userdata
) {
594 pa_stream_get_time(s
, &usec
) < 0 ||
595 pa_stream_get_latency(s
, &l
, &negative
) < 0) {
596 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context
)));
601 fprintf(stderr
, _("Time: %0.3f sec; Latency: %0.0f usec."),
602 (float) usec
/ 1000000,
603 (float) l
* (negative
?-1.0f
:1.0f
));
604 fprintf(stderr
, " \r");
608 /* Someone requested that the latency is shown */
609 static void sigusr1_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
614 pa_operation_unref(pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
));
618 static void time_event_callback(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
619 if (stream
&& pa_stream_get_state(stream
) == PA_STREAM_READY
) {
621 if (!(o
= pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
)))
622 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context
)));
624 pa_operation_unref(o
);
627 pa_context_rttime_restart(context
, e
, pa_rtclock_now() + TIME_EVENT_USEC
);
630 static void help(const char *argv0
) {
632 printf(_("%s [options]\n\n"
633 " -h, --help Show this help\n"
634 " --version Show version\n\n"
635 " -r, --record Create a connection for recording\n"
636 " -p, --playback Create a connection for playback\n\n"
637 " -v, --verbose Enable verbose operations\n\n"
638 " -s, --server=SERVER The name of the server to connect to\n"
639 " -d, --device=DEVICE The name of the sink/source to connect to\n"
640 " -n, --client-name=NAME How to call this client on the server\n"
641 " --stream-name=NAME How to call this stream on the server\n"
642 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
643 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
644 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
645 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
646 " s24-32le, s24-32be (defaults to s16ne)\n"
647 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
649 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
650 " --fix-format Take the sample format from the sink the stream is\n"
651 " being connected to.\n"
652 " --fix-rate Take the sampling rate from the sink the stream is\n"
653 " being connected to.\n"
654 " --fix-channels Take the number of channels and the channel map\n"
655 " from the sink the stream is being connected to.\n"
656 " --no-remix Don't upmix or downmix channels.\n"
657 " --no-remap Map channels by index instead of name.\n"
658 " --latency=BYTES Request the specified latency in bytes.\n"
659 " --process-time=BYTES Request the specified process time per request in bytes.\n"
660 " --latency-msec=MSEC Request the specified latency in msec.\n"
661 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
662 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
663 " --raw Record/play raw PCM data.\n"
664 " --passthrough passthrough data \n"
665 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
666 " --list-file-formats List available file formats.\n")
689 ARG_LIST_FILE_FORMATS
,
691 ARG_PROCESS_TIME_MSEC
694 int main(int argc
, char *argv
[]) {
695 pa_mainloop
* m
= NULL
;
697 char *bn
, *server
= NULL
;
698 pa_time_event
*time_event
= NULL
;
699 const char *filename
= NULL
;
701 static const struct option long_options
[] = {
702 {"record", 0, NULL
, 'r'},
703 {"playback", 0, NULL
, 'p'},
704 {"device", 1, NULL
, 'd'},
705 {"server", 1, NULL
, 's'},
706 {"client-name", 1, NULL
, 'n'},
707 {"stream-name", 1, NULL
, ARG_STREAM_NAME
},
708 {"version", 0, NULL
, ARG_VERSION
},
709 {"help", 0, NULL
, 'h'},
710 {"verbose", 0, NULL
, 'v'},
711 {"volume", 1, NULL
, ARG_VOLUME
},
712 {"rate", 1, NULL
, ARG_SAMPLERATE
},
713 {"format", 1, NULL
, ARG_SAMPLEFORMAT
},
714 {"channels", 1, NULL
, ARG_CHANNELS
},
715 {"channel-map", 1, NULL
, ARG_CHANNELMAP
},
716 {"fix-format", 0, NULL
, ARG_FIX_FORMAT
},
717 {"fix-rate", 0, NULL
, ARG_FIX_RATE
},
718 {"fix-channels", 0, NULL
, ARG_FIX_CHANNELS
},
719 {"no-remap", 0, NULL
, ARG_NO_REMAP
},
720 {"no-remix", 0, NULL
, ARG_NO_REMIX
},
721 {"latency", 1, NULL
, ARG_LATENCY
},
722 {"process-time", 1, NULL
, ARG_PROCESS_TIME
},
723 {"property", 1, NULL
, ARG_PROPERTY
},
724 {"raw", 0, NULL
, ARG_RAW
},
725 {"passthrough", 0, NULL
, ARG_PASSTHROUGH
},
726 {"file-format", 2, NULL
, ARG_FILE_FORMAT
},
727 {"list-file-formats", 0, NULL
, ARG_LIST_FILE_FORMATS
},
728 {"latency-msec", 1, NULL
, ARG_LATENCY_MSEC
},
729 {"process-time-msec", 1, NULL
, ARG_PROCESS_TIME_MSEC
},
733 setlocale(LC_ALL
, "");
734 bindtextdomain(GETTEXT_PACKAGE
, PULSE_LOCALEDIR
);
736 bn
= pa_path_get_filename(argv
[0]);
738 if (strstr(bn
, "play")) {
741 } else if (strstr(bn
, "record")) {
744 } else if (strstr(bn
, "cat")) {
747 } if (strstr(bn
, "rec") || strstr(bn
, "mon")) {
752 proplist
= pa_proplist_new();
754 while ((c
= getopt_long(argc
, argv
, "rpd:s:n:hv", long_options
, NULL
)) != -1) {
763 printf(_("pacat %s\n"
764 "Compiled with libpulse %s\n"
765 "Linked with libpulse %s\n"),
767 pa_get_headers_version(),
768 pa_get_library_version());
782 device
= pa_xstrdup(optarg
);
787 server
= pa_xstrdup(optarg
);
793 if (!(t
= pa_locale_to_utf8(optarg
)) ||
794 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
) < 0) {
796 pa_log(_("Invalid client name '%s'"), t
? t
: optarg
);
805 case ARG_STREAM_NAME
: {
808 if (!(t
= pa_locale_to_utf8(optarg
)) ||
809 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
) < 0) {
811 pa_log(_("Invalid stream name '%s'"), t
? t
: optarg
);
825 int v
= atoi(optarg
);
826 volume
= v
< 0 ? 0U : (pa_volume_t
) v
;
827 volume_is_set
= TRUE
;
832 sample_spec
.channels
= (uint8_t) atoi(optarg
);
833 sample_spec_set
= TRUE
;
836 case ARG_SAMPLEFORMAT
:
837 sample_spec
.format
= pa_parse_sample_format(optarg
);
838 sample_spec_set
= TRUE
;
842 sample_spec
.rate
= (uint32_t) atoi(optarg
);
843 sample_spec_set
= TRUE
;
847 if (!pa_channel_map_parse(&channel_map
, optarg
)) {
848 pa_log(_("Invalid channel map '%s'"), optarg
);
852 channel_map_set
= TRUE
;
855 case ARG_FIX_CHANNELS
:
856 flags
|= PA_STREAM_FIX_CHANNELS
;
860 flags
|= PA_STREAM_FIX_RATE
;
864 flags
|= PA_STREAM_FIX_FORMAT
;
868 flags
|= PA_STREAM_NO_REMIX_CHANNELS
;
872 flags
|= PA_STREAM_NO_REMAP_CHANNELS
;
876 if (((latency
= (size_t) atoi(optarg
))) <= 0) {
877 pa_log(_("Invalid latency specification '%s'"), optarg
);
882 case ARG_PROCESS_TIME
:
883 if (((process_time
= (size_t) atoi(optarg
))) <= 0) {
884 pa_log(_("Invalid process time specification '%s'"), optarg
);
889 case ARG_LATENCY_MSEC
:
890 if (((latency_msec
= (int32_t) atoi(optarg
))) <= 0) {
891 pa_log(_("Invalid latency specification '%s'"), optarg
);
896 case ARG_PROCESS_TIME_MSEC
:
897 if (((process_time_msec
= (int32_t) atoi(optarg
))) <= 0) {
898 pa_log(_("Invalid process time specification '%s'"), optarg
);
906 if (!(t
= pa_locale_to_utf8(optarg
)) ||
907 pa_proplist_setp(proplist
, t
) < 0) {
910 pa_log(_("Invalid property '%s'"), optarg
);
922 case ARG_PASSTHROUGH
:
923 flags
|= PA_STREAM_PASSTHROUGH
;
926 case ARG_FILE_FORMAT
:
930 if ((file_format
= pa_sndfile_format_from_string(optarg
)) < 0) {
931 pa_log(_("Unknown file format %s."), optarg
);
939 case ARG_LIST_FILE_FORMATS
:
940 pa_sndfile_dump_formats();
949 if (!pa_sample_spec_valid(&sample_spec
)) {
950 pa_log(_("Invalid sample specification"));
954 if (optind
+1 == argc
) {
957 filename
= argv
[optind
];
959 if ((fd
= pa_open_cloexec(argv
[optind
], mode
== PLAYBACK
? O_RDONLY
: O_WRONLY
|O_TRUNC
|O_CREAT
, 0666)) < 0) {
960 pa_log(_("open(): %s"), strerror(errno
));
964 if (dup2(fd
, mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
) < 0) {
965 pa_log(_("dup2(): %s"), strerror(errno
));
971 } else if (optind
+1 <= argc
) {
972 pa_log(_("Too many arguments."));
980 if (mode
== RECORD
) {
981 /* This might patch up the sample spec */
982 if (pa_sndfile_write_sample_spec(&sfi
, &sample_spec
) < 0) {
983 pa_log(_("Failed to generate sample specification for file."));
987 /* Transparently upgrade classic .wav to wavex for multichannel audio */
988 if (file_format
<= 0) {
989 if ((sample_spec
.channels
== 2 && (!channel_map_set
|| (channel_map
.map
[0] == PA_CHANNEL_POSITION_LEFT
&&
990 channel_map
.map
[1] == PA_CHANNEL_POSITION_RIGHT
))) ||
991 (sample_spec
.channels
== 1 && (!channel_map_set
|| (channel_map
.map
[0] == PA_CHANNEL_POSITION_MONO
))))
992 file_format
= SF_FORMAT_WAV
;
994 file_format
= SF_FORMAT_WAVEX
;
997 sfi
.format
|= file_format
;
1000 if (!(sndfile
= sf_open_fd(mode
== RECORD
? STDOUT_FILENO
: STDIN_FILENO
,
1001 mode
== RECORD
? SFM_WRITE
: SFM_READ
,
1003 pa_log(_("Failed to open audio file."));
1007 if (mode
== PLAYBACK
) {
1008 if (sample_spec_set
)
1009 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1011 if (pa_sndfile_read_sample_spec(sndfile
, &sample_spec
) < 0) {
1012 pa_log(_("Failed to determine sample specification from file."));
1015 sample_spec_set
= TRUE
;
1017 if (!channel_map_set
) {
1018 /* Allow the user to overwrite the channel map on the command line */
1019 if (pa_sndfile_read_channel_map(sndfile
, &channel_map
) < 0) {
1020 if (sample_spec
.channels
> 2)
1021 pa_log(_("Warning: Failed to determine channel map from file."));
1023 channel_map_set
= TRUE
;
1028 if (!channel_map_set
)
1029 pa_channel_map_init_extend(&channel_map
, sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
);
1031 if (!pa_channel_map_compatible(&channel_map
, &sample_spec
)) {
1032 pa_log(_("Channel map doesn't match sample specification"));
1039 if (mode
== PLAYBACK
)
1040 readf_function
= pa_sndfile_readf_function(&sample_spec
);
1042 if (pa_sndfile_write_channel_map(sndfile
, &channel_map
) < 0)
1043 pa_log(_("Warning: failed to write channel map to file."));
1045 writef_function
= pa_sndfile_writef_function(&sample_spec
);
1048 /* Fill in libsndfile prop list data */
1049 sfp
= pa_proplist_new();
1050 pa_sndfile_init_proplist(sndfile
, sfp
);
1051 pa_proplist_update(proplist
, PA_UPDATE_MERGE
, sfp
);
1052 pa_proplist_free(sfp
);
1056 char tss
[PA_SAMPLE_SPEC_SNPRINT_MAX
], tcm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
1058 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1059 mode
== RECORD
? _("recording") : _("playback"),
1060 pa_sample_spec_snprint(tss
, sizeof(tss
), &sample_spec
),
1061 pa_channel_map_snprint(tcm
, sizeof(tcm
), &channel_map
));
1064 /* Fill in client name if none was set */
1065 if (!pa_proplist_contains(proplist
, PA_PROP_APPLICATION_NAME
)) {
1068 if ((t
= pa_locale_to_utf8(bn
))) {
1069 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
);
1074 /* Fill in media name if none was set */
1075 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1078 if ((t
= filename
) ||
1079 (t
= pa_proplist_gets(proplist
, PA_PROP_APPLICATION_NAME
)))
1080 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
);
1083 /* Set up a new main loop */
1084 if (!(m
= pa_mainloop_new())) {
1085 pa_log(_("pa_mainloop_new() failed."));
1089 mainloop_api
= pa_mainloop_get_api(m
);
1091 pa_assert_se(pa_signal_init(mainloop_api
) == 0);
1092 pa_signal_new(SIGINT
, exit_signal_callback
, NULL
);
1093 pa_signal_new(SIGTERM
, exit_signal_callback
, NULL
);
1095 pa_signal_new(SIGUSR1
, sigusr1_signal_callback
, NULL
);
1097 pa_disable_sigpipe();
1100 if (!(stdio_event
= mainloop_api
->io_new(mainloop_api
,
1101 mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
,
1102 mode
== PLAYBACK
? PA_IO_EVENT_INPUT
: PA_IO_EVENT_OUTPUT
,
1103 mode
== PLAYBACK
? stdin_callback
: stdout_callback
, NULL
))) {
1104 pa_log(_("io_new() failed."));
1109 /* Create a new connection context */
1110 if (!(context
= pa_context_new_with_proplist(mainloop_api
, NULL
, proplist
))) {
1111 pa_log(_("pa_context_new() failed."));
1115 pa_context_set_state_callback(context
, context_state_callback
, NULL
);
1117 /* Connect the context */
1118 if (pa_context_connect(context
, server
, 0, NULL
) < 0) {
1119 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context
)));
1124 if (!(time_event
= pa_context_rttime_new(context
, pa_rtclock_now() + TIME_EVENT_USEC
, time_event_callback
, NULL
))) {
1125 pa_log(_("pa_context_rttime_new() failed."));
1130 /* Run the main loop */
1131 if (pa_mainloop_run(m
, &ret
) < 0) {
1132 pa_log(_("pa_mainloop_run() failed."));
1138 pa_stream_unref(stream
);
1141 pa_context_unref(context
);
1144 pa_assert(mainloop_api
);
1145 mainloop_api
->io_free(stdio_event
);
1149 pa_assert(mainloop_api
);
1150 mainloop_api
->time_free(time_event
);
1155 pa_mainloop_free(m
);
1167 pa_proplist_free(proplist
);