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
38 #include <pulse/i18n.h>
39 #include <pulse/pulseaudio.h>
41 #define TIME_EVENT_USEC 50000
43 #define CLEAR_LINE "\x1B[K"
45 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
47 static pa_context *context = NULL;
48 static pa_stream *stream = NULL;
49 static pa_mainloop_api *mainloop_api = NULL;
51 static void *buffer = NULL;
52 static size_t buffer_length = 0, buffer_index = 0;
54 static pa_io_event* stdio_event = NULL;
56 static char *stream_name = NULL, *client_name = NULL, *device = NULL;
58 static int verbose = 0;
59 static pa_volume_t volume = PA_VOLUME_NORM;
60 static int volume_is_set = 0;
62 static pa_sample_spec sample_spec = {
63 .format = PA_SAMPLE_S16LE,
68 static pa_channel_map channel_map;
69 static int channel_map_set = 0;
71 static pa_stream_flags_t flags = 0;
73 static size_t latency = 0, process_time=0;
75 /* A shortcut for terminating the application */
76 static void quit(int ret) {
78 mainloop_api->quit(mainloop_api, ret);
81 /* Write some data to the stream */
82 static void do_stream_write(size_t length) {
86 if (!buffer || !buffer_length)
90 if (l > buffer_length)
93 if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
94 fprintf(stderr, _("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context)));
102 if (!buffer_length) {
105 buffer_index = buffer_length = 0;
109 /* This is called whenever new data may be written to the stream */
110 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
115 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
120 do_stream_write(length);
123 /* This is called whenever new data may is available */
124 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
130 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
132 if (pa_stream_peek(s, &data, &length) < 0) {
133 fprintf(stderr, _("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
142 buffer = pa_xrealloc(buffer, buffer_length + length);
143 memcpy((uint8_t*) buffer + buffer_length, data, length);
144 buffer_length += length;
146 buffer = pa_xmalloc(length);
147 memcpy(buffer, data, length);
148 buffer_length = length;
155 /* This routine is called whenever the stream state changes */
156 static void stream_state_callback(pa_stream *s, void *userdata) {
159 switch (pa_stream_get_state(s)) {
160 case PA_STREAM_CREATING:
161 case PA_STREAM_TERMINATED:
164 case PA_STREAM_READY:
166 const pa_buffer_attr *a;
167 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
169 fprintf(stderr, _("Stream successfully created.\n"));
171 if (!(a = pa_stream_get_buffer_attr(s)))
172 fprintf(stderr, _("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
175 if (mode == PLAYBACK)
176 fprintf(stderr, _("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a->maxlength, a->tlength, a->prebuf, a->minreq);
178 assert(mode == RECORD);
179 fprintf(stderr, _("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize);
183 fprintf(stderr, _("Using sample spec '%s', channel map '%s'.\n"),
184 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
185 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
187 fprintf(stderr, _("Connected to device %s (%u, %ssuspended).\n"),
188 pa_stream_get_device_name(s),
189 pa_stream_get_device_index(s),
190 pa_stream_is_suspended(s) ? "" : "not ");
195 case PA_STREAM_FAILED:
197 fprintf(stderr, _("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
202 static void stream_suspended_callback(pa_stream *s, void *userdata) {
206 if (pa_stream_is_suspended(s))
207 fprintf(stderr, _("Stream device suspended.%s \n"), CLEAR_LINE);
209 fprintf(stderr, _("Stream device resumed.%s \n"), CLEAR_LINE);
213 static void stream_underflow_callback(pa_stream *s, void *userdata) {
217 fprintf(stderr, _("Stream underrun.%s \n"), CLEAR_LINE);
220 static void stream_overflow_callback(pa_stream *s, void *userdata) {
224 fprintf(stderr, _("Stream overrun.%s \n"), CLEAR_LINE);
227 static void stream_started_callback(pa_stream *s, void *userdata) {
231 fprintf(stderr, _("Stream started.%s \n"), CLEAR_LINE);
234 static void stream_moved_callback(pa_stream *s, void *userdata) {
238 fprintf(stderr, _("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);
241 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
248 t = pa_proplist_to_string_sep(pl, ", ");
249 fprintf(stderr, "Got event '%s', properties '%s'\n", name, t);
253 /* This is called whenever the context status changes */
254 static void context_state_callback(pa_context *c, void *userdata) {
257 switch (pa_context_get_state(c)) {
258 case PA_CONTEXT_CONNECTING:
259 case PA_CONTEXT_AUTHORIZING:
260 case PA_CONTEXT_SETTING_NAME:
263 case PA_CONTEXT_READY: {
265 pa_buffer_attr buffer_attr;
271 fprintf(stderr, _("Connection established.%s \n"), CLEAR_LINE);
273 if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
274 fprintf(stderr, _("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c)));
278 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
279 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
280 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
281 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
282 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
283 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
284 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
285 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
286 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
289 memset(&buffer_attr, 0, sizeof(buffer_attr));
290 buffer_attr.tlength = (uint32_t) latency;
291 buffer_attr.minreq = (uint32_t) process_time;
292 buffer_attr.maxlength = (uint32_t) -1;
293 buffer_attr.prebuf = (uint32_t) -1;
294 buffer_attr.fragsize = (uint32_t) latency;
295 flags |= PA_STREAM_ADJUST_LATENCY;
298 if (mode == PLAYBACK) {
300 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) {
301 fprintf(stderr, _("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c)));
306 if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) {
307 fprintf(stderr, _("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c)));
315 case PA_CONTEXT_TERMINATED:
319 case PA_CONTEXT_FAILED:
321 fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
332 /* Connection draining complete */
333 static void context_drain_complete(pa_context*c, void *userdata) {
334 pa_context_disconnect(c);
337 /* Stream draining complete */
338 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
341 fprintf(stderr, _("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
346 fprintf(stderr, _("Playback stream drained.\n"));
348 pa_stream_disconnect(stream);
349 pa_stream_unref(stream);
352 if (!pa_context_drain(context, context_drain_complete, NULL))
353 pa_context_disconnect(context);
356 fprintf(stderr, _("Draining connection to server.\n"));
360 /* New data on STDIN **/
361 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
365 assert(a == mainloop_api);
367 assert(stdio_event == e);
370 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
374 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
377 buffer = pa_xmalloc(l);
379 if ((r = read(fd, buffer, l)) <= 0) {
382 fprintf(stderr, _("Got EOF.\n"));
387 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
388 fprintf(stderr, _("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context)));
393 pa_operation_unref(o);
398 fprintf(stderr, _("read() failed: %s\n"), strerror(errno));
402 mainloop_api->io_free(stdio_event);
407 buffer_length = (uint32_t) r;
414 /* Some data may be written to STDOUT */
415 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
418 assert(a == mainloop_api);
420 assert(stdio_event == e);
423 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
427 assert(buffer_length);
429 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
430 fprintf(stderr, _("write() failed: %s\n"), strerror(errno));
433 mainloop_api->io_free(stdio_event);
438 buffer_length -= (uint32_t) r;
439 buffer_index += (uint32_t) r;
441 if (!buffer_length) {
444 buffer_length = buffer_index = 0;
448 /* UNIX signal to quit recieved */
449 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
451 fprintf(stderr, _("Got signal, exiting.\n"));
455 /* Show the current latency */
456 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
463 pa_stream_get_time(s, &usec) < 0 ||
464 pa_stream_get_latency(s, &l, &negative) < 0) {
465 fprintf(stderr, _("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context)));
470 fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec. \r"),
471 (float) usec / 1000000,
472 (float) l * (negative?-1.0f:1.0f));
475 /* Someone requested that the latency is shown */
476 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
481 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
484 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
487 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
489 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
490 fprintf(stderr, _("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context)));
492 pa_operation_unref(o);
495 pa_gettimeofday(&next);
496 pa_timeval_add(&next, TIME_EVENT_USEC);
498 m->time_restart(e, &next);
501 static void help(const char *argv0) {
503 printf(_("%s [options]\n\n"
504 " -h, --help Show this help\n"
505 " --version Show version\n\n"
506 " -r, --record Create a connection for recording\n"
507 " -p, --playback Create a connection for playback\n\n"
508 " -v, --verbose Enable verbose operations\n\n"
509 " -s, --server=SERVER The name of the server to connect to\n"
510 " -d, --device=DEVICE The name of the sink/source to connect to\n"
511 " -n, --client-name=NAME How to call this client on the server\n"
512 " --stream-name=NAME How to call this stream on the server\n"
513 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
514 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
515 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
516 " float32be, ulaw, alaw, s32le, s32be (defaults to s16ne)\n"
517 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
519 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
520 " --fix-format Take the sample format from the sink the stream is\n"
521 " being connected to.\n"
522 " --fix-rate Take the sampling rate from the sink the stream is\n"
523 " being connected to.\n"
524 " --fix-channels Take the number of channels and the channel map\n"
525 " from the sink the stream is being connected to.\n"
526 " --no-remix Don't upmix or downmix channels.\n"
527 " --no-remap Map channels by index instead of name.\n"
528 " --latency=BYTES Request the specified latency in bytes.\n"
529 " --process-time=BYTES Request the specified process time per request in bytes.\n")
551 int main(int argc, char *argv[]) {
552 pa_mainloop* m = NULL;
554 char *bn, *server = NULL;
555 pa_time_event *time_event = NULL;
557 static const struct option long_options[] = {
558 {"record", 0, NULL, 'r'},
559 {"playback", 0, NULL, 'p'},
560 {"device", 1, NULL, 'd'},
561 {"server", 1, NULL, 's'},
562 {"client-name", 1, NULL, 'n'},
563 {"stream-name", 1, NULL, ARG_STREAM_NAME},
564 {"version", 0, NULL, ARG_VERSION},
565 {"help", 0, NULL, 'h'},
566 {"verbose", 0, NULL, 'v'},
567 {"volume", 1, NULL, ARG_VOLUME},
568 {"rate", 1, NULL, ARG_SAMPLERATE},
569 {"format", 1, NULL, ARG_SAMPLEFORMAT},
570 {"channels", 1, NULL, ARG_CHANNELS},
571 {"channel-map", 1, NULL, ARG_CHANNELMAP},
572 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
573 {"fix-rate", 0, NULL, ARG_FIX_RATE},
574 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
575 {"no-remap", 0, NULL, ARG_NO_REMAP},
576 {"no-remix", 0, NULL, ARG_NO_REMIX},
577 {"latency", 1, NULL, ARG_LATENCY},
578 {"process-time", 1, NULL, ARG_PROCESS_TIME},
582 setlocale(LC_ALL, "");
583 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
585 if (!(bn = strrchr(argv[0], '/')))
590 if (strstr(bn, "rec") || strstr(bn, "mon"))
592 else if (strstr(bn, "cat") || strstr(bn, "play"))
595 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
604 printf(_("pacat %s\nCompiled with libpulse %s\nLinked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version());
618 device = pa_xstrdup(optarg);
623 server = pa_xstrdup(optarg);
627 pa_xfree(client_name);
628 client_name = pa_xstrdup(optarg);
631 case ARG_STREAM_NAME:
632 pa_xfree(stream_name);
633 stream_name = pa_xstrdup(optarg);
641 int v = atoi(optarg);
642 volume = v < 0 ? 0U : (pa_volume_t) v;
648 sample_spec.channels = (uint8_t) atoi(optarg);
651 case ARG_SAMPLEFORMAT:
652 sample_spec.format = pa_parse_sample_format(optarg);
656 sample_spec.rate = (uint32_t) atoi(optarg);
660 if (!pa_channel_map_parse(&channel_map, optarg)) {
661 fprintf(stderr, _("Invalid channel map '%s'\n"), optarg);
668 case ARG_FIX_CHANNELS:
669 flags |= PA_STREAM_FIX_CHANNELS;
673 flags |= PA_STREAM_FIX_RATE;
677 flags |= PA_STREAM_FIX_FORMAT;
681 flags |= PA_STREAM_NO_REMIX_CHANNELS;
685 flags |= PA_STREAM_NO_REMAP_CHANNELS;
689 if (((latency = (size_t) atoi(optarg))) <= 0) {
690 fprintf(stderr, _("Invalid latency specification '%s'\n"), optarg);
695 case ARG_PROCESS_TIME:
696 if (((process_time = (size_t) atoi(optarg))) <= 0) {
697 fprintf(stderr, _("Invalid process time specification '%s'\n"), optarg);
707 if (!pa_sample_spec_valid(&sample_spec)) {
708 fprintf(stderr, _("Invalid sample specification\n"));
712 if (channel_map_set && pa_channel_map_compatible(&channel_map, &sample_spec)) {
713 fprintf(stderr, _("Channel map doesn't match sample specification\n"));
718 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
719 pa_sample_spec_snprint(t, sizeof(t), &sample_spec);
720 fprintf(stderr, _("Opening a %s stream with sample specification '%s'.\n"), mode == RECORD ? _("recording") : _("playback"), t);
723 if (!(optind >= argc)) {
724 if (optind+1 == argc) {
727 if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
728 fprintf(stderr, _("open(): %s\n"), strerror(errno));
732 if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
733 fprintf(stderr, _("dup2(): %s\n"), strerror(errno));
740 stream_name = pa_xstrdup(argv[optind]);
743 fprintf(stderr, _("Too many arguments.\n"));
749 client_name = pa_xstrdup(bn);
752 stream_name = pa_xstrdup(client_name);
754 /* Set up a new main loop */
755 if (!(m = pa_mainloop_new())) {
756 fprintf(stderr, _("pa_mainloop_new() failed.\n"));
760 mainloop_api = pa_mainloop_get_api(m);
762 r = pa_signal_init(mainloop_api);
764 pa_signal_new(SIGINT, exit_signal_callback, NULL);
765 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
767 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
770 signal(SIGPIPE, SIG_IGN);
773 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
774 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
775 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
776 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
777 fprintf(stderr, _("io_new() failed.\n"));
781 /* Create a new connection context */
782 if (!(context = pa_context_new(mainloop_api, client_name))) {
783 fprintf(stderr, _("pa_context_new() failed.\n"));
787 pa_context_set_state_callback(context, context_state_callback, NULL);
789 /* Connect the context */
790 if (pa_context_connect(context, server, 0, NULL) < 0) {
791 fprintf(stderr, _("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
798 pa_gettimeofday(&tv);
799 pa_timeval_add(&tv, TIME_EVENT_USEC);
801 if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
802 fprintf(stderr, _("time_new() failed.\n"));
807 /* Run the main loop */
808 if (pa_mainloop_run(m, &ret) < 0) {
809 fprintf(stderr, _("pa_mainloop_run() failed.\n"));
815 pa_stream_unref(stream);
818 pa_context_unref(context);
821 assert(mainloop_api);
822 mainloop_api->io_free(stdio_event);
826 assert(mainloop_api);
827 mainloop_api->time_free(time_event);
839 pa_xfree(client_name);
840 pa_xfree(stream_name);