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