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