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