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