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