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 cork_requests
= 0;
100 /* A shortcut for terminating the application */
101 static void quit(int ret
) {
102 pa_assert(mainloop_api
);
103 mainloop_api
->quit(mainloop_api
, ret
);
106 /* Connection draining complete */
107 static void context_drain_complete(pa_context
*c
, void *userdata
) {
108 pa_context_disconnect(c
);
111 /* Stream draining complete */
112 static void stream_drain_complete(pa_stream
*s
, int success
, void *userdata
) {
113 pa_operation
*o
= NULL
;
116 pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context
)));
121 pa_log(_("Playback stream drained."));
123 pa_stream_disconnect(stream
);
124 pa_stream_unref(stream
);
127 if (!(o
= pa_context_drain(context
, context_drain_complete
, NULL
)))
128 pa_context_disconnect(context
);
130 pa_operation_unref(o
);
132 pa_log(_("Draining connection to server."));
137 static void start_drain(void) {
142 pa_stream_set_write_callback(stream
, NULL
, NULL
);
144 if (!(o
= pa_stream_drain(stream
, stream_drain_complete
, NULL
))) {
145 pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context
)));
150 pa_operation_unref(o
);
155 /* Write some data to the stream */
156 static void do_stream_write(size_t length
) {
160 if (!buffer
|| !buffer_length
)
164 if (l
> buffer_length
)
167 if (pa_stream_write(stream
, (uint8_t*) buffer
+ buffer_index
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0) {
168 pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
176 if (!buffer_length
) {
179 buffer_index
= buffer_length
= 0;
183 /* This is called whenever new data may be written to the stream */
184 static void stream_write_callback(pa_stream
*s
, size_t length
, void *userdata
) {
186 pa_assert(length
> 0);
192 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_INPUT
);
197 do_stream_write(length
);
206 size_t data_length
= length
;
208 if (pa_stream_begin_write(s
, &data
, &data_length
) < 0) {
209 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
214 if (readf_function
) {
215 size_t k
= pa_frame_size(&sample_spec
);
217 if ((bytes
= readf_function(sndfile
, data
, (sf_count_t
) (data_length
/k
))) > 0)
218 bytes
*= (sf_count_t
) k
;
221 bytes
= sf_read_raw(sndfile
, data
, (sf_count_t
) data_length
);
224 pa_stream_write(s
, data
, (size_t) bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
226 pa_stream_cancel_write(s
);
229 if (bytes
< (sf_count_t
) data_length
) {
234 /* Request fulfilled */
235 if ((size_t) bytes
>= length
)
243 /* This is called whenever new data may is available */
244 static void stream_read_callback(pa_stream
*s
, size_t length
, void *userdata
) {
247 pa_assert(length
> 0);
253 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_OUTPUT
);
255 while (pa_stream_readable_size(s
) > 0) {
258 if (pa_stream_peek(s
, &data
, &length
) < 0) {
259 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
264 pa_assert(length
> 0);
266 /* If there is a hole in the stream, we generate silence, except
267 * if it's a passthrough stream in which case we skip the hole. */
268 if (data
|| !(flags
& PA_STREAM_PASSTHROUGH
)) {
269 buffer
= pa_xrealloc(buffer
, buffer_length
+ length
);
271 memcpy((uint8_t *) buffer
+ buffer_length
, data
, length
);
273 pa_silence_memory((uint8_t *) buffer
+ buffer_length
, length
, &sample_spec
);
275 buffer_length
+= length
;
284 while (pa_stream_readable_size(s
) > 0) {
288 if (pa_stream_peek(s
, &data
, &length
) < 0) {
289 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
294 pa_assert(length
> 0);
296 if (!data
&& (flags
& PA_STREAM_PASSTHROUGH
)) {
301 if (!data
&& length
> silence_buffer_length
) {
302 silence_buffer
= pa_xrealloc(silence_buffer
, length
);
303 pa_silence_memory((uint8_t *) silence_buffer
+ silence_buffer_length
, length
- silence_buffer_length
, &sample_spec
);
304 silence_buffer_length
= length
;
307 if (writef_function
) {
308 size_t k
= pa_frame_size(&sample_spec
);
310 if ((bytes
= writef_function(sndfile
, data
? data
: silence_buffer
, (sf_count_t
) (length
/k
))) > 0)
311 bytes
*= (sf_count_t
) k
;
314 bytes
= sf_write_raw(sndfile
, data
? data
: silence_buffer
, (sf_count_t
) length
);
316 if (bytes
< (sf_count_t
) length
)
324 /* This routine is called whenever the stream state changes */
325 static void stream_state_callback(pa_stream
*s
, void *userdata
) {
328 switch (pa_stream_get_state(s
)) {
329 case PA_STREAM_CREATING
:
330 case PA_STREAM_TERMINATED
:
333 case PA_STREAM_READY
:
336 const pa_buffer_attr
*a
;
337 char cmt
[PA_CHANNEL_MAP_SNPRINT_MAX
], sst
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
339 pa_log(_("Stream successfully created."));
341 if (!(a
= pa_stream_get_buffer_attr(s
)))
342 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
345 if (mode
== PLAYBACK
)
346 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a
->maxlength
, a
->tlength
, a
->prebuf
, a
->minreq
);
348 pa_assert(mode
== RECORD
);
349 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a
->maxlength
, a
->fragsize
);
353 pa_log(_("Using sample spec '%s', channel map '%s'."),
354 pa_sample_spec_snprint(sst
, sizeof(sst
), pa_stream_get_sample_spec(s
)),
355 pa_channel_map_snprint(cmt
, sizeof(cmt
), pa_stream_get_channel_map(s
)));
357 pa_log(_("Connected to device %s (%u, %ssuspended)."),
358 pa_stream_get_device_name(s
),
359 pa_stream_get_device_index(s
),
360 pa_stream_is_suspended(s
) ? "" : "not ");
365 case PA_STREAM_FAILED
:
367 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
372 static void stream_suspended_callback(pa_stream
*s
, void *userdata
) {
376 if (pa_stream_is_suspended(s
))
377 pa_log(_("Stream device suspended.%s"), CLEAR_LINE
);
379 pa_log(_("Stream device resumed.%s"), CLEAR_LINE
);
383 static void stream_underflow_callback(pa_stream
*s
, void *userdata
) {
387 pa_log(_("Stream underrun.%s"), CLEAR_LINE
);
390 static void stream_overflow_callback(pa_stream
*s
, void *userdata
) {
394 pa_log(_("Stream overrun.%s"), CLEAR_LINE
);
397 static void stream_started_callback(pa_stream
*s
, void *userdata
) {
401 pa_log(_("Stream started.%s"), CLEAR_LINE
);
404 static void stream_moved_callback(pa_stream
*s
, void *userdata
) {
408 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
);
411 static void stream_buffer_attr_callback(pa_stream
*s
, void *userdata
) {
415 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE
);
418 static void stream_event_callback(pa_stream
*s
, const char *name
, pa_proplist
*pl
, void *userdata
) {
425 t
= pa_proplist_to_string_sep(pl
, ", ");
426 pa_log("Got event '%s', properties '%s'", name
, t
);
428 if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_CORK
)) {
429 if (cork_requests
== 0) {
430 pa_log(_("Cork request stack is empty: corking stream"));
431 pa_operation_unref(pa_stream_cork(s
, 1, NULL
, NULL
));
434 } else if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_UNCORK
)) {
435 if (cork_requests
== 1) {
436 pa_log(_("Cork request stack is empty: uncorking stream"));
437 pa_operation_unref(pa_stream_cork(s
, 0, NULL
, NULL
));
439 if (cork_requests
== 0)
440 pa_log(_("Warning: Received more uncork requests than cork requests!"));
448 /* This is called whenever the context status changes */
449 static void context_state_callback(pa_context
*c
, void *userdata
) {
452 switch (pa_context_get_state(c
)) {
453 case PA_CONTEXT_CONNECTING
:
454 case PA_CONTEXT_AUTHORIZING
:
455 case PA_CONTEXT_SETTING_NAME
:
458 case PA_CONTEXT_READY
: {
459 pa_buffer_attr buffer_attr
;
465 pa_log(_("Connection established.%s"), CLEAR_LINE
);
467 if (!(stream
= pa_stream_new_with_proplist(c
, NULL
, &sample_spec
, &channel_map
, proplist
))) {
468 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c
)));
472 pa_stream_set_state_callback(stream
, stream_state_callback
, NULL
);
473 pa_stream_set_write_callback(stream
, stream_write_callback
, NULL
);
474 pa_stream_set_read_callback(stream
, stream_read_callback
, NULL
);
475 pa_stream_set_suspended_callback(stream
, stream_suspended_callback
, NULL
);
476 pa_stream_set_moved_callback(stream
, stream_moved_callback
, NULL
);
477 pa_stream_set_underflow_callback(stream
, stream_underflow_callback
, NULL
);
478 pa_stream_set_overflow_callback(stream
, stream_overflow_callback
, NULL
);
479 pa_stream_set_started_callback(stream
, stream_started_callback
, NULL
);
480 pa_stream_set_event_callback(stream
, stream_event_callback
, NULL
);
481 pa_stream_set_buffer_attr_callback(stream
, stream_buffer_attr_callback
, NULL
);
483 pa_zero(buffer_attr
);
484 buffer_attr
.maxlength
= (uint32_t) -1;
485 buffer_attr
.prebuf
= (uint32_t) -1;
487 if (latency_msec
> 0) {
488 buffer_attr
.fragsize
= buffer_attr
.tlength
= pa_usec_to_bytes(latency_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
489 flags
|= PA_STREAM_ADJUST_LATENCY
;
490 } else if (latency
> 0) {
491 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) latency
;
492 flags
|= PA_STREAM_ADJUST_LATENCY
;
494 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) -1;
496 if (process_time_msec
> 0) {
497 buffer_attr
.minreq
= pa_usec_to_bytes(process_time_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
498 } else if (process_time
> 0)
499 buffer_attr
.minreq
= (uint32_t) process_time
;
501 buffer_attr
.minreq
= (uint32_t) -1;
503 if (mode
== PLAYBACK
) {
505 if (pa_stream_connect_playback(stream
, device
, &buffer_attr
, flags
, volume_is_set
? pa_cvolume_set(&cv
, sample_spec
.channels
, volume
) : NULL
, NULL
) < 0) {
506 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c
)));
511 if (pa_stream_connect_record(stream
, device
, &buffer_attr
, flags
) < 0) {
512 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c
)));
520 case PA_CONTEXT_TERMINATED
:
524 case PA_CONTEXT_FAILED
:
526 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c
)));
537 /* New data on STDIN **/
538 static void stdin_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
542 pa_assert(a
== mainloop_api
);
544 pa_assert(stdio_event
== e
);
547 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
551 if (!stream
|| pa_stream_get_state(stream
) != PA_STREAM_READY
|| !(l
= w
= pa_stream_writable_size(stream
)))
554 buffer
= pa_xmalloc(l
);
556 if ((r
= pa_read(fd
, buffer
, l
, userdata
)) <= 0) {
559 pa_log(_("Got EOF."));
564 pa_log(_("read() failed: %s"), strerror(errno
));
568 mainloop_api
->io_free(stdio_event
);
573 buffer_length
= (uint32_t) r
;
580 /* Some data may be written to STDOUT */
581 static void stdout_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
584 pa_assert(a
== mainloop_api
);
586 pa_assert(stdio_event
== e
);
589 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
593 pa_assert(buffer_length
);
595 if ((r
= pa_write(fd
, (uint8_t*) buffer
+buffer_index
, buffer_length
, userdata
)) <= 0) {
596 pa_log(_("write() failed: %s"), strerror(errno
));
599 mainloop_api
->io_free(stdio_event
);
604 buffer_length
-= (uint32_t) r
;
605 buffer_index
+= (uint32_t) r
;
607 if (!buffer_length
) {
610 buffer_length
= buffer_index
= 0;
614 /* UNIX signal to quit received */
615 static void exit_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
617 pa_log(_("Got signal, exiting."));
621 /* Show the current latency */
622 static void stream_update_timing_callback(pa_stream
*s
, int success
, void *userdata
) {
629 pa_stream_get_time(s
, &usec
) < 0 ||
630 pa_stream_get_latency(s
, &l
, &negative
) < 0) {
631 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context
)));
636 fprintf(stderr
, _("Time: %0.3f sec; Latency: %0.0f usec."),
637 (float) usec
/ 1000000,
638 (float) l
* (negative
?-1.0f
:1.0f
));
639 fprintf(stderr
, " \r");
643 /* Someone requested that the latency is shown */
644 static void sigusr1_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
649 pa_operation_unref(pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
));
653 static void time_event_callback(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
654 if (stream
&& pa_stream_get_state(stream
) == PA_STREAM_READY
) {
656 if (!(o
= pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
)))
657 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context
)));
659 pa_operation_unref(o
);
662 pa_context_rttime_restart(context
, e
, pa_rtclock_now() + TIME_EVENT_USEC
);
665 static void help(const char *argv0
) {
667 printf(_("%s [options]\n\n"
668 " -h, --help Show this help\n"
669 " --version Show version\n\n"
670 " -r, --record Create a connection for recording\n"
671 " -p, --playback Create a connection for playback\n\n"
672 " -v, --verbose Enable verbose operations\n\n"
673 " -s, --server=SERVER The name of the server to connect to\n"
674 " -d, --device=DEVICE The name of the sink/source to connect to\n"
675 " -n, --client-name=NAME How to call this client on the server\n"
676 " --stream-name=NAME How to call this stream on the server\n"
677 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
678 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
679 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
680 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
681 " s24-32le, s24-32be (defaults to s16ne)\n"
682 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
684 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
685 " --fix-format Take the sample format from the sink the stream is\n"
686 " being connected to.\n"
687 " --fix-rate Take the sampling rate from the sink the stream is\n"
688 " being connected to.\n"
689 " --fix-channels Take the number of channels and the channel map\n"
690 " from the sink the stream is being connected to.\n"
691 " --no-remix Don't upmix or downmix channels.\n"
692 " --no-remap Map channels by index instead of name.\n"
693 " --latency=BYTES Request the specified latency in bytes.\n"
694 " --process-time=BYTES Request the specified process time per request in bytes.\n"
695 " --latency-msec=MSEC Request the specified latency in msec.\n"
696 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
697 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
698 " --raw Record/play raw PCM data.\n"
699 " --passthrough passthrough data \n"
700 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
701 " --list-file-formats List available file formats.\n")
724 ARG_LIST_FILE_FORMATS
,
726 ARG_PROCESS_TIME_MSEC
729 int main(int argc
, char *argv
[]) {
730 pa_mainloop
* m
= NULL
;
732 char *bn
, *server
= NULL
;
733 pa_time_event
*time_event
= NULL
;
734 const char *filename
= NULL
;
735 /* type for pa_read/_write. passed as userdata to the callbacks */
736 unsigned long type
= 0;
738 static const struct option long_options
[] = {
739 {"record", 0, NULL
, 'r'},
740 {"playback", 0, NULL
, 'p'},
741 {"device", 1, NULL
, 'd'},
742 {"server", 1, NULL
, 's'},
743 {"client-name", 1, NULL
, 'n'},
744 {"stream-name", 1, NULL
, ARG_STREAM_NAME
},
745 {"version", 0, NULL
, ARG_VERSION
},
746 {"help", 0, NULL
, 'h'},
747 {"verbose", 0, NULL
, 'v'},
748 {"volume", 1, NULL
, ARG_VOLUME
},
749 {"rate", 1, NULL
, ARG_SAMPLERATE
},
750 {"format", 1, NULL
, ARG_SAMPLEFORMAT
},
751 {"channels", 1, NULL
, ARG_CHANNELS
},
752 {"channel-map", 1, NULL
, ARG_CHANNELMAP
},
753 {"fix-format", 0, NULL
, ARG_FIX_FORMAT
},
754 {"fix-rate", 0, NULL
, ARG_FIX_RATE
},
755 {"fix-channels", 0, NULL
, ARG_FIX_CHANNELS
},
756 {"no-remap", 0, NULL
, ARG_NO_REMAP
},
757 {"no-remix", 0, NULL
, ARG_NO_REMIX
},
758 {"latency", 1, NULL
, ARG_LATENCY
},
759 {"process-time", 1, NULL
, ARG_PROCESS_TIME
},
760 {"property", 1, NULL
, ARG_PROPERTY
},
761 {"raw", 0, NULL
, ARG_RAW
},
762 {"passthrough", 0, NULL
, ARG_PASSTHROUGH
},
763 {"file-format", 2, NULL
, ARG_FILE_FORMAT
},
764 {"list-file-formats", 0, NULL
, ARG_LIST_FILE_FORMATS
},
765 {"latency-msec", 1, NULL
, ARG_LATENCY_MSEC
},
766 {"process-time-msec", 1, NULL
, ARG_PROCESS_TIME_MSEC
},
770 setlocale(LC_ALL
, "");
772 bindtextdomain(GETTEXT_PACKAGE
, PULSE_LOCALEDIR
);
775 bn
= pa_path_get_filename(argv
[0]);
777 if (strstr(bn
, "play")) {
780 } else if (strstr(bn
, "record")) {
783 } else if (strstr(bn
, "cat")) {
786 } else if (strstr(bn
, "rec") || strstr(bn
, "mon")) {
791 proplist
= pa_proplist_new();
793 while ((c
= getopt_long(argc
, argv
, "rpd:s:n:hv", long_options
, NULL
)) != -1) {
802 printf(_("pacat %s\n"
803 "Compiled with libpulse %s\n"
804 "Linked with libpulse %s\n"),
806 pa_get_headers_version(),
807 pa_get_library_version());
821 device
= pa_xstrdup(optarg
);
826 server
= pa_xstrdup(optarg
);
832 if (!(t
= pa_locale_to_utf8(optarg
)) ||
833 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
) < 0) {
835 pa_log(_("Invalid client name '%s'"), t
? t
: optarg
);
844 case ARG_STREAM_NAME
: {
847 if (!(t
= pa_locale_to_utf8(optarg
)) ||
848 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
) < 0) {
850 pa_log(_("Invalid stream name '%s'"), t
? t
: optarg
);
864 int v
= atoi(optarg
);
865 volume
= v
< 0 ? 0U : (pa_volume_t
) v
;
866 volume_is_set
= true;
871 sample_spec
.channels
= (uint8_t) atoi(optarg
);
872 sample_spec_set
= true;
875 case ARG_SAMPLEFORMAT
:
876 sample_spec
.format
= pa_parse_sample_format(optarg
);
877 sample_spec_set
= true;
881 sample_spec
.rate
= (uint32_t) atoi(optarg
);
882 sample_spec_set
= true;
886 if (!pa_channel_map_parse(&channel_map
, optarg
)) {
887 pa_log(_("Invalid channel map '%s'"), optarg
);
891 channel_map_set
= true;
894 case ARG_FIX_CHANNELS
:
895 flags
|= PA_STREAM_FIX_CHANNELS
;
899 flags
|= PA_STREAM_FIX_RATE
;
903 flags
|= PA_STREAM_FIX_FORMAT
;
907 flags
|= PA_STREAM_NO_REMIX_CHANNELS
;
911 flags
|= PA_STREAM_NO_REMAP_CHANNELS
;
915 if (((latency
= (size_t) atoi(optarg
))) <= 0) {
916 pa_log(_("Invalid latency specification '%s'"), optarg
);
921 case ARG_PROCESS_TIME
:
922 if (((process_time
= (size_t) atoi(optarg
))) <= 0) {
923 pa_log(_("Invalid process time specification '%s'"), optarg
);
928 case ARG_LATENCY_MSEC
:
929 if (((latency_msec
= (int32_t) atoi(optarg
))) <= 0) {
930 pa_log(_("Invalid latency specification '%s'"), optarg
);
935 case ARG_PROCESS_TIME_MSEC
:
936 if (((process_time_msec
= (int32_t) atoi(optarg
))) <= 0) {
937 pa_log(_("Invalid process time specification '%s'"), optarg
);
945 if (!(t
= pa_locale_to_utf8(optarg
)) ||
946 pa_proplist_setp(proplist
, t
) < 0) {
949 pa_log(_("Invalid property '%s'"), optarg
);
961 case ARG_PASSTHROUGH
:
962 flags
|= PA_STREAM_PASSTHROUGH
;
965 case ARG_FILE_FORMAT
:
967 if ((file_format
= pa_sndfile_format_from_string(optarg
)) < 0) {
968 pa_log(_("Unknown file format %s."), optarg
);
976 case ARG_LIST_FILE_FORMATS
:
977 pa_sndfile_dump_formats();
986 if (!pa_sample_spec_valid(&sample_spec
)) {
987 pa_log(_("Invalid sample specification"));
991 if (optind
+1 == argc
) {
994 filename
= argv
[optind
];
996 if ((fd
= pa_open_cloexec(argv
[optind
], mode
== PLAYBACK
? O_RDONLY
: O_WRONLY
|O_TRUNC
|O_CREAT
, 0666)) < 0) {
997 pa_log(_("open(): %s"), strerror(errno
));
1001 if (dup2(fd
, mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
) < 0) {
1002 pa_log(_("dup2(): %s"), strerror(errno
));
1008 } else if (optind
+1 <= argc
) {
1009 pa_log(_("Too many arguments."));
1017 if (mode
== RECORD
) {
1018 /* This might patch up the sample spec */
1019 if (pa_sndfile_write_sample_spec(&sfi
, &sample_spec
) < 0) {
1020 pa_log(_("Failed to generate sample specification for file."));
1024 if (file_format
<= 0) {
1026 if (filename
&& (extension
= strrchr(filename
, '.')))
1027 file_format
= pa_sndfile_format_from_string(extension
+1);
1028 if (file_format
<= 0)
1029 file_format
= SF_FORMAT_WAV
;
1030 /* Transparently upgrade classic .wav to wavex for multichannel audio */
1031 if (file_format
== SF_FORMAT_WAV
&&
1032 (sample_spec
.channels
> 2 ||
1034 !(sample_spec
.channels
== 1 && channel_map
.map
[0] == PA_CHANNEL_POSITION_MONO
) &&
1035 !(sample_spec
.channels
== 2 && channel_map
.map
[0] == PA_CHANNEL_POSITION_LEFT
1036 && channel_map
.map
[1] == PA_CHANNEL_POSITION_RIGHT
))))
1037 file_format
= SF_FORMAT_WAVEX
;
1040 sfi
.format
|= file_format
;
1043 if (!(sndfile
= sf_open_fd(mode
== RECORD
? STDOUT_FILENO
: STDIN_FILENO
,
1044 mode
== RECORD
? SFM_WRITE
: SFM_READ
,
1046 pa_log(_("Failed to open audio file."));
1050 if (mode
== PLAYBACK
) {
1051 if (sample_spec_set
)
1052 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1054 if (pa_sndfile_read_sample_spec(sndfile
, &sample_spec
) < 0) {
1055 pa_log(_("Failed to determine sample specification from file."));
1058 sample_spec_set
= true;
1060 if (!channel_map_set
) {
1061 /* Allow the user to overwrite the channel map on the command line */
1062 if (pa_sndfile_read_channel_map(sndfile
, &channel_map
) < 0) {
1063 if (sample_spec
.channels
> 2)
1064 pa_log(_("Warning: Failed to determine channel map from file."));
1066 channel_map_set
= true;
1071 if (!channel_map_set
)
1072 pa_channel_map_init_extend(&channel_map
, sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
);
1074 if (!pa_channel_map_compatible(&channel_map
, &sample_spec
)) {
1075 pa_log(_("Channel map doesn't match sample specification"));
1082 if (mode
== PLAYBACK
)
1083 readf_function
= pa_sndfile_readf_function(&sample_spec
);
1085 if (pa_sndfile_write_channel_map(sndfile
, &channel_map
) < 0)
1086 pa_log(_("Warning: failed to write channel map to file."));
1088 writef_function
= pa_sndfile_writef_function(&sample_spec
);
1091 /* Fill in libsndfile prop list data */
1092 sfp
= pa_proplist_new();
1093 pa_sndfile_init_proplist(sndfile
, sfp
);
1094 pa_proplist_update(proplist
, PA_UPDATE_MERGE
, sfp
);
1095 pa_proplist_free(sfp
);
1099 char tss
[PA_SAMPLE_SPEC_SNPRINT_MAX
], tcm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
1101 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1102 mode
== RECORD
? _("recording") : _("playback"),
1103 pa_sample_spec_snprint(tss
, sizeof(tss
), &sample_spec
),
1104 pa_channel_map_snprint(tcm
, sizeof(tcm
), &channel_map
));
1107 /* Fill in client name if none was set */
1108 if (!pa_proplist_contains(proplist
, PA_PROP_APPLICATION_NAME
)) {
1111 if ((t
= pa_locale_to_utf8(bn
))) {
1112 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
);
1117 /* Fill in media name if none was set */
1118 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1121 if ((t
= filename
) ||
1122 (t
= pa_proplist_gets(proplist
, PA_PROP_APPLICATION_NAME
)))
1123 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
);
1125 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1126 pa_log(_("Failed to set media name."));
1131 /* Set up a new main loop */
1132 if (!(m
= pa_mainloop_new())) {
1133 pa_log(_("pa_mainloop_new() failed."));
1137 mainloop_api
= pa_mainloop_get_api(m
);
1139 pa_assert_se(pa_signal_init(mainloop_api
) == 0);
1140 pa_signal_new(SIGINT
, exit_signal_callback
, NULL
);
1141 pa_signal_new(SIGTERM
, exit_signal_callback
, NULL
);
1143 pa_signal_new(SIGUSR1
, sigusr1_signal_callback
, NULL
);
1145 pa_disable_sigpipe();
1149 /* need to turn on binary mode for stdio io. Windows, meh */
1150 setmode(mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
, O_BINARY
);
1152 if (!(stdio_event
= mainloop_api
->io_new(mainloop_api
,
1153 mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
,
1154 mode
== PLAYBACK
? PA_IO_EVENT_INPUT
: PA_IO_EVENT_OUTPUT
,
1155 mode
== PLAYBACK
? stdin_callback
: stdout_callback
, &type
))) {
1156 pa_log(_("io_new() failed."));
1161 /* Create a new connection context */
1162 if (!(context
= pa_context_new_with_proplist(mainloop_api
, NULL
, proplist
))) {
1163 pa_log(_("pa_context_new() failed."));
1167 pa_context_set_state_callback(context
, context_state_callback
, NULL
);
1169 /* Connect the context */
1170 if (pa_context_connect(context
, server
, 0, NULL
) < 0) {
1171 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context
)));
1176 if (!(time_event
= pa_context_rttime_new(context
, pa_rtclock_now() + TIME_EVENT_USEC
, time_event_callback
, NULL
))) {
1177 pa_log(_("pa_context_rttime_new() failed."));
1182 /* Run the main loop */
1183 if (pa_mainloop_run(m
, &ret
) < 0) {
1184 pa_log(_("pa_mainloop_run() failed."));
1190 pa_stream_unref(stream
);
1193 pa_context_unref(context
);
1196 pa_assert(mainloop_api
);
1197 mainloop_api
->io_free(stdio_event
);
1201 pa_assert(mainloop_api
);
1202 mainloop_api
->time_free(time_event
);
1207 pa_mainloop_free(m
);
1210 pa_xfree(silence_buffer
);
1220 pa_proplist_free(proplist
);