2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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
40 #include <pulse/pulseaudio.h>
41 #include <pulse/rtclock.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/i18n.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/macro.h>
47 #include <pulsecore/sndfile-util.h>
48 #include <pulsecore/sample-util.h>
50 #define TIME_EVENT_USEC 50000
52 #define CLEAR_LINE "\x1B[K"
54 static enum { RECORD
, PLAYBACK
} mode
= PLAYBACK
;
56 static pa_context
*context
= NULL
;
57 static pa_stream
*stream
= NULL
;
58 static pa_mainloop_api
*mainloop_api
= NULL
;
60 static void *buffer
= NULL
;
61 static size_t buffer_length
= 0, buffer_index
= 0;
63 static void *silence_buffer
= NULL
;
64 static size_t silence_buffer_length
= 0;
66 static pa_io_event
* stdio_event
= NULL
;
68 static pa_proplist
*proplist
= NULL
;
69 static char *device
= NULL
;
71 static SNDFILE
* sndfile
= NULL
;
73 static bool verbose
= false;
74 static pa_volume_t volume
= PA_VOLUME_NORM
;
75 static bool volume_is_set
= false;
77 static pa_sample_spec sample_spec
= {
78 .format
= PA_SAMPLE_S16LE
,
82 static bool sample_spec_set
= false;
84 static pa_channel_map channel_map
;
85 static bool channel_map_set
= false;
87 static sf_count_t (*readf_function
)(SNDFILE
*_sndfile
, void *ptr
, sf_count_t frames
) = NULL
;
88 static sf_count_t (*writef_function
)(SNDFILE
*_sndfile
, const void *ptr
, sf_count_t frames
) = NULL
;
90 static pa_stream_flags_t flags
= 0;
92 static size_t latency
= 0, process_time
= 0;
93 static int32_t latency_msec
= 0, process_time_msec
= 0;
95 static bool raw
= true;
96 static int file_format
= -1;
98 static uint32_t monitor_stream
= PA_INVALID_INDEX
;
100 static uint32_t cork_requests
= 0;
102 /* A shortcut for terminating the application */
103 static void quit(int ret
) {
104 pa_assert(mainloop_api
);
105 mainloop_api
->quit(mainloop_api
, ret
);
108 /* Connection draining complete */
109 static void context_drain_complete(pa_context
*c
, void *userdata
) {
110 pa_context_disconnect(c
);
113 /* Stream draining complete */
114 static void stream_drain_complete(pa_stream
*s
, int success
, void *userdata
) {
115 pa_operation
*o
= NULL
;
118 pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context
)));
123 pa_log(_("Playback stream drained."));
125 pa_stream_disconnect(stream
);
126 pa_stream_unref(stream
);
129 if (!(o
= pa_context_drain(context
, context_drain_complete
, NULL
)))
130 pa_context_disconnect(context
);
132 pa_operation_unref(o
);
134 pa_log(_("Draining connection to server."));
139 static void start_drain(void) {
144 pa_stream_set_write_callback(stream
, NULL
, NULL
);
146 if (!(o
= pa_stream_drain(stream
, stream_drain_complete
, NULL
))) {
147 pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context
)));
152 pa_operation_unref(o
);
157 /* Write some data to the stream */
158 static void do_stream_write(size_t length
) {
162 if (!buffer
|| !buffer_length
)
166 if (l
> buffer_length
)
169 if (pa_stream_write(stream
, (uint8_t*) buffer
+ buffer_index
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0) {
170 pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
178 if (!buffer_length
) {
181 buffer_index
= buffer_length
= 0;
185 /* This is called whenever new data may be written to the stream */
186 static void stream_write_callback(pa_stream
*s
, size_t length
, void *userdata
) {
188 pa_assert(length
> 0);
194 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_INPUT
);
199 do_stream_write(length
);
208 size_t data_length
= length
;
210 if (pa_stream_begin_write(s
, &data
, &data_length
) < 0) {
211 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
216 if (readf_function
) {
217 size_t k
= pa_frame_size(&sample_spec
);
219 if ((bytes
= readf_function(sndfile
, data
, (sf_count_t
) (data_length
/k
))) > 0)
220 bytes
*= (sf_count_t
) k
;
223 bytes
= sf_read_raw(sndfile
, data
, (sf_count_t
) data_length
);
226 pa_stream_write(s
, data
, (size_t) bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
228 pa_stream_cancel_write(s
);
231 if (bytes
< (sf_count_t
) data_length
) {
236 /* Request fulfilled */
237 if ((size_t) bytes
>= length
)
245 /* This is called whenever new data may is available */
246 static void stream_read_callback(pa_stream
*s
, size_t length
, void *userdata
) {
249 pa_assert(length
> 0);
255 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_OUTPUT
);
257 while (pa_stream_readable_size(s
) > 0) {
260 if (pa_stream_peek(s
, &data
, &length
) < 0) {
261 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
266 pa_assert(length
> 0);
268 /* If there is a hole in the stream, we generate silence, except
269 * if it's a passthrough stream in which case we skip the hole. */
270 if (data
|| !(flags
& PA_STREAM_PASSTHROUGH
)) {
271 buffer
= pa_xrealloc(buffer
, buffer_length
+ length
);
273 memcpy((uint8_t *) buffer
+ buffer_length
, data
, length
);
275 pa_silence_memory((uint8_t *) buffer
+ buffer_length
, length
, &sample_spec
);
277 buffer_length
+= length
;
286 while (pa_stream_readable_size(s
) > 0) {
290 if (pa_stream_peek(s
, &data
, &length
) < 0) {
291 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
296 pa_assert(length
> 0);
298 if (!data
&& (flags
& PA_STREAM_PASSTHROUGH
)) {
303 if (!data
&& length
> silence_buffer_length
) {
304 silence_buffer
= pa_xrealloc(silence_buffer
, length
);
305 pa_silence_memory((uint8_t *) silence_buffer
+ silence_buffer_length
, length
- silence_buffer_length
, &sample_spec
);
306 silence_buffer_length
= length
;
309 if (writef_function
) {
310 size_t k
= pa_frame_size(&sample_spec
);
312 if ((bytes
= writef_function(sndfile
, data
? data
: silence_buffer
, (sf_count_t
) (length
/k
))) > 0)
313 bytes
*= (sf_count_t
) k
;
316 bytes
= sf_write_raw(sndfile
, data
? data
: silence_buffer
, (sf_count_t
) length
);
318 if (bytes
< (sf_count_t
) length
)
326 /* This routine is called whenever the stream state changes */
327 static void stream_state_callback(pa_stream
*s
, void *userdata
) {
330 switch (pa_stream_get_state(s
)) {
331 case PA_STREAM_CREATING
:
332 case PA_STREAM_TERMINATED
:
335 case PA_STREAM_READY
:
338 const pa_buffer_attr
*a
;
339 char cmt
[PA_CHANNEL_MAP_SNPRINT_MAX
], sst
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
341 pa_log(_("Stream successfully created."));
343 if (!(a
= pa_stream_get_buffer_attr(s
)))
344 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
347 if (mode
== PLAYBACK
)
348 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a
->maxlength
, a
->tlength
, a
->prebuf
, a
->minreq
);
350 pa_assert(mode
== RECORD
);
351 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a
->maxlength
, a
->fragsize
);
355 pa_log(_("Using sample spec '%s', channel map '%s'."),
356 pa_sample_spec_snprint(sst
, sizeof(sst
), pa_stream_get_sample_spec(s
)),
357 pa_channel_map_snprint(cmt
, sizeof(cmt
), pa_stream_get_channel_map(s
)));
359 pa_log(_("Connected to device %s (index: %u, suspended: %s)."),
360 pa_stream_get_device_name(s
),
361 pa_stream_get_device_index(s
),
362 pa_yes_no(pa_stream_is_suspended(s
)));
367 case PA_STREAM_FAILED
:
369 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
374 static void stream_suspended_callback(pa_stream
*s
, void *userdata
) {
378 if (pa_stream_is_suspended(s
))
379 pa_log(_("Stream device suspended.%s"), CLEAR_LINE
);
381 pa_log(_("Stream device resumed.%s"), CLEAR_LINE
);
385 static void stream_underflow_callback(pa_stream
*s
, void *userdata
) {
389 pa_log(_("Stream underrun.%s"), CLEAR_LINE
);
392 static void stream_overflow_callback(pa_stream
*s
, void *userdata
) {
396 pa_log(_("Stream overrun.%s"), CLEAR_LINE
);
399 static void stream_started_callback(pa_stream
*s
, void *userdata
) {
403 pa_log(_("Stream started.%s"), CLEAR_LINE
);
406 static void stream_moved_callback(pa_stream
*s
, void *userdata
) {
410 pa_log(_("Stream moved to device %s (%u, %ssuspended).%s"), pa_stream_get_device_name(s
), pa_stream_get_device_index(s
), pa_stream_is_suspended(s
) ? "" : _("not "), CLEAR_LINE
);
413 static void stream_buffer_attr_callback(pa_stream
*s
, void *userdata
) {
417 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE
);
420 static void stream_event_callback(pa_stream
*s
, const char *name
, pa_proplist
*pl
, void *userdata
) {
427 t
= pa_proplist_to_string_sep(pl
, ", ");
428 pa_log("Got event '%s', properties '%s'", name
, t
);
430 if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_CORK
)) {
431 if (cork_requests
== 0) {
432 pa_log(_("Cork request stack is empty: corking stream"));
433 pa_operation_unref(pa_stream_cork(s
, 1, NULL
, NULL
));
436 } else if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_UNCORK
)) {
437 if (cork_requests
== 1) {
438 pa_log(_("Cork request stack is empty: uncorking stream"));
439 pa_operation_unref(pa_stream_cork(s
, 0, NULL
, NULL
));
441 if (cork_requests
== 0)
442 pa_log(_("Warning: Received more uncork requests than cork requests!"));
450 /* This is called whenever the context status changes */
451 static void context_state_callback(pa_context
*c
, void *userdata
) {
454 switch (pa_context_get_state(c
)) {
455 case PA_CONTEXT_CONNECTING
:
456 case PA_CONTEXT_AUTHORIZING
:
457 case PA_CONTEXT_SETTING_NAME
:
460 case PA_CONTEXT_READY
: {
461 pa_buffer_attr buffer_attr
;
467 pa_log(_("Connection established.%s"), CLEAR_LINE
);
469 if (!(stream
= pa_stream_new_with_proplist(c
, NULL
, &sample_spec
, &channel_map
, proplist
))) {
470 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c
)));
474 pa_stream_set_state_callback(stream
, stream_state_callback
, NULL
);
475 pa_stream_set_write_callback(stream
, stream_write_callback
, NULL
);
476 pa_stream_set_read_callback(stream
, stream_read_callback
, NULL
);
477 pa_stream_set_suspended_callback(stream
, stream_suspended_callback
, NULL
);
478 pa_stream_set_moved_callback(stream
, stream_moved_callback
, NULL
);
479 pa_stream_set_underflow_callback(stream
, stream_underflow_callback
, NULL
);
480 pa_stream_set_overflow_callback(stream
, stream_overflow_callback
, NULL
);
481 pa_stream_set_started_callback(stream
, stream_started_callback
, NULL
);
482 pa_stream_set_event_callback(stream
, stream_event_callback
, NULL
);
483 pa_stream_set_buffer_attr_callback(stream
, stream_buffer_attr_callback
, NULL
);
485 pa_zero(buffer_attr
);
486 buffer_attr
.maxlength
= (uint32_t) -1;
487 buffer_attr
.prebuf
= (uint32_t) -1;
489 if (latency_msec
> 0) {
490 buffer_attr
.fragsize
= buffer_attr
.tlength
= pa_usec_to_bytes(latency_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
491 flags
|= PA_STREAM_ADJUST_LATENCY
;
492 } else if (latency
> 0) {
493 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) latency
;
494 flags
|= PA_STREAM_ADJUST_LATENCY
;
496 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) -1;
498 if (process_time_msec
> 0) {
499 buffer_attr
.minreq
= pa_usec_to_bytes(process_time_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
500 } else if (process_time
> 0)
501 buffer_attr
.minreq
= (uint32_t) process_time
;
503 buffer_attr
.minreq
= (uint32_t) -1;
505 if (mode
== PLAYBACK
) {
507 if (pa_stream_connect_playback(stream
, device
, &buffer_attr
, flags
, volume_is_set
? pa_cvolume_set(&cv
, sample_spec
.channels
, volume
) : NULL
, NULL
) < 0) {
508 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c
)));
513 if (monitor_stream
!= PA_INVALID_INDEX
&& (pa_stream_set_monitor_stream(stream
, monitor_stream
) < 0)) {
514 pa_log(_("Failed to set monitor stream: %s"), pa_strerror(pa_context_errno(c
)));
517 if (pa_stream_connect_record(stream
, device
, &buffer_attr
, flags
) < 0) {
518 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c
)));
525 case PA_CONTEXT_TERMINATED
:
529 case PA_CONTEXT_FAILED
:
531 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c
)));
542 /* New data on STDIN **/
543 static void stdin_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
547 pa_assert(a
== mainloop_api
);
549 pa_assert(stdio_event
== e
);
552 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
556 if (!stream
|| pa_stream_get_state(stream
) != PA_STREAM_READY
|| !(l
= w
= pa_stream_writable_size(stream
)))
559 buffer
= pa_xmalloc(l
);
561 if ((r
= pa_read(fd
, buffer
, l
, userdata
)) <= 0) {
564 pa_log(_("Got EOF."));
569 pa_log(_("read() failed: %s"), strerror(errno
));
573 mainloop_api
->io_free(stdio_event
);
578 buffer_length
= (uint32_t) r
;
585 /* Some data may be written to STDOUT */
586 static void stdout_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
589 pa_assert(a
== mainloop_api
);
591 pa_assert(stdio_event
== e
);
594 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
598 pa_assert(buffer_length
);
600 if ((r
= pa_write(fd
, (uint8_t*) buffer
+buffer_index
, buffer_length
, userdata
)) <= 0) {
601 pa_log(_("write() failed: %s"), strerror(errno
));
604 mainloop_api
->io_free(stdio_event
);
609 buffer_length
-= (uint32_t) r
;
610 buffer_index
+= (uint32_t) r
;
612 if (!buffer_length
) {
615 buffer_length
= buffer_index
= 0;
619 /* UNIX signal to quit received */
620 static void exit_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
622 pa_log(_("Got signal, exiting."));
626 /* Show the current latency */
627 static void stream_update_timing_callback(pa_stream
*s
, int success
, void *userdata
) {
634 pa_stream_get_time(s
, &usec
) < 0 ||
635 pa_stream_get_latency(s
, &l
, &negative
) < 0) {
636 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context
)));
641 fprintf(stderr
, _("Time: %0.3f sec; Latency: %0.0f usec."),
642 (float) usec
/ 1000000,
643 (float) l
* (negative
?-1.0f
:1.0f
));
644 fprintf(stderr
, " \r");
648 /* Someone requested that the latency is shown */
649 static void sigusr1_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
654 pa_operation_unref(pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
));
658 static void time_event_callback(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
659 if (stream
&& pa_stream_get_state(stream
) == PA_STREAM_READY
) {
661 if (!(o
= pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
)))
662 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context
)));
664 pa_operation_unref(o
);
667 pa_context_rttime_restart(context
, e
, pa_rtclock_now() + TIME_EVENT_USEC
);
670 static void help(const char *argv0
) {
672 printf(_("%s [options]\n\n"
673 " -h, --help Show this help\n"
674 " --version Show version\n\n"
675 " -r, --record Create a connection for recording\n"
676 " -p, --playback Create a connection for playback\n\n"
677 " -v, --verbose Enable verbose operations\n\n"
678 " -s, --server=SERVER The name of the server to connect to\n"
679 " -d, --device=DEVICE The name of the sink/source to connect to\n"
680 " -n, --client-name=NAME How to call this client on the server\n"
681 " --stream-name=NAME How to call this stream on the server\n"
682 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
683 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
684 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
685 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
686 " s24-32le, s24-32be (defaults to s16ne)\n"
687 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
689 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
690 " --fix-format Take the sample format from the sink the stream is\n"
691 " being connected to.\n"
692 " --fix-rate Take the sampling rate from the sink the stream is\n"
693 " being connected to.\n"
694 " --fix-channels Take the number of channels and the channel map\n"
695 " from the sink the stream is being connected to.\n"
696 " --no-remix Don't upmix or downmix channels.\n"
697 " --no-remap Map channels by index instead of name.\n"
698 " --latency=BYTES Request the specified latency in bytes.\n"
699 " --process-time=BYTES Request the specified process time per request in bytes.\n"
700 " --latency-msec=MSEC Request the specified latency in msec.\n"
701 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
702 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
703 " --raw Record/play raw PCM data.\n"
704 " --passthrough passthrough data \n"
705 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
706 " --list-file-formats List available file formats.\n"
707 " --monitor-stream=INDEX Record from the sink input with index INDEX.\n")
730 ARG_LIST_FILE_FORMATS
,
732 ARG_PROCESS_TIME_MSEC
,
736 int main(int argc
, char *argv
[]) {
737 pa_mainloop
* m
= NULL
;
739 char *bn
, *server
= NULL
;
740 pa_time_event
*time_event
= NULL
;
741 const char *filename
= NULL
;
742 /* type for pa_read/_write. passed as userdata to the callbacks */
743 unsigned long type
= 0;
745 static const struct option long_options
[] = {
746 {"record", 0, NULL
, 'r'},
747 {"playback", 0, NULL
, 'p'},
748 {"device", 1, NULL
, 'd'},
749 {"server", 1, NULL
, 's'},
750 {"client-name", 1, NULL
, 'n'},
751 {"stream-name", 1, NULL
, ARG_STREAM_NAME
},
752 {"version", 0, NULL
, ARG_VERSION
},
753 {"help", 0, NULL
, 'h'},
754 {"verbose", 0, NULL
, 'v'},
755 {"volume", 1, NULL
, ARG_VOLUME
},
756 {"rate", 1, NULL
, ARG_SAMPLERATE
},
757 {"format", 1, NULL
, ARG_SAMPLEFORMAT
},
758 {"channels", 1, NULL
, ARG_CHANNELS
},
759 {"channel-map", 1, NULL
, ARG_CHANNELMAP
},
760 {"fix-format", 0, NULL
, ARG_FIX_FORMAT
},
761 {"fix-rate", 0, NULL
, ARG_FIX_RATE
},
762 {"fix-channels", 0, NULL
, ARG_FIX_CHANNELS
},
763 {"no-remap", 0, NULL
, ARG_NO_REMAP
},
764 {"no-remix", 0, NULL
, ARG_NO_REMIX
},
765 {"latency", 1, NULL
, ARG_LATENCY
},
766 {"process-time", 1, NULL
, ARG_PROCESS_TIME
},
767 {"property", 1, NULL
, ARG_PROPERTY
},
768 {"raw", 0, NULL
, ARG_RAW
},
769 {"passthrough", 0, NULL
, ARG_PASSTHROUGH
},
770 {"file-format", 2, NULL
, ARG_FILE_FORMAT
},
771 {"list-file-formats", 0, NULL
, ARG_LIST_FILE_FORMATS
},
772 {"latency-msec", 1, NULL
, ARG_LATENCY_MSEC
},
773 {"process-time-msec", 1, NULL
, ARG_PROCESS_TIME_MSEC
},
774 {"monitor-stream", 1, NULL
, ARG_MONITOR_STREAM
},
778 setlocale(LC_ALL
, "");
780 bindtextdomain(GETTEXT_PACKAGE
, PULSE_LOCALEDIR
);
783 bn
= pa_path_get_filename(argv
[0]);
785 if (strstr(bn
, "play")) {
788 } else if (strstr(bn
, "record")) {
791 } else if (strstr(bn
, "cat")) {
794 } else if (strstr(bn
, "rec") || strstr(bn
, "mon")) {
799 proplist
= pa_proplist_new();
801 while ((c
= getopt_long(argc
, argv
, "rpd:s:n:hv", long_options
, NULL
)) != -1) {
810 printf(_("pacat %s\n"
811 "Compiled with libpulse %s\n"
812 "Linked with libpulse %s\n"),
814 pa_get_headers_version(),
815 pa_get_library_version());
829 device
= pa_xstrdup(optarg
);
834 server
= pa_xstrdup(optarg
);
840 if (!(t
= pa_locale_to_utf8(optarg
)) ||
841 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
) < 0) {
843 pa_log(_("Invalid client name '%s'"), t
? t
: optarg
);
852 case ARG_STREAM_NAME
: {
855 if (!(t
= pa_locale_to_utf8(optarg
)) ||
856 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
) < 0) {
858 pa_log(_("Invalid stream name '%s'"), t
? t
: optarg
);
872 int v
= atoi(optarg
);
873 volume
= v
< 0 ? 0U : (pa_volume_t
) v
;
874 volume_is_set
= true;
879 sample_spec
.channels
= (uint8_t) atoi(optarg
);
880 sample_spec_set
= true;
883 case ARG_SAMPLEFORMAT
:
884 sample_spec
.format
= pa_parse_sample_format(optarg
);
885 sample_spec_set
= true;
889 sample_spec
.rate
= (uint32_t) atoi(optarg
);
890 sample_spec_set
= true;
894 if (!pa_channel_map_parse(&channel_map
, optarg
)) {
895 pa_log(_("Invalid channel map '%s'"), optarg
);
899 channel_map_set
= true;
902 case ARG_FIX_CHANNELS
:
903 flags
|= PA_STREAM_FIX_CHANNELS
;
907 flags
|= PA_STREAM_FIX_RATE
;
911 flags
|= PA_STREAM_FIX_FORMAT
;
915 flags
|= PA_STREAM_NO_REMIX_CHANNELS
;
919 flags
|= PA_STREAM_NO_REMAP_CHANNELS
;
923 if (((latency
= (size_t) atoi(optarg
))) <= 0) {
924 pa_log(_("Invalid latency specification '%s'"), optarg
);
929 case ARG_PROCESS_TIME
:
930 if (((process_time
= (size_t) atoi(optarg
))) <= 0) {
931 pa_log(_("Invalid process time specification '%s'"), optarg
);
936 case ARG_LATENCY_MSEC
:
937 if (((latency_msec
= (int32_t) atoi(optarg
))) <= 0) {
938 pa_log(_("Invalid latency specification '%s'"), optarg
);
943 case ARG_PROCESS_TIME_MSEC
:
944 if (((process_time_msec
= (int32_t) atoi(optarg
))) <= 0) {
945 pa_log(_("Invalid process time specification '%s'"), optarg
);
953 if (!(t
= pa_locale_to_utf8(optarg
)) ||
954 pa_proplist_setp(proplist
, t
) < 0) {
957 pa_log(_("Invalid property '%s'"), optarg
);
969 case ARG_PASSTHROUGH
:
970 flags
|= PA_STREAM_PASSTHROUGH
;
973 case ARG_FILE_FORMAT
:
975 if ((file_format
= pa_sndfile_format_from_string(optarg
)) < 0) {
976 pa_log(_("Unknown file format %s."), optarg
);
984 case ARG_LIST_FILE_FORMATS
:
985 pa_sndfile_dump_formats();
989 case ARG_MONITOR_STREAM
:
990 if (pa_atou(optarg
, &monitor_stream
) < 0) {
991 pa_log(_("Failed to parse the argument for --monitor-stream"));
1001 if (!pa_sample_spec_valid(&sample_spec
)) {
1002 pa_log(_("Invalid sample specification"));
1006 if (optind
+1 == argc
) {
1009 filename
= argv
[optind
];
1011 if ((fd
= pa_open_cloexec(argv
[optind
], mode
== PLAYBACK
? O_RDONLY
: O_WRONLY
|O_TRUNC
|O_CREAT
, 0666)) < 0) {
1012 pa_log(_("open(): %s"), strerror(errno
));
1016 if (dup2(fd
, mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
) < 0) {
1017 pa_log(_("dup2(): %s"), strerror(errno
));
1023 } else if (optind
+1 <= argc
) {
1024 pa_log(_("Too many arguments."));
1032 if (mode
== RECORD
) {
1033 /* This might patch up the sample spec */
1034 if (pa_sndfile_write_sample_spec(&sfi
, &sample_spec
) < 0) {
1035 pa_log(_("Failed to generate sample specification for file."));
1039 if (file_format
<= 0) {
1041 if (filename
&& (extension
= strrchr(filename
, '.')))
1042 file_format
= pa_sndfile_format_from_string(extension
+1);
1043 if (file_format
<= 0)
1044 file_format
= SF_FORMAT_WAV
;
1045 /* Transparently upgrade classic .wav to wavex for multichannel audio */
1046 if (file_format
== SF_FORMAT_WAV
&&
1047 (sample_spec
.channels
> 2 ||
1049 !(sample_spec
.channels
== 1 && channel_map
.map
[0] == PA_CHANNEL_POSITION_MONO
) &&
1050 !(sample_spec
.channels
== 2 && channel_map
.map
[0] == PA_CHANNEL_POSITION_LEFT
1051 && channel_map
.map
[1] == PA_CHANNEL_POSITION_RIGHT
))))
1052 file_format
= SF_FORMAT_WAVEX
;
1055 sfi
.format
|= file_format
;
1058 if (!(sndfile
= sf_open_fd(mode
== RECORD
? STDOUT_FILENO
: STDIN_FILENO
,
1059 mode
== RECORD
? SFM_WRITE
: SFM_READ
,
1061 pa_log(_("Failed to open audio file."));
1065 if (mode
== PLAYBACK
) {
1066 if (sample_spec_set
)
1067 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1069 if (pa_sndfile_read_sample_spec(sndfile
, &sample_spec
) < 0) {
1070 pa_log(_("Failed to determine sample specification from file."));
1073 sample_spec_set
= true;
1075 if (!channel_map_set
) {
1076 /* Allow the user to overwrite the channel map on the command line */
1077 if (pa_sndfile_read_channel_map(sndfile
, &channel_map
) < 0) {
1078 if (sample_spec
.channels
> 2)
1079 pa_log(_("Warning: Failed to determine channel map from file."));
1081 channel_map_set
= true;
1086 if (!channel_map_set
)
1087 pa_channel_map_init_extend(&channel_map
, sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
);
1089 if (!pa_channel_map_compatible(&channel_map
, &sample_spec
)) {
1090 pa_log(_("Channel map doesn't match sample specification"));
1097 if (mode
== PLAYBACK
)
1098 readf_function
= pa_sndfile_readf_function(&sample_spec
);
1100 if (pa_sndfile_write_channel_map(sndfile
, &channel_map
) < 0)
1101 pa_log(_("Warning: failed to write channel map to file."));
1103 writef_function
= pa_sndfile_writef_function(&sample_spec
);
1106 /* Fill in libsndfile prop list data */
1107 sfp
= pa_proplist_new();
1108 pa_sndfile_init_proplist(sndfile
, sfp
);
1109 pa_proplist_update(proplist
, PA_UPDATE_MERGE
, sfp
);
1110 pa_proplist_free(sfp
);
1114 char tss
[PA_SAMPLE_SPEC_SNPRINT_MAX
], tcm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
1116 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1117 mode
== RECORD
? _("recording") : _("playback"),
1118 pa_sample_spec_snprint(tss
, sizeof(tss
), &sample_spec
),
1119 pa_channel_map_snprint(tcm
, sizeof(tcm
), &channel_map
));
1122 /* Fill in client name if none was set */
1123 if (!pa_proplist_contains(proplist
, PA_PROP_APPLICATION_NAME
)) {
1126 if ((t
= pa_locale_to_utf8(bn
))) {
1127 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
);
1132 /* Fill in media name if none was set */
1133 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1136 if ((t
= filename
) ||
1137 (t
= pa_proplist_gets(proplist
, PA_PROP_APPLICATION_NAME
)))
1138 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
);
1140 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1141 pa_log(_("Failed to set media name."));
1146 /* Set up a new main loop */
1147 if (!(m
= pa_mainloop_new())) {
1148 pa_log(_("pa_mainloop_new() failed."));
1152 mainloop_api
= pa_mainloop_get_api(m
);
1154 pa_assert_se(pa_signal_init(mainloop_api
) == 0);
1155 pa_signal_new(SIGINT
, exit_signal_callback
, NULL
);
1156 pa_signal_new(SIGTERM
, exit_signal_callback
, NULL
);
1158 pa_signal_new(SIGUSR1
, sigusr1_signal_callback
, NULL
);
1160 pa_disable_sigpipe();
1164 /* need to turn on binary mode for stdio io. Windows, meh */
1165 setmode(mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
, O_BINARY
);
1167 if (!(stdio_event
= mainloop_api
->io_new(mainloop_api
,
1168 mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
,
1169 mode
== PLAYBACK
? PA_IO_EVENT_INPUT
: PA_IO_EVENT_OUTPUT
,
1170 mode
== PLAYBACK
? stdin_callback
: stdout_callback
, &type
))) {
1171 pa_log(_("io_new() failed."));
1176 /* Create a new connection context */
1177 if (!(context
= pa_context_new_with_proplist(mainloop_api
, NULL
, proplist
))) {
1178 pa_log(_("pa_context_new() failed."));
1182 pa_context_set_state_callback(context
, context_state_callback
, NULL
);
1184 /* Connect the context */
1185 if (pa_context_connect(context
, server
, 0, NULL
) < 0) {
1186 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context
)));
1191 if (!(time_event
= pa_context_rttime_new(context
, pa_rtclock_now() + TIME_EVENT_USEC
, time_event_callback
, NULL
))) {
1192 pa_log(_("pa_context_rttime_new() failed."));
1197 /* Run the main loop */
1198 if (pa_mainloop_run(m
, &ret
) < 0) {
1199 pa_log(_("pa_mainloop_run() failed."));
1205 pa_stream_unref(stream
);
1208 pa_context_unref(context
);
1211 pa_assert(mainloop_api
);
1212 mainloop_api
->io_free(stdio_event
);
1216 pa_assert(mainloop_api
);
1217 mainloop_api
->time_free(time_event
);
1222 pa_mainloop_free(m
);
1225 pa_xfree(silence_buffer
);
1235 pa_proplist_free(proplist
);