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