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);
198 if (pa_stream_begin_write(s, &data, &length) < 0) {
199 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
204 if (readf_function) {
205 size_t k = pa_frame_size(&sample_spec);
207 if ((bytes = readf_function(sndfile, data, (sf_count_t) (length/k))) > 0)
208 bytes *= (sf_count_t) k;
211 bytes = sf_read_raw(sndfile, data, (sf_count_t) length);
214 pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE);
216 pa_stream_cancel_write(s);
218 if (bytes < (sf_count_t) length)
223 /* This is called whenever new data may is available */
224 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
227 pa_assert(length > 0);
233 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
235 while (pa_stream_readable_size(s) > 0) {
238 if (pa_stream_peek(s, &data, &length) < 0) {
239 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
245 pa_assert(length > 0);
248 buffer = pa_xrealloc(buffer, buffer_length + length);
249 memcpy((uint8_t*) buffer + buffer_length, data, length);
250 buffer_length += length;
252 buffer = pa_xmalloc(length);
253 memcpy(buffer, data, length);
254 buffer_length = length;
264 while (pa_stream_readable_size(s) > 0) {
268 if (pa_stream_peek(s, &data, &length) < 0) {
269 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
275 pa_assert(length > 0);
277 if (writef_function) {
278 size_t k = pa_frame_size(&sample_spec);
280 if ((bytes = writef_function(sndfile, data, (sf_count_t) (length/k))) > 0)
281 bytes *= (sf_count_t) k;
284 bytes = sf_write_raw(sndfile, data, (sf_count_t) length);
286 if (bytes < (sf_count_t) length)
294 /* This routine is called whenever the stream state changes */
295 static void stream_state_callback(pa_stream *s, void *userdata) {
298 switch (pa_stream_get_state(s)) {
299 case PA_STREAM_CREATING:
300 case PA_STREAM_TERMINATED:
303 case PA_STREAM_READY:
306 const pa_buffer_attr *a;
307 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
309 pa_log(_("Stream successfully created."));
311 if (!(a = pa_stream_get_buffer_attr(s)))
312 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
315 if (mode == PLAYBACK)
316 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a->maxlength, a->tlength, a->prebuf, a->minreq);
318 pa_assert(mode == RECORD);
319 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a->maxlength, a->fragsize);
323 pa_log(_("Using sample spec '%s', channel map '%s'."),
324 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
325 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
327 pa_log(_("Connected to device %s (%u, %ssuspended)."),
328 pa_stream_get_device_name(s),
329 pa_stream_get_device_index(s),
330 pa_stream_is_suspended(s) ? "" : "not ");
335 case PA_STREAM_FAILED:
337 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
342 static void stream_suspended_callback(pa_stream *s, void *userdata) {
346 if (pa_stream_is_suspended(s))
347 pa_log(_("Stream device suspended.%s"), CLEAR_LINE);
349 pa_log(_("Stream device resumed.%s"), CLEAR_LINE);
353 static void stream_underflow_callback(pa_stream *s, void *userdata) {
357 pa_log(_("Stream underrun.%s"), CLEAR_LINE);
360 static void stream_overflow_callback(pa_stream *s, void *userdata) {
364 pa_log(_("Stream overrun.%s"), CLEAR_LINE);
367 static void stream_started_callback(pa_stream *s, void *userdata) {
371 pa_log(_("Stream started.%s"), CLEAR_LINE);
374 static void stream_moved_callback(pa_stream *s, void *userdata) {
378 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);
381 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
385 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE);
388 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
395 t = pa_proplist_to_string_sep(pl, ", ");
396 pa_log("Got event '%s', properties '%s'", name, t);
400 /* This is called whenever the context status changes */
401 static void context_state_callback(pa_context *c, void *userdata) {
404 switch (pa_context_get_state(c)) {
405 case PA_CONTEXT_CONNECTING:
406 case PA_CONTEXT_AUTHORIZING:
407 case PA_CONTEXT_SETTING_NAME:
410 case PA_CONTEXT_READY: {
411 pa_buffer_attr buffer_attr;
412 const pa_buffer_attr *active_buffer_attr = NULL;
418 pa_log(_("Connection established.%s"), CLEAR_LINE);
420 if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) {
421 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c)));
425 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
426 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
427 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
428 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
429 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
430 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
431 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
432 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
433 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
434 pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
436 pa_zero(buffer_attr);
437 buffer_attr.maxlength = (uint32_t) -1;
438 buffer_attr.prebuf = (uint32_t) -1;
440 if (latency_msec > 0) {
441 buffer_attr.fragsize = buffer_attr.tlength = pa_usec_to_bytes(latency_msec * PA_USEC_PER_MSEC, &sample_spec);
442 active_buffer_attr = &buffer_attr;
443 flags |= PA_STREAM_ADJUST_LATENCY;
444 } else if (latency > 0) {
445 buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) latency;
446 active_buffer_attr = &buffer_attr;
447 flags |= PA_STREAM_ADJUST_LATENCY;
449 buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) -1;
451 if (process_time_msec > 0) {
452 buffer_attr.minreq = pa_usec_to_bytes(process_time_msec * PA_USEC_PER_MSEC, &sample_spec);
453 active_buffer_attr = &buffer_attr;
454 } else if (process_time > 0) {
455 buffer_attr.minreq = (uint32_t) process_time;
456 active_buffer_attr = &buffer_attr;
458 buffer_attr.minreq = (uint32_t) -1;
460 if (mode == PLAYBACK) {
462 if (pa_stream_connect_playback(stream, device, active_buffer_attr, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL) < 0) {
463 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c)));
468 if (pa_stream_connect_record(stream, device, active_buffer_attr, flags) < 0) {
469 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c)));
477 case PA_CONTEXT_TERMINATED:
481 case PA_CONTEXT_FAILED:
483 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
494 /* New data on STDIN **/
495 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
499 pa_assert(a == mainloop_api);
501 pa_assert(stdio_event == e);
504 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
508 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
511 buffer = pa_xmalloc(l);
513 if ((r = read(fd, buffer, l)) <= 0) {
516 pa_log(_("Got EOF."));
521 pa_log(_("read() failed: %s"), strerror(errno));
525 mainloop_api->io_free(stdio_event);
530 buffer_length = (uint32_t) r;
537 /* Some data may be written to STDOUT */
538 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
541 pa_assert(a == mainloop_api);
543 pa_assert(stdio_event == e);
546 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
550 pa_assert(buffer_length);
552 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
553 pa_log(_("write() failed: %s"), strerror(errno));
556 mainloop_api->io_free(stdio_event);
561 buffer_length -= (uint32_t) r;
562 buffer_index += (uint32_t) r;
564 if (!buffer_length) {
567 buffer_length = buffer_index = 0;
571 /* UNIX signal to quit recieved */
572 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
574 pa_log(_("Got signal, exiting."));
578 /* Show the current latency */
579 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
586 pa_stream_get_time(s, &usec) < 0 ||
587 pa_stream_get_latency(s, &l, &negative) < 0) {
588 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context)));
593 fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec."),
594 (float) usec / 1000000,
595 (float) l * (negative?-1.0f:1.0f));
596 fprintf(stderr, " \r");
599 /* Someone requested that the latency is shown */
600 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
605 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
608 static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
609 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
611 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
612 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context)));
614 pa_operation_unref(o);
617 pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
620 static void help(const char *argv0) {
622 printf(_("%s [options]\n\n"
623 " -h, --help Show this help\n"
624 " --version Show version\n\n"
625 " -r, --record Create a connection for recording\n"
626 " -p, --playback Create a connection for playback\n\n"
627 " -v, --verbose Enable verbose operations\n\n"
628 " -s, --server=SERVER The name of the server to connect to\n"
629 " -d, --device=DEVICE The name of the sink/source to connect to\n"
630 " -n, --client-name=NAME How to call this client on the server\n"
631 " --stream-name=NAME How to call this stream on the server\n"
632 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
633 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
634 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
635 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
636 " s24-32le, s24-32be (defaults to s16ne)\n"
637 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
639 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
640 " --fix-format Take the sample format from the sink the stream is\n"
641 " being connected to.\n"
642 " --fix-rate Take the sampling rate from the sink the stream is\n"
643 " being connected to.\n"
644 " --fix-channels Take the number of channels and the channel map\n"
645 " from the sink the stream is being connected to.\n"
646 " --no-remix Don't upmix or downmix channels.\n"
647 " --no-remap Map channels by index instead of name.\n"
648 " --latency=BYTES Request the specified latency in bytes.\n"
649 " --process-time=BYTES Request the specified process time per request in bytes.\n"
650 " --latency-msec=MSEC Request the specified latency in msec.\n"
651 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
652 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
653 " --raw Record/play raw PCM data.\n"
654 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
655 " --list-file-formats List available file formats.\n")
677 ARG_LIST_FILE_FORMATS,
679 ARG_PROCESS_TIME_MSEC
682 int main(int argc, char *argv[]) {
683 pa_mainloop* m = NULL;
685 char *bn, *server = NULL;
686 pa_time_event *time_event = NULL;
687 const char *filename = NULL;
689 static const struct option long_options[] = {
690 {"record", 0, NULL, 'r'},
691 {"playback", 0, NULL, 'p'},
692 {"device", 1, NULL, 'd'},
693 {"server", 1, NULL, 's'},
694 {"client-name", 1, NULL, 'n'},
695 {"stream-name", 1, NULL, ARG_STREAM_NAME},
696 {"version", 0, NULL, ARG_VERSION},
697 {"help", 0, NULL, 'h'},
698 {"verbose", 0, NULL, 'v'},
699 {"volume", 1, NULL, ARG_VOLUME},
700 {"rate", 1, NULL, ARG_SAMPLERATE},
701 {"format", 1, NULL, ARG_SAMPLEFORMAT},
702 {"channels", 1, NULL, ARG_CHANNELS},
703 {"channel-map", 1, NULL, ARG_CHANNELMAP},
704 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
705 {"fix-rate", 0, NULL, ARG_FIX_RATE},
706 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
707 {"no-remap", 0, NULL, ARG_NO_REMAP},
708 {"no-remix", 0, NULL, ARG_NO_REMIX},
709 {"latency", 1, NULL, ARG_LATENCY},
710 {"process-time", 1, NULL, ARG_PROCESS_TIME},
711 {"property", 1, NULL, ARG_PROPERTY},
712 {"raw", 0, NULL, ARG_RAW},
713 {"file-format", 2, NULL, ARG_FILE_FORMAT},
714 {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
715 {"latency-msec", 1, NULL, ARG_LATENCY_MSEC},
716 {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC},
720 setlocale(LC_ALL, "");
721 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
723 bn = pa_path_get_filename(argv[0]);
725 if (strstr(bn, "play")) {
728 } else if (strstr(bn, "record")) {
731 } else if (strstr(bn, "cat")) {
734 } if (strstr(bn, "rec") || strstr(bn, "mon")) {
739 proplist = pa_proplist_new();
741 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
750 printf(_("pacat %s\n"
751 "Compiled with libpulse %s\n"
752 "Linked with libpulse %s\n"),
754 pa_get_headers_version(),
755 pa_get_library_version());
769 device = pa_xstrdup(optarg);
774 server = pa_xstrdup(optarg);
780 if (!(t = pa_locale_to_utf8(optarg)) ||
781 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
783 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
792 case ARG_STREAM_NAME: {
795 if (!(t = pa_locale_to_utf8(optarg)) ||
796 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {
798 pa_log(_("Invalid stream name '%s'"), t ? t : optarg);
812 int v = atoi(optarg);
813 volume = v < 0 ? 0U : (pa_volume_t) v;
814 volume_is_set = TRUE;
819 sample_spec.channels = (uint8_t) atoi(optarg);
820 sample_spec_set = TRUE;
823 case ARG_SAMPLEFORMAT:
824 sample_spec.format = pa_parse_sample_format(optarg);
825 sample_spec_set = TRUE;
829 sample_spec.rate = (uint32_t) atoi(optarg);
830 sample_spec_set = TRUE;
834 if (!pa_channel_map_parse(&channel_map, optarg)) {
835 pa_log(_("Invalid channel map '%s'"), optarg);
839 channel_map_set = TRUE;
842 case ARG_FIX_CHANNELS:
843 flags |= PA_STREAM_FIX_CHANNELS;
847 flags |= PA_STREAM_FIX_RATE;
851 flags |= PA_STREAM_FIX_FORMAT;
855 flags |= PA_STREAM_NO_REMIX_CHANNELS;
859 flags |= PA_STREAM_NO_REMAP_CHANNELS;
863 if (((latency = (size_t) atoi(optarg))) <= 0) {
864 pa_log(_("Invalid latency specification '%s'"), optarg);
869 case ARG_PROCESS_TIME:
870 if (((process_time = (size_t) atoi(optarg))) <= 0) {
871 pa_log(_("Invalid process time specification '%s'"), optarg);
876 case ARG_LATENCY_MSEC:
877 if (((latency_msec = (int32_t) atoi(optarg))) <= 0) {
878 pa_log(_("Invalid latency specification '%s'"), optarg);
883 case ARG_PROCESS_TIME_MSEC:
884 if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) {
885 pa_log(_("Invalid process time specification '%s'"), optarg);
893 if (!(t = pa_locale_to_utf8(optarg)) ||
894 pa_proplist_setp(proplist, t) < 0) {
897 pa_log(_("Invalid property '%s'"), optarg);
909 case ARG_FILE_FORMAT:
913 if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
914 pa_log(_("Unknown file format %s."), optarg);
922 case ARG_LIST_FILE_FORMATS:
923 pa_sndfile_dump_formats();
932 if (!pa_sample_spec_valid(&sample_spec)) {
933 pa_log(_("Invalid sample specification"));
937 if (optind+1 == argc) {
940 filename = argv[optind];
942 if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
943 pa_log(_("open(): %s"), strerror(errno));
947 if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
948 pa_log(_("dup2(): %s"), strerror(errno));
954 } else if (optind+1 <= argc) {
955 pa_log(_("Too many arguments."));
963 if (mode == RECORD) {
964 /* This might patch up the sample spec */
965 if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
966 pa_log(_("Failed to generate sample specification for file."));
970 /* Transparently upgrade classic .wav to wavex for multichannel audio */
971 if (file_format <= 0) {
972 if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT &&
973 channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) ||
974 (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO))))
975 file_format = SF_FORMAT_WAV;
977 file_format = SF_FORMAT_WAVEX;
980 sfi.format |= file_format;
983 if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
984 mode == RECORD ? SFM_WRITE : SFM_READ,
986 pa_log(_("Failed to open audio file."));
990 if (mode == PLAYBACK) {
992 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
994 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
995 pa_log(_("Failed to determine sample specification from file."));
998 sample_spec_set = TRUE;
1000 if (!channel_map_set) {
1001 /* Allow the user to overwrite the channel map on the command line */
1002 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1003 if (sample_spec.channels > 2)
1004 pa_log(_("Warning: Failed to determine channel map from file."));
1006 channel_map_set = TRUE;
1011 if (!channel_map_set)
1012 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1014 if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
1015 pa_log(_("Channel map doesn't match sample specification"));
1022 if (mode == PLAYBACK)
1023 readf_function = pa_sndfile_readf_function(&sample_spec);
1025 if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
1026 pa_log(_("Warning: failed to write channel map to file."));
1028 writef_function = pa_sndfile_writef_function(&sample_spec);
1031 /* Fill in libsndfile prop list data */
1032 sfp = pa_proplist_new();
1033 pa_sndfile_init_proplist(sndfile, sfp);
1034 pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
1035 pa_proplist_free(sfp);
1039 char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1041 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1042 mode == RECORD ? _("recording") : _("playback"),
1043 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1044 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1047 /* Fill in client name if none was set */
1048 if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1051 if ((t = pa_locale_to_utf8(bn))) {
1052 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1057 /* Fill in media name if none was set */
1058 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1061 if ((t = filename) ||
1062 (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1063 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1066 /* Set up a new main loop */
1067 if (!(m = pa_mainloop_new())) {
1068 pa_log(_("pa_mainloop_new() failed."));
1072 mainloop_api = pa_mainloop_get_api(m);
1074 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1075 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1076 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1078 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1080 pa_disable_sigpipe();
1083 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1084 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1085 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1086 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
1087 pa_log(_("io_new() failed."));
1092 /* Create a new connection context */
1093 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1094 pa_log(_("pa_context_new() failed."));
1098 pa_context_set_state_callback(context, context_state_callback, NULL);
1100 /* Connect the context */
1101 if (pa_context_connect(context, server, 0, NULL) < 0) {
1102 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1107 if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1108 pa_log(_("pa_context_rttime_new() failed."));
1113 /* Run the main loop */
1114 if (pa_mainloop_run(m, &ret) < 0) {
1115 pa_log(_("pa_mainloop_run() failed."));
1121 pa_stream_unref(stream);
1124 pa_context_unref(context);
1127 pa_assert(mainloop_api);
1128 mainloop_api->io_free(stdio_event);
1132 pa_assert(mainloop_api);
1133 mainloop_api->time_free(time_event);
1138 pa_mainloop_free(m);
1150 pa_proplist_free(proplist);