]> code.delx.au - pulseaudio/blob - src/utils/pacat.c
parecord: Automatically detect file format from extension
[pulseaudio] / 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 if (optarg) {
930 if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
931 pa_log(_("Unknown file format %s."), optarg);
932 goto quit;
933 }
934 }
935
936 raw = FALSE;
937 break;
938
939 case ARG_LIST_FILE_FORMATS:
940 pa_sndfile_dump_formats();
941 ret = 0;
942 goto quit;
943
944 default:
945 goto quit;
946 }
947 }
948
949 if (!pa_sample_spec_valid(&sample_spec)) {
950 pa_log(_("Invalid sample specification"));
951 goto quit;
952 }
953
954 if (optind+1 == argc) {
955 int fd;
956
957 filename = argv[optind];
958
959 if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
960 pa_log(_("open(): %s"), strerror(errno));
961 goto quit;
962 }
963
964 if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
965 pa_log(_("dup2(): %s"), strerror(errno));
966 goto quit;
967 }
968
969 pa_close(fd);
970
971 } else if (optind+1 <= argc) {
972 pa_log(_("Too many arguments."));
973 goto quit;
974 }
975
976 if (!raw) {
977 SF_INFO sfi;
978 pa_zero(sfi);
979
980 if (mode == RECORD) {
981 /* This might patch up the sample spec */
982 if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
983 pa_log(_("Failed to generate sample specification for file."));
984 goto quit;
985 }
986
987 if (file_format <= 0) {
988 char *extension;
989 if (filename && (extension = strrchr(filename, '.')))
990 file_format = pa_sndfile_format_from_string(extension+1);
991 if (file_format <= 0)
992 file_format = SF_FORMAT_WAV;
993 /* Transparently upgrade classic .wav to wavex for multichannel audio */
994 if (file_format == SF_FORMAT_WAV &&
995 (sample_spec.channels > 2 ||
996 (channel_map_set &&
997 !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) &&
998 !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT
999 && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))))
1000 file_format = SF_FORMAT_WAVEX;
1001 }
1002
1003 sfi.format |= file_format;
1004 }
1005
1006 if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
1007 mode == RECORD ? SFM_WRITE : SFM_READ,
1008 &sfi, 0))) {
1009 pa_log(_("Failed to open audio file."));
1010 goto quit;
1011 }
1012
1013 if (mode == PLAYBACK) {
1014 if (sample_spec_set)
1015 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1016
1017 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1018 pa_log(_("Failed to determine sample specification from file."));
1019 goto quit;
1020 }
1021 sample_spec_set = TRUE;
1022
1023 if (!channel_map_set) {
1024 /* Allow the user to overwrite the channel map on the command line */
1025 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1026 if (sample_spec.channels > 2)
1027 pa_log(_("Warning: Failed to determine channel map from file."));
1028 } else
1029 channel_map_set = TRUE;
1030 }
1031 }
1032 }
1033
1034 if (!channel_map_set)
1035 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1036
1037 if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
1038 pa_log(_("Channel map doesn't match sample specification"));
1039 goto quit;
1040 }
1041
1042 if (!raw) {
1043 pa_proplist *sfp;
1044
1045 if (mode == PLAYBACK)
1046 readf_function = pa_sndfile_readf_function(&sample_spec);
1047 else {
1048 if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
1049 pa_log(_("Warning: failed to write channel map to file."));
1050
1051 writef_function = pa_sndfile_writef_function(&sample_spec);
1052 }
1053
1054 /* Fill in libsndfile prop list data */
1055 sfp = pa_proplist_new();
1056 pa_sndfile_init_proplist(sndfile, sfp);
1057 pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
1058 pa_proplist_free(sfp);
1059 }
1060
1061 if (verbose) {
1062 char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1063
1064 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1065 mode == RECORD ? _("recording") : _("playback"),
1066 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1067 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1068 }
1069
1070 /* Fill in client name if none was set */
1071 if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1072 char *t;
1073
1074 if ((t = pa_locale_to_utf8(bn))) {
1075 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1076 pa_xfree(t);
1077 }
1078 }
1079
1080 /* Fill in media name if none was set */
1081 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1082 const char *t;
1083
1084 if ((t = filename) ||
1085 (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1086 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1087 }
1088
1089 /* Set up a new main loop */
1090 if (!(m = pa_mainloop_new())) {
1091 pa_log(_("pa_mainloop_new() failed."));
1092 goto quit;
1093 }
1094
1095 mainloop_api = pa_mainloop_get_api(m);
1096
1097 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1098 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1099 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1100 #ifdef SIGUSR1
1101 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1102 #endif
1103 pa_disable_sigpipe();
1104
1105 if (raw) {
1106 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1107 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1108 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1109 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
1110 pa_log(_("io_new() failed."));
1111 goto quit;
1112 }
1113 }
1114
1115 /* Create a new connection context */
1116 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1117 pa_log(_("pa_context_new() failed."));
1118 goto quit;
1119 }
1120
1121 pa_context_set_state_callback(context, context_state_callback, NULL);
1122
1123 /* Connect the context */
1124 if (pa_context_connect(context, server, 0, NULL) < 0) {
1125 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1126 goto quit;
1127 }
1128
1129 if (verbose) {
1130 if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1131 pa_log(_("pa_context_rttime_new() failed."));
1132 goto quit;
1133 }
1134 }
1135
1136 /* Run the main loop */
1137 if (pa_mainloop_run(m, &ret) < 0) {
1138 pa_log(_("pa_mainloop_run() failed."));
1139 goto quit;
1140 }
1141
1142 quit:
1143 if (stream)
1144 pa_stream_unref(stream);
1145
1146 if (context)
1147 pa_context_unref(context);
1148
1149 if (stdio_event) {
1150 pa_assert(mainloop_api);
1151 mainloop_api->io_free(stdio_event);
1152 }
1153
1154 if (time_event) {
1155 pa_assert(mainloop_api);
1156 mainloop_api->time_free(time_event);
1157 }
1158
1159 if (m) {
1160 pa_signal_done();
1161 pa_mainloop_free(m);
1162 }
1163
1164 pa_xfree(buffer);
1165
1166 pa_xfree(server);
1167 pa_xfree(device);
1168
1169 if (sndfile)
1170 sf_close(sndfile);
1171
1172 if (proplist)
1173 pa_proplist_free(proplist);
1174
1175 return ret;
1176 }