pacat: add missing newline
[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_buffer_attr_callback(pa_stream *s, void *userdata) {
242     assert(s);
243
244     if (verbose)
245         fprintf(stderr, _("Stream buffer attributes changed.%s \n"),  CLEAR_LINE);
246 }
247
248 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
249     char *t;
250
251     assert(s);
252     assert(name);
253     assert(pl);
254
255     t = pa_proplist_to_string_sep(pl, ", ");
256     fprintf(stderr, "Got event '%s', properties '%s'\n", name, t);
257     pa_xfree(t);
258 }
259
260 /* This is called whenever the context status changes */
261 static void context_state_callback(pa_context *c, void *userdata) {
262     assert(c);
263
264     switch (pa_context_get_state(c)) {
265         case PA_CONTEXT_CONNECTING:
266         case PA_CONTEXT_AUTHORIZING:
267         case PA_CONTEXT_SETTING_NAME:
268             break;
269
270         case PA_CONTEXT_READY: {
271             int r;
272             pa_buffer_attr buffer_attr;
273
274             assert(c);
275             assert(!stream);
276
277             if (verbose)
278                 fprintf(stderr, _("Connection established.%s \n"), CLEAR_LINE);
279
280             if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
281                 fprintf(stderr, _("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c)));
282                 goto fail;
283             }
284
285             pa_stream_set_state_callback(stream, stream_state_callback, NULL);
286             pa_stream_set_write_callback(stream, stream_write_callback, NULL);
287             pa_stream_set_read_callback(stream, stream_read_callback, NULL);
288             pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
289             pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
290             pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
291             pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
292             pa_stream_set_started_callback(stream, stream_started_callback, NULL);
293             pa_stream_set_event_callback(stream, stream_event_callback, NULL);
294             pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
295
296             if (latency > 0) {
297                 memset(&buffer_attr, 0, sizeof(buffer_attr));
298                 buffer_attr.tlength = (uint32_t) latency;
299                 buffer_attr.minreq = (uint32_t) process_time;
300                 buffer_attr.maxlength = (uint32_t) -1;
301                 buffer_attr.prebuf = (uint32_t) -1;
302                 buffer_attr.fragsize = (uint32_t) latency;
303                 flags |= PA_STREAM_ADJUST_LATENCY;
304             }
305
306             if (mode == PLAYBACK) {
307                 pa_cvolume cv;
308                 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) {
309                     fprintf(stderr, _("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c)));
310                     goto fail;
311                 }
312
313             } else {
314                 if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) {
315                     fprintf(stderr, _("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c)));
316                     goto fail;
317                 }
318             }
319
320             break;
321         }
322
323         case PA_CONTEXT_TERMINATED:
324             quit(0);
325             break;
326
327         case PA_CONTEXT_FAILED:
328         default:
329             fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
330             goto fail;
331     }
332
333     return;
334
335 fail:
336     quit(1);
337
338 }
339
340 /* Connection draining complete */
341 static void context_drain_complete(pa_context*c, void *userdata) {
342     pa_context_disconnect(c);
343 }
344
345 /* Stream draining complete */
346 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
347
348     if (!success) {
349         fprintf(stderr, _("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
350         quit(1);
351     }
352
353     if (verbose)
354         fprintf(stderr, _("Playback stream drained.\n"));
355
356     pa_stream_disconnect(stream);
357     pa_stream_unref(stream);
358     stream = NULL;
359
360     if (!pa_context_drain(context, context_drain_complete, NULL))
361         pa_context_disconnect(context);
362     else {
363         if (verbose)
364             fprintf(stderr, _("Draining connection to server.\n"));
365     }
366 }
367
368 /* New data on STDIN **/
369 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
370     size_t l, w = 0;
371     ssize_t r;
372
373     assert(a == mainloop_api);
374     assert(e);
375     assert(stdio_event == e);
376
377     if (buffer) {
378         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
379         return;
380     }
381
382     if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
383         l = 4096;
384
385     buffer = pa_xmalloc(l);
386
387     if ((r = read(fd, buffer, l)) <= 0) {
388         if (r == 0) {
389             if (verbose)
390                 fprintf(stderr, _("Got EOF.\n"));
391
392             if (stream) {
393                 pa_operation *o;
394
395                 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
396                     fprintf(stderr, _("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context)));
397                     quit(1);
398                     return;
399                 }
400
401                 pa_operation_unref(o);
402             } else
403                 quit(0);
404
405         } else {
406             fprintf(stderr, _("read() failed: %s\n"), strerror(errno));
407             quit(1);
408         }
409
410         mainloop_api->io_free(stdio_event);
411         stdio_event = NULL;
412         return;
413     }
414
415     buffer_length = (uint32_t) r;
416     buffer_index = 0;
417
418     if (w)
419         do_stream_write(w);
420 }
421
422 /* Some data may be written to STDOUT */
423 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
424     ssize_t r;
425
426     assert(a == mainloop_api);
427     assert(e);
428     assert(stdio_event == e);
429
430     if (!buffer) {
431         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
432         return;
433     }
434
435     assert(buffer_length);
436
437     if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
438         fprintf(stderr, _("write() failed: %s\n"), strerror(errno));
439         quit(1);
440
441         mainloop_api->io_free(stdio_event);
442         stdio_event = NULL;
443         return;
444     }
445
446     buffer_length -= (uint32_t) r;
447     buffer_index += (uint32_t) r;
448
449     if (!buffer_length) {
450         pa_xfree(buffer);
451         buffer = NULL;
452         buffer_length = buffer_index = 0;
453     }
454 }
455
456 /* UNIX signal to quit recieved */
457 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
458     if (verbose)
459         fprintf(stderr, _("Got signal, exiting.\n"));
460     quit(0);
461 }
462
463 /* Show the current latency */
464 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
465     pa_usec_t l, usec;
466     int negative = 0;
467
468     assert(s);
469
470     if (!success ||
471         pa_stream_get_time(s, &usec) < 0 ||
472         pa_stream_get_latency(s, &l, &negative) < 0) {
473         fprintf(stderr, _("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context)));
474         quit(1);
475         return;
476     }
477
478     fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec.  \r"),
479             (float) usec / 1000000,
480             (float) l * (negative?-1.0f:1.0f));
481 }
482
483 /* Someone requested that the latency is shown */
484 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
485
486     if (!stream)
487         return;
488
489     pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
490 }
491
492 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
493     struct timeval next;
494
495     if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
496         pa_operation *o;
497         if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
498             fprintf(stderr, _("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context)));
499         else
500             pa_operation_unref(o);
501     }
502
503     pa_gettimeofday(&next);
504     pa_timeval_add(&next, TIME_EVENT_USEC);
505
506     m->time_restart(e, &next);
507 }
508
509 static void help(const char *argv0) {
510
511     printf(_("%s [options]\n\n"
512            "  -h, --help                            Show this help\n"
513            "      --version                         Show version\n\n"
514            "  -r, --record                          Create a connection for recording\n"
515            "  -p, --playback                        Create a connection for playback\n\n"
516            "  -v, --verbose                         Enable verbose operations\n\n"
517            "  -s, --server=SERVER                   The name of the server to connect to\n"
518            "  -d, --device=DEVICE                   The name of the sink/source to connect to\n"
519            "  -n, --client-name=NAME                How to call this client on the server\n"
520            "      --stream-name=NAME                How to call this stream on the server\n"
521            "      --volume=VOLUME                   Specify the initial (linear) volume in range 0...65536\n"
522            "      --rate=SAMPLERATE                 The sample rate in Hz (defaults to 44100)\n"
523            "      --format=SAMPLEFORMAT             The sample type, one of s16le, s16be, u8, float32le,\n"
524            "                                        float32be, ulaw, alaw, s32le, s32be (defaults to s16ne)\n"
525            "      --channels=CHANNELS               The number of channels, 1 for mono, 2 for stereo\n"
526            "                                        (defaults to 2)\n"
527            "      --channel-map=CHANNELMAP          Channel map to use instead of the default\n"
528            "      --fix-format                      Take the sample format from the sink the stream is\n"
529            "                                        being connected to.\n"
530            "      --fix-rate                        Take the sampling rate from the sink the stream is\n"
531            "                                        being connected to.\n"
532            "      --fix-channels                    Take the number of channels and the channel map\n"
533            "                                        from the sink the stream is being connected to.\n"
534            "      --no-remix                        Don't upmix or downmix channels.\n"
535            "      --no-remap                        Map channels by index instead of name.\n"
536            "      --latency=BYTES                   Request the specified latency in bytes.\n"
537            "      --process-time=BYTES              Request the specified process time per request in bytes.\n")
538            ,
539            argv0);
540 }
541
542 enum {
543     ARG_VERSION = 256,
544     ARG_STREAM_NAME,
545     ARG_VOLUME,
546     ARG_SAMPLERATE,
547     ARG_SAMPLEFORMAT,
548     ARG_CHANNELS,
549     ARG_CHANNELMAP,
550     ARG_FIX_FORMAT,
551     ARG_FIX_RATE,
552     ARG_FIX_CHANNELS,
553     ARG_NO_REMAP,
554     ARG_NO_REMIX,
555     ARG_LATENCY,
556     ARG_PROCESS_TIME
557 };
558
559 int main(int argc, char *argv[]) {
560     pa_mainloop* m = NULL;
561     int ret = 1, r, c;
562     char *bn, *server = NULL;
563     pa_time_event *time_event = NULL;
564
565     static const struct option long_options[] = {
566         {"record",       0, NULL, 'r'},
567         {"playback",     0, NULL, 'p'},
568         {"device",       1, NULL, 'd'},
569         {"server",       1, NULL, 's'},
570         {"client-name",  1, NULL, 'n'},
571         {"stream-name",  1, NULL, ARG_STREAM_NAME},
572         {"version",      0, NULL, ARG_VERSION},
573         {"help",         0, NULL, 'h'},
574         {"verbose",      0, NULL, 'v'},
575         {"volume",       1, NULL, ARG_VOLUME},
576         {"rate",         1, NULL, ARG_SAMPLERATE},
577         {"format",       1, NULL, ARG_SAMPLEFORMAT},
578         {"channels",     1, NULL, ARG_CHANNELS},
579         {"channel-map",  1, NULL, ARG_CHANNELMAP},
580         {"fix-format",   0, NULL, ARG_FIX_FORMAT},
581         {"fix-rate",     0, NULL, ARG_FIX_RATE},
582         {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
583         {"no-remap",     0, NULL, ARG_NO_REMAP},
584         {"no-remix",     0, NULL, ARG_NO_REMIX},
585         {"latency",      1, NULL, ARG_LATENCY},
586         {"process-time", 1, NULL, ARG_PROCESS_TIME},
587         {NULL,           0, NULL, 0}
588     };
589
590     setlocale(LC_ALL, "");
591     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
592
593     if (!(bn = strrchr(argv[0], '/')))
594         bn = argv[0];
595     else
596         bn++;
597
598     if (strstr(bn, "rec") || strstr(bn, "mon"))
599         mode = RECORD;
600     else if (strstr(bn, "cat") || strstr(bn, "play"))
601         mode = PLAYBACK;
602
603     while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
604
605         switch (c) {
606             case 'h' :
607                 help(bn);
608                 ret = 0;
609                 goto quit;
610
611             case ARG_VERSION:
612                 printf(_("pacat %s\nCompiled with libpulse %s\nLinked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version());
613                 ret = 0;
614                 goto quit;
615
616             case 'r':
617                 mode = RECORD;
618                 break;
619
620             case 'p':
621                 mode = PLAYBACK;
622                 break;
623
624             case 'd':
625                 pa_xfree(device);
626                 device = pa_xstrdup(optarg);
627                 break;
628
629             case 's':
630                 pa_xfree(server);
631                 server = pa_xstrdup(optarg);
632                 break;
633
634             case 'n':
635                 pa_xfree(client_name);
636                 client_name = pa_xstrdup(optarg);
637                 break;
638
639             case ARG_STREAM_NAME:
640                 pa_xfree(stream_name);
641                 stream_name = pa_xstrdup(optarg);
642                 break;
643
644             case 'v':
645                 verbose = 1;
646                 break;
647
648             case ARG_VOLUME: {
649                 int v = atoi(optarg);
650                 volume = v < 0 ? 0U : (pa_volume_t) v;
651                 volume_is_set = 1;
652                 break;
653             }
654
655             case ARG_CHANNELS:
656                 sample_spec.channels = (uint8_t) atoi(optarg);
657                 break;
658
659             case ARG_SAMPLEFORMAT:
660                 sample_spec.format = pa_parse_sample_format(optarg);
661                 break;
662
663             case ARG_SAMPLERATE:
664                 sample_spec.rate = (uint32_t) atoi(optarg);
665                 break;
666
667             case ARG_CHANNELMAP:
668                 if (!pa_channel_map_parse(&channel_map, optarg)) {
669                     fprintf(stderr, _("Invalid channel map '%s'\n"), optarg);
670                     goto quit;
671                 }
672
673                 channel_map_set = 1;
674                 break;
675
676             case ARG_FIX_CHANNELS:
677                 flags |= PA_STREAM_FIX_CHANNELS;
678                 break;
679
680             case ARG_FIX_RATE:
681                 flags |= PA_STREAM_FIX_RATE;
682                 break;
683
684             case ARG_FIX_FORMAT:
685                 flags |= PA_STREAM_FIX_FORMAT;
686                 break;
687
688             case ARG_NO_REMIX:
689                 flags |= PA_STREAM_NO_REMIX_CHANNELS;
690                 break;
691
692             case ARG_NO_REMAP:
693                 flags |= PA_STREAM_NO_REMAP_CHANNELS;
694                 break;
695
696             case ARG_LATENCY:
697                 if (((latency = (size_t) atoi(optarg))) <= 0) {
698                     fprintf(stderr, _("Invalid latency specification '%s'\n"), optarg);
699                     goto quit;
700                 }
701                 break;
702
703             case ARG_PROCESS_TIME:
704                 if (((process_time = (size_t) atoi(optarg))) <= 0) {
705                     fprintf(stderr, _("Invalid process time specification '%s'\n"), optarg);
706                     goto quit;
707                 }
708                 break;
709
710             default:
711                 goto quit;
712         }
713     }
714
715     if (!pa_sample_spec_valid(&sample_spec)) {
716         fprintf(stderr, _("Invalid sample specification\n"));
717         goto quit;
718     }
719
720     if (channel_map_set && pa_channel_map_compatible(&channel_map, &sample_spec)) {
721         fprintf(stderr, _("Channel map doesn't match sample specification\n"));
722         goto quit;
723     }
724
725     if (verbose) {
726         char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
727         pa_sample_spec_snprint(t, sizeof(t), &sample_spec);
728         fprintf(stderr, _("Opening a %s stream with sample specification '%s'.\n"), mode == RECORD ? _("recording") : _("playback"), t);
729     }
730
731     if (!(optind >= argc)) {
732         if (optind+1 == argc) {
733             int fd;
734
735             if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
736                 fprintf(stderr, _("open(): %s\n"), strerror(errno));
737                 goto quit;
738             }
739
740             if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
741                 fprintf(stderr, _("dup2(): %s\n"), strerror(errno));
742                 goto quit;
743             }
744
745             close(fd);
746
747             if (!stream_name)
748                 stream_name = pa_xstrdup(argv[optind]);
749
750         } else {
751             fprintf(stderr, _("Too many arguments.\n"));
752             goto quit;
753         }
754     }
755
756     if (!client_name)
757         client_name = pa_xstrdup(bn);
758
759     if (!stream_name)
760         stream_name = pa_xstrdup(client_name);
761
762     /* Set up a new main loop */
763     if (!(m = pa_mainloop_new())) {
764         fprintf(stderr, _("pa_mainloop_new() failed.\n"));
765         goto quit;
766     }
767
768     mainloop_api = pa_mainloop_get_api(m);
769
770     r = pa_signal_init(mainloop_api);
771     assert(r == 0);
772     pa_signal_new(SIGINT, exit_signal_callback, NULL);
773     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
774 #ifdef SIGUSR1
775     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
776 #endif
777 #ifdef SIGPIPE
778     signal(SIGPIPE, SIG_IGN);
779 #endif
780
781     if (!(stdio_event = mainloop_api->io_new(mainloop_api,
782                                              mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
783                                              mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
784                                              mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
785         fprintf(stderr, _("io_new() failed.\n"));
786         goto quit;
787     }
788
789     /* Create a new connection context */
790     if (!(context = pa_context_new(mainloop_api, client_name))) {
791         fprintf(stderr, _("pa_context_new() failed.\n"));
792         goto quit;
793     }
794
795     pa_context_set_state_callback(context, context_state_callback, NULL);
796
797     /* Connect the context */
798     if (pa_context_connect(context, server, 0, NULL) < 0) {
799         fprintf(stderr, _("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context)));
800         goto quit;
801     }
802
803     if (verbose) {
804         struct timeval tv;
805
806         pa_gettimeofday(&tv);
807         pa_timeval_add(&tv, TIME_EVENT_USEC);
808
809         if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
810             fprintf(stderr, _("time_new() failed.\n"));
811             goto quit;
812         }
813     }
814
815     /* Run the main loop */
816     if (pa_mainloop_run(m, &ret) < 0) {
817         fprintf(stderr, _("pa_mainloop_run() failed.\n"));
818         goto quit;
819     }
820
821 quit:
822     if (stream)
823         pa_stream_unref(stream);
824
825     if (context)
826         pa_context_unref(context);
827
828     if (stdio_event) {
829         assert(mainloop_api);
830         mainloop_api->io_free(stdio_event);
831     }
832
833     if (time_event) {
834         assert(mainloop_api);
835         mainloop_api->time_free(time_event);
836     }
837
838     if (m) {
839         pa_signal_done();
840         pa_mainloop_free(m);
841     }
842
843     pa_xfree(buffer);
844
845     pa_xfree(server);
846     pa_xfree(device);
847     pa_xfree(client_name);
848     pa_xfree(stream_name);
849
850     return ret;
851 }