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, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <signal.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <getopt.h>
33 #include <fcntl.h>
34 #include <locale.h>
35
36 #include <sndfile.h>
37
38 #include <pulse/pulseaudio.h>
39 #include <pulse/rtclock.h>
40
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/i18n.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/sndfile-util.h>
46 #include <pulsecore/sample-util.h>
47
48 #define TIME_EVENT_USEC 50000
49
50 #define CLEAR_LINE "\x1B[K"
51
52 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
53 static const char *purpose = NULL;
54
55 static pa_context *context = NULL;
56 static pa_stream *stream = NULL;
57 static pa_mainloop_api *mainloop_api = NULL;
58
59 /* Playback Mode (raw):
60 *
61 * We can only write audio to the PA stream in multiples of the stream's
62 * sample-spec frame size. Meanwhile, the STDIN read(2) system call can return
63 * a length much smaller than the frame-aligned size requested - leading to
64 * invalid writes. This can be reproduced by choosing a starved STDIN backend
65 * (e.g. "pacat /dev/random", "echo 1234 | pacat"), or an incomplete WAV file
66 * in raw non-paplay mode.
67 *
68 * Solve this by writing only frame-aligned sizes, while caching the resulting
69 * trailing partial frames here. This partial frame is then directly written
70 * in the next stream write iteration. Rinse and repeat.
71 */
72 static void *partialframe_buf = NULL;
73 static size_t partialframe_len = 0;
74
75 /* Recording Mode buffers */
76 static void *buffer = NULL;
77 static size_t buffer_length = 0, buffer_index = 0;
78
79 static void *silence_buffer = NULL;
80 static size_t silence_buffer_length = 0;
81
82 static pa_io_event* stdio_event = NULL;
83
84 static pa_proplist *proplist = NULL;
85 static char *device = NULL;
86
87 static SNDFILE* sndfile = NULL;
88
89 static bool verbose = false;
90 static pa_volume_t volume = PA_VOLUME_NORM;
91 static bool volume_is_set = false;
92
93 static pa_sample_spec sample_spec = {
94 .format = PA_SAMPLE_S16LE,
95 .rate = 44100,
96 .channels = 2
97 };
98 static bool sample_spec_set = false;
99
100 static pa_channel_map channel_map;
101 static bool channel_map_set = false;
102
103 static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames) = NULL;
104 static sf_count_t (*writef_function)(SNDFILE *_sndfile, const void *ptr, sf_count_t frames) = NULL;
105
106 static pa_stream_flags_t flags = 0;
107
108 static size_t latency = 0, process_time = 0;
109 static int32_t latency_msec = 0, process_time_msec = 0;
110
111 static bool raw = true;
112 static int file_format = -1;
113
114 static uint32_t monitor_stream = PA_INVALID_INDEX;
115
116 static uint32_t cork_requests = 0;
117
118 /* A shortcut for terminating the application */
quit(int ret)119 static void quit(int ret) {
120 pa_assert(mainloop_api);
121 mainloop_api->quit(mainloop_api, ret);
122 }
123
124 /* Connection draining complete */
context_drain_complete(pa_context * c,void * userdata)125 static void context_drain_complete(pa_context*c, void *userdata) {
126 pa_context_disconnect(c);
127 }
128
129 /* Stream draining complete */
stream_drain_complete(pa_stream * s,int success,void * userdata)130 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
131 pa_operation *o = NULL;
132
133 if (!success) {
134 pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context)));
135 quit(1);
136 }
137
138 if (verbose)
139 pa_log(_("Playback stream drained."));
140
141 pa_stream_disconnect(stream);
142 pa_stream_unref(stream);
143 stream = NULL;
144
145 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
146 pa_context_disconnect(context);
147 else {
148 pa_operation_unref(o);
149 if (verbose)
150 pa_log(_("Draining connection to server."));
151 }
152 }
153
154 /* Start draining */
start_drain(void)155 static void start_drain(void) {
156
157 if (stream) {
158 pa_operation *o;
159
160 pa_stream_set_write_callback(stream, NULL, NULL);
161
162 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
163 pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context)));
164 quit(1);
165 return;
166 }
167
168 pa_operation_unref(o);
169 } else
170 quit(0);
171 }
172
173 /* This is called whenever new data may be written to the stream */
stream_write_callback(pa_stream * s,size_t length,void * userdata)174 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
175 pa_assert(s);
176 pa_assert(length > 0);
177
178 if (raw) {
179 pa_assert(!sndfile);
180
181 if (stdio_event)
182 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
183
184 } else {
185 sf_count_t bytes;
186 void *data;
187
188 pa_assert(sndfile);
189
190 for (;;) {
191 size_t data_length = length;
192
193 if (pa_stream_begin_write(s, &data, &data_length) < 0) {
194 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
195 quit(1);
196 return;
197 }
198
199 if (readf_function) {
200 size_t k = pa_frame_size(&sample_spec);
201
202 if ((bytes = readf_function(sndfile, data, (sf_count_t) (data_length/k))) > 0)
203 bytes *= (sf_count_t) k;
204
205 } else
206 bytes = sf_read_raw(sndfile, data, (sf_count_t) data_length);
207
208 if (bytes > 0)
209 pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE);
210 else
211 pa_stream_cancel_write(s);
212
213 /* EOF? */
214 if (bytes < (sf_count_t) data_length) {
215 start_drain();
216 break;
217 }
218
219 /* Request fulfilled */
220 if ((size_t) bytes >= length)
221 break;
222
223 length -= bytes;
224 }
225 }
226 }
227
228 /* This is called whenever new data is available */
stream_read_callback(pa_stream * s,size_t length,void * userdata)229 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
230
231 pa_assert(s);
232 pa_assert(length > 0);
233
234 if (raw) {
235 pa_assert(!sndfile);
236
237 if (stdio_event)
238 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
239
240 while (pa_stream_readable_size(s) > 0) {
241 const void *data;
242
243 if (pa_stream_peek(s, &data, &length) < 0) {
244 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
245 quit(1);
246 return;
247 }
248
249 pa_assert(length > 0);
250
251 /* If there is a hole in the stream, we generate silence, except
252 * if it's a passthrough stream in which case we skip the hole. */
253 if (data || !(flags & PA_STREAM_PASSTHROUGH)) {
254 buffer = pa_xrealloc(buffer, buffer_index + buffer_length + length);
255 if (data)
256 memcpy((uint8_t *) buffer + buffer_index + buffer_length, data, length);
257 else
258 pa_silence_memory((uint8_t *) buffer + buffer_index + buffer_length, length, &sample_spec);
259
260 buffer_length += length;
261 }
262
263 pa_stream_drop(s);
264 }
265
266 } else {
267 pa_assert(sndfile);
268
269 while (pa_stream_readable_size(s) > 0) {
270 sf_count_t bytes;
271 const void *data;
272
273 if (pa_stream_peek(s, &data, &length) < 0) {
274 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
275 quit(1);
276 return;
277 }
278
279 pa_assert(length > 0);
280
281 if (!data && (flags & PA_STREAM_PASSTHROUGH)) {
282 pa_stream_drop(s);
283 continue;
284 }
285
286 if (!data && length > silence_buffer_length) {
287 silence_buffer = pa_xrealloc(silence_buffer, length);
288 pa_silence_memory((uint8_t *) silence_buffer + silence_buffer_length, length - silence_buffer_length, &sample_spec);
289 silence_buffer_length = length;
290 }
291
292 if (writef_function) {
293 size_t k = pa_frame_size(&sample_spec);
294
295 if ((bytes = writef_function(sndfile, data ? data : silence_buffer, (sf_count_t) (length/k))) > 0)
296 bytes *= (sf_count_t) k;
297
298 } else
299 bytes = sf_write_raw(sndfile, data ? data : silence_buffer, (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 */
stream_state_callback(pa_stream * s,void * userdata)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 (index: %u, suspended: %s)."),
343 pa_stream_get_device_name(s),
344 pa_stream_get_device_index(s),
345 pa_yes_no(pa_stream_is_suspended(s)));
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
stream_suspended_callback(pa_stream * s,void * userdata)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
stream_underflow_callback(pa_stream * s,void * userdata)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
stream_overflow_callback(pa_stream * s,void * userdata)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
stream_started_callback(pa_stream * s,void * userdata)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
stream_moved_callback(pa_stream * s,void * userdata)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
stream_buffer_attr_callback(pa_stream * s,void * userdata)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
stream_event_callback(pa_stream * s,const char * name,pa_proplist * pl,void * userdata)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
413 if (pa_streq(name, PA_STREAM_EVENT_REQUEST_CORK)) {
414 if (cork_requests == 0) {
415 pa_log(_("Cork request stack is empty: corking stream"));
416 pa_operation_unref(pa_stream_cork(s, 1, NULL, NULL));
417 }
418 cork_requests++;
419 } else if (pa_streq(name, PA_STREAM_EVENT_REQUEST_UNCORK)) {
420 if (cork_requests == 1) {
421 pa_log(_("Cork request stack is empty: uncorking stream"));
422 pa_operation_unref(pa_stream_cork(s, 0, NULL, NULL));
423 }
424 if (cork_requests == 0)
425 pa_log(_("Warning: Received more uncork requests than cork requests."));
426 else
427 cork_requests--;
428 }
429
430 pa_xfree(t);
431 }
432
433 /* This is called whenever the context status changes */
context_state_callback(pa_context * c,void * userdata)434 static void context_state_callback(pa_context *c, void *userdata) {
435 pa_assert(c);
436
437 switch (pa_context_get_state(c)) {
438 case PA_CONTEXT_CONNECTING:
439 case PA_CONTEXT_AUTHORIZING:
440 case PA_CONTEXT_SETTING_NAME:
441 break;
442
443 case PA_CONTEXT_READY: {
444 pa_buffer_attr buffer_attr;
445
446 pa_assert(c);
447 pa_assert(!stream);
448
449 if (verbose)
450 pa_log(_("Connection established.%s"), CLEAR_LINE);
451
452 if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) {
453 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c)));
454 goto fail;
455 }
456
457 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
458 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
459 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
460 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
461 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
462 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
463 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
464 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
465 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
466 pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
467
468 pa_zero(buffer_attr);
469 buffer_attr.maxlength = (uint32_t) -1;
470 buffer_attr.prebuf = (uint32_t) -1;
471
472 if (latency_msec > 0) {
473 buffer_attr.fragsize = buffer_attr.tlength = pa_usec_to_bytes(latency_msec * PA_USEC_PER_MSEC, &sample_spec);
474 flags |= PA_STREAM_ADJUST_LATENCY;
475 } else if (latency > 0) {
476 buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) latency;
477 flags |= PA_STREAM_ADJUST_LATENCY;
478 } else
479 buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) -1;
480
481 if (process_time_msec > 0) {
482 buffer_attr.minreq = pa_usec_to_bytes(process_time_msec * PA_USEC_PER_MSEC, &sample_spec);
483 } else if (process_time > 0)
484 buffer_attr.minreq = (uint32_t) process_time;
485 else
486 buffer_attr.minreq = (uint32_t) -1;
487
488 if (mode == PLAYBACK) {
489 pa_cvolume cv;
490 if (pa_stream_connect_playback(stream, device, &buffer_attr, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL) < 0) {
491 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c)));
492 goto fail;
493 }
494
495 } else {
496 if (monitor_stream != PA_INVALID_INDEX && (pa_stream_set_monitor_stream(stream, monitor_stream) < 0)) {
497 pa_log(_("Failed to set monitor stream: %s"), pa_strerror(pa_context_errno(c)));
498 goto fail;
499 }
500 if (pa_stream_connect_record(stream, device, &buffer_attr, flags) < 0) {
501 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c)));
502 goto fail;
503 }
504 }
505 break;
506 }
507
508 case PA_CONTEXT_TERMINATED:
509 quit(0);
510 break;
511
512 case PA_CONTEXT_FAILED:
513 default:
514 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
515 goto fail;
516 }
517
518 return;
519
520 fail:
521 quit(1);
522
523 }
524
525 /* New data on STDIN **/
stdin_callback(pa_mainloop_api * a,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)526 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
527 uint8_t *buf = NULL;
528 size_t writable, towrite, r;
529
530 pa_assert(a == mainloop_api);
531 pa_assert(e);
532 pa_assert(stdio_event == e);
533
534 /* Stream not ready? */
535 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY ||
536 !(writable = pa_stream_writable_size(stream))) {
537
538 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
539 return;
540 }
541
542 if (pa_stream_begin_write(stream, (void **)&buf, &writable) < 0) {
543 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
544 quit(1);
545 return;
546 }
547
548 /* Partial frame cached from a previous write iteration? */
549 if (partialframe_len) {
550 pa_assert(partialframe_len < pa_frame_size(&sample_spec));
551 memcpy(buf, partialframe_buf, partialframe_len);
552 }
553
554 if ((r = pa_read(fd, buf + partialframe_len, writable - partialframe_len, userdata)) <= 0) {
555 if (r == 0) {
556 if (verbose)
557 pa_log(_("Got EOF."));
558
559 start_drain();
560
561 } else {
562 pa_log(_("read() failed: %s"), strerror(errno));
563 quit(1);
564 }
565
566 mainloop_api->io_free(stdio_event);
567 stdio_event = NULL;
568 return;
569 }
570 r += partialframe_len;
571
572 /* Cache any trailing partial frames for the next write */
573 towrite = pa_frame_align(r, &sample_spec);
574 partialframe_len = r - towrite;
575
576 if (partialframe_len)
577 memcpy(partialframe_buf, buf + towrite, partialframe_len);
578
579 if (towrite) {
580 if (pa_stream_write(stream, buf, towrite, NULL, 0, PA_SEEK_RELATIVE) < 0) {
581 pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context)));
582 quit(1);
583 return;
584 }
585 } else
586 pa_stream_cancel_write(stream);
587 }
588
589 /* Some data may be written to STDOUT */
stdout_callback(pa_mainloop_api * a,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)590 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
591 ssize_t r;
592
593 pa_assert(a == mainloop_api);
594 pa_assert(e);
595 pa_assert(stdio_event == e);
596
597 if (!buffer) {
598 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
599 return;
600 }
601
602 pa_assert(buffer_length);
603
604 if ((r = pa_write(fd, (uint8_t*) buffer+buffer_index, buffer_length, userdata)) <= 0) {
605 pa_log(_("write() failed: %s"), strerror(errno));
606 quit(1);
607
608 mainloop_api->io_free(stdio_event);
609 stdio_event = NULL;
610 return;
611 }
612
613 buffer_length -= (uint32_t) r;
614 buffer_index += (uint32_t) r;
615
616 if (!buffer_length) {
617 pa_xfree(buffer);
618 buffer = NULL;
619 buffer_length = buffer_index = 0;
620 }
621 }
622
623 /* UNIX signal to quit received */
exit_signal_callback(pa_mainloop_api * m,pa_signal_event * e,int sig,void * userdata)624 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
625 if (verbose)
626 pa_log(_("Got signal, exiting."));
627 quit(0);
628 }
629
630 /* Show the current latency */
stream_update_timing_callback(pa_stream * s,int success,void * userdata)631 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
632 pa_usec_t l, usec;
633 int negative = 0;
634
635 pa_assert(s);
636
637 if (!success ||
638 pa_stream_get_time(s, &usec) < 0 ||
639 pa_stream_get_latency(s, &l, &negative) < 0) {
640 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context)));
641 quit(1);
642 return;
643 }
644
645 fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec."),
646 (float) usec / 1000000,
647 (float) l * (negative?-1.0f:1.0f));
648 fprintf(stderr, " \r");
649 }
650
651 #ifdef SIGUSR1
652 /* Someone requested that the latency is shown */
sigusr1_signal_callback(pa_mainloop_api * m,pa_signal_event * e,int sig,void * userdata)653 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
654
655 if (!stream)
656 return;
657
658 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
659 }
660 #endif
661
time_event_callback(pa_mainloop_api * m,pa_time_event * e,const struct timeval * t,void * userdata)662 static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
663 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
664 pa_operation *o;
665 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
666 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context)));
667 else
668 pa_operation_unref(o);
669 }
670
671 pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
672 }
673
help(const char * argv0)674 static void help(const char *argv0) {
675
676 printf(_("%s [options]\n"
677 "%s\n\n"
678 " -h, --help Show this help\n"
679 " --version Show version\n\n"
680 " -r, --record Create a connection for recording\n"
681 " -p, --playback Create a connection for playback\n\n"
682 " -v, --verbose Enable verbose operations\n\n"
683 " -s, --server=SERVER The name of the server to connect to\n"
684 " -d, --device=DEVICE The name of the sink/source to connect to. The special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@ can be used to specify the default sink, source and monitor respectively.\n"
685 " -n, --client-name=NAME How to call this client on the server\n"
686 " --stream-name=NAME How to call this stream on the server\n"
687 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
688 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
689 " --format=SAMPLEFORMAT The sample format, see\n"
690 " https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n"
691 " for possible values (defaults to s16ne)\n"
692 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
693 " (defaults to 2)\n"
694 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
695 " --fix-format Take the sample format from the sink/source the stream is\n"
696 " being connected to.\n"
697 " --fix-rate Take the sampling rate from the sink/source the stream is\n"
698 " being connected to.\n"
699 " --fix-channels Take the number of channels and the channel map\n"
700 " from the sink/source the stream is being connected to.\n"
701 " --no-remix Don't upmix or downmix channels.\n"
702 " --no-remap Map channels by index instead of name.\n"
703 " --latency=BYTES Request the specified latency in bytes.\n"
704 " --process-time=BYTES Request the specified process time per request in bytes.\n"
705 " --latency-msec=MSEC Request the specified latency in msec.\n"
706 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
707 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
708 " --raw Record/play raw PCM data.\n"
709 " --passthrough Passthrough data.\n"
710 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
711 " --list-file-formats List available file formats.\n"
712 " --monitor-stream=INDEX Record from the sink input with index INDEX.\n")
713 , argv0, purpose);
714 }
715
716 enum {
717 ARG_VERSION = 256,
718 ARG_STREAM_NAME,
719 ARG_VOLUME,
720 ARG_SAMPLERATE,
721 ARG_SAMPLEFORMAT,
722 ARG_CHANNELS,
723 ARG_CHANNELMAP,
724 ARG_FIX_FORMAT,
725 ARG_FIX_RATE,
726 ARG_FIX_CHANNELS,
727 ARG_NO_REMAP,
728 ARG_NO_REMIX,
729 ARG_LATENCY,
730 ARG_PROCESS_TIME,
731 ARG_RAW,
732 ARG_PASSTHROUGH,
733 ARG_PROPERTY,
734 ARG_FILE_FORMAT,
735 ARG_LIST_FILE_FORMATS,
736 ARG_LATENCY_MSEC,
737 ARG_PROCESS_TIME_MSEC,
738 ARG_MONITOR_STREAM,
739 };
740
main(int argc,char * argv[])741 int main(int argc, char *argv[]) {
742 pa_mainloop* m = NULL;
743 int ret = 1, c;
744 char *bn, *server = NULL;
745 pa_time_event *time_event = NULL;
746 const char *filename = NULL;
747 /* type for pa_read/_write. passed as userdata to the callbacks */
748 unsigned long type = 0;
749
750 static const struct option long_options[] = {
751 {"record", 0, NULL, 'r'},
752 {"playback", 0, NULL, 'p'},
753 {"device", 1, NULL, 'd'},
754 {"server", 1, NULL, 's'},
755 {"client-name", 1, NULL, 'n'},
756 {"stream-name", 1, NULL, ARG_STREAM_NAME},
757 {"version", 0, NULL, ARG_VERSION},
758 {"help", 0, NULL, 'h'},
759 {"verbose", 0, NULL, 'v'},
760 {"volume", 1, NULL, ARG_VOLUME},
761 {"rate", 1, NULL, ARG_SAMPLERATE},
762 {"format", 1, NULL, ARG_SAMPLEFORMAT},
763 {"channels", 1, NULL, ARG_CHANNELS},
764 {"channel-map", 1, NULL, ARG_CHANNELMAP},
765 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
766 {"fix-rate", 0, NULL, ARG_FIX_RATE},
767 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
768 {"no-remap", 0, NULL, ARG_NO_REMAP},
769 {"no-remix", 0, NULL, ARG_NO_REMIX},
770 {"latency", 1, NULL, ARG_LATENCY},
771 {"process-time", 1, NULL, ARG_PROCESS_TIME},
772 {"property", 1, NULL, ARG_PROPERTY},
773 {"raw", 0, NULL, ARG_RAW},
774 {"passthrough", 0, NULL, ARG_PASSTHROUGH},
775 {"file-format", 2, NULL, ARG_FILE_FORMAT},
776 {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
777 {"latency-msec", 1, NULL, ARG_LATENCY_MSEC},
778 {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC},
779 {"monitor-stream", 1, NULL, ARG_MONITOR_STREAM},
780 {NULL, 0, NULL, 0}
781 };
782
783 setlocale(LC_ALL, "");
784 #ifdef ENABLE_NLS
785 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
786 #endif
787
788 bn = pa_path_get_filename(argv[0]);
789
790 if (strstr(bn, "play")) {
791 mode = PLAYBACK;
792 raw = false;
793 purpose = _("Play back encoded audio files on a PulseAudio sound server.");
794 } else if (strstr(bn, "record")) {
795 mode = RECORD;
796 raw = false;
797 purpose = _("Capture audio data from a PulseAudio sound server and write it to a file.");
798 } else if (strstr(bn, "rec") || strstr(bn, "mon")) {
799 mode = RECORD;
800 raw = true;
801 purpose = _("Capture audio data from a PulseAudio sound server and write it to STDOUT or the specified file.");
802 } else { /* pacat */
803 mode = PLAYBACK;
804 raw = true;
805 purpose = _("Play back audio data from STDIN or the specified file on a PulseAudio sound server.");
806 }
807
808 proplist = pa_proplist_new();
809
810 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
811
812 switch (c) {
813 case 'h':
814 help(bn);
815 ret = 0;
816 goto quit;
817
818 case ARG_VERSION:
819 printf(_("pacat %s\n"
820 "Compiled with libpulse %s\n"
821 "Linked with libpulse %s\n"),
822 PACKAGE_VERSION,
823 pa_get_headers_version(),
824 pa_get_library_version());
825 ret = 0;
826 goto quit;
827
828 case 'r':
829 mode = RECORD;
830 break;
831
832 case 'p':
833 mode = PLAYBACK;
834 break;
835
836 case 'd':
837 pa_xfree(device);
838 device = pa_xstrdup(optarg);
839 break;
840
841 case 's':
842 pa_xfree(server);
843 server = pa_xstrdup(optarg);
844 break;
845
846 case 'n': {
847 char *t;
848
849 if (!(t = pa_locale_to_utf8(optarg)) ||
850 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
851
852 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
853 pa_xfree(t);
854 goto quit;
855 }
856
857 pa_xfree(t);
858 break;
859 }
860
861 case ARG_STREAM_NAME: {
862 char *t;
863
864 if (!(t = pa_locale_to_utf8(optarg)) ||
865 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {
866
867 pa_log(_("Invalid stream name '%s'"), t ? t : optarg);
868 pa_xfree(t);
869 goto quit;
870 }
871
872 pa_xfree(t);
873 break;
874 }
875
876 case 'v':
877 verbose = 1;
878 break;
879
880 case ARG_VOLUME: {
881 int v = atoi(optarg);
882 volume = v < 0 ? 0U : (pa_volume_t) v;
883 volume_is_set = true;
884 break;
885 }
886
887 case ARG_CHANNELS:
888 sample_spec.channels = (uint8_t) atoi(optarg);
889 sample_spec_set = true;
890 break;
891
892 case ARG_SAMPLEFORMAT:
893 sample_spec.format = pa_parse_sample_format(optarg);
894 sample_spec_set = true;
895 break;
896
897 case ARG_SAMPLERATE:
898 sample_spec.rate = (uint32_t) atoi(optarg);
899 sample_spec_set = true;
900 break;
901
902 case ARG_CHANNELMAP:
903 if (!pa_channel_map_parse(&channel_map, optarg)) {
904 pa_log(_("Invalid channel map '%s'"), optarg);
905 goto quit;
906 }
907
908 channel_map_set = true;
909 break;
910
911 case ARG_FIX_CHANNELS:
912 flags |= PA_STREAM_FIX_CHANNELS;
913 break;
914
915 case ARG_FIX_RATE:
916 flags |= PA_STREAM_FIX_RATE;
917 break;
918
919 case ARG_FIX_FORMAT:
920 flags |= PA_STREAM_FIX_FORMAT;
921 break;
922
923 case ARG_NO_REMIX:
924 flags |= PA_STREAM_NO_REMIX_CHANNELS;
925 break;
926
927 case ARG_NO_REMAP:
928 flags |= PA_STREAM_NO_REMAP_CHANNELS;
929 break;
930
931 case ARG_LATENCY:
932 if (((latency = (size_t) atoi(optarg))) <= 0) {
933 pa_log(_("Invalid latency specification '%s'"), optarg);
934 goto quit;
935 }
936 break;
937
938 case ARG_PROCESS_TIME:
939 if (((process_time = (size_t) atoi(optarg))) <= 0) {
940 pa_log(_("Invalid process time specification '%s'"), optarg);
941 goto quit;
942 }
943 break;
944
945 case ARG_LATENCY_MSEC:
946 if (((latency_msec = (int32_t) atoi(optarg))) <= 0) {
947 pa_log(_("Invalid latency specification '%s'"), optarg);
948 goto quit;
949 }
950 break;
951
952 case ARG_PROCESS_TIME_MSEC:
953 if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) {
954 pa_log(_("Invalid process time specification '%s'"), optarg);
955 goto quit;
956 }
957 break;
958
959 case ARG_PROPERTY: {
960 char *t;
961
962 if (!(t = pa_locale_to_utf8(optarg)) ||
963 pa_proplist_setp(proplist, t) < 0) {
964
965 pa_xfree(t);
966 pa_log(_("Invalid property '%s'"), optarg);
967 goto quit;
968 }
969
970 pa_xfree(t);
971 break;
972 }
973
974 case ARG_RAW:
975 raw = true;
976 break;
977
978 case ARG_PASSTHROUGH:
979 flags |= PA_STREAM_PASSTHROUGH;
980 break;
981
982 case ARG_FILE_FORMAT:
983 if (optarg) {
984 if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
985 pa_log(_("Unknown file format %s."), optarg);
986 goto quit;
987 }
988 }
989
990 raw = false;
991 break;
992
993 case ARG_LIST_FILE_FORMATS:
994 pa_sndfile_dump_formats();
995 ret = 0;
996 goto quit;
997
998 case ARG_MONITOR_STREAM:
999 if (pa_atou(optarg, &monitor_stream) < 0) {
1000 pa_log(_("Failed to parse the argument for --monitor-stream"));
1001 goto quit;
1002 }
1003 break;
1004
1005 default:
1006 goto quit;
1007 }
1008 }
1009
1010 if (!pa_sample_spec_valid(&sample_spec)) {
1011 pa_log(_("Invalid sample specification"));
1012 goto quit;
1013 }
1014
1015 if (optind+1 == argc) {
1016 int fd;
1017
1018 filename = argv[optind];
1019
1020 if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
1021 pa_log(_("open(): %s"), strerror(errno));
1022 goto quit;
1023 }
1024
1025 if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
1026 pa_log(_("dup2(): %s"), strerror(errno));
1027 goto quit;
1028 }
1029
1030 pa_close(fd);
1031
1032 } else if (optind+1 <= argc) {
1033 pa_log(_("Too many arguments."));
1034 goto quit;
1035 }
1036
1037 if (!raw) {
1038 SF_INFO sfi;
1039 pa_zero(sfi);
1040
1041 if (mode == RECORD) {
1042 /* This might patch up the sample spec */
1043 if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
1044 pa_log(_("Failed to generate sample specification for file."));
1045 goto quit;
1046 }
1047
1048 if (file_format <= 0) {
1049 char *extension;
1050 if (filename && (extension = strrchr(filename, '.')))
1051 file_format = pa_sndfile_format_from_string(extension+1);
1052 if (file_format <= 0)
1053 file_format = SF_FORMAT_WAV;
1054 /* Transparently upgrade classic .wav to wavex for multichannel audio */
1055 if (file_format == SF_FORMAT_WAV &&
1056 (sample_spec.channels > 2 ||
1057 (channel_map_set &&
1058 !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) &&
1059 !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT
1060 && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))))
1061 file_format = SF_FORMAT_WAVEX;
1062 }
1063
1064 sfi.format |= file_format;
1065
1066 /*
1067 * Endianness has been set in pa_sndfile_write_sample_spec(), but
1068 * libsndfile errors out if endianness is set to anything other than
1069 * SF_ENDIAN_FILE for OGG or FLAC. Clear it.
1070 * For OGG, libsndfile accepts only subformat SF_FORMAT_VORBIS.
1071 */
1072 if (file_format == SF_FORMAT_OGG || file_format == SF_FORMAT_FLAC)
1073 sfi.format = (sfi.format & ~SF_FORMAT_ENDMASK) | SF_ENDIAN_FILE;
1074 if (file_format == SF_FORMAT_OGG)
1075 sfi.format = (sfi.format & ~SF_FORMAT_SUBMASK) | SF_FORMAT_VORBIS;
1076
1077 }
1078
1079 if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
1080 mode == RECORD ? SFM_WRITE : SFM_READ,
1081 &sfi, 0))) {
1082 pa_log(_("Failed to open audio file."));
1083 goto quit;
1084 }
1085
1086 if (mode == PLAYBACK) {
1087 if (sample_spec_set)
1088 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1089
1090 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1091 pa_log(_("Failed to determine sample specification from file."));
1092 goto quit;
1093 }
1094 sample_spec_set = true;
1095
1096 if (!channel_map_set) {
1097 /* Allow the user to overwrite the channel map on the command line */
1098 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1099 if (sample_spec.channels > 2)
1100 pa_log(_("Warning: Failed to determine channel map from file."));
1101 } else
1102 channel_map_set = true;
1103 }
1104 }
1105 }
1106
1107 if (!channel_map_set)
1108 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1109
1110 if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
1111 pa_log(_("Channel map doesn't match sample specification"));
1112 goto quit;
1113 }
1114
1115 if (!raw) {
1116 pa_proplist *sfp;
1117
1118 if (mode == PLAYBACK)
1119 readf_function = pa_sndfile_readf_function(&sample_spec);
1120 else {
1121 if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
1122 pa_log(_("Warning: failed to write channel map to file."));
1123
1124 writef_function = pa_sndfile_writef_function(&sample_spec);
1125 }
1126
1127 /* Fill in libsndfile prop list data */
1128 sfp = pa_proplist_new();
1129 pa_sndfile_init_proplist(sndfile, sfp);
1130 pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
1131 pa_proplist_free(sfp);
1132 }
1133
1134 if (verbose) {
1135 char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1136
1137 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1138 mode == RECORD ? _("recording") : _("playback"),
1139 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1140 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1141 }
1142
1143 /* Fill in client name if none was set */
1144 if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1145 char *t;
1146
1147 if ((t = pa_locale_to_utf8(bn))) {
1148 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1149 pa_xfree(t);
1150 }
1151 }
1152
1153 /* Fill in media name if none was set */
1154 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1155 const char *t;
1156
1157 if ((t = filename) ||
1158 (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1159 pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1160
1161 if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1162 pa_log(_("Failed to set media name."));
1163 goto quit;
1164 }
1165 }
1166
1167 if (raw && mode == PLAYBACK)
1168 partialframe_buf = pa_xmalloc(pa_frame_size(&sample_spec));
1169
1170 /* Set up a new main loop */
1171 if (!(m = pa_mainloop_new())) {
1172 pa_log(_("pa_mainloop_new() failed."));
1173 goto quit;
1174 }
1175
1176 mainloop_api = pa_mainloop_get_api(m);
1177
1178 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1179 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1180 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1181 #ifdef SIGUSR1
1182 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1183 #endif
1184 pa_disable_sigpipe();
1185
1186 if (raw) {
1187 #ifdef OS_IS_WIN32
1188 /* need to turn on binary mode for stdio io. Windows, meh */
1189 setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY);
1190 #endif
1191 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1192 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1193 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1194 mode == PLAYBACK ? stdin_callback : stdout_callback, &type))) {
1195 pa_log(_("io_new() failed."));
1196 goto quit;
1197 }
1198 }
1199
1200 /* Create a new connection context */
1201 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1202 pa_log(_("pa_context_new() failed."));
1203 goto quit;
1204 }
1205
1206 pa_context_set_state_callback(context, context_state_callback, NULL);
1207
1208 /* Connect the context */
1209 if (pa_context_connect(context, server, 0, NULL) < 0) {
1210 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1211 goto quit;
1212 }
1213
1214 if (verbose) {
1215 if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1216 pa_log(_("pa_context_rttime_new() failed."));
1217 goto quit;
1218 }
1219 }
1220
1221 /* Run the main loop */
1222 if (pa_mainloop_run(m, &ret) < 0) {
1223 pa_log(_("pa_mainloop_run() failed."));
1224 goto quit;
1225 }
1226
1227 quit:
1228 if (stream)
1229 pa_stream_unref(stream);
1230
1231 if (context)
1232 pa_context_unref(context);
1233
1234 if (stdio_event) {
1235 pa_assert(mainloop_api);
1236 mainloop_api->io_free(stdio_event);
1237 }
1238
1239 if (time_event) {
1240 pa_assert(mainloop_api);
1241 mainloop_api->time_free(time_event);
1242 }
1243
1244 if (m) {
1245 pa_signal_done();
1246 pa_mainloop_free(m);
1247 }
1248
1249 pa_xfree(silence_buffer);
1250 pa_xfree(buffer);
1251 pa_xfree(partialframe_buf);
1252
1253 pa_xfree(server);
1254 pa_xfree(device);
1255
1256 if (sndfile)
1257 sf_close(sndfile);
1258
1259 if (proplist)
1260 pa_proplist_free(proplist);
1261
1262 return ret;
1263 }
1264