Merge branch 'master' into dbus-work
[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 <sndfile.h>
39
40 #include <pulse/i18n.h>
41 #include <pulse/pulseaudio.h>
42 #include <pulse/rtclock.h>
43
44 #include <pulsecore/macro.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/sndfile-util.h>
48
49 #define TIME_EVENT_USEC 50000
50
51 #define CLEAR_LINE "\x1B[K"
52
53 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
54
55 static pa_context *context = NULL;
56 static pa_stream *stream = NULL;
57 static pa_mainloop_api *mainloop_api = NULL;
58
59 static void *buffer = NULL;
60 static size_t buffer_length = 0, buffer_index = 0;
61
62 static pa_io_event* stdio_event = NULL;
63
64 static pa_proplist *proplist = NULL;
65 static char *device = NULL;
66
67 static SNDFILE* sndfile = NULL;
68
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;
72
73 static pa_sample_spec sample_spec = {
74     .format = PA_SAMPLE_S16LE,
75     .rate = 44100,
76     .channels = 2
77 };
78 static pa_bool_t sample_spec_set = FALSE;
79
80 static pa_channel_map channel_map;
81 static pa_bool_t channel_map_set = FALSE;
82
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;
85
86 static pa_stream_flags_t flags = 0;
87
88 static size_t latency = 0, process_time = 0;
89
90 static pa_bool_t raw = TRUE;
91 static int file_format = -1;
92
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);
97 }
98
99 /* Connection draining complete */
100 static void context_drain_complete(pa_context*c, void *userdata) {
101     pa_context_disconnect(c);
102 }
103
104 /* Stream draining complete */
105 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
106
107     if (!success) {
108         pa_log(_("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
109         quit(1);
110     }
111
112     if (verbose)
113         pa_log(_("Playback stream drained.\n"));
114
115     pa_stream_disconnect(stream);
116     pa_stream_unref(stream);
117     stream = NULL;
118
119     if (!pa_context_drain(context, context_drain_complete, NULL))
120         pa_context_disconnect(context);
121     else {
122         if (verbose)
123             pa_log(_("Draining connection to server.\n"));
124     }
125 }
126
127 /* Start draining */
128 static void start_drain(void) {
129
130     if (stream) {
131         pa_operation *o;
132
133         pa_stream_set_write_callback(stream, NULL, NULL);
134
135         if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
136             pa_log(_("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context)));
137             quit(1);
138             return;
139         }
140
141         pa_operation_unref(o);
142     } else
143         quit(0);
144 }
145
146 /* Write some data to the stream */
147 static void do_stream_write(size_t length) {
148     size_t l;
149     pa_assert(length);
150
151     if (!buffer || !buffer_length)
152         return;
153
154     l = length;
155     if (l > buffer_length)
156         l = buffer_length;
157
158     if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
159         pa_log(_("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context)));
160         quit(1);
161         return;
162     }
163
164     buffer_length -= l;
165     buffer_index += l;
166
167     if (!buffer_length) {
168         pa_xfree(buffer);
169         buffer = NULL;
170         buffer_index = buffer_length = 0;
171     }
172 }
173
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) {
176     pa_assert(s);
177     pa_assert(length > 0);
178
179     if (raw) {
180         pa_assert(!sndfile);
181
182         if (stdio_event)
183             mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
184
185         if (!buffer)
186             return;
187
188         do_stream_write(length);
189
190     } else {
191         sf_count_t bytes;
192         void *data;
193
194         pa_assert(sndfile);
195
196         data = pa_xmalloc(length);
197
198         if (readf_function) {
199             size_t k = pa_frame_size(&sample_spec);
200
201             if ((bytes = readf_function(sndfile, data, (sf_count_t) (length/k))) > 0)
202                 bytes *= (sf_count_t) k;
203
204         } else
205             bytes = sf_read_raw(sndfile, data, (sf_count_t) length);
206
207         if (bytes > 0)
208             pa_stream_write(s, data, (size_t) bytes, pa_xfree, 0, PA_SEEK_RELATIVE);
209         else
210             pa_xfree(data);
211
212         if (bytes < (sf_count_t) length)
213             start_drain();
214     }
215 }
216
217 /* This is called whenever new data may is available */
218 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
219
220     pa_assert(s);
221     pa_assert(length > 0);
222
223     if (raw) {
224         pa_assert(!sndfile);
225
226         if (stdio_event)
227             mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
228
229
230         while (pa_stream_readable_size(s) > 0) {
231             const void *data;
232
233             if (pa_stream_peek(s, &data, &length) < 0) {
234                 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
235                 quit(1);
236                 return;
237             }
238
239             pa_assert(data);
240             pa_assert(length > 0);
241
242             if (buffer) {
243                 buffer = pa_xrealloc(buffer, buffer_length + length);
244                 memcpy((uint8_t*) buffer + buffer_length, data, length);
245                 buffer_length += length;
246             } else {
247                 buffer = pa_xmalloc(length);
248                 memcpy(buffer, data, length);
249                 buffer_length = length;
250                 buffer_index = 0;
251             }
252             pa_stream_drop(s);
253         }
254
255     } else {
256         pa_assert(sndfile);
257
258         while (pa_stream_readable_size(s) > 0) {
259             sf_count_t bytes;
260             const void *data;
261
262             if (pa_stream_peek(s, &data, &length) < 0) {
263                 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
264                 quit(1);
265                 return;
266             }
267
268             pa_assert(data);
269             pa_assert(length > 0);
270
271             if (writef_function) {
272                 size_t k = pa_frame_size(&sample_spec);
273
274                 if ((bytes = writef_function(sndfile, data, (sf_count_t) (length/k))) > 0)
275                     bytes *= (sf_count_t) k;
276
277             } else
278                 bytes = sf_write_raw(sndfile, data, (sf_count_t) length);
279
280             if (bytes < (sf_count_t) length)
281                 quit(1);
282
283             pa_stream_drop(s);
284         }
285     }
286 }
287
288 /* This routine is called whenever the stream state changes */
289 static void stream_state_callback(pa_stream *s, void *userdata) {
290     pa_assert(s);
291
292     switch (pa_stream_get_state(s)) {
293         case PA_STREAM_CREATING:
294         case PA_STREAM_TERMINATED:
295             break;
296
297         case PA_STREAM_READY:
298
299             if (verbose) {
300                 const pa_buffer_attr *a;
301                 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
302
303                 pa_log(_("Stream successfully created.\n"));
304
305                 if (!(a = pa_stream_get_buffer_attr(s)))
306                     pa_log(_("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
307                 else {
308
309                     if (mode == PLAYBACK)
310                         pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a->maxlength, a->tlength, a->prebuf, a->minreq);
311                     else {
312                         pa_assert(mode == RECORD);
313                         pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize);
314                     }
315                 }
316
317                 pa_log(_("Using sample spec '%s', channel map '%s'.\n"),
318                         pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
319                         pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
320
321                 pa_log(_("Connected to device %s (%u, %ssuspended).\n"),
322                         pa_stream_get_device_name(s),
323                         pa_stream_get_device_index(s),
324                         pa_stream_is_suspended(s) ? "" : "not ");
325             }
326
327             break;
328
329         case PA_STREAM_FAILED:
330         default:
331             pa_log(_("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
332             quit(1);
333     }
334 }
335
336 static void stream_suspended_callback(pa_stream *s, void *userdata) {
337     pa_assert(s);
338
339     if (verbose) {
340         if (pa_stream_is_suspended(s))
341             pa_log(_("Stream device suspended.%s \n"), CLEAR_LINE);
342         else
343             pa_log(_("Stream device resumed.%s \n"), CLEAR_LINE);
344     }
345 }
346
347 static void stream_underflow_callback(pa_stream *s, void *userdata) {
348     pa_assert(s);
349
350     if (verbose)
351         pa_log(_("Stream underrun.%s \n"),  CLEAR_LINE);
352 }
353
354 static void stream_overflow_callback(pa_stream *s, void *userdata) {
355     pa_assert(s);
356
357     if (verbose)
358         pa_log(_("Stream overrun.%s \n"), CLEAR_LINE);
359 }
360
361 static void stream_started_callback(pa_stream *s, void *userdata) {
362     pa_assert(s);
363
364     if (verbose)
365         pa_log(_("Stream started.%s \n"), CLEAR_LINE);
366 }
367
368 static void stream_moved_callback(pa_stream *s, void *userdata) {
369     pa_assert(s);
370
371     if (verbose)
372         pa_log(_("Stream moved to device %s (%u, %ssuspended).%s \n"), pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : _("not "),  CLEAR_LINE);
373 }
374
375 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
376     pa_assert(s);
377
378     if (verbose)
379         pa_log(_("Stream buffer attributes changed.%s \n"),  CLEAR_LINE);
380 }
381
382 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
383     char *t;
384
385     pa_assert(s);
386     pa_assert(name);
387     pa_assert(pl);
388
389     t = pa_proplist_to_string_sep(pl, ", ");
390     pa_log("Got event '%s', properties '%s'\n", name, t);
391     pa_xfree(t);
392 }
393
394 /* This is called whenever the context status changes */
395 static void context_state_callback(pa_context *c, void *userdata) {
396     pa_assert(c);
397
398     switch (pa_context_get_state(c)) {
399         case PA_CONTEXT_CONNECTING:
400         case PA_CONTEXT_AUTHORIZING:
401         case PA_CONTEXT_SETTING_NAME:
402             break;
403
404         case PA_CONTEXT_READY: {
405             int r;
406             pa_buffer_attr buffer_attr;
407
408             pa_assert(c);
409             pa_assert(!stream);
410
411             if (verbose)
412                 pa_log(_("Connection established.%s \n"), CLEAR_LINE);
413
414             if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) {
415                 pa_log(_("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c)));
416                 goto fail;
417             }
418
419             pa_stream_set_state_callback(stream, stream_state_callback, NULL);
420             pa_stream_set_write_callback(stream, stream_write_callback, NULL);
421             pa_stream_set_read_callback(stream, stream_read_callback, NULL);
422             pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
423             pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
424             pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
425             pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
426             pa_stream_set_started_callback(stream, stream_started_callback, NULL);
427             pa_stream_set_event_callback(stream, stream_event_callback, NULL);
428             pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
429
430             if (latency > 0) {
431                 memset(&buffer_attr, 0, sizeof(buffer_attr));
432                 buffer_attr.tlength = (uint32_t) latency;
433                 buffer_attr.minreq = (uint32_t) process_time;
434                 buffer_attr.maxlength = (uint32_t) -1;
435                 buffer_attr.prebuf = (uint32_t) -1;
436                 buffer_attr.fragsize = (uint32_t) latency;
437                 flags |= PA_STREAM_ADJUST_LATENCY;
438             }
439
440             if (mode == PLAYBACK) {
441                 pa_cvolume cv;
442                 if ((r = pa_stream_connect_playback(stream, device, latency > 0 ? &buffer_attr : NULL, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL)) < 0) {
443                     pa_log(_("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c)));
444                     goto fail;
445                 }
446
447             } else {
448                 if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) {
449                     pa_log(_("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c)));
450                     goto fail;
451                 }
452             }
453
454             break;
455         }
456
457         case PA_CONTEXT_TERMINATED:
458             quit(0);
459             break;
460
461         case PA_CONTEXT_FAILED:
462         default:
463             pa_log(_("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
464             goto fail;
465     }
466
467     return;
468
469 fail:
470     quit(1);
471
472 }
473
474 /* New data on STDIN **/
475 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
476     size_t l, w = 0;
477     ssize_t r;
478
479     pa_assert(a == mainloop_api);
480     pa_assert(e);
481     pa_assert(stdio_event == e);
482
483     if (buffer) {
484         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
485         return;
486     }
487
488     if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
489         l = 4096;
490
491     buffer = pa_xmalloc(l);
492
493     if ((r = read(fd, buffer, l)) <= 0) {
494         if (r == 0) {
495             if (verbose)
496                 pa_log(_("Got EOF.\n"));
497
498             start_drain();
499
500         } else {
501             pa_log(_("read() failed: %s\n"), strerror(errno));
502             quit(1);
503         }
504
505         mainloop_api->io_free(stdio_event);
506         stdio_event = NULL;
507         return;
508     }
509
510     buffer_length = (uint32_t) r;
511     buffer_index = 0;
512
513     if (w)
514         do_stream_write(w);
515 }
516
517 /* Some data may be written to STDOUT */
518 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
519     ssize_t r;
520
521     pa_assert(a == mainloop_api);
522     pa_assert(e);
523     pa_assert(stdio_event == e);
524
525     if (!buffer) {
526         mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
527         return;
528     }
529
530     pa_assert(buffer_length);
531
532     if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
533         pa_log(_("write() failed: %s\n"), strerror(errno));
534         quit(1);
535
536         mainloop_api->io_free(stdio_event);
537         stdio_event = NULL;
538         return;
539     }
540
541     buffer_length -= (uint32_t) r;
542     buffer_index += (uint32_t) r;
543
544     if (!buffer_length) {
545         pa_xfree(buffer);
546         buffer = NULL;
547         buffer_length = buffer_index = 0;
548     }
549 }
550
551 /* UNIX signal to quit recieved */
552 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
553     if (verbose)
554         pa_log(_("Got signal, exiting.\n"));
555     quit(0);
556 }
557
558 /* Show the current latency */
559 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
560     pa_usec_t l, usec;
561     int negative = 0;
562
563     pa_assert(s);
564
565     if (!success ||
566         pa_stream_get_time(s, &usec) < 0 ||
567         pa_stream_get_latency(s, &l, &negative) < 0) {
568         pa_log(_("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context)));
569         quit(1);
570         return;
571     }
572
573     pa_log(_("Time: %0.3f sec; Latency: %0.0f usec.  \r"),
574             (float) usec / 1000000,
575             (float) l * (negative?-1.0f:1.0f));
576 }
577
578 /* Someone requested that the latency is shown */
579 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
580
581     if (!stream)
582         return;
583
584     pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
585 }
586
587 static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
588     if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
589         pa_operation *o;
590         if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
591             pa_log(_("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context)));
592         else
593             pa_operation_unref(o);
594     }
595
596     pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
597 }
598
599 static void help(const char *argv0) {
600
601     printf(_("%s [options]\n\n"
602              "  -h, --help                            Show this help\n"
603              "      --version                         Show version\n\n"
604              "  -r, --record                          Create a connection for recording\n"
605              "  -p, --playback                        Create a connection for playback\n\n"
606              "  -v, --verbose                         Enable verbose operations\n\n"
607              "  -s, --server=SERVER                   The name of the server to connect to\n"
608              "  -d, --device=DEVICE                   The name of the sink/source to connect to\n"
609              "  -n, --client-name=NAME                How to call this client on the server\n"
610              "      --stream-name=NAME                How to call this stream on the server\n"
611              "      --volume=VOLUME                   Specify the initial (linear) volume in range 0...65536\n"
612              "      --rate=SAMPLERATE                 The sample rate in Hz (defaults to 44100)\n"
613              "      --format=SAMPLEFORMAT             The sample type, one of s16le, s16be, u8, float32le,\n"
614              "                                        float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
615              "                                        s24-32le, s24-32be (defaults to s16ne)\n"
616              "      --channels=CHANNELS               The number of channels, 1 for mono, 2 for stereo\n"
617              "                                        (defaults to 2)\n"
618              "      --channel-map=CHANNELMAP          Channel map to use instead of the default\n"
619              "      --fix-format                      Take the sample format from the sink the stream is\n"
620              "                                        being connected to.\n"
621              "      --fix-rate                        Take the sampling rate from the sink the stream is\n"
622              "                                        being connected to.\n"
623              "      --fix-channels                    Take the number of channels and the channel map\n"
624              "                                        from the sink the stream is being connected to.\n"
625              "      --no-remix                        Don't upmix or downmix channels.\n"
626              "      --no-remap                        Map channels by index instead of name.\n"
627              "      --latency=BYTES                   Request the specified latency in bytes.\n"
628              "      --process-time=BYTES              Request the specified process time per request in bytes.\n"
629              "      --property=PROPERTY=VALUE         Set the specified property to the specified value.\n"
630              "      --raw                             Record/play raw PCM data.\n"
631              "      --file-format=FFORMAT             Record/play formatted PCM data.\n"
632              "      --list-file-formats               List available file formats.\n")
633            , argv0);
634 }
635
636 enum {
637     ARG_VERSION = 256,
638     ARG_STREAM_NAME,
639     ARG_VOLUME,
640     ARG_SAMPLERATE,
641     ARG_SAMPLEFORMAT,
642     ARG_CHANNELS,
643     ARG_CHANNELMAP,
644     ARG_FIX_FORMAT,
645     ARG_FIX_RATE,
646     ARG_FIX_CHANNELS,
647     ARG_NO_REMAP,
648     ARG_NO_REMIX,
649     ARG_LATENCY,
650     ARG_PROCESS_TIME,
651     ARG_RAW,
652     ARG_PROPERTY,
653     ARG_FILE_FORMAT,
654     ARG_LIST_FILE_FORMATS
655 };
656
657 int main(int argc, char *argv[]) {
658     pa_mainloop* m = NULL;
659     int ret = 1, c;
660     char *bn, *server = NULL;
661     pa_time_event *time_event = NULL;
662     const char *filename = NULL;
663
664     static const struct option long_options[] = {
665         {"record",       0, NULL, 'r'},
666         {"playback",     0, NULL, 'p'},
667         {"device",       1, NULL, 'd'},
668         {"server",       1, NULL, 's'},
669         {"client-name",  1, NULL, 'n'},
670         {"stream-name",  1, NULL, ARG_STREAM_NAME},
671         {"version",      0, NULL, ARG_VERSION},
672         {"help",         0, NULL, 'h'},
673         {"verbose",      0, NULL, 'v'},
674         {"volume",       1, NULL, ARG_VOLUME},
675         {"rate",         1, NULL, ARG_SAMPLERATE},
676         {"format",       1, NULL, ARG_SAMPLEFORMAT},
677         {"channels",     1, NULL, ARG_CHANNELS},
678         {"channel-map",  1, NULL, ARG_CHANNELMAP},
679         {"fix-format",   0, NULL, ARG_FIX_FORMAT},
680         {"fix-rate",     0, NULL, ARG_FIX_RATE},
681         {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
682         {"no-remap",     0, NULL, ARG_NO_REMAP},
683         {"no-remix",     0, NULL, ARG_NO_REMIX},
684         {"latency",      1, NULL, ARG_LATENCY},
685         {"process-time", 1, NULL, ARG_PROCESS_TIME},
686         {"property",     1, NULL, ARG_PROPERTY},
687         {"raw",          0, NULL, ARG_RAW},
688         {"file-format",  2, NULL, ARG_FILE_FORMAT},
689         {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
690         {NULL,           0, NULL, 0}
691     };
692
693     setlocale(LC_ALL, "");
694     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
695
696     bn = pa_path_get_filename(argv[0]);
697
698     if (strstr(bn, "play")) {
699         mode = PLAYBACK;
700         raw = FALSE;
701     } else if (strstr(bn, "record")) {
702         mode = RECORD;
703         raw = FALSE;
704     } else if (strstr(bn, "cat")) {
705         mode = PLAYBACK;
706         raw = TRUE;
707     } if (strstr(bn, "rec") || strstr(bn, "mon")) {
708         mode = RECORD;
709         raw = TRUE;
710     }
711
712     proplist = pa_proplist_new();
713
714     while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
715
716         switch (c) {
717             case 'h' :
718                 help(bn);
719                 ret = 0;
720                 goto quit;
721
722             case ARG_VERSION:
723                 printf(_("pacat %s\n"
724                          "Compiled with libpulse %s\n"
725                          "Linked with libpulse %s\n"),
726                        PACKAGE_VERSION,
727                        pa_get_headers_version(),
728                        pa_get_library_version());
729                 ret = 0;
730                 goto quit;
731
732             case 'r':
733                 mode = RECORD;
734                 break;
735
736             case 'p':
737                 mode = PLAYBACK;
738                 break;
739
740             case 'd':
741                 pa_xfree(device);
742                 device = pa_xstrdup(optarg);
743                 break;
744
745             case 's':
746                 pa_xfree(server);
747                 server = pa_xstrdup(optarg);
748                 break;
749
750             case 'n': {
751                 char *t;
752
753                 if (!(t = pa_locale_to_utf8(optarg)) ||
754                     pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
755
756                     pa_log(_("Invalid client name '%s'\n"), t ? t : optarg);
757                     pa_xfree(t);
758                     goto quit;
759                 }
760
761                 pa_xfree(t);
762                 break;
763             }
764
765             case ARG_STREAM_NAME: {
766                 char *t;
767                 t = pa_locale_to_utf8(optarg);
768
769                 if (!(t = pa_locale_to_utf8(optarg)) ||
770                     pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {
771
772                     pa_log(_("Invalid stream name '%s'\n"), t ? t : optarg);
773                     pa_xfree(t);
774                     goto quit;
775                 }
776
777                 pa_xfree(t);
778                 break;
779             }
780
781             case 'v':
782                 verbose = 1;
783                 break;
784
785             case ARG_VOLUME: {
786                 int v = atoi(optarg);
787                 volume = v < 0 ? 0U : (pa_volume_t) v;
788                 volume_is_set = TRUE;
789                 break;
790             }
791
792             case ARG_CHANNELS:
793                 sample_spec.channels = (uint8_t) atoi(optarg);
794                 sample_spec_set = TRUE;
795                 break;
796
797             case ARG_SAMPLEFORMAT:
798                 sample_spec.format = pa_parse_sample_format(optarg);
799                 sample_spec_set = TRUE;
800                 break;
801
802             case ARG_SAMPLERATE:
803                 sample_spec.rate = (uint32_t) atoi(optarg);
804                 sample_spec_set = TRUE;
805                 break;
806
807             case ARG_CHANNELMAP:
808                 if (!pa_channel_map_parse(&channel_map, optarg)) {
809                     pa_log(_("Invalid channel map '%s'\n"), optarg);
810                     goto quit;
811                 }
812
813                 channel_map_set = TRUE;
814                 break;
815
816             case ARG_FIX_CHANNELS:
817                 flags |= PA_STREAM_FIX_CHANNELS;
818                 break;
819
820             case ARG_FIX_RATE:
821                 flags |= PA_STREAM_FIX_RATE;
822                 break;
823
824             case ARG_FIX_FORMAT:
825                 flags |= PA_STREAM_FIX_FORMAT;
826                 break;
827
828             case ARG_NO_REMIX:
829                 flags |= PA_STREAM_NO_REMIX_CHANNELS;
830                 break;
831
832             case ARG_NO_REMAP:
833                 flags |= PA_STREAM_NO_REMAP_CHANNELS;
834                 break;
835
836             case ARG_LATENCY:
837                 if (((latency = (size_t) atoi(optarg))) <= 0) {
838                     pa_log(_("Invalid latency specification '%s'\n"), optarg);
839                     goto quit;
840                 }
841                 break;
842
843             case ARG_PROCESS_TIME:
844                 if (((process_time = (size_t) atoi(optarg))) <= 0) {
845                     pa_log(_("Invalid process time specification '%s'\n"), optarg);
846                     goto quit;
847                 }
848                 break;
849
850             case ARG_PROPERTY: {
851                 char *t;
852
853                 if (!(t = pa_locale_to_utf8(optarg)) ||
854                     pa_proplist_setp(proplist, t) < 0) {
855
856                     pa_xfree(t);
857                     pa_log(_("Invalid property '%s'\n"), optarg);
858                     goto quit;
859                 }
860
861                 pa_xfree(t);
862                 break;
863             }
864
865             case ARG_RAW:
866                 raw = TRUE;
867                 break;
868
869             case ARG_FILE_FORMAT:
870                 raw = FALSE;
871
872                 if (optarg) {
873                     if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
874                         pa_log(_("Unknown file format %s."), optarg);
875                         goto quit;
876                     }
877                 }
878
879                 raw = FALSE;
880                 break;
881
882             case ARG_LIST_FILE_FORMATS:
883                 pa_sndfile_dump_formats();
884                 ret = 0;
885                 goto quit;
886
887             default:
888                 goto quit;
889         }
890     }
891
892     if (!pa_sample_spec_valid(&sample_spec)) {
893         pa_log(_("Invalid sample specification\n"));
894         goto quit;
895     }
896
897     if (optind+1 == argc) {
898         int fd;
899
900         filename = argv[optind];
901
902         if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
903             pa_log(_("open(): %s\n"), strerror(errno));
904             goto quit;
905         }
906
907         if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
908             pa_log(_("dup2(): %s\n"), strerror(errno));
909             goto quit;
910         }
911
912         pa_close(fd);
913
914     } else if (optind+1 <= argc) {
915         pa_log(_("Too many arguments.\n"));
916         goto quit;
917     }
918
919     if (!raw) {
920         SF_INFO sfi;
921         pa_zero(sfi);
922
923         if (mode == RECORD) {
924             /* This might patch up the sample spec */
925             if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
926                 pa_log(_("Failed to generate sample specification for file.\n"));
927                 goto quit;
928             }
929
930             /* Transparently upgrade classic .wav to wavex for multichannel audio */
931             if (file_format <= 0) {
932                 if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT &&
933                                                                         channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) ||
934                     (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO))))
935                     file_format = SF_FORMAT_WAV;
936                 else
937                     file_format = SF_FORMAT_WAVEX;
938             }
939
940             sfi.format |= file_format;
941         }
942
943         if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
944                                    mode == RECORD ? SFM_WRITE : SFM_READ,
945                                    &sfi, 0))) {
946             pa_log(_("Failed to open audio file.\n"));
947             goto quit;
948         }
949
950         if (mode == PLAYBACK) {
951             if (sample_spec_set)
952                 pa_log(_("Warning: specified sample specification will be overwritten with specification from file.\n"));
953
954             if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
955                 pa_log(_("Failed to determine sample specification from file.\n"));
956                 goto quit;
957             }
958             sample_spec_set = TRUE;
959
960             if (!channel_map_set) {
961                 /* Allow the user to overwrite the channel map on the command line */
962                 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
963                     if (sample_spec.channels > 2)
964                         pa_log(_("Warning: Failed to determine channel map from file.\n"));
965                 } else
966                     channel_map_set = TRUE;
967             }
968         }
969     }
970
971     if (!channel_map_set)
972         pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
973
974     if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
975         pa_log(_("Channel map doesn't match sample specification\n"));
976         goto quit;
977     }
978
979     if (!raw) {
980         pa_proplist *sfp;
981
982         if (mode == PLAYBACK)
983             readf_function = pa_sndfile_readf_function(&sample_spec);
984         else {
985             if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
986                 pa_log(_("Warning: failed to write channel map to file.\n"));
987
988             writef_function = pa_sndfile_writef_function(&sample_spec);
989         }
990
991         /* Fill in libsndfile prop list data */
992         sfp = pa_proplist_new();
993         pa_sndfile_init_proplist(sndfile, sfp);
994         pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
995         pa_proplist_free(sfp);
996     }
997
998     if (verbose) {
999         char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1000
1001         pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'.\n"),
1002                 mode == RECORD ? _("recording") : _("playback"),
1003                 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1004                 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1005     }
1006
1007     /* Fill in client name if none was set */
1008     if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1009         char *t;
1010
1011         if ((t = pa_locale_to_utf8(bn))) {
1012             pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1013             pa_xfree(t);
1014         }
1015     }
1016
1017     /* Fill in media name if none was set */
1018     if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1019         const char *t;
1020
1021         if ((t = filename) ||
1022             (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1023             pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1024     }
1025
1026     /* Set up a new main loop */
1027     if (!(m = pa_mainloop_new())) {
1028         pa_log(_("pa_mainloop_new() failed.\n"));
1029         goto quit;
1030     }
1031
1032     mainloop_api = pa_mainloop_get_api(m);
1033
1034     pa_assert_se(pa_signal_init(mainloop_api) == 0);
1035     pa_signal_new(SIGINT, exit_signal_callback, NULL);
1036     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1037 #ifdef SIGUSR1
1038     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1039 #endif
1040     pa_disable_sigpipe();
1041
1042     if (raw) {
1043         if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1044                                                  mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1045                                                  mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1046                                                  mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
1047             pa_log(_("io_new() failed.\n"));
1048             goto quit;
1049         }
1050     }
1051
1052     /* Create a new connection context */
1053     if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1054         pa_log(_("pa_context_new() failed.\n"));
1055         goto quit;
1056     }
1057
1058     pa_context_set_state_callback(context, context_state_callback, NULL);
1059
1060     /* Connect the context */
1061     if (pa_context_connect(context, server, 0, NULL) < 0) {
1062         pa_log(_("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context)));
1063         goto quit;
1064     }
1065
1066     if (verbose) {
1067         if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1068             pa_log(_("pa_context_rttime_new() failed.\n"));
1069             goto quit;
1070         }
1071     }
1072
1073     /* Run the main loop */
1074     if (pa_mainloop_run(m, &ret) < 0) {
1075         pa_log(_("pa_mainloop_run() failed.\n"));
1076         goto quit;
1077     }
1078
1079 quit:
1080     if (stream)
1081         pa_stream_unref(stream);
1082
1083     if (context)
1084         pa_context_unref(context);
1085
1086     if (stdio_event) {
1087         pa_assert(mainloop_api);
1088         mainloop_api->io_free(stdio_event);
1089     }
1090
1091     if (time_event) {
1092         pa_assert(mainloop_api);
1093         mainloop_api->time_free(time_event);
1094     }
1095
1096     if (m) {
1097         pa_signal_done();
1098         pa_mainloop_free(m);
1099     }
1100
1101     pa_xfree(buffer);
1102
1103     pa_xfree(server);
1104     pa_xfree(device);
1105
1106     if (sndfile)
1107         sf_close(sndfile);
1108
1109     if (proplist)
1110         pa_proplist_free(proplist);
1111
1112     return ret;
1113 }