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