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"), pa_strerror(pa_context_errno(context)));
113 pa_log(_("Playback stream drained."));
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."));
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"), 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"), 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 if (pa_stream_begin_write(s, &data, &length) < 0) {
197 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
202 if (readf_function) {
203 size_t k = pa_frame_size(&sample_spec);
205 if ((bytes = readf_function(sndfile, data, (sf_count_t) (length/k))) > 0)
206 bytes *= (sf_count_t) k;
209 bytes = sf_read_raw(sndfile, data, (sf_count_t) length);
212 pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE);
214 pa_stream_cancel_write(s);
216 if (bytes < (sf_count_t) length)
221 /* This is called whenever new data may is available */
222 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
225 pa_assert(length > 0);
231 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
233 while (pa_stream_readable_size(s) > 0) {
236 if (pa_stream_peek(s, &data, &length) < 0) {
237 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
243 pa_assert(length > 0);
246 buffer = pa_xrealloc(buffer, buffer_length + length);
247 memcpy((uint8_t*) buffer + buffer_length, data, length);
248 buffer_length += length;
250 buffer = pa_xmalloc(length);
251 memcpy(buffer, data, length);
252 buffer_length = length;
262 while (pa_stream_readable_size(s) > 0) {
266 if (pa_stream_peek(s, &data, &length) < 0) {
267 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
273 pa_assert(length > 0);
275 if (writef_function) {
276 size_t k = pa_frame_size(&sample_spec);
278 if ((bytes = writef_function(sndfile, data, (sf_count_t) (length/k))) > 0)
279 bytes *= (sf_count_t) k;
282 bytes = sf_write_raw(sndfile, data, (sf_count_t) length);
284 if (bytes < (sf_count_t) length)
292 /* This routine is called whenever the stream state changes */
293 static void stream_state_callback(pa_stream *s, void *userdata) {
296 switch (pa_stream_get_state(s)) {
297 case PA_STREAM_CREATING:
298 case PA_STREAM_TERMINATED:
301 case PA_STREAM_READY:
304 const pa_buffer_attr *a;
305 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
307 pa_log(_("Stream successfully created."));
309 if (!(a = pa_stream_get_buffer_attr(s)))
310 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
313 if (mode == PLAYBACK)
314 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a->maxlength, a->tlength, a->prebuf, a->minreq);
316 pa_assert(mode == RECORD);
317 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a->maxlength, a->fragsize);
321 pa_log(_("Using sample spec '%s', channel map '%s'."),
322 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
323 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
325 pa_log(_("Connected to device %s (%u, %ssuspended)."),
326 pa_stream_get_device_name(s),
327 pa_stream_get_device_index(s),
328 pa_stream_is_suspended(s) ? "" : "not ");
333 case PA_STREAM_FAILED:
335 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
340 static void stream_suspended_callback(pa_stream *s, void *userdata) {
344 if (pa_stream_is_suspended(s))
345 pa_log(_("Stream device suspended.%s"), CLEAR_LINE);
347 pa_log(_("Stream device resumed.%s"), CLEAR_LINE);
351 static void stream_underflow_callback(pa_stream *s, void *userdata) {
355 pa_log(_("Stream underrun.%s"), CLEAR_LINE);
358 static void stream_overflow_callback(pa_stream *s, void *userdata) {
362 pa_log(_("Stream overrun.%s"), CLEAR_LINE);
365 static void stream_started_callback(pa_stream *s, void *userdata) {
369 pa_log(_("Stream started.%s"), CLEAR_LINE);
372 static void stream_moved_callback(pa_stream *s, void *userdata) {
376 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);
379 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
383 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE);
386 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
393 t = pa_proplist_to_string_sep(pl, ", ");
394 pa_log("Got event '%s', properties '%s'", name, t);
398 /* This is called whenever the context status changes */
399 static void context_state_callback(pa_context *c, void *userdata) {
402 switch (pa_context_get_state(c)) {
403 case PA_CONTEXT_CONNECTING:
404 case PA_CONTEXT_AUTHORIZING:
405 case PA_CONTEXT_SETTING_NAME:
408 case PA_CONTEXT_READY: {
409 pa_buffer_attr buffer_attr;
415 pa_log(_("Connection established.%s"), CLEAR_LINE);
417 if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) {
418 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c)));
422 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
423 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
424 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
425 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
426 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
427 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
428 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
429 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
430 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
431 pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
433 pa_zero(buffer_attr);
434 buffer_attr.maxlength = (uint32_t) -1;
435 buffer_attr.prebuf = (uint32_t) -1;
438 buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) latency;
439 buffer_attr.minreq = (uint32_t) process_time;
440 flags |= PA_STREAM_ADJUST_LATENCY;
442 buffer_attr.tlength = (uint32_t) -1;
443 buffer_attr.minreq = (uint32_t) -1;
444 buffer_attr.fragsize = (uint32_t) -1;
447 if (mode == PLAYBACK) {
449 if (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) {
450 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c)));
455 if (pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags) < 0) {
456 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c)));
464 case PA_CONTEXT_TERMINATED:
468 case PA_CONTEXT_FAILED:
470 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
481 /* New data on STDIN **/
482 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
486 pa_assert(a == mainloop_api);
488 pa_assert(stdio_event == e);
491 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
495 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
498 buffer = pa_xmalloc(l);
500 if ((r = read(fd, buffer, l)) <= 0) {
503 pa_log(_("Got EOF."));
508 pa_log(_("read() failed: %s"), strerror(errno));
512 mainloop_api->io_free(stdio_event);
517 buffer_length = (uint32_t) r;
524 /* Some data may be written to STDOUT */
525 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
528 pa_assert(a == mainloop_api);
530 pa_assert(stdio_event == e);
533 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
537 pa_assert(buffer_length);
539 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
540 pa_log(_("write() failed: %s"), strerror(errno));
543 mainloop_api->io_free(stdio_event);
548 buffer_length -= (uint32_t) r;
549 buffer_index += (uint32_t) r;
551 if (!buffer_length) {
554 buffer_length = buffer_index = 0;
558 /* UNIX signal to quit recieved */
559 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
561 pa_log(_("Got signal, exiting."));
565 /* Show the current latency */
566 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
573 pa_stream_get_time(s, &usec) < 0 ||
574 pa_stream_get_latency(s, &l, &negative) < 0) {
575 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context)));
580 fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec."),
581 (float) usec / 1000000,
582 (float) l * (negative?-1.0f:1.0f));
583 fprintf(stderr, " \r");
586 /* Someone requested that the latency is shown */
587 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
592 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
595 static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
596 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
598 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
599 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context)));
601 pa_operation_unref(o);
604 pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
607 static void help(const char *argv0) {
609 printf(_("%s [options]\n\n"
610 " -h, --help Show this help\n"
611 " --version Show version\n\n"
612 " -r, --record Create a connection for recording\n"
613 " -p, --playback Create a connection for playback\n\n"
614 " -v, --verbose Enable verbose operations\n\n"
615 " -s, --server=SERVER The name of the server to connect to\n"
616 " -d, --device=DEVICE The name of the sink/source to connect to\n"
617 " -n, --client-name=NAME How to call this client on the server\n"
618 " --stream-name=NAME How to call this stream on the server\n"
619 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
620 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
621 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
622 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
623 " s24-32le, s24-32be (defaults to s16ne)\n"
624 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
626 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
627 " --fix-format Take the sample format from the sink the stream is\n"
628 " being connected to.\n"
629 " --fix-rate Take the sampling rate from the sink the stream is\n"
630 " being connected to.\n"
631 " --fix-channels Take the number of channels and the channel map\n"
632 " from the sink the stream is being connected to.\n"
633 " --no-remix Don't upmix or downmix channels.\n"
634 " --no-remap Map channels by index instead of name.\n"
635 " --latency=BYTES Request the specified latency in bytes.\n"
636 " --process-time=BYTES Request the specified process time per request in bytes.\n"
637 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
638 " --raw Record/play raw PCM data.\n"
639 " --file-format=FFORMAT Record/play formatted PCM data.\n"
640 " --list-file-formats List available file formats.\n")
662 ARG_LIST_FILE_FORMATS
665 int main(int argc, char *argv[]) {
666 pa_mainloop* m = NULL;
668 char *bn, *server = NULL;
669 pa_time_event *time_event = NULL;
670 const char *filename = NULL;
672 static const struct option long_options[] = {
673 {"record", 0, NULL, 'r'},
674 {"playback", 0, NULL, 'p'},
675 {"device", 1, NULL, 'd'},
676 {"server", 1, NULL, 's'},
677 {"client-name", 1, NULL, 'n'},
678 {"stream-name", 1, NULL, ARG_STREAM_NAME},
679 {"version", 0, NULL, ARG_VERSION},
680 {"help", 0, NULL, 'h'},
681 {"verbose", 0, NULL, 'v'},
682 {"volume", 1, NULL, ARG_VOLUME},
683 {"rate", 1, NULL, ARG_SAMPLERATE},
684 {"format", 1, NULL, ARG_SAMPLEFORMAT},
685 {"channels", 1, NULL, ARG_CHANNELS},
686 {"channel-map", 1, NULL, ARG_CHANNELMAP},
687 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
688 {"fix-rate", 0, NULL, ARG_FIX_RATE},
689 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
690 {"no-remap", 0, NULL, ARG_NO_REMAP},
691 {"no-remix", 0, NULL, ARG_NO_REMIX},
692 {"latency", 1, NULL, ARG_LATENCY},
693 {"process-time", 1, NULL, ARG_PROCESS_TIME},
694 {"property", 1, NULL, ARG_PROPERTY},
695 {"raw", 0, NULL, ARG_RAW},
696 {"file-format", 2, NULL, ARG_FILE_FORMAT},
697 {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
701 setlocale(LC_ALL, "");
702 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
704 bn = pa_path_get_filename(argv[0]);
706 if (strstr(bn, "play")) {
709 } else if (strstr(bn, "record")) {
712 } else if (strstr(bn, "cat")) {
715 } if (strstr(bn, "rec") || strstr(bn, "mon")) {
720 proplist = pa_proplist_new();
722 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
731 printf(_("pacat %s\n"
732 "Compiled with libpulse %s\n"
733 "Linked with libpulse %s\n"),
735 pa_get_headers_version(),
736 pa_get_library_version());
750 device = pa_xstrdup(optarg);
755 server = pa_xstrdup(optarg);
761 if (!(t = pa_locale_to_utf8(optarg)) ||
762 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
764 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
773 case ARG_STREAM_NAME: {
776 if (!(t = pa_locale_to_utf8(optarg)) ||
777 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {
779 pa_log(_("Invalid stream name '%s'"), t ? t : optarg);
793 int v = atoi(optarg);
794 volume = v < 0 ? 0U : (pa_volume_t) v;
795 volume_is_set = TRUE;
800 sample_spec.channels = (uint8_t) atoi(optarg);
801 sample_spec_set = TRUE;
804 case ARG_SAMPLEFORMAT:
805 sample_spec.format = pa_parse_sample_format(optarg);
806 sample_spec_set = TRUE;
810 sample_spec.rate = (uint32_t) atoi(optarg);
811 sample_spec_set = TRUE;
815 if (!pa_channel_map_parse(&channel_map, optarg)) {
816 pa_log(_("Invalid channel map '%s'"), optarg);
820 channel_map_set = TRUE;
823 case ARG_FIX_CHANNELS:
824 flags |= PA_STREAM_FIX_CHANNELS;
828 flags |= PA_STREAM_FIX_RATE;
832 flags |= PA_STREAM_FIX_FORMAT;
836 flags |= PA_STREAM_NO_REMIX_CHANNELS;
840 flags |= PA_STREAM_NO_REMAP_CHANNELS;
844 if (((latency = (size_t) atoi(optarg))) <= 0) {
845 pa_log(_("Invalid latency specification '%s'"), optarg);
850 case ARG_PROCESS_TIME:
851 if (((process_time = (size_t) atoi(optarg))) <= 0) {
852 pa_log(_("Invalid process time specification '%s'"), optarg);
860 if (!(t = pa_locale_to_utf8(optarg)) ||
861 pa_proplist_setp(proplist, t) < 0) {
864 pa_log(_("Invalid property '%s'"), optarg);
876 case ARG_FILE_FORMAT:
880 if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
881 pa_log(_("Unknown file format %s."), optarg);
889 case ARG_LIST_FILE_FORMATS:
890 pa_sndfile_dump_formats();
899 if (!pa_sample_spec_valid(&sample_spec)) {
900 pa_log(_("Invalid sample specification"));
904 if (optind+1 == argc) {
907 filename = argv[optind];
909 if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
910 pa_log(_("open(): %s"), strerror(errno));
914 if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
915 pa_log(_("dup2(): %s"), strerror(errno));
921 } else if (optind+1 <= argc) {
922 pa_log(_("Too many arguments."));
930 if (mode == RECORD) {
931 /* This might patch up the sample spec */
932 if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
933 pa_log(_("Failed to generate sample specification for file."));
937 /* Transparently upgrade classic .wav to wavex for multichannel audio */
938 if (file_format <= 0) {
939 if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT &&
940 channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) ||
941 (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO))))
942 file_format = SF_FORMAT_WAV;
944 file_format = SF_FORMAT_WAVEX;
947 sfi.format |= file_format;
950 if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
951 mode == RECORD ? SFM_WRITE : SFM_READ,
953 pa_log(_("Failed to open audio file."));
957 if (mode == PLAYBACK) {
959 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
961 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
962 pa_log(_("Failed to determine sample specification from file."));
965 sample_spec_set = TRUE;
967 if (!channel_map_set) {
968 /* Allow the user to overwrite the channel map on the command line */
969 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
970 if (sample_spec.channels > 2)
971 pa_log(_("Warning: Failed to determine channel map from file."));
973 channel_map_set = TRUE;
978 if (!channel_map_set)
979 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
981 if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
982 pa_log(_("Channel map doesn't match sample specification"));
989 if (mode == PLAYBACK)
990 readf_function = pa_sndfile_readf_function(&sample_spec);
992 if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
993 pa_log(_("Warning: failed to write channel map to file."));
995 writef_function = pa_sndfile_writef_function(&sample_spec);
998 /* Fill in libsndfile prop list data */
999 sfp = pa_proplist_new();
1000 pa_sndfile_init_proplist(sndfile, sfp);
1001 pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
1002 pa_proplist_free(sfp);
1006 char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1008 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1009 mode == RECORD ? _("recording") : _("playback"),
1010 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1011 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1014 /* Fill in client name if none was set */
1015 if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1018 if ((t = pa_locale_to_utf8(bn))) {
1019 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1024 /* Fill in media name if none was set */
1025 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1028 if ((t = filename) ||
1029 (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1030 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1033 /* Set up a new main loop */
1034 if (!(m = pa_mainloop_new())) {
1035 pa_log(_("pa_mainloop_new() failed."));
1039 mainloop_api = pa_mainloop_get_api(m);
1041 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1042 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1043 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1045 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1047 pa_disable_sigpipe();
1050 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1051 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1052 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1053 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
1054 pa_log(_("io_new() failed."));
1059 /* Create a new connection context */
1060 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1061 pa_log(_("pa_context_new() failed."));
1065 pa_context_set_state_callback(context, context_state_callback, NULL);
1067 /* Connect the context */
1068 if (pa_context_connect(context, server, 0, NULL) < 0) {
1069 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1074 if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1075 pa_log(_("pa_context_rttime_new() failed."));
1080 /* Run the main loop */
1081 if (pa_mainloop_run(m, &ret) < 0) {
1082 pa_log(_("pa_mainloop_run() failed."));
1088 pa_stream_unref(stream);
1091 pa_context_unref(context);
1094 pa_assert(mainloop_api);
1095 mainloop_api->io_free(stdio_event);
1099 pa_assert(mainloop_api);
1100 mainloop_api->time_free(time_event);
1105 pa_mainloop_free(m);
1117 pa_proplist_free(proplist);