• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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\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         if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
1068                                    mode == RECORD ? SFM_WRITE : SFM_READ,
1069                                    &sfi, 0))) {
1070             pa_log(_("Failed to open audio file."));
1071             goto quit;
1072         }
1073 
1074         if (mode == PLAYBACK) {
1075             if (sample_spec_set)
1076                 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1077 
1078             if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1079                 pa_log(_("Failed to determine sample specification from file."));
1080                 goto quit;
1081             }
1082             sample_spec_set = true;
1083 
1084             if (!channel_map_set) {
1085                 /* Allow the user to overwrite the channel map on the command line */
1086                 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1087                     if (sample_spec.channels > 2)
1088                         pa_log(_("Warning: Failed to determine channel map from file."));
1089                 } else
1090                     channel_map_set = true;
1091             }
1092         }
1093     }
1094 
1095     if (!channel_map_set)
1096         pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1097 
1098     if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
1099         pa_log(_("Channel map doesn't match sample specification"));
1100         goto quit;
1101     }
1102 
1103     if (!raw) {
1104         pa_proplist *sfp;
1105 
1106         if (mode == PLAYBACK)
1107             readf_function = pa_sndfile_readf_function(&sample_spec);
1108         else {
1109             if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
1110                 pa_log(_("Warning: failed to write channel map to file."));
1111 
1112             writef_function = pa_sndfile_writef_function(&sample_spec);
1113         }
1114 
1115         /* Fill in libsndfile prop list data */
1116         sfp = pa_proplist_new();
1117         pa_sndfile_init_proplist(sndfile, sfp);
1118         pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
1119         pa_proplist_free(sfp);
1120     }
1121 
1122     if (verbose) {
1123         char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];
1124 
1125         pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1126                 mode == RECORD ? _("recording") : _("playback"),
1127                 pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
1128                 pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
1129     }
1130 
1131     /* Fill in client name if none was set */
1132     if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
1133         char *t;
1134 
1135         if ((t = pa_locale_to_utf8(bn))) {
1136             pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
1137             pa_xfree(t);
1138         }
1139     }
1140 
1141     /* Fill in media name if none was set */
1142     if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1143         const char *t;
1144 
1145         if ((t = filename) ||
1146             (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
1147             pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);
1148 
1149         if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
1150             pa_log(_("Failed to set media name."));
1151             goto quit;
1152         }
1153     }
1154 
1155     if (raw && mode == PLAYBACK)
1156         partialframe_buf = pa_xmalloc(pa_frame_size(&sample_spec));
1157 
1158     /* Set up a new main loop */
1159     if (!(m = pa_mainloop_new())) {
1160         pa_log(_("pa_mainloop_new() failed."));
1161         goto quit;
1162     }
1163 
1164     mainloop_api = pa_mainloop_get_api(m);
1165 
1166     pa_assert_se(pa_signal_init(mainloop_api) == 0);
1167     pa_signal_new(SIGINT, exit_signal_callback, NULL);
1168     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1169 #ifdef SIGUSR1
1170     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
1171 #endif
1172     pa_disable_sigpipe();
1173 
1174     if (raw) {
1175 #ifdef OS_IS_WIN32
1176         /* need to turn on binary mode for stdio io. Windows, meh */
1177         setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY);
1178 #endif
1179         if (!(stdio_event = mainloop_api->io_new(mainloop_api,
1180                                                  mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
1181                                                  mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
1182                                                  mode == PLAYBACK ? stdin_callback : stdout_callback, &type))) {
1183             pa_log(_("io_new() failed."));
1184             goto quit;
1185         }
1186     }
1187 
1188     /* Create a new connection context */
1189     if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1190         pa_log(_("pa_context_new() failed."));
1191         goto quit;
1192     }
1193 
1194     pa_context_set_state_callback(context, context_state_callback, NULL);
1195 
1196     /* Connect the context */
1197     if (pa_context_connect(context, server, 0, NULL) < 0) {
1198         pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1199         goto quit;
1200     }
1201 
1202     if (verbose) {
1203         if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
1204             pa_log(_("pa_context_rttime_new() failed."));
1205             goto quit;
1206         }
1207     }
1208 
1209     /* Run the main loop */
1210     if (pa_mainloop_run(m, &ret) < 0) {
1211         pa_log(_("pa_mainloop_run() failed."));
1212         goto quit;
1213     }
1214 
1215 quit:
1216     if (stream)
1217         pa_stream_unref(stream);
1218 
1219     if (context)
1220         pa_context_unref(context);
1221 
1222     if (stdio_event) {
1223         pa_assert(mainloop_api);
1224         mainloop_api->io_free(stdio_event);
1225     }
1226 
1227     if (time_event) {
1228         pa_assert(mainloop_api);
1229         mainloop_api->time_free(time_event);
1230     }
1231 
1232     if (m) {
1233         pa_signal_done();
1234         pa_mainloop_free(m);
1235     }
1236 
1237     pa_xfree(silence_buffer);
1238     pa_xfree(buffer);
1239     pa_xfree(partialframe_buf);
1240 
1241     pa_xfree(server);
1242     pa_xfree(device);
1243 
1244     if (sndfile)
1245         sf_close(sndfile);
1246 
1247     if (proplist)
1248         pa_proplist_free(proplist);
1249 
1250     return ret;
1251 }
1252