]> code.delx.au - pulseaudio/blob - src/utils/pacat.c
pacat: add missing newline
[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 <pulse/i18n.h>
39 #include <pulse/pulseaudio.h>
40
41 #define TIME_EVENT_USEC 50000
42
43 #define CLEAR_LINE "\x1B[K"
44
45 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
46
47 static pa_context *context = NULL;
48 static pa_stream *stream = NULL;
49 static pa_mainloop_api *mainloop_api = NULL;
50
51 static void *buffer = NULL;
52 static size_t buffer_length = 0, buffer_index = 0;
53
54 static pa_io_event* stdio_event = NULL;
55
56 static char *stream_name = NULL, *client_name = NULL, *device = NULL;
57
58 static int verbose = 0;
59 static pa_volume_t volume = PA_VOLUME_NORM;
60 static int volume_is_set = 0;
61
62 static pa_sample_spec sample_spec = {
63 .format = PA_SAMPLE_S16LE,
64 .rate = 44100,
65 .channels = 2
66 };
67
68 static pa_channel_map channel_map;
69 static int channel_map_set = 0;
70
71 static pa_stream_flags_t flags = 0;
72
73 static size_t latency = 0, process_time=0;
74
75 /* A shortcut for terminating the application */
76 static void quit(int ret) {
77 assert(mainloop_api);
78 mainloop_api->quit(mainloop_api, ret);
79 }
80
81 /* Write some data to the stream */
82 static void do_stream_write(size_t length) {
83 size_t l;
84 assert(length);
85
86 if (!buffer || !buffer_length)
87 return;
88
89 l = length;
90 if (l > buffer_length)
91 l = buffer_length;
92
93 if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
94 fprintf(stderr, _("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context)));
95 quit(1);
96 return;
97 }
98
99 buffer_length -= l;
100 buffer_index += l;
101
102 if (!buffer_length) {
103 pa_xfree(buffer);
104 buffer = NULL;
105 buffer_index = buffer_length = 0;
106 }
107 }
108
109 /* This is called whenever new data may be written to the stream */
110 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
111 assert(s);
112 assert(length > 0);
113
114 if (stdio_event)
115 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT);
116
117 if (!buffer)
118 return;
119
120 do_stream_write(length);
121 }
122
123 /* This is called whenever new data may is available */
124 static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
125 const void *data;
126 assert(s);
127 assert(length > 0);
128
129 if (stdio_event)
130 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
131
132 if (pa_stream_peek(s, &data, &length) < 0) {
133 fprintf(stderr, _("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context)));
134 quit(1);
135 return;
136 }
137
138 assert(data);
139 assert(length > 0);
140
141 if (buffer) {
142 buffer = pa_xrealloc(buffer, buffer_length + length);
143 memcpy((uint8_t*) buffer + buffer_length, data, length);
144 buffer_length += length;
145 } else {
146 buffer = pa_xmalloc(length);
147 memcpy(buffer, data, length);
148 buffer_length = length;
149 buffer_index = 0;
150 }
151
152 pa_stream_drop(s);
153 }
154
155 /* This routine is called whenever the stream state changes */
156 static void stream_state_callback(pa_stream *s, void *userdata) {
157 assert(s);
158
159 switch (pa_stream_get_state(s)) {
160 case PA_STREAM_CREATING:
161 case PA_STREAM_TERMINATED:
162 break;
163
164 case PA_STREAM_READY:
165 if (verbose) {
166 const pa_buffer_attr *a;
167 char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX];
168
169 fprintf(stderr, _("Stream successfully created.\n"));
170
171 if (!(a = pa_stream_get_buffer_attr(s)))
172 fprintf(stderr, _("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
173 else {
174
175 if (mode == PLAYBACK)
176 fprintf(stderr, _("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a->maxlength, a->tlength, a->prebuf, a->minreq);
177 else {
178 assert(mode == RECORD);
179 fprintf(stderr, _("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize);
180 }
181 }
182
183 fprintf(stderr, _("Using sample spec '%s', channel map '%s'.\n"),
184 pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)),
185 pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s)));
186
187 fprintf(stderr, _("Connected to device %s (%u, %ssuspended).\n"),
188 pa_stream_get_device_name(s),
189 pa_stream_get_device_index(s),
190 pa_stream_is_suspended(s) ? "" : "not ");
191 }
192
193 break;
194
195 case PA_STREAM_FAILED:
196 default:
197 fprintf(stderr, _("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
198 quit(1);
199 }
200 }
201
202 static void stream_suspended_callback(pa_stream *s, void *userdata) {
203 assert(s);
204
205 if (verbose) {
206 if (pa_stream_is_suspended(s))
207 fprintf(stderr, _("Stream device suspended.%s \n"), CLEAR_LINE);
208 else
209 fprintf(stderr, _("Stream device resumed.%s \n"), CLEAR_LINE);
210 }
211 }
212
213 static void stream_underflow_callback(pa_stream *s, void *userdata) {
214 assert(s);
215
216 if (verbose)
217 fprintf(stderr, _("Stream underrun.%s \n"), CLEAR_LINE);
218 }
219
220 static void stream_overflow_callback(pa_stream *s, void *userdata) {
221 assert(s);
222
223 if (verbose)
224 fprintf(stderr, _("Stream overrun.%s \n"), CLEAR_LINE);
225 }
226
227 static void stream_started_callback(pa_stream *s, void *userdata) {
228 assert(s);
229
230 if (verbose)
231 fprintf(stderr, _("Stream started.%s \n"), CLEAR_LINE);
232 }
233
234 static void stream_moved_callback(pa_stream *s, void *userdata) {
235 assert(s);
236
237 if (verbose)
238 fprintf(stderr, _("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);
239 }
240
241 static void stream_buffer_attr_callback(pa_stream *s, void *userdata) {
242 assert(s);
243
244 if (verbose)
245 fprintf(stderr, _("Stream buffer attributes changed.%s \n"), CLEAR_LINE);
246 }
247
248 static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
249 char *t;
250
251 assert(s);
252 assert(name);
253 assert(pl);
254
255 t = pa_proplist_to_string_sep(pl, ", ");
256 fprintf(stderr, "Got event '%s', properties '%s'\n", name, t);
257 pa_xfree(t);
258 }
259
260 /* This is called whenever the context status changes */
261 static void context_state_callback(pa_context *c, void *userdata) {
262 assert(c);
263
264 switch (pa_context_get_state(c)) {
265 case PA_CONTEXT_CONNECTING:
266 case PA_CONTEXT_AUTHORIZING:
267 case PA_CONTEXT_SETTING_NAME:
268 break;
269
270 case PA_CONTEXT_READY: {
271 int r;
272 pa_buffer_attr buffer_attr;
273
274 assert(c);
275 assert(!stream);
276
277 if (verbose)
278 fprintf(stderr, _("Connection established.%s \n"), CLEAR_LINE);
279
280 if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
281 fprintf(stderr, _("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c)));
282 goto fail;
283 }
284
285 pa_stream_set_state_callback(stream, stream_state_callback, NULL);
286 pa_stream_set_write_callback(stream, stream_write_callback, NULL);
287 pa_stream_set_read_callback(stream, stream_read_callback, NULL);
288 pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
289 pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
290 pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
291 pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
292 pa_stream_set_started_callback(stream, stream_started_callback, NULL);
293 pa_stream_set_event_callback(stream, stream_event_callback, NULL);
294 pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
295
296 if (latency > 0) {
297 memset(&buffer_attr, 0, sizeof(buffer_attr));
298 buffer_attr.tlength = (uint32_t) latency;
299 buffer_attr.minreq = (uint32_t) process_time;
300 buffer_attr.maxlength = (uint32_t) -1;
301 buffer_attr.prebuf = (uint32_t) -1;
302 buffer_attr.fragsize = (uint32_t) latency;
303 flags |= PA_STREAM_ADJUST_LATENCY;
304 }
305
306 if (mode == PLAYBACK) {
307 pa_cvolume cv;
308 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) {
309 fprintf(stderr, _("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c)));
310 goto fail;
311 }
312
313 } else {
314 if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) {
315 fprintf(stderr, _("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c)));
316 goto fail;
317 }
318 }
319
320 break;
321 }
322
323 case PA_CONTEXT_TERMINATED:
324 quit(0);
325 break;
326
327 case PA_CONTEXT_FAILED:
328 default:
329 fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
330 goto fail;
331 }
332
333 return;
334
335 fail:
336 quit(1);
337
338 }
339
340 /* Connection draining complete */
341 static void context_drain_complete(pa_context*c, void *userdata) {
342 pa_context_disconnect(c);
343 }
344
345 /* Stream draining complete */
346 static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
347
348 if (!success) {
349 fprintf(stderr, _("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context)));
350 quit(1);
351 }
352
353 if (verbose)
354 fprintf(stderr, _("Playback stream drained.\n"));
355
356 pa_stream_disconnect(stream);
357 pa_stream_unref(stream);
358 stream = NULL;
359
360 if (!pa_context_drain(context, context_drain_complete, NULL))
361 pa_context_disconnect(context);
362 else {
363 if (verbose)
364 fprintf(stderr, _("Draining connection to server.\n"));
365 }
366 }
367
368 /* New data on STDIN **/
369 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
370 size_t l, w = 0;
371 ssize_t r;
372
373 assert(a == mainloop_api);
374 assert(e);
375 assert(stdio_event == e);
376
377 if (buffer) {
378 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
379 return;
380 }
381
382 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
383 l = 4096;
384
385 buffer = pa_xmalloc(l);
386
387 if ((r = read(fd, buffer, l)) <= 0) {
388 if (r == 0) {
389 if (verbose)
390 fprintf(stderr, _("Got EOF.\n"));
391
392 if (stream) {
393 pa_operation *o;
394
395 if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) {
396 fprintf(stderr, _("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context)));
397 quit(1);
398 return;
399 }
400
401 pa_operation_unref(o);
402 } else
403 quit(0);
404
405 } else {
406 fprintf(stderr, _("read() failed: %s\n"), strerror(errno));
407 quit(1);
408 }
409
410 mainloop_api->io_free(stdio_event);
411 stdio_event = NULL;
412 return;
413 }
414
415 buffer_length = (uint32_t) r;
416 buffer_index = 0;
417
418 if (w)
419 do_stream_write(w);
420 }
421
422 /* Some data may be written to STDOUT */
423 static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
424 ssize_t r;
425
426 assert(a == mainloop_api);
427 assert(e);
428 assert(stdio_event == e);
429
430 if (!buffer) {
431 mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL);
432 return;
433 }
434
435 assert(buffer_length);
436
437 if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) {
438 fprintf(stderr, _("write() failed: %s\n"), strerror(errno));
439 quit(1);
440
441 mainloop_api->io_free(stdio_event);
442 stdio_event = NULL;
443 return;
444 }
445
446 buffer_length -= (uint32_t) r;
447 buffer_index += (uint32_t) r;
448
449 if (!buffer_length) {
450 pa_xfree(buffer);
451 buffer = NULL;
452 buffer_length = buffer_index = 0;
453 }
454 }
455
456 /* UNIX signal to quit recieved */
457 static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
458 if (verbose)
459 fprintf(stderr, _("Got signal, exiting.\n"));
460 quit(0);
461 }
462
463 /* Show the current latency */
464 static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) {
465 pa_usec_t l, usec;
466 int negative = 0;
467
468 assert(s);
469
470 if (!success ||
471 pa_stream_get_time(s, &usec) < 0 ||
472 pa_stream_get_latency(s, &l, &negative) < 0) {
473 fprintf(stderr, _("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context)));
474 quit(1);
475 return;
476 }
477
478 fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec. \r"),
479 (float) usec / 1000000,
480 (float) l * (negative?-1.0f:1.0f));
481 }
482
483 /* Someone requested that the latency is shown */
484 static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
485
486 if (!stream)
487 return;
488
489 pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
490 }
491
492 static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
493 struct timeval next;
494
495 if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
496 pa_operation *o;
497 if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
498 fprintf(stderr, _("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context)));
499 else
500 pa_operation_unref(o);
501 }
502
503 pa_gettimeofday(&next);
504 pa_timeval_add(&next, TIME_EVENT_USEC);
505
506 m->time_restart(e, &next);
507 }
508
509 static void help(const char *argv0) {
510
511 printf(_("%s [options]\n\n"
512 " -h, --help Show this help\n"
513 " --version Show version\n\n"
514 " -r, --record Create a connection for recording\n"
515 " -p, --playback Create a connection for playback\n\n"
516 " -v, --verbose Enable verbose operations\n\n"
517 " -s, --server=SERVER The name of the server to connect to\n"
518 " -d, --device=DEVICE The name of the sink/source to connect to\n"
519 " -n, --client-name=NAME How to call this client on the server\n"
520 " --stream-name=NAME How to call this stream on the server\n"
521 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
522 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
523 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
524 " float32be, ulaw, alaw, s32le, s32be (defaults to s16ne)\n"
525 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
526 " (defaults to 2)\n"
527 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
528 " --fix-format Take the sample format from the sink the stream is\n"
529 " being connected to.\n"
530 " --fix-rate Take the sampling rate from the sink the stream is\n"
531 " being connected to.\n"
532 " --fix-channels Take the number of channels and the channel map\n"
533 " from the sink the stream is being connected to.\n"
534 " --no-remix Don't upmix or downmix channels.\n"
535 " --no-remap Map channels by index instead of name.\n"
536 " --latency=BYTES Request the specified latency in bytes.\n"
537 " --process-time=BYTES Request the specified process time per request in bytes.\n")
538 ,
539 argv0);
540 }
541
542 enum {
543 ARG_VERSION = 256,
544 ARG_STREAM_NAME,
545 ARG_VOLUME,
546 ARG_SAMPLERATE,
547 ARG_SAMPLEFORMAT,
548 ARG_CHANNELS,
549 ARG_CHANNELMAP,
550 ARG_FIX_FORMAT,
551 ARG_FIX_RATE,
552 ARG_FIX_CHANNELS,
553 ARG_NO_REMAP,
554 ARG_NO_REMIX,
555 ARG_LATENCY,
556 ARG_PROCESS_TIME
557 };
558
559 int main(int argc, char *argv[]) {
560 pa_mainloop* m = NULL;
561 int ret = 1, r, c;
562 char *bn, *server = NULL;
563 pa_time_event *time_event = NULL;
564
565 static const struct option long_options[] = {
566 {"record", 0, NULL, 'r'},
567 {"playback", 0, NULL, 'p'},
568 {"device", 1, NULL, 'd'},
569 {"server", 1, NULL, 's'},
570 {"client-name", 1, NULL, 'n'},
571 {"stream-name", 1, NULL, ARG_STREAM_NAME},
572 {"version", 0, NULL, ARG_VERSION},
573 {"help", 0, NULL, 'h'},
574 {"verbose", 0, NULL, 'v'},
575 {"volume", 1, NULL, ARG_VOLUME},
576 {"rate", 1, NULL, ARG_SAMPLERATE},
577 {"format", 1, NULL, ARG_SAMPLEFORMAT},
578 {"channels", 1, NULL, ARG_CHANNELS},
579 {"channel-map", 1, NULL, ARG_CHANNELMAP},
580 {"fix-format", 0, NULL, ARG_FIX_FORMAT},
581 {"fix-rate", 0, NULL, ARG_FIX_RATE},
582 {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
583 {"no-remap", 0, NULL, ARG_NO_REMAP},
584 {"no-remix", 0, NULL, ARG_NO_REMIX},
585 {"latency", 1, NULL, ARG_LATENCY},
586 {"process-time", 1, NULL, ARG_PROCESS_TIME},
587 {NULL, 0, NULL, 0}
588 };
589
590 setlocale(LC_ALL, "");
591 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
592
593 if (!(bn = strrchr(argv[0], '/')))
594 bn = argv[0];
595 else
596 bn++;
597
598 if (strstr(bn, "rec") || strstr(bn, "mon"))
599 mode = RECORD;
600 else if (strstr(bn, "cat") || strstr(bn, "play"))
601 mode = PLAYBACK;
602
603 while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {
604
605 switch (c) {
606 case 'h' :
607 help(bn);
608 ret = 0;
609 goto quit;
610
611 case ARG_VERSION:
612 printf(_("pacat %s\nCompiled with libpulse %s\nLinked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version());
613 ret = 0;
614 goto quit;
615
616 case 'r':
617 mode = RECORD;
618 break;
619
620 case 'p':
621 mode = PLAYBACK;
622 break;
623
624 case 'd':
625 pa_xfree(device);
626 device = pa_xstrdup(optarg);
627 break;
628
629 case 's':
630 pa_xfree(server);
631 server = pa_xstrdup(optarg);
632 break;
633
634 case 'n':
635 pa_xfree(client_name);
636 client_name = pa_xstrdup(optarg);
637 break;
638
639 case ARG_STREAM_NAME:
640 pa_xfree(stream_name);
641 stream_name = pa_xstrdup(optarg);
642 break;
643
644 case 'v':
645 verbose = 1;
646 break;
647
648 case ARG_VOLUME: {
649 int v = atoi(optarg);
650 volume = v < 0 ? 0U : (pa_volume_t) v;
651 volume_is_set = 1;
652 break;
653 }
654
655 case ARG_CHANNELS:
656 sample_spec.channels = (uint8_t) atoi(optarg);
657 break;
658
659 case ARG_SAMPLEFORMAT:
660 sample_spec.format = pa_parse_sample_format(optarg);
661 break;
662
663 case ARG_SAMPLERATE:
664 sample_spec.rate = (uint32_t) atoi(optarg);
665 break;
666
667 case ARG_CHANNELMAP:
668 if (!pa_channel_map_parse(&channel_map, optarg)) {
669 fprintf(stderr, _("Invalid channel map '%s'\n"), optarg);
670 goto quit;
671 }
672
673 channel_map_set = 1;
674 break;
675
676 case ARG_FIX_CHANNELS:
677 flags |= PA_STREAM_FIX_CHANNELS;
678 break;
679
680 case ARG_FIX_RATE:
681 flags |= PA_STREAM_FIX_RATE;
682 break;
683
684 case ARG_FIX_FORMAT:
685 flags |= PA_STREAM_FIX_FORMAT;
686 break;
687
688 case ARG_NO_REMIX:
689 flags |= PA_STREAM_NO_REMIX_CHANNELS;
690 break;
691
692 case ARG_NO_REMAP:
693 flags |= PA_STREAM_NO_REMAP_CHANNELS;
694 break;
695
696 case ARG_LATENCY:
697 if (((latency = (size_t) atoi(optarg))) <= 0) {
698 fprintf(stderr, _("Invalid latency specification '%s'\n"), optarg);
699 goto quit;
700 }
701 break;
702
703 case ARG_PROCESS_TIME:
704 if (((process_time = (size_t) atoi(optarg))) <= 0) {
705 fprintf(stderr, _("Invalid process time specification '%s'\n"), optarg);
706 goto quit;
707 }
708 break;
709
710 default:
711 goto quit;
712 }
713 }
714
715 if (!pa_sample_spec_valid(&sample_spec)) {
716 fprintf(stderr, _("Invalid sample specification\n"));
717 goto quit;
718 }
719
720 if (channel_map_set && pa_channel_map_compatible(&channel_map, &sample_spec)) {
721 fprintf(stderr, _("Channel map doesn't match sample specification\n"));
722 goto quit;
723 }
724
725 if (verbose) {
726 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
727 pa_sample_spec_snprint(t, sizeof(t), &sample_spec);
728 fprintf(stderr, _("Opening a %s stream with sample specification '%s'.\n"), mode == RECORD ? _("recording") : _("playback"), t);
729 }
730
731 if (!(optind >= argc)) {
732 if (optind+1 == argc) {
733 int fd;
734
735 if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
736 fprintf(stderr, _("open(): %s\n"), strerror(errno));
737 goto quit;
738 }
739
740 if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) {
741 fprintf(stderr, _("dup2(): %s\n"), strerror(errno));
742 goto quit;
743 }
744
745 close(fd);
746
747 if (!stream_name)
748 stream_name = pa_xstrdup(argv[optind]);
749
750 } else {
751 fprintf(stderr, _("Too many arguments.\n"));
752 goto quit;
753 }
754 }
755
756 if (!client_name)
757 client_name = pa_xstrdup(bn);
758
759 if (!stream_name)
760 stream_name = pa_xstrdup(client_name);
761
762 /* Set up a new main loop */
763 if (!(m = pa_mainloop_new())) {
764 fprintf(stderr, _("pa_mainloop_new() failed.\n"));
765 goto quit;
766 }
767
768 mainloop_api = pa_mainloop_get_api(m);
769
770 r = pa_signal_init(mainloop_api);
771 assert(r == 0);
772 pa_signal_new(SIGINT, exit_signal_callback, NULL);
773 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
774 #ifdef SIGUSR1
775 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
776 #endif
777 #ifdef SIGPIPE
778 signal(SIGPIPE, SIG_IGN);
779 #endif
780
781 if (!(stdio_event = mainloop_api->io_new(mainloop_api,
782 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
783 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
784 mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) {
785 fprintf(stderr, _("io_new() failed.\n"));
786 goto quit;
787 }
788
789 /* Create a new connection context */
790 if (!(context = pa_context_new(mainloop_api, client_name))) {
791 fprintf(stderr, _("pa_context_new() failed.\n"));
792 goto quit;
793 }
794
795 pa_context_set_state_callback(context, context_state_callback, NULL);
796
797 /* Connect the context */
798 if (pa_context_connect(context, server, 0, NULL) < 0) {
799 fprintf(stderr, _("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context)));
800 goto quit;
801 }
802
803 if (verbose) {
804 struct timeval tv;
805
806 pa_gettimeofday(&tv);
807 pa_timeval_add(&tv, TIME_EVENT_USEC);
808
809 if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) {
810 fprintf(stderr, _("time_new() failed.\n"));
811 goto quit;
812 }
813 }
814
815 /* Run the main loop */
816 if (pa_mainloop_run(m, &ret) < 0) {
817 fprintf(stderr, _("pa_mainloop_run() failed.\n"));
818 goto quit;
819 }
820
821 quit:
822 if (stream)
823 pa_stream_unref(stream);
824
825 if (context)
826 pa_context_unref(context);
827
828 if (stdio_event) {
829 assert(mainloop_api);
830 mainloop_api->io_free(stdio_event);
831 }
832
833 if (time_event) {
834 assert(mainloop_api);
835 mainloop_api->time_free(time_event);
836 }
837
838 if (m) {
839 pa_signal_done();
840 pa_mainloop_free(m);
841 }
842
843 pa_xfree(buffer);
844
845 pa_xfree(server);
846 pa_xfree(device);
847 pa_xfree(client_name);
848 pa_xfree(stream_name);
849
850 return ret;
851 }