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