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