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