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>
49 #define TIME_EVENT_USEC 50000
51 #define CLEAR_LINE "\x1B[K"
53 static enum { RECORD
, PLAYBACK
} mode
= PLAYBACK
;
55 static pa_context
*context
= NULL
;
56 static pa_stream
*stream
= NULL
;
57 static pa_mainloop_api
*mainloop_api
= NULL
;
59 static void *buffer
= NULL
;
60 static size_t buffer_length
= 0, buffer_index
= 0;
62 static pa_io_event
* stdio_event
= NULL
;
64 static pa_proplist
*proplist
= NULL
;
65 static char *device
= NULL
;
67 static SNDFILE
* sndfile
= NULL
;
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
;
73 static pa_sample_spec sample_spec
= {
74 .format
= PA_SAMPLE_S16LE
,
78 static pa_bool_t sample_spec_set
= FALSE
;
80 static pa_channel_map channel_map
;
81 static pa_bool_t channel_map_set
= FALSE
;
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
;
86 static pa_stream_flags_t flags
= 0;
88 static size_t latency
= 0, process_time
= 0;
89 static int32_t latency_msec
= 0, process_time_msec
= 0;
91 static pa_bool_t raw
= TRUE
;
92 static int file_format
= -1;
94 static uint32_t cork_requests
= 0;
96 /* A shortcut for terminating the application */
97 static void quit(int ret
) {
98 pa_assert(mainloop_api
);
99 mainloop_api
->quit(mainloop_api
, ret
);
102 /* Connection draining complete */
103 static void context_drain_complete(pa_context
*c
, void *userdata
) {
104 pa_context_disconnect(c
);
107 /* Stream draining complete */
108 static void stream_drain_complete(pa_stream
*s
, int success
, void *userdata
) {
109 pa_operation
*o
= NULL
;
112 pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context
)));
117 pa_log(_("Playback stream drained."));
119 pa_stream_disconnect(stream
);
120 pa_stream_unref(stream
);
123 if (!(o
= pa_context_drain(context
, context_drain_complete
, NULL
)))
124 pa_context_disconnect(context
);
126 pa_operation_unref(o
);
128 pa_log(_("Draining connection to server."));
133 static void start_drain(void) {
138 pa_stream_set_write_callback(stream
, NULL
, NULL
);
140 if (!(o
= pa_stream_drain(stream
, stream_drain_complete
, NULL
))) {
141 pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context
)));
146 pa_operation_unref(o
);
151 /* Write some data to the stream */
152 static void do_stream_write(size_t length
) {
156 if (!buffer
|| !buffer_length
)
160 if (l
> buffer_length
)
163 if (pa_stream_write(stream
, (uint8_t*) buffer
+ buffer_index
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0) {
164 pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
172 if (!buffer_length
) {
175 buffer_index
= buffer_length
= 0;
179 /* This is called whenever new data may be written to the stream */
180 static void stream_write_callback(pa_stream
*s
, size_t length
, void *userdata
) {
182 pa_assert(length
> 0);
188 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_INPUT
);
193 do_stream_write(length
);
202 size_t data_length
= length
;
204 if (pa_stream_begin_write(s
, &data
, &data_length
) < 0) {
205 pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context
)));
210 if (readf_function
) {
211 size_t k
= pa_frame_size(&sample_spec
);
213 if ((bytes
= readf_function(sndfile
, data
, (sf_count_t
) (data_length
/k
))) > 0)
214 bytes
*= (sf_count_t
) k
;
217 bytes
= sf_read_raw(sndfile
, data
, (sf_count_t
) data_length
);
220 pa_stream_write(s
, data
, (size_t) bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
222 pa_stream_cancel_write(s
);
225 if (bytes
< (sf_count_t
) data_length
) {
230 /* Request fulfilled */
231 if ((size_t) bytes
>= length
)
239 /* This is called whenever new data may is available */
240 static void stream_read_callback(pa_stream
*s
, size_t length
, void *userdata
) {
243 pa_assert(length
> 0);
249 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_OUTPUT
);
251 while (pa_stream_readable_size(s
) > 0) {
254 if (pa_stream_peek(s
, &data
, &length
) < 0) {
255 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
261 pa_assert(length
> 0);
264 buffer
= pa_xrealloc(buffer
, buffer_length
+ length
);
265 memcpy((uint8_t*) buffer
+ buffer_length
, data
, length
);
266 buffer_length
+= length
;
268 buffer
= pa_xmalloc(length
);
269 memcpy(buffer
, data
, length
);
270 buffer_length
= length
;
280 while (pa_stream_readable_size(s
) > 0) {
284 if (pa_stream_peek(s
, &data
, &length
) < 0) {
285 pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context
)));
291 pa_assert(length
> 0);
293 if (writef_function
) {
294 size_t k
= pa_frame_size(&sample_spec
);
296 if ((bytes
= writef_function(sndfile
, data
, (sf_count_t
) (length
/k
))) > 0)
297 bytes
*= (sf_count_t
) k
;
300 bytes
= sf_write_raw(sndfile
, data
, (sf_count_t
) length
);
302 if (bytes
< (sf_count_t
) length
)
310 /* This routine is called whenever the stream state changes */
311 static void stream_state_callback(pa_stream
*s
, void *userdata
) {
314 switch (pa_stream_get_state(s
)) {
315 case PA_STREAM_CREATING
:
316 case PA_STREAM_TERMINATED
:
319 case PA_STREAM_READY
:
322 const pa_buffer_attr
*a
;
323 char cmt
[PA_CHANNEL_MAP_SNPRINT_MAX
], sst
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
325 pa_log(_("Stream successfully created."));
327 if (!(a
= pa_stream_get_buffer_attr(s
)))
328 pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
331 if (mode
== PLAYBACK
)
332 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a
->maxlength
, a
->tlength
, a
->prebuf
, a
->minreq
);
334 pa_assert(mode
== RECORD
);
335 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a
->maxlength
, a
->fragsize
);
339 pa_log(_("Using sample spec '%s', channel map '%s'."),
340 pa_sample_spec_snprint(sst
, sizeof(sst
), pa_stream_get_sample_spec(s
)),
341 pa_channel_map_snprint(cmt
, sizeof(cmt
), pa_stream_get_channel_map(s
)));
343 pa_log(_("Connected to device %s (%u, %ssuspended)."),
344 pa_stream_get_device_name(s
),
345 pa_stream_get_device_index(s
),
346 pa_stream_is_suspended(s
) ? "" : "not ");
351 case PA_STREAM_FAILED
:
353 pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
358 static void stream_suspended_callback(pa_stream
*s
, void *userdata
) {
362 if (pa_stream_is_suspended(s
))
363 pa_log(_("Stream device suspended.%s"), CLEAR_LINE
);
365 pa_log(_("Stream device resumed.%s"), CLEAR_LINE
);
369 static void stream_underflow_callback(pa_stream
*s
, void *userdata
) {
373 pa_log(_("Stream underrun.%s"), CLEAR_LINE
);
376 static void stream_overflow_callback(pa_stream
*s
, void *userdata
) {
380 pa_log(_("Stream overrun.%s"), CLEAR_LINE
);
383 static void stream_started_callback(pa_stream
*s
, void *userdata
) {
387 pa_log(_("Stream started.%s"), CLEAR_LINE
);
390 static void stream_moved_callback(pa_stream
*s
, void *userdata
) {
394 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
);
397 static void stream_buffer_attr_callback(pa_stream
*s
, void *userdata
) {
401 pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE
);
404 static void stream_event_callback(pa_stream
*s
, const char *name
, pa_proplist
*pl
, void *userdata
) {
411 t
= pa_proplist_to_string_sep(pl
, ", ");
412 pa_log("Got event '%s', properties '%s'", name
, t
);
414 if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_CORK
)) {
415 if (cork_requests
== 0) {
416 pa_log(_("Cork request stack is empty: corking stream"));
417 pa_operation_unref(pa_stream_cork(s
, 1, NULL
, NULL
));
420 } else if (pa_streq(name
, PA_STREAM_EVENT_REQUEST_UNCORK
)) {
421 if (cork_requests
== 1) {
422 pa_log(_("Cork request stack is empty: uncorking stream"));
423 pa_operation_unref(pa_stream_cork(s
, 0, NULL
, NULL
));
425 if (cork_requests
== 0)
426 pa_log(_("Warning: Received more uncork requests than cork requests!"));
434 /* This is called whenever the context status changes */
435 static void context_state_callback(pa_context
*c
, void *userdata
) {
438 switch (pa_context_get_state(c
)) {
439 case PA_CONTEXT_CONNECTING
:
440 case PA_CONTEXT_AUTHORIZING
:
441 case PA_CONTEXT_SETTING_NAME
:
444 case PA_CONTEXT_READY
: {
445 pa_buffer_attr buffer_attr
;
451 pa_log(_("Connection established.%s"), CLEAR_LINE
);
453 if (!(stream
= pa_stream_new_with_proplist(c
, NULL
, &sample_spec
, &channel_map
, proplist
))) {
454 pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c
)));
458 pa_stream_set_state_callback(stream
, stream_state_callback
, NULL
);
459 pa_stream_set_write_callback(stream
, stream_write_callback
, NULL
);
460 pa_stream_set_read_callback(stream
, stream_read_callback
, NULL
);
461 pa_stream_set_suspended_callback(stream
, stream_suspended_callback
, NULL
);
462 pa_stream_set_moved_callback(stream
, stream_moved_callback
, NULL
);
463 pa_stream_set_underflow_callback(stream
, stream_underflow_callback
, NULL
);
464 pa_stream_set_overflow_callback(stream
, stream_overflow_callback
, NULL
);
465 pa_stream_set_started_callback(stream
, stream_started_callback
, NULL
);
466 pa_stream_set_event_callback(stream
, stream_event_callback
, NULL
);
467 pa_stream_set_buffer_attr_callback(stream
, stream_buffer_attr_callback
, NULL
);
469 pa_zero(buffer_attr
);
470 buffer_attr
.maxlength
= (uint32_t) -1;
471 buffer_attr
.prebuf
= (uint32_t) -1;
473 if (latency_msec
> 0) {
474 buffer_attr
.fragsize
= buffer_attr
.tlength
= pa_usec_to_bytes(latency_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
475 flags
|= PA_STREAM_ADJUST_LATENCY
;
476 } else if (latency
> 0) {
477 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) latency
;
478 flags
|= PA_STREAM_ADJUST_LATENCY
;
480 buffer_attr
.fragsize
= buffer_attr
.tlength
= (uint32_t) -1;
482 if (process_time_msec
> 0) {
483 buffer_attr
.minreq
= pa_usec_to_bytes(process_time_msec
* PA_USEC_PER_MSEC
, &sample_spec
);
484 } else if (process_time
> 0)
485 buffer_attr
.minreq
= (uint32_t) process_time
;
487 buffer_attr
.minreq
= (uint32_t) -1;
489 if (mode
== PLAYBACK
) {
491 if (pa_stream_connect_playback(stream
, device
, &buffer_attr
, flags
, volume_is_set
? pa_cvolume_set(&cv
, sample_spec
.channels
, volume
) : NULL
, NULL
) < 0) {
492 pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c
)));
497 if (pa_stream_connect_record(stream
, device
, &buffer_attr
, flags
) < 0) {
498 pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c
)));
506 case PA_CONTEXT_TERMINATED
:
510 case PA_CONTEXT_FAILED
:
512 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c
)));
523 /* New data on STDIN **/
524 static void stdin_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
528 pa_assert(a
== mainloop_api
);
530 pa_assert(stdio_event
== e
);
533 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
537 if (!stream
|| pa_stream_get_state(stream
) != PA_STREAM_READY
|| !(l
= w
= pa_stream_writable_size(stream
)))
540 buffer
= pa_xmalloc(l
);
542 if ((r
= pa_read(fd
, buffer
, l
, userdata
)) <= 0) {
545 pa_log(_("Got EOF."));
550 pa_log(_("read() failed: %s"), strerror(errno
));
554 mainloop_api
->io_free(stdio_event
);
559 buffer_length
= (uint32_t) r
;
566 /* Some data may be written to STDOUT */
567 static void stdout_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
570 pa_assert(a
== mainloop_api
);
572 pa_assert(stdio_event
== e
);
575 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
579 pa_assert(buffer_length
);
581 if ((r
= pa_write(fd
, (uint8_t*) buffer
+buffer_index
, buffer_length
, userdata
)) <= 0) {
582 pa_log(_("write() failed: %s"), strerror(errno
));
585 mainloop_api
->io_free(stdio_event
);
590 buffer_length
-= (uint32_t) r
;
591 buffer_index
+= (uint32_t) r
;
593 if (!buffer_length
) {
596 buffer_length
= buffer_index
= 0;
600 /* UNIX signal to quit received */
601 static void exit_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
603 pa_log(_("Got signal, exiting."));
607 /* Show the current latency */
608 static void stream_update_timing_callback(pa_stream
*s
, int success
, void *userdata
) {
615 pa_stream_get_time(s
, &usec
) < 0 ||
616 pa_stream_get_latency(s
, &l
, &negative
) < 0) {
617 pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context
)));
622 fprintf(stderr
, _("Time: %0.3f sec; Latency: %0.0f usec."),
623 (float) usec
/ 1000000,
624 (float) l
* (negative
?-1.0f
:1.0f
));
625 fprintf(stderr
, " \r");
629 /* Someone requested that the latency is shown */
630 static void sigusr1_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
635 pa_operation_unref(pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
));
639 static void time_event_callback(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
640 if (stream
&& pa_stream_get_state(stream
) == PA_STREAM_READY
) {
642 if (!(o
= pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
)))
643 pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context
)));
645 pa_operation_unref(o
);
648 pa_context_rttime_restart(context
, e
, pa_rtclock_now() + TIME_EVENT_USEC
);
651 static void help(const char *argv0
) {
653 printf(_("%s [options]\n\n"
654 " -h, --help Show this help\n"
655 " --version Show version\n\n"
656 " -r, --record Create a connection for recording\n"
657 " -p, --playback Create a connection for playback\n\n"
658 " -v, --verbose Enable verbose operations\n\n"
659 " -s, --server=SERVER The name of the server to connect to\n"
660 " -d, --device=DEVICE The name of the sink/source to connect to\n"
661 " -n, --client-name=NAME How to call this client on the server\n"
662 " --stream-name=NAME How to call this stream on the server\n"
663 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
664 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
665 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
666 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
667 " s24-32le, s24-32be (defaults to s16ne)\n"
668 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
670 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
671 " --fix-format Take the sample format from the sink the stream is\n"
672 " being connected to.\n"
673 " --fix-rate Take the sampling rate from the sink the stream is\n"
674 " being connected to.\n"
675 " --fix-channels Take the number of channels and the channel map\n"
676 " from the sink the stream is being connected to.\n"
677 " --no-remix Don't upmix or downmix channels.\n"
678 " --no-remap Map channels by index instead of name.\n"
679 " --latency=BYTES Request the specified latency in bytes.\n"
680 " --process-time=BYTES Request the specified process time per request in bytes.\n"
681 " --latency-msec=MSEC Request the specified latency in msec.\n"
682 " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
683 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
684 " --raw Record/play raw PCM data.\n"
685 " --passthrough passthrough data \n"
686 " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
687 " --list-file-formats List available file formats.\n")
710 ARG_LIST_FILE_FORMATS
,
712 ARG_PROCESS_TIME_MSEC
715 int main(int argc
, char *argv
[]) {
716 pa_mainloop
* m
= NULL
;
718 char *bn
, *server
= NULL
;
719 pa_time_event
*time_event
= NULL
;
720 const char *filename
= NULL
;
721 /* type for pa_read/_write. passed as userdata to the callbacks */
722 unsigned long type
= 0;
724 static const struct option long_options
[] = {
725 {"record", 0, NULL
, 'r'},
726 {"playback", 0, NULL
, 'p'},
727 {"device", 1, NULL
, 'd'},
728 {"server", 1, NULL
, 's'},
729 {"client-name", 1, NULL
, 'n'},
730 {"stream-name", 1, NULL
, ARG_STREAM_NAME
},
731 {"version", 0, NULL
, ARG_VERSION
},
732 {"help", 0, NULL
, 'h'},
733 {"verbose", 0, NULL
, 'v'},
734 {"volume", 1, NULL
, ARG_VOLUME
},
735 {"rate", 1, NULL
, ARG_SAMPLERATE
},
736 {"format", 1, NULL
, ARG_SAMPLEFORMAT
},
737 {"channels", 1, NULL
, ARG_CHANNELS
},
738 {"channel-map", 1, NULL
, ARG_CHANNELMAP
},
739 {"fix-format", 0, NULL
, ARG_FIX_FORMAT
},
740 {"fix-rate", 0, NULL
, ARG_FIX_RATE
},
741 {"fix-channels", 0, NULL
, ARG_FIX_CHANNELS
},
742 {"no-remap", 0, NULL
, ARG_NO_REMAP
},
743 {"no-remix", 0, NULL
, ARG_NO_REMIX
},
744 {"latency", 1, NULL
, ARG_LATENCY
},
745 {"process-time", 1, NULL
, ARG_PROCESS_TIME
},
746 {"property", 1, NULL
, ARG_PROPERTY
},
747 {"raw", 0, NULL
, ARG_RAW
},
748 {"passthrough", 0, NULL
, ARG_PASSTHROUGH
},
749 {"file-format", 2, NULL
, ARG_FILE_FORMAT
},
750 {"list-file-formats", 0, NULL
, ARG_LIST_FILE_FORMATS
},
751 {"latency-msec", 1, NULL
, ARG_LATENCY_MSEC
},
752 {"process-time-msec", 1, NULL
, ARG_PROCESS_TIME_MSEC
},
756 setlocale(LC_ALL
, "");
758 bindtextdomain(GETTEXT_PACKAGE
, PULSE_LOCALEDIR
);
761 bn
= pa_path_get_filename(argv
[0]);
763 if (strstr(bn
, "play")) {
766 } else if (strstr(bn
, "record")) {
769 } else if (strstr(bn
, "cat")) {
772 } if (strstr(bn
, "rec") || strstr(bn
, "mon")) {
777 proplist
= pa_proplist_new();
779 while ((c
= getopt_long(argc
, argv
, "rpd:s:n:hv", long_options
, NULL
)) != -1) {
788 printf(_("pacat %s\n"
789 "Compiled with libpulse %s\n"
790 "Linked with libpulse %s\n"),
792 pa_get_headers_version(),
793 pa_get_library_version());
807 device
= pa_xstrdup(optarg
);
812 server
= pa_xstrdup(optarg
);
818 if (!(t
= pa_locale_to_utf8(optarg
)) ||
819 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
) < 0) {
821 pa_log(_("Invalid client name '%s'"), t
? t
: optarg
);
830 case ARG_STREAM_NAME
: {
833 if (!(t
= pa_locale_to_utf8(optarg
)) ||
834 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
) < 0) {
836 pa_log(_("Invalid stream name '%s'"), t
? t
: optarg
);
850 int v
= atoi(optarg
);
851 volume
= v
< 0 ? 0U : (pa_volume_t
) v
;
852 volume_is_set
= TRUE
;
857 sample_spec
.channels
= (uint8_t) atoi(optarg
);
858 sample_spec_set
= TRUE
;
861 case ARG_SAMPLEFORMAT
:
862 sample_spec
.format
= pa_parse_sample_format(optarg
);
863 sample_spec_set
= TRUE
;
867 sample_spec
.rate
= (uint32_t) atoi(optarg
);
868 sample_spec_set
= TRUE
;
872 if (!pa_channel_map_parse(&channel_map
, optarg
)) {
873 pa_log(_("Invalid channel map '%s'"), optarg
);
877 channel_map_set
= TRUE
;
880 case ARG_FIX_CHANNELS
:
881 flags
|= PA_STREAM_FIX_CHANNELS
;
885 flags
|= PA_STREAM_FIX_RATE
;
889 flags
|= PA_STREAM_FIX_FORMAT
;
893 flags
|= PA_STREAM_NO_REMIX_CHANNELS
;
897 flags
|= PA_STREAM_NO_REMAP_CHANNELS
;
901 if (((latency
= (size_t) atoi(optarg
))) <= 0) {
902 pa_log(_("Invalid latency specification '%s'"), optarg
);
907 case ARG_PROCESS_TIME
:
908 if (((process_time
= (size_t) atoi(optarg
))) <= 0) {
909 pa_log(_("Invalid process time specification '%s'"), optarg
);
914 case ARG_LATENCY_MSEC
:
915 if (((latency_msec
= (int32_t) atoi(optarg
))) <= 0) {
916 pa_log(_("Invalid latency specification '%s'"), optarg
);
921 case ARG_PROCESS_TIME_MSEC
:
922 if (((process_time_msec
= (int32_t) atoi(optarg
))) <= 0) {
923 pa_log(_("Invalid process time specification '%s'"), optarg
);
931 if (!(t
= pa_locale_to_utf8(optarg
)) ||
932 pa_proplist_setp(proplist
, t
) < 0) {
935 pa_log(_("Invalid property '%s'"), optarg
);
947 case ARG_PASSTHROUGH
:
948 flags
|= PA_STREAM_PASSTHROUGH
;
951 case ARG_FILE_FORMAT
:
953 if ((file_format
= pa_sndfile_format_from_string(optarg
)) < 0) {
954 pa_log(_("Unknown file format %s."), optarg
);
962 case ARG_LIST_FILE_FORMATS
:
963 pa_sndfile_dump_formats();
972 if (!pa_sample_spec_valid(&sample_spec
)) {
973 pa_log(_("Invalid sample specification"));
977 if (optind
+1 == argc
) {
980 filename
= argv
[optind
];
982 if ((fd
= pa_open_cloexec(argv
[optind
], mode
== PLAYBACK
? O_RDONLY
: O_WRONLY
|O_TRUNC
|O_CREAT
, 0666)) < 0) {
983 pa_log(_("open(): %s"), strerror(errno
));
987 if (dup2(fd
, mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
) < 0) {
988 pa_log(_("dup2(): %s"), strerror(errno
));
994 } else if (optind
+1 <= argc
) {
995 pa_log(_("Too many arguments."));
1003 if (mode
== RECORD
) {
1004 /* This might patch up the sample spec */
1005 if (pa_sndfile_write_sample_spec(&sfi
, &sample_spec
) < 0) {
1006 pa_log(_("Failed to generate sample specification for file."));
1010 if (file_format
<= 0) {
1012 if (filename
&& (extension
= strrchr(filename
, '.')))
1013 file_format
= pa_sndfile_format_from_string(extension
+1);
1014 if (file_format
<= 0)
1015 file_format
= SF_FORMAT_WAV
;
1016 /* Transparently upgrade classic .wav to wavex for multichannel audio */
1017 if (file_format
== SF_FORMAT_WAV
&&
1018 (sample_spec
.channels
> 2 ||
1020 !(sample_spec
.channels
== 1 && channel_map
.map
[0] == PA_CHANNEL_POSITION_MONO
) &&
1021 !(sample_spec
.channels
== 2 && channel_map
.map
[0] == PA_CHANNEL_POSITION_LEFT
1022 && channel_map
.map
[1] == PA_CHANNEL_POSITION_RIGHT
))))
1023 file_format
= SF_FORMAT_WAVEX
;
1026 sfi
.format
|= file_format
;
1029 if (!(sndfile
= sf_open_fd(mode
== RECORD
? STDOUT_FILENO
: STDIN_FILENO
,
1030 mode
== RECORD
? SFM_WRITE
: SFM_READ
,
1032 pa_log(_("Failed to open audio file."));
1036 if (mode
== PLAYBACK
) {
1037 if (sample_spec_set
)
1038 pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));
1040 if (pa_sndfile_read_sample_spec(sndfile
, &sample_spec
) < 0) {
1041 pa_log(_("Failed to determine sample specification from file."));
1044 sample_spec_set
= TRUE
;
1046 if (!channel_map_set
) {
1047 /* Allow the user to overwrite the channel map on the command line */
1048 if (pa_sndfile_read_channel_map(sndfile
, &channel_map
) < 0) {
1049 if (sample_spec
.channels
> 2)
1050 pa_log(_("Warning: Failed to determine channel map from file."));
1052 channel_map_set
= TRUE
;
1057 if (!channel_map_set
)
1058 pa_channel_map_init_extend(&channel_map
, sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
);
1060 if (!pa_channel_map_compatible(&channel_map
, &sample_spec
)) {
1061 pa_log(_("Channel map doesn't match sample specification"));
1068 if (mode
== PLAYBACK
)
1069 readf_function
= pa_sndfile_readf_function(&sample_spec
);
1071 if (pa_sndfile_write_channel_map(sndfile
, &channel_map
) < 0)
1072 pa_log(_("Warning: failed to write channel map to file."));
1074 writef_function
= pa_sndfile_writef_function(&sample_spec
);
1077 /* Fill in libsndfile prop list data */
1078 sfp
= pa_proplist_new();
1079 pa_sndfile_init_proplist(sndfile
, sfp
);
1080 pa_proplist_update(proplist
, PA_UPDATE_MERGE
, sfp
);
1081 pa_proplist_free(sfp
);
1085 char tss
[PA_SAMPLE_SPEC_SNPRINT_MAX
], tcm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
1087 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
1088 mode
== RECORD
? _("recording") : _("playback"),
1089 pa_sample_spec_snprint(tss
, sizeof(tss
), &sample_spec
),
1090 pa_channel_map_snprint(tcm
, sizeof(tcm
), &channel_map
));
1093 /* Fill in client name if none was set */
1094 if (!pa_proplist_contains(proplist
, PA_PROP_APPLICATION_NAME
)) {
1097 if ((t
= pa_locale_to_utf8(bn
))) {
1098 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
);
1103 /* Fill in media name if none was set */
1104 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1107 if ((t
= filename
) ||
1108 (t
= pa_proplist_gets(proplist
, PA_PROP_APPLICATION_NAME
)))
1109 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
);
1111 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1112 pa_log(_("Failed to set media name."));
1117 /* Set up a new main loop */
1118 if (!(m
= pa_mainloop_new())) {
1119 pa_log(_("pa_mainloop_new() failed."));
1123 mainloop_api
= pa_mainloop_get_api(m
);
1125 pa_assert_se(pa_signal_init(mainloop_api
) == 0);
1126 pa_signal_new(SIGINT
, exit_signal_callback
, NULL
);
1127 pa_signal_new(SIGTERM
, exit_signal_callback
, NULL
);
1129 pa_signal_new(SIGUSR1
, sigusr1_signal_callback
, NULL
);
1131 pa_disable_sigpipe();
1135 /* need to turn on binary mode for stdio io. Windows, meh */
1136 setmode(mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
, O_BINARY
);
1138 if (!(stdio_event
= mainloop_api
->io_new(mainloop_api
,
1139 mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
,
1140 mode
== PLAYBACK
? PA_IO_EVENT_INPUT
: PA_IO_EVENT_OUTPUT
,
1141 mode
== PLAYBACK
? stdin_callback
: stdout_callback
, &type
))) {
1142 pa_log(_("io_new() failed."));
1147 /* Create a new connection context */
1148 if (!(context
= pa_context_new_with_proplist(mainloop_api
, NULL
, proplist
))) {
1149 pa_log(_("pa_context_new() failed."));
1153 pa_context_set_state_callback(context
, context_state_callback
, NULL
);
1155 /* Connect the context */
1156 if (pa_context_connect(context
, server
, 0, NULL
) < 0) {
1157 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context
)));
1162 if (!(time_event
= pa_context_rttime_new(context
, pa_rtclock_now() + TIME_EVENT_USEC
, time_event_callback
, NULL
))) {
1163 pa_log(_("pa_context_rttime_new() failed."));
1168 /* Run the main loop */
1169 if (pa_mainloop_run(m
, &ret
) < 0) {
1170 pa_log(_("pa_mainloop_run() failed."));
1176 pa_stream_unref(stream
);
1179 pa_context_unref(context
);
1182 pa_assert(mainloop_api
);
1183 mainloop_api
->io_free(stdio_event
);
1187 pa_assert(mainloop_api
);
1188 mainloop_api
->time_free(time_event
);
1193 pa_mainloop_free(m
);
1205 pa_proplist_free(proplist
);