Use LGPL 2.1 on all files previously using LGPL 2
[profile/ivi/pulseaudio.git] / src / utils / pacat.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <signal.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <getopt.h>
35 #include <fcntl.h>
36 #include <locale.h>
37
38 #include <pulse/i18n.h>
39 #include <pulse/pulseaudio.h>
40
41 #define TIME_EVENT_USEC 50000
42
43 #define CLEAR_LINE "\x1B[K"
44
45 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
46
47 static pa_context *context = NULL;
48 static pa_stream *stream = NULL;
49 static pa_mainloop_api *mainloop_api = NULL;
50
51 static void *buffer = NULL;
52 static size_t buffer_length = 0, buffer_index = 0;
53
54 static pa_io_event* stdio_event = NULL;
55
56 static char *stream_name = NULL, *client_name = NULL, *device = NULL;
57
58 static int verbose = 0;
59 static pa_volume_t volume = PA_VOLUME_NORM;
60 static int volume_is_set = 0;
61
62 static pa_sample_spec sample_spec = {
63     .format = PA_SAMPLE_S16LE,
64     .rate = 44100,
65     .channels = 2
66 };
67
68 static pa_channel_map channel_map;
69 static int channel_map_set = 0;
70
71 static pa_stream_flags_t flags = 0;
72
73 static size_t latency = 0, process_time=0;
74
75 /* A shortcut for terminating the application */
76 static void quit(int ret) {
77     assert(mainloop_api);
78     mainloop_api->quit(mainloop_api, ret);
79 }
80
81 /* Write some data to the stream */
82 static void do_stream_write(size_t length) {
83     size_t l;
84     assert(length);
85
86     if (!buffer || !buffer_length)
87         return;
88
89     l = length;
90     if (l > buffer_length)
91         l = buffer_length;
92
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)));
95         quit(1);
96         return;
97     }
98
99     buffer_length -= l;
100     buffer_index += l;
101
102     if (!buffer_length) {
103         pa_xfree(buffer);
104         buffer = NULL;
105         buffer_index = buffer_length = 0;
106     }
107 }
108
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) {
111     assert(s);
112     assert(length > 0);
113
114     if (stdio_event)
115         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
116
117     if (!buffer)
118         return;
119
120     do_stream_write(length);
121 }
122
123 /* This is called whenever new data may is available */
124 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
125     const void *data;
126     assert(s);
127     assert(length > 0);
128
129     if (stdio_event)
130         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
131
132     if (pa_stream_peek(s, &data, &length) < 0) {
133         fprintf(stderr, _("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
134         quit(1);
135         return;
136     }
137
138     assert(data);
139     assert(length > 0);
140
141     if (buffer) {
142         buffer = pa_xrealloc(buffer, buffer_length + length);
143         memcpy((uint8_t*) buffer + buffer_length, data, length);
144         buffer_length += length;
145     } else {
146         buffer = pa_xmalloc(length);
147         memcpy(buffer, data, length);
148         buffer_length = length;
149         buffer_index = 0;
150     }
151
152     pa_stream_drop(s);
153 }
154
155 /* This routine is called whenever the stream state changes */
156 static void stream_state_callback(pa_stream *s, void *userdata) {
157     assert(s);
158
159     switch (pa_stream_get_state(s)) {
160         case PA_STREAM_CREATING:
161         case PA_STREAM_TERMINATED:
162             break;
163
164         case PA_STREAM_READY:
165             if (verbose) {
166                 const pa_buffer_attr *a;
167                 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
168
169                 fprintf(stderr, _("Stream successfully created.\n"));
170
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))));
173                 else {
174
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);
177                     else {
178                         assert(mode == RECORD);
179                         fprintf(stderr, _("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize);
180                     }
181                 }
182
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)));
186
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 ");
191             }
192
193             break;
194
195         case PA_STREAM_FAILED:
196         default:
197             fprintf(stderr, _("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
198             quit(1);
199     }
200 }
201
202 static void stream_suspended_callback(pa_stream *s, void *userdata) {
203     assert(s);
204
205     if (verbose) {
206         if (pa_stream_is_suspended(s))
207             fprintf(stderr, _("Stream device suspended.%s \n"), CLEAR_LINE);
208         else
209             fprintf(stderr, _("Stream device resumed.%s \n"), CLEAR_LINE);
210     }
211 }
212
213 static void stream_underflow_callback(pa_stream *s, void *userdata) {
214     assert(s);
215
216     if (verbose)
217         fprintf(stderr, _("Stream underrun.%s \n"),  CLEAR_LINE);
218 }
219
220 static void stream_overflow_callback(pa_stream *s, void *userdata) {
221     assert(s);
222
223     if (verbose)
224         fprintf(stderr, _("Stream overrun.%s \n"), CLEAR_LINE);
225 }
226
227 static void stream_started_callback(pa_stream *s, void *userdata) {
228     assert(s);
229
230     if (verbose)
231         fprintf(stderr, _("Stream started.%s \n"), CLEAR_LINE);
232 }
233
234 static void stream_moved_callback(pa_stream *s, void *userdata) {
235     assert(s);
236
237     if (verbose)
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);
239 }
240
241 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
242     char *t;
243
244     assert(s);
245     assert(name);
246     assert(pl);
247
248     t = pa_proplist_to_string_sep(pl, ", ");
249     fprintf(stderr, "Got event '%s', properties '%s'\n", name, t);
250     pa_xfree(t);
251 }
252
253 /* This is called whenever the context status changes */
254 static void context_state_callback(pa_context *c, void *userdata) {
255     assert(c);
256
257     switch (pa_context_get_state(c)) {
258         case PA_CONTEXT_CONNECTING:
259         case PA_CONTEXT_AUTHORIZING:
260         case PA_CONTEXT_SETTING_NAME:
261             break;
262
263         case PA_CONTEXT_READY: {
264             int r;
265             pa_buffer_attr buffer_attr;
266
267             assert(c);
268             assert(!stream);
269
270             if (verbose)
271                 fprintf(stderr, _("Connection established.%s \n"), CLEAR_LINE);
272
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)));
275                 goto fail;
276             }
277
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);
287
288             if (latency > 0) {
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;
296             }
297
298             if (mode == PLAYBACK) {
299                 pa_cvolume cv;
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)));
302                     goto fail;
303                 }
304
305             } else {
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)));
308                     goto fail;
309                 }
310             }
311
312             break;
313         }
314
315         case PA_CONTEXT_TERMINATED:
316             quit(0);
317             break;
318
319         case PA_CONTEXT_FAILED:
320         default:
321             fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
322             goto fail;
323     }
324
325     return;
326
327 fail:
328     quit(1);
329
330 }
331
332 /* Connection draining complete */
333 static void context_drain_complete(pa_context*c, void *userdata) {
334     pa_context_disconnect(c);
335 }
336
337 /* Stream draining complete */
338 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
339
340     if (!success) {
341         fprintf(stderr, _("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
342         quit(1);
343     }
344
345     if (verbose)
346         fprintf(stderr, _("Playback stream drained.\n"));
347
348     pa_stream_disconnect(stream);
349     pa_stream_unref(stream);
350     stream = NULL;
351
352     if (!pa_context_drain(context, context_drain_complete, NULL))
353         pa_context_disconnect(context);
354     else {
355         if (verbose)
356             fprintf(stderr, _("Draining connection to server.\n"));
357     }
358 }
359
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) {
362     size_t l, w = 0;
363     ssize_t r;
364
365     assert(a == mainloop_api);
366     assert(e);
367     assert(stdio_event == e);
368
369     if (buffer) {
370         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
371         return;
372     }
373
374     if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
375         l = 4096;
376
377     buffer = pa_xmalloc(l);
378
379     if ((r = read(fd, buffer, l)) <= 0) {
380         if (r == 0) {
381             if (verbose)
382                 fprintf(stderr, _("Got EOF.\n"));
383
384             if (stream) {
385                 pa_operation *o;
386
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)));
389                     quit(1);
390                     return;
391                 }
392
393                 pa_operation_unref(o);
394             } else
395                 quit(0);
396
397         } else {
398             fprintf(stderr, _("read() failed: %s\n"), strerror(errno));
399             quit(1);
400         }
401
402         mainloop_api->io_free(stdio_event);
403         stdio_event = NULL;
404         return;
405     }
406
407     buffer_length = (uint32_t) r;
408     buffer_index = 0;
409
410     if (w)
411         do_stream_write(w);
412 }
413
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) {
416     ssize_t r;
417
418     assert(a == mainloop_api);
419     assert(e);
420     assert(stdio_event == e);
421
422     if (!buffer) {
423         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
424         return;
425     }
426
427     assert(buffer_length);
428
429     if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
430         fprintf(stderr, _("write() failed: %s\n"), strerror(errno));
431         quit(1);
432
433         mainloop_api->io_free(stdio_event);
434         stdio_event = NULL;
435         return;
436     }
437
438     buffer_length -= (uint32_t) r;
439     buffer_index += (uint32_t) r;
440
441     if (!buffer_length) {
442         pa_xfree(buffer);
443         buffer = NULL;
444         buffer_length = buffer_index = 0;
445     }
446 }
447
448 /* UNIX signal to quit recieved */
449 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
450     if (verbose)
451         fprintf(stderr, _("Got signal, exiting.\n"));
452     quit(0);
453 }
454
455 /* Show the current latency */
456 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
457     pa_usec_t l, usec;
458     int negative = 0;
459
460     assert(s);
461
462     if (!success ||
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)));
466         quit(1);
467         return;
468     }
469
470     fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec.  \r"),
471             (float) usec / 1000000,
472             (float) l * (negative?-1.0f:1.0f));
473 }
474
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) {
477
478     if (!stream)
479         return;
480
481     pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
482 }
483
484 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
485     struct timeval next;
486
487     if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
488         pa_operation *o;
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)));
491         else
492             pa_operation_unref(o);
493     }
494
495     pa_gettimeofday(&next);
496     pa_timeval_add(&next, TIME_EVENT_USEC);
497
498     m->time_restart(e, &next);
499 }
500
501 static void help(const char *argv0) {
502
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"
518            "                                        (defaults to 2)\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")
530            ,
531            argv0);
532 }
533
534 enum {
535     ARG_VERSION = 256,
536     ARG_STREAM_NAME,
537     ARG_VOLUME,
538     ARG_SAMPLERATE,
539     ARG_SAMPLEFORMAT,
540     ARG_CHANNELS,
541     ARG_CHANNELMAP,
542     ARG_FIX_FORMAT,
543     ARG_FIX_RATE,
544     ARG_FIX_CHANNELS,
545     ARG_NO_REMAP,
546     ARG_NO_REMIX,
547     ARG_LATENCY,
548     ARG_PROCESS_TIME
549 };
550
551 int main(int argc, char *argv[]) {
552     pa_mainloop* m = NULL;
553     int ret = 1, r, c;
554     char *bn, *server = NULL;
555     pa_time_event *time_event = NULL;
556
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},
579         {NULL,           0, NULL, 0}
580     };
581
582     setlocale(LC_ALL, "");
583     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
584
585     if (!(bn = strrchr(argv[0], '/')))
586         bn = argv[0];
587     else
588         bn++;
589
590     if (strstr(bn, "rec") || strstr(bn, "mon"))
591         mode = RECORD;
592     else if (strstr(bn, "cat") || strstr(bn, "play"))
593         mode = PLAYBACK;
594
595     while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
596
597         switch (c) {
598             case 'h' :
599                 help(bn);
600                 ret = 0;
601                 goto quit;
602
603             case ARG_VERSION:
604                 printf(_("pacat %s\nCompiled with libpulse %s\nLinked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version());
605                 ret = 0;
606                 goto quit;
607
608             case 'r':
609                 mode = RECORD;
610                 break;
611
612             case 'p':
613                 mode = PLAYBACK;
614                 break;
615
616             case 'd':
617                 pa_xfree(device);
618                 device = pa_xstrdup(optarg);
619                 break;
620
621             case 's':
622                 pa_xfree(server);
623                 server = pa_xstrdup(optarg);
624                 break;
625
626             case 'n':
627                 pa_xfree(client_name);
628                 client_name = pa_xstrdup(optarg);
629                 break;
630
631             case ARG_STREAM_NAME:
632                 pa_xfree(stream_name);
633                 stream_name = pa_xstrdup(optarg);
634                 break;
635
636             case 'v':
637                 verbose = 1;
638                 break;
639
640             case ARG_VOLUME: {
641                 int v = atoi(optarg);
642                 volume = v < 0 ? 0U : (pa_volume_t) v;
643                 volume_is_set = 1;
644                 break;
645             }
646
647             case ARG_CHANNELS:
648                 sample_spec.channels = (uint8_t) atoi(optarg);
649                 break;
650
651             case ARG_SAMPLEFORMAT:
652                 sample_spec.format = pa_parse_sample_format(optarg);
653                 break;
654
655             case ARG_SAMPLERATE:
656                 sample_spec.rate = (uint32_t) atoi(optarg);
657                 break;
658
659             case ARG_CHANNELMAP:
660                 if (!pa_channel_map_parse(&channel_map, optarg)) {
661                     fprintf(stderr, _("Invalid channel map '%s'\n"), optarg);
662                     goto quit;
663                 }
664
665                 channel_map_set = 1;
666                 break;
667
668             case ARG_FIX_CHANNELS:
669                 flags |= PA_STREAM_FIX_CHANNELS;
670                 break;
671
672             case ARG_FIX_RATE:
673                 flags |= PA_STREAM_FIX_RATE;
674                 break;
675
676             case ARG_FIX_FORMAT:
677                 flags |= PA_STREAM_FIX_FORMAT;
678                 break;
679
680             case ARG_NO_REMIX:
681                 flags |= PA_STREAM_NO_REMIX_CHANNELS;
682                 break;
683
684             case ARG_NO_REMAP:
685                 flags |= PA_STREAM_NO_REMAP_CHANNELS;
686                 break;
687
688             case ARG_LATENCY:
689                 if (((latency = (size_t) atoi(optarg))) <= 0) {
690                     fprintf(stderr, _("Invalid latency specification '%s'\n"), optarg);
691                     goto quit;
692                 }
693                 break;
694
695             case ARG_PROCESS_TIME:
696                 if (((process_time = (size_t) atoi(optarg))) <= 0) {
697                     fprintf(stderr, _("Invalid process time specification '%s'\n"), optarg);
698                     goto quit;
699                 }
700                 break;
701
702             default:
703                 goto quit;
704         }
705     }
706
707     if (!pa_sample_spec_valid(&sample_spec)) {
708         fprintf(stderr, _("Invalid sample specification\n"));
709         goto quit;
710     }
711
712     if (channel_map_set && pa_channel_map_compatible(&channel_map, &sample_spec)) {
713         fprintf(stderr, _("Channel map doesn't match sample specification\n"));
714         goto quit;
715     }
716
717     if (verbose) {
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);
721     }
722
723     if (!(optind >= argc)) {
724         if (optind+1 == argc) {
725             int fd;
726
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));
729                 goto quit;
730             }
731
732             if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
733                 fprintf(stderr, _("dup2(): %s\n"), strerror(errno));
734                 goto quit;
735             }
736
737             close(fd);
738
739             if (!stream_name)
740                 stream_name = pa_xstrdup(argv[optind]);
741
742         } else {
743             fprintf(stderr, _("Too many arguments.\n"));
744             goto quit;
745         }
746     }
747
748     if (!client_name)
749         client_name = pa_xstrdup(bn);
750
751     if (!stream_name)
752         stream_name = pa_xstrdup(client_name);
753
754     /* Set up a new main loop */
755     if (!(m = pa_mainloop_new())) {
756         fprintf(stderr, _("pa_mainloop_new() failed.\n"));
757         goto quit;
758     }
759
760     mainloop_api = pa_mainloop_get_api(m);
761
762     r = pa_signal_init(mainloop_api);
763     assert(r == 0);
764     pa_signal_new(SIGINT, exit_signal_callback, NULL);
765     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
766 #ifdef SIGUSR1
767     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
768 #endif
769 #ifdef SIGPIPE
770     signal(SIGPIPE, SIG_IGN);
771 #endif
772
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"));
778         goto quit;
779     }
780
781     /* Create a new connection context */
782     if (!(context = pa_context_new(mainloop_api, client_name))) {
783         fprintf(stderr, _("pa_context_new() failed.\n"));
784         goto quit;
785     }
786
787     pa_context_set_state_callback(context, context_state_callback, NULL);
788
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)));
792         goto quit;
793     }
794
795     if (verbose) {
796         struct timeval tv;
797
798         pa_gettimeofday(&tv);
799         pa_timeval_add(&tv, TIME_EVENT_USEC);
800
801         if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
802             fprintf(stderr, _("time_new() failed.\n"));
803             goto quit;
804         }
805     }
806
807     /* Run the main loop */
808     if (pa_mainloop_run(m, &ret) < 0) {
809         fprintf(stderr, _("pa_mainloop_run() failed.\n"));
810         goto quit;
811     }
812
813 quit:
814     if (stream)
815         pa_stream_unref(stream);
816
817     if (context)
818         pa_context_unref(context);
819
820     if (stdio_event) {
821         assert(mainloop_api);
822         mainloop_api->io_free(stdio_event);
823     }
824
825     if (time_event) {
826         assert(mainloop_api);
827         mainloop_api->time_free(time_event);
828     }
829
830     if (m) {
831         pa_signal_done();
832         pa_mainloop_free(m);
833     }
834
835     pa_xfree(buffer);
836
837     pa_xfree(server);
838     pa_xfree(device);
839     pa_xfree(client_name);
840     pa_xfree(stream_name);
841
842     return ret;
843 }