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>
49 #define TIME_EVENT_USEC 50000
51 #define CLEAR_LINE "\x1B[K"
53 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
55 static pa_context *context = NULL;
56 static pa_stream *stream = NULL;
57 static pa_mainloop_api *mainloop_api = NULL;
59 static void *buffer = NULL;
60 static size_t buffer_length = 0, buffer_index = 0;
62 static pa_io_event* stdio_event = NULL;
64 static pa_proplist *proplist = NULL;
65 static char *device = NULL;
67 static SNDFILE* sndfile = NULL;
69 static pa_bool_t verbose = FALSE;
70 static pa_volume_t volume = PA_VOLUME_NORM;
71 static pa_bool_t volume_is_set = FALSE;
73 static pa_sample_spec sample_spec = {
74 .format = PA_SAMPLE_S16LE,
78 static pa_bool_t sample_spec_set = FALSE;
80 static pa_channel_map channel_map;
81 static pa_bool_t channel_map_set = FALSE;
83 static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames) = NULL;
84 static sf_count_t (*writef_function)(SNDFILE *_sndfile, const void *ptr, sf_count_t frames) = NULL;
86 static pa_stream_flags_t flags = 0;
88 static size_t latency = 0, process_time = 0;
90 static pa_bool_t raw = TRUE;
91 static int file_format = -1;
93 /* A shortcut for terminating the application */
94 static void quit(int ret) {
95 pa_assert(mainloop_api);
96 mainloop_api->quit(mainloop_api, ret);
99 /* Connection draining complete */
100 static void context_drain_complete(pa_context*c, void *userdata) {
101 pa_context_disconnect(c);
104 /* Stream draining complete */
105 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
108 pa_log(_("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
113 pa_log(_("Playback stream drained.\n"));
115 pa_stream_disconnect(stream);
116 pa_stream_unref(stream);
119 if (!pa_context_drain(context, context_drain_complete, NULL))
120 pa_context_disconnect(context);
123 pa_log(_("Draining connection to server.\n"));
128 static void start_drain(void) {
133 pa_stream_set_write_callback(stream, NULL, NULL);
135 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
136 pa_log(_("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context)));
141 pa_operation_unref(o);
146 /* Write some data to the stream */
147 static void do_stream_write(size_t length) {
151 if (!buffer || !buffer_length)
155 if (l > buffer_length)
158 if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
159 pa_log(_("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context)));
167 if (!buffer_length) {
170 buffer_index = buffer_length = 0;
174 /* This is called whenever new data may be written to the stream */
175 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
177 pa_assert(length > 0);
183 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
188 do_stream_write(length);
196 data = pa_xmalloc(length);
198 if (readf_function) {
199 size_t k = pa_frame_size(&sample_spec);
201 if ((bytes = readf_function(sndfile, data, (sf_count_t) (length/k))) > 0)
202 bytes *= (sf_count_t) k;
205 bytes = sf_read_raw(sndfile, data, (sf_count_t) length);
208 pa_stream_write(s, data, (size_t) bytes, pa_xfree, 0, PA_SEEK_RELATIVE);
212 if (bytes < (sf_count_t) length)
217 /* This is called whenever new data may is available */
218 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
221 pa_assert(length > 0);
227 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
230 while (pa_stream_readable_size(s) > 0) {
233 if (pa_stream_peek(s, &data, &length) < 0) {
234 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
240 pa_assert(length > 0);
243 buffer = pa_xrealloc(buffer, buffer_length + length);
244 memcpy((uint8_t*) buffer + buffer_length, data, length);
245 buffer_length += length;
247 buffer = pa_xmalloc(length);
248 memcpy(buffer, data, length);
249 buffer_length = length;
258 while (pa_stream_readable_size(s) > 0) {
262 if (pa_stream_peek(s, &data, &length) < 0) {
263 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
269 pa_assert(length > 0);
271 if (writef_function) {
272 size_t k = pa_frame_size(&sample_spec);
274 if ((bytes = writef_function(sndfile, data, (sf_count_t) (length/k))) > 0)
275 bytes *= (sf_count_t) k;
278 bytes = sf_write_raw(sndfile, data, (sf_count_t) length);
280 if (bytes < (sf_count_t) length)
288 /* This routine is called whenever the stream state changes */
289 static void stream_state_callback(pa_stream *s, void *userdata) {
292 switch (pa_stream_get_state(s)) {
293 case PA_STREAM_CREATING:
294 case PA_STREAM_TERMINATED:
297 case PA_STREAM_READY:
300 const pa_buffer_attr *a;
301 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
303 pa_log(_("Stream successfully created.\n"));
305 if (!(a = pa_stream_get_buffer_attr(s)))
306 pa_log(_("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
309 if (mode == PLAYBACK)
310 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a->maxlength, a->tlength, a->prebuf, a->minreq);
312 pa_assert(mode == RECORD);
313 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize);
317 pa_log(_("Using sample spec '%s', channel map '%s'.\n"),
318 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
319 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
321 pa_log(_("Connected to device %s (%u, %ssuspended).\n"),
322 pa_stream_get_device_name(s),
323 pa_stream_get_device_index(s),
324 pa_stream_is_suspended(s) ? "" : "not ");
329 case PA_STREAM_FAILED:
331 pa_log(_("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
336 static void stream_suspended_callback(pa_stream *s, void *userdata) {
340 if (pa_stream_is_suspended(s))
341 pa_log(_("Stream device suspended.%s \n"), CLEAR_LINE);
343 pa_log(_("Stream device resumed.%s \n"), CLEAR_LINE);
347 static void stream_underflow_callback(pa_stream *s, void *userdata) {
351 pa_log(_("Stream underrun.%s \n"), CLEAR_LINE);
354 static void stream_overflow_callback(pa_stream *s, void *userdata) {
358 pa_log(_("Stream overrun.%s \n"), CLEAR_LINE);
361 static void stream_started_callback(pa_stream *s, void *userdata) {
365 pa_log(_("Stream started.%s \n"), CLEAR_LINE);
368 static void stream_moved_callback(pa_stream *s, void *userdata) {
372 pa_log(_("Stream moved to device %s (%u, %ssuspended).%s \n"), pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : _("not "), CLEAR_LINE);
375 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
379 pa_log(_("Stream buffer attributes changed.%s \n"), CLEAR_LINE);
382 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
389 t = pa_proplist_to_string_sep(pl, ", ");
390 pa_log("Got event '%s', properties '%s'\n", name, t);
394 /* This is called whenever the context status changes */
395 static void context_state_callback(pa_context *c, void *userdata) {
398 switch (pa_context_get_state(c)) {
399 case PA_CONTEXT_CONNECTING:
400 case PA_CONTEXT_AUTHORIZING:
401 case PA_CONTEXT_SETTING_NAME:
404 case PA_CONTEXT_READY: {
406 pa_buffer_attr buffer_attr;
412 pa_log(_("Connection established.%s \n"), CLEAR_LINE);
414 if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) {
415 pa_log(_("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c)));
419 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
420 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
421 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
422 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
423 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
424 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
425 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
426 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
427 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
428 pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
431 memset(&buffer_attr, 0, sizeof(buffer_attr));
432 buffer_attr.tlength = (uint32_t) latency;
433 buffer_attr.minreq = (uint32_t) process_time;
434 buffer_attr.maxlength = (uint32_t) -1;
435 buffer_attr.prebuf = (uint32_t) -1;
436 buffer_attr.fragsize = (uint32_t) latency;
437 flags |= PA_STREAM_ADJUST_LATENCY;
440 if (mode == PLAYBACK) {
442 if ((r = pa_stream_connect_playback(stream, device, latency > 0 ? &buffer_attr : NULL, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL)) < 0) {
443 pa_log(_("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c)));
448 if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) {
449 pa_log(_("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c)));
457 case PA_CONTEXT_TERMINATED:
461 case PA_CONTEXT_FAILED:
463 pa_log(_("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
474 /* New data on STDIN **/
475 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
479 pa_assert(a == mainloop_api);
481 pa_assert(stdio_event == e);
484 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
488 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
491 buffer = pa_xmalloc(l);
493 if ((r = read(fd, buffer, l)) <= 0) {
496 pa_log(_("Got EOF.\n"));
501 pa_log(_("read() failed: %s\n"), strerror(errno));
505 mainloop_api->io_free(stdio_event);
510 buffer_length = (uint32_t) r;
517 /* Some data may be written to STDOUT */
518 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
521 pa_assert(a == mainloop_api);
523 pa_assert(stdio_event == e);
526 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
530 pa_assert(buffer_length);
532 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
533 pa_log(_("write() failed: %s\n"), strerror(errno));
536 mainloop_api->io_free(stdio_event);
541 buffer_length -= (uint32_t) r;
542 buffer_index += (uint32_t) r;
544 if (!buffer_length) {
547 buffer_length = buffer_index = 0;
551 /* UNIX signal to quit recieved */
552 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
554 pa_log(_("Got signal, exiting.\n"));
558 /* Show the current latency */
559 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
566 pa_stream_get_time(s, &usec) < 0 ||
567 pa_stream_get_latency(s, &l, &negative) < 0) {
568 pa_log(_("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context)));
573 pa_log(_("Time: %0.3f sec; Latency: %0.0f usec. \r"),
574 (float) usec / 1000000,
575 (float) l * (negative?-1.0f:1.0f));
578 /* Someone requested that the latency is shown */
579 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
584 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
587 static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
588 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
590 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
591 pa_log(_("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context)));
593 pa_operation_unref(o);
596 pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
599 static void help(const char *argv0) {
601 printf(_("%s [options]\n\n"
602 " -h, --help Show this help\n"
603 " --version Show version\n\n"
604 " -r, --record Create a connection for recording\n"
605 " -p, --playback Create a connection for playback\n\n"
606 " -v, --verbose Enable verbose operations\n\n"
607 " -s, --server=SERVER The name of the server to connect to\n"
608 " -d, --device=DEVICE The name of the sink/source to connect to\n"
609 " -n, --client-name=NAME How to call this client on the server\n"
610 " --stream-name=NAME How to call this stream on the server\n"
611 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
612 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
613 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
614 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
615 " s24-32le, s24-32be (defaults to s16ne)\n"
616 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
618 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
619 " --fix-format Take the sample format from the sink the stream is\n"
620 " being connected to.\n"
621 " --fix-rate Take the sampling rate from the sink the stream is\n"
622 " being connected to.\n"
623 " --fix-channels Take the number of channels and the channel map\n"
624 " from the sink the stream is being connected to.\n"
625 " --no-remix Don't upmix or downmix channels.\n"
626 " --no-remap Map channels by index instead of name.\n"
627 " --latency=BYTES Request the specified latency in bytes.\n"
628 " --process-time=BYTES Request the specified process time per request in bytes.\n"
629 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
630 " --raw Record/play raw PCM data.\n"
631 " --file-format=FFORMAT Record/play formatted PCM data.\n"
632 " --list-file-formats List available file formats.\n")
654 ARG_LIST_FILE_FORMATS
657 int main(int argc, char *argv[]) {
658 pa_mainloop* m = NULL;
660 char *bn, *server = NULL;
661 pa_time_event *time_event = NULL;
662 const char *filename = NULL;
664 static const struct option long_options[] = {
665 {"record", 0, NULL, 'r'},
666 {"playback", 0, NULL, 'p'},
667 {"device", 1, NULL, 'd'},
668 {"server", 1, NULL, 's'},
669 {"client-name", 1, NULL, 'n'},
670 {"stream-name", 1, NULL, ARG_STREAM_NAME},
671 {"version", 0, NULL, ARG_VERSION},
672 {"help", 0, NULL, 'h'},
673 {"verbose", 0, NULL, 'v'},
674 {"volume", 1, NULL, ARG_VOLUME},
675 {"rate", 1, NULL, ARG_SAMPLERATE},
676 {"format", 1, NULL, ARG_SAMPLEFORMAT},
677 {"channels", 1, NULL, ARG_CHANNELS},
678 {"channel-map", 1, NULL, ARG_CHANNELMAP},
679 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
680 {"fix-rate", 0, NULL, ARG_FIX_RATE},
681 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
682 {"no-remap", 0, NULL, ARG_NO_REMAP},
683 {"no-remix", 0, NULL, ARG_NO_REMIX},
684 {"latency", 1, NULL, ARG_LATENCY},
685 {"process-time", 1, NULL, ARG_PROCESS_TIME},
686 {"property", 1, NULL, ARG_PROPERTY},
687 {"raw", 0, NULL, ARG_RAW},
688 {"file-format", 2, NULL, ARG_FILE_FORMAT},
689 {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
693 setlocale(LC_ALL, "");
694 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
696 bn = pa_path_get_filename(argv[0]);
698 if (strstr(bn, "play")) {
701 } else if (strstr(bn, "record")) {
704 } else if (strstr(bn, "cat")) {
707 } if (strstr(bn, "rec") || strstr(bn, "mon")) {
712 proplist = pa_proplist_new();
714 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
723 printf(_("pacat %s\n"
724 "Compiled with libpulse %s\n"
725 "Linked with libpulse %s\n"),
727 pa_get_headers_version(),
728 pa_get_library_version());
742 device = pa_xstrdup(optarg);
747 server = pa_xstrdup(optarg);
753 if (!(t = pa_locale_to_utf8(optarg)) ||
754 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
756 pa_log(_("Invalid client name '%s'\n"), t ? t : optarg);
765 case ARG_STREAM_NAME: {
767 t = pa_locale_to_utf8(optarg);
769 if (!(t = pa_locale_to_utf8(optarg)) ||
770 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {
772 pa_log(_("Invalid stream name '%s'\n"), t ? t : optarg);
786 int v = atoi(optarg);
787 volume = v < 0 ? 0U : (pa_volume_t) v;
788 volume_is_set = TRUE;
793 sample_spec.channels = (uint8_t) atoi(optarg);
794 sample_spec_set = TRUE;
797 case ARG_SAMPLEFORMAT:
798 sample_spec.format = pa_parse_sample_format(optarg);
799 sample_spec_set = TRUE;
803 sample_spec.rate = (uint32_t) atoi(optarg);
804 sample_spec_set = TRUE;
808 if (!pa_channel_map_parse(&channel_map, optarg)) {
809 pa_log(_("Invalid channel map '%s'\n"), optarg);
813 channel_map_set = TRUE;
816 case ARG_FIX_CHANNELS:
817 flags |= PA_STREAM_FIX_CHANNELS;
821 flags |= PA_STREAM_FIX_RATE;
825 flags |= PA_STREAM_FIX_FORMAT;
829 flags |= PA_STREAM_NO_REMIX_CHANNELS;
833 flags |= PA_STREAM_NO_REMAP_CHANNELS;
837 if (((latency = (size_t) atoi(optarg))) <= 0) {
838 pa_log(_("Invalid latency specification '%s'\n"), optarg);
843 case ARG_PROCESS_TIME:
844 if (((process_time = (size_t) atoi(optarg))) <= 0) {
845 pa_log(_("Invalid process time specification '%s'\n"), optarg);
853 if (!(t = pa_locale_to_utf8(optarg)) ||
854 pa_proplist_setp(proplist, t) < 0) {
857 pa_log(_("Invalid property '%s'\n"), optarg);
869 case ARG_FILE_FORMAT:
873 if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
874 pa_log(_("Unknown file format %s."), optarg);
882 case ARG_LIST_FILE_FORMATS:
883 pa_sndfile_dump_formats();
892 if (!pa_sample_spec_valid(&sample_spec)) {
893 pa_log(_("Invalid sample specification\n"));
897 if (optind+1 == argc) {
900 filename = argv[optind];
902 if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
903 pa_log(_("open(): %s\n"), strerror(errno));
907 if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
908 pa_log(_("dup2(): %s\n"), strerror(errno));
914 } else if (optind+1 <= argc) {
915 pa_log(_("Too many arguments.\n"));
923 if (mode == RECORD) {
924 /* This might patch up the sample spec */
925 if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
926 pa_log(_("Failed to generate sample specification for file.\n"));
930 /* Transparently upgrade classic .wav to wavex for multichannel audio */
931 if (file_format <= 0) {
932 if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT &&
933 channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) ||
934 (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO))))
935 file_format = SF_FORMAT_WAV;
937 file_format = SF_FORMAT_WAVEX;
940 sfi.format |= file_format;
943 if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
944 mode == RECORD ? SFM_WRITE : SFM_READ,
946 pa_log(_("Failed to open audio file.\n"));
950 if (mode == PLAYBACK) {
952 pa_log(_("Warning: specified sample specification will be overwritten with specification from file.\n"));
954 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
955 pa_log(_("Failed to determine sample specification from file.\n"));
958 sample_spec_set = TRUE;
960 if (!channel_map_set) {
961 /* Allow the user to overwrite the channel map on the command line */
962 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
963 if (sample_spec.channels > 2)
964 pa_log(_("Warning: Failed to determine channel map from file.\n"));
966 channel_map_set = TRUE;
971 if (!channel_map_set)
972 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
974 if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
975 pa_log(_("Channel map doesn't match sample specification\n"));
982 if (mode == PLAYBACK)
983 readf_function = pa_sndfile_readf_function(&sample_spec);
985 if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
986 pa_log(_("Warning: failed to write channel map to file.\n"));
988 writef_function = pa_sndfile_writef_function(&sample_spec);
991 /* Fill in libsndfile prop list data */
992 sfp = pa_proplist_new();
993 pa_sndfile_init_proplist(sndfile, sfp);
994 pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
995 pa_proplist_free(sfp);
999 char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1001 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'.\n"),
1002 mode == RECORD ? _("recording") : _("playback"),
1003 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1004 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1007 /* Fill in client name if none was set */
1008 if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1011 if ((t = pa_locale_to_utf8(bn))) {
1012 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1017 /* Fill in media name if none was set */
1018 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1021 if ((t = filename) ||
1022 (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1023 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1026 /* Set up a new main loop */
1027 if (!(m = pa_mainloop_new())) {
1028 pa_log(_("pa_mainloop_new() failed.\n"));
1032 mainloop_api = pa_mainloop_get_api(m);
1034 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1035 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1036 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1038 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1040 pa_disable_sigpipe();
1043 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1044 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1045 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1046 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
1047 pa_log(_("io_new() failed.\n"));
1052 /* Create a new connection context */
1053 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1054 pa_log(_("pa_context_new() failed.\n"));
1058 pa_context_set_state_callback(context, context_state_callback, NULL);
1060 /* Connect the context */
1061 if (pa_context_connect(context, server, 0, NULL) < 0) {
1062 pa_log(_("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context)));
1067 if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1068 pa_log(_("pa_context_rttime_new() failed.\n"));
1073 /* Run the main loop */
1074 if (pa_mainloop_run(m, &ret) < 0) {
1075 pa_log(_("pa_mainloop_run() failed.\n"));
1081 pa_stream_unref(stream);
1084 pa_context_unref(context);
1087 pa_assert(mainloop_api);
1088 mainloop_api->io_free(stdio_event);
1092 pa_assert(mainloop_api);
1093 mainloop_api->time_free(time_event);
1098 pa_mainloop_free(m);
1110 pa_proplist_free(proplist);