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/i18n.h>
41 #include <pulse/pulseaudio.h>
43 #include <pulsecore/macro.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/sndfile-util.h>
48 #define TIME_EVENT_USEC 50000
50 #define CLEAR_LINE "\x1B[K"
52 static enum { RECORD
, PLAYBACK
} mode
= PLAYBACK
;
54 static pa_context
*context
= NULL
;
55 static pa_stream
*stream
= NULL
;
56 static pa_mainloop_api
*mainloop_api
= NULL
;
58 static void *buffer
= NULL
;
59 static size_t buffer_length
= 0, buffer_index
= 0;
61 static pa_io_event
* stdio_event
= NULL
;
63 static pa_proplist
*proplist
= NULL
;
64 static char *device
= NULL
;
66 static SNDFILE
* sndfile
= NULL
;
68 static pa_bool_t verbose
= FALSE
;
69 static pa_volume_t volume
= PA_VOLUME_NORM
;
70 static pa_bool_t volume_is_set
= FALSE
;
72 static pa_sample_spec sample_spec
= {
73 .format
= PA_SAMPLE_S16LE
,
77 static pa_bool_t sample_spec_set
= FALSE
;
79 static pa_channel_map channel_map
;
80 static pa_bool_t channel_map_set
= FALSE
;
82 static sf_count_t (*readf_function
)(SNDFILE
*_sndfile
, void *ptr
, sf_count_t frames
) = NULL
;
83 static sf_count_t (*writef_function
)(SNDFILE
*_sndfile
, const void *ptr
, sf_count_t frames
) = NULL
;
85 static pa_stream_flags_t flags
= 0;
87 static size_t latency
= 0, process_time
= 0;
89 static pa_bool_t raw
= TRUE
;
90 static int file_format
= -1;
92 /* A shortcut for terminating the application */
93 static void quit(int ret
) {
94 pa_assert(mainloop_api
);
95 mainloop_api
->quit(mainloop_api
, ret
);
98 /* Connection draining complete */
99 static void context_drain_complete(pa_context
*c
, void *userdata
) {
100 pa_context_disconnect(c
);
103 /* Stream draining complete */
104 static void stream_drain_complete(pa_stream
*s
, int success
, void *userdata
) {
107 pa_log(_("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context
)));
112 pa_log(_("Playback stream drained.\n"));
114 pa_stream_disconnect(stream
);
115 pa_stream_unref(stream
);
118 if (!pa_context_drain(context
, context_drain_complete
, NULL
))
119 pa_context_disconnect(context
);
122 pa_log(_("Draining connection to server.\n"));
127 static void start_drain(void) {
132 pa_stream_set_write_callback(stream
, NULL
, NULL
);
134 if (!(o
= pa_stream_drain(stream
, stream_drain_complete
, NULL
))) {
135 pa_log(_("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context
)));
140 pa_operation_unref(o
);
145 /* Write some data to the stream */
146 static void do_stream_write(size_t length
) {
150 if (!buffer
|| !buffer_length
)
154 if (l
> buffer_length
)
157 if (pa_stream_write(stream
, (uint8_t*) buffer
+ buffer_index
, l
, NULL
, 0, PA_SEEK_RELATIVE
) < 0) {
158 pa_log(_("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context
)));
166 if (!buffer_length
) {
169 buffer_index
= buffer_length
= 0;
173 /* This is called whenever new data may be written to the stream */
174 static void stream_write_callback(pa_stream
*s
, size_t length
, void *userdata
) {
176 pa_assert(length
> 0);
182 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_INPUT
);
187 do_stream_write(length
);
195 data
= pa_xmalloc(length
);
197 if (readf_function
) {
198 size_t k
= pa_frame_size(&sample_spec
);
200 if ((bytes
= readf_function(sndfile
, data
, (sf_count_t
) (length
/k
))) > 0)
201 bytes
*= (sf_count_t
) k
;
204 bytes
= sf_read_raw(sndfile
, data
, (sf_count_t
) length
);
207 pa_stream_write(s
, data
, (size_t) bytes
, pa_xfree
, 0, PA_SEEK_RELATIVE
);
211 if (bytes
< (sf_count_t
) length
)
216 /* This is called whenever new data may is available */
217 static void stream_read_callback(pa_stream
*s
, size_t length
, void *userdata
) {
220 pa_assert(length
> 0);
226 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_OUTPUT
);
229 while (pa_stream_readable_size(s
) > 0) {
232 if (pa_stream_peek(s
, &data
, &length
) < 0) {
233 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context
)));
239 pa_assert(length
> 0);
242 buffer
= pa_xrealloc(buffer
, buffer_length
+ length
);
243 memcpy((uint8_t*) buffer
+ buffer_length
, data
, length
);
244 buffer_length
+= length
;
246 buffer
= pa_xmalloc(length
);
247 memcpy(buffer
, data
, length
);
248 buffer_length
= length
;
257 while (pa_stream_readable_size(s
) > 0) {
261 if (pa_stream_peek(s
, &data
, &length
) < 0) {
262 pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context
)));
268 pa_assert(length
> 0);
270 if (writef_function
) {
271 size_t k
= pa_frame_size(&sample_spec
);
273 if ((bytes
= writef_function(sndfile
, data
, (sf_count_t
) (length
/k
))) > 0)
274 bytes
*= (sf_count_t
) k
;
277 bytes
= sf_write_raw(sndfile
, data
, (sf_count_t
) length
);
279 if (bytes
< (sf_count_t
) length
)
287 /* This routine is called whenever the stream state changes */
288 static void stream_state_callback(pa_stream
*s
, void *userdata
) {
291 switch (pa_stream_get_state(s
)) {
292 case PA_STREAM_CREATING
:
293 case PA_STREAM_TERMINATED
:
296 case PA_STREAM_READY
:
299 const pa_buffer_attr
*a
;
300 char cmt
[PA_CHANNEL_MAP_SNPRINT_MAX
], sst
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
302 pa_log(_("Stream successfully created.\n"));
304 if (!(a
= pa_stream_get_buffer_attr(s
)))
305 pa_log(_("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
308 if (mode
== PLAYBACK
)
309 pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a
->maxlength
, a
->tlength
, a
->prebuf
, a
->minreq
);
311 pa_assert(mode
== RECORD
);
312 pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u\n"), a
->maxlength
, a
->fragsize
);
316 pa_log(_("Using sample spec '%s', channel map '%s'.\n"),
317 pa_sample_spec_snprint(sst
, sizeof(sst
), pa_stream_get_sample_spec(s
)),
318 pa_channel_map_snprint(cmt
, sizeof(cmt
), pa_stream_get_channel_map(s
)));
320 pa_log(_("Connected to device %s (%u, %ssuspended).\n"),
321 pa_stream_get_device_name(s
),
322 pa_stream_get_device_index(s
),
323 pa_stream_is_suspended(s
) ? "" : "not ");
328 case PA_STREAM_FAILED
:
330 pa_log(_("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s
))));
335 static void stream_suspended_callback(pa_stream
*s
, void *userdata
) {
339 if (pa_stream_is_suspended(s
))
340 pa_log(_("Stream device suspended.%s \n"), CLEAR_LINE
);
342 pa_log(_("Stream device resumed.%s \n"), CLEAR_LINE
);
346 static void stream_underflow_callback(pa_stream
*s
, void *userdata
) {
350 pa_log(_("Stream underrun.%s \n"), CLEAR_LINE
);
353 static void stream_overflow_callback(pa_stream
*s
, void *userdata
) {
357 pa_log(_("Stream overrun.%s \n"), CLEAR_LINE
);
360 static void stream_started_callback(pa_stream
*s
, void *userdata
) {
364 pa_log(_("Stream started.%s \n"), CLEAR_LINE
);
367 static void stream_moved_callback(pa_stream
*s
, void *userdata
) {
371 pa_log(_("Stream moved to device %s (%u, %ssuspended).%s \n"), pa_stream_get_device_name(s
), pa_stream_get_device_index(s
), pa_stream_is_suspended(s
) ? "" : _("not "), CLEAR_LINE
);
374 static void stream_buffer_attr_callback(pa_stream
*s
, void *userdata
) {
378 pa_log(_("Stream buffer attributes changed.%s \n"), CLEAR_LINE
);
381 static void stream_event_callback(pa_stream
*s
, const char *name
, pa_proplist
*pl
, void *userdata
) {
388 t
= pa_proplist_to_string_sep(pl
, ", ");
389 pa_log("Got event '%s', properties '%s'\n", name
, t
);
393 /* This is called whenever the context status changes */
394 static void context_state_callback(pa_context
*c
, void *userdata
) {
397 switch (pa_context_get_state(c
)) {
398 case PA_CONTEXT_CONNECTING
:
399 case PA_CONTEXT_AUTHORIZING
:
400 case PA_CONTEXT_SETTING_NAME
:
403 case PA_CONTEXT_READY
: {
405 pa_buffer_attr buffer_attr
;
411 pa_log(_("Connection established.%s \n"), CLEAR_LINE
);
413 if (!(stream
= pa_stream_new_with_proplist(c
, NULL
, &sample_spec
, &channel_map
, proplist
))) {
414 pa_log(_("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c
)));
418 pa_stream_set_state_callback(stream
, stream_state_callback
, NULL
);
419 pa_stream_set_write_callback(stream
, stream_write_callback
, NULL
);
420 pa_stream_set_read_callback(stream
, stream_read_callback
, NULL
);
421 pa_stream_set_suspended_callback(stream
, stream_suspended_callback
, NULL
);
422 pa_stream_set_moved_callback(stream
, stream_moved_callback
, NULL
);
423 pa_stream_set_underflow_callback(stream
, stream_underflow_callback
, NULL
);
424 pa_stream_set_overflow_callback(stream
, stream_overflow_callback
, NULL
);
425 pa_stream_set_started_callback(stream
, stream_started_callback
, NULL
);
426 pa_stream_set_event_callback(stream
, stream_event_callback
, NULL
);
427 pa_stream_set_buffer_attr_callback(stream
, stream_buffer_attr_callback
, NULL
);
430 memset(&buffer_attr
, 0, sizeof(buffer_attr
));
431 buffer_attr
.tlength
= (uint32_t) latency
;
432 buffer_attr
.minreq
= (uint32_t) process_time
;
433 buffer_attr
.maxlength
= (uint32_t) -1;
434 buffer_attr
.prebuf
= (uint32_t) -1;
435 buffer_attr
.fragsize
= (uint32_t) latency
;
436 flags
|= PA_STREAM_ADJUST_LATENCY
;
439 if (mode
== PLAYBACK
) {
441 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) {
442 pa_log(_("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c
)));
447 if ((r
= pa_stream_connect_record(stream
, device
, latency
> 0 ? &buffer_attr
: NULL
, flags
)) < 0) {
448 pa_log(_("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c
)));
456 case PA_CONTEXT_TERMINATED
:
460 case PA_CONTEXT_FAILED
:
462 pa_log(_("Connection failure: %s\n"), pa_strerror(pa_context_errno(c
)));
473 /* New data on STDIN **/
474 static void stdin_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
478 pa_assert(a
== mainloop_api
);
480 pa_assert(stdio_event
== e
);
483 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
487 if (!stream
|| pa_stream_get_state(stream
) != PA_STREAM_READY
|| !(l
= w
= pa_stream_writable_size(stream
)))
490 buffer
= pa_xmalloc(l
);
492 if ((r
= read(fd
, buffer
, l
)) <= 0) {
495 pa_log(_("Got EOF.\n"));
500 pa_log(_("read() failed: %s\n"), strerror(errno
));
504 mainloop_api
->io_free(stdio_event
);
509 buffer_length
= (uint32_t) r
;
516 /* Some data may be written to STDOUT */
517 static void stdout_callback(pa_mainloop_api
*a
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
520 pa_assert(a
== mainloop_api
);
522 pa_assert(stdio_event
== e
);
525 mainloop_api
->io_enable(stdio_event
, PA_IO_EVENT_NULL
);
529 pa_assert(buffer_length
);
531 if ((r
= write(fd
, (uint8_t*) buffer
+buffer_index
, buffer_length
)) <= 0) {
532 pa_log(_("write() failed: %s\n"), strerror(errno
));
535 mainloop_api
->io_free(stdio_event
);
540 buffer_length
-= (uint32_t) r
;
541 buffer_index
+= (uint32_t) r
;
543 if (!buffer_length
) {
546 buffer_length
= buffer_index
= 0;
550 /* UNIX signal to quit recieved */
551 static void exit_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
553 pa_log(_("Got signal, exiting.\n"));
557 /* Show the current latency */
558 static void stream_update_timing_callback(pa_stream
*s
, int success
, void *userdata
) {
565 pa_stream_get_time(s
, &usec
) < 0 ||
566 pa_stream_get_latency(s
, &l
, &negative
) < 0) {
567 pa_log(_("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context
)));
572 pa_log(_("Time: %0.3f sec; Latency: %0.0f usec. \r"),
573 (float) usec
/ 1000000,
574 (float) l
* (negative
?-1.0f
:1.0f
));
577 /* Someone requested that the latency is shown */
578 static void sigusr1_signal_callback(pa_mainloop_api
*m
, pa_signal_event
*e
, int sig
, void *userdata
) {
583 pa_operation_unref(pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
));
586 static void time_event_callback(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
589 if (stream
&& pa_stream_get_state(stream
) == PA_STREAM_READY
) {
591 if (!(o
= pa_stream_update_timing_info(stream
, stream_update_timing_callback
, NULL
)))
592 pa_log(_("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context
)));
594 pa_operation_unref(o
);
597 pa_gettimeofday(&next
);
598 pa_timeval_add(&next
, TIME_EVENT_USEC
);
600 m
->time_restart(e
, &next
);
603 static void help(const char *argv0
) {
605 printf(_("%s [options]\n\n"
606 " -h, --help Show this help\n"
607 " --version Show version\n\n"
608 " -r, --record Create a connection for recording\n"
609 " -p, --playback Create a connection for playback\n\n"
610 " -v, --verbose Enable verbose operations\n\n"
611 " -s, --server=SERVER The name of the server to connect to\n"
612 " -d, --device=DEVICE The name of the sink/source to connect to\n"
613 " -n, --client-name=NAME How to call this client on the server\n"
614 " --stream-name=NAME How to call this stream on the server\n"
615 " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
616 " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
617 " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
618 " float32be, ulaw, alaw, s32le, s32be, s24le, s24be,\n"
619 " s24-32le, s24-32be (defaults to s16ne)\n"
620 " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
622 " --channel-map=CHANNELMAP Channel map to use instead of the default\n"
623 " --fix-format Take the sample format from the sink the stream is\n"
624 " being connected to.\n"
625 " --fix-rate Take the sampling rate from the sink the stream is\n"
626 " being connected to.\n"
627 " --fix-channels Take the number of channels and the channel map\n"
628 " from the sink the stream is being connected to.\n"
629 " --no-remix Don't upmix or downmix channels.\n"
630 " --no-remap Map channels by index instead of name.\n"
631 " --latency=BYTES Request the specified latency in bytes.\n"
632 " --process-time=BYTES Request the specified process time per request in bytes.\n"
633 " --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
634 " --raw Record/play raw PCM data.\n"
635 " --file-format=FFORMAT Record/play formatted PCM data.\n"
636 " --list-file-formats List available file formats.\n")
658 ARG_LIST_FILE_FORMATS
661 int main(int argc
, char *argv
[]) {
662 pa_mainloop
* m
= NULL
;
664 char *bn
, *server
= NULL
;
665 pa_time_event
*time_event
= NULL
;
666 const char *filename
= NULL
;
668 static const struct option long_options
[] = {
669 {"record", 0, NULL
, 'r'},
670 {"playback", 0, NULL
, 'p'},
671 {"device", 1, NULL
, 'd'},
672 {"server", 1, NULL
, 's'},
673 {"client-name", 1, NULL
, 'n'},
674 {"stream-name", 1, NULL
, ARG_STREAM_NAME
},
675 {"version", 0, NULL
, ARG_VERSION
},
676 {"help", 0, NULL
, 'h'},
677 {"verbose", 0, NULL
, 'v'},
678 {"volume", 1, NULL
, ARG_VOLUME
},
679 {"rate", 1, NULL
, ARG_SAMPLERATE
},
680 {"format", 1, NULL
, ARG_SAMPLEFORMAT
},
681 {"channels", 1, NULL
, ARG_CHANNELS
},
682 {"channel-map", 1, NULL
, ARG_CHANNELMAP
},
683 {"fix-format", 0, NULL
, ARG_FIX_FORMAT
},
684 {"fix-rate", 0, NULL
, ARG_FIX_RATE
},
685 {"fix-channels", 0, NULL
, ARG_FIX_CHANNELS
},
686 {"no-remap", 0, NULL
, ARG_NO_REMAP
},
687 {"no-remix", 0, NULL
, ARG_NO_REMIX
},
688 {"latency", 1, NULL
, ARG_LATENCY
},
689 {"process-time", 1, NULL
, ARG_PROCESS_TIME
},
690 {"property", 1, NULL
, ARG_PROPERTY
},
691 {"raw", 0, NULL
, ARG_RAW
},
692 {"file-format", 2, NULL
, ARG_FILE_FORMAT
},
693 {"list-file-formats", 0, NULL
, ARG_LIST_FILE_FORMATS
},
697 setlocale(LC_ALL
, "");
698 bindtextdomain(GETTEXT_PACKAGE
, PULSE_LOCALEDIR
);
700 bn
= pa_path_get_filename(argv
[0]);
702 if (strstr(bn
, "play")) {
705 } else if (strstr(bn
, "record")) {
708 } else if (strstr(bn
, "cat")) {
711 } if (strstr(bn
, "rec") || strstr(bn
, "mon")) {
716 proplist
= pa_proplist_new();
718 while ((c
= getopt_long(argc
, argv
, "rpd:s:n:hv", long_options
, NULL
)) != -1) {
727 printf(_("pacat %s\n"
728 "Compiled with libpulse %s\n"
729 "Linked with libpulse %s\n"),
731 pa_get_headers_version(),
732 pa_get_library_version());
746 device
= pa_xstrdup(optarg
);
751 server
= pa_xstrdup(optarg
);
757 if (!(t
= pa_locale_to_utf8(optarg
)) ||
758 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
) < 0) {
760 pa_log(_("Invalid client name '%s'\n"), t
? t
: optarg
);
769 case ARG_STREAM_NAME
: {
771 t
= pa_locale_to_utf8(optarg
);
773 if (!(t
= pa_locale_to_utf8(optarg
)) ||
774 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
) < 0) {
776 pa_log(_("Invalid stream name '%s'\n"), t
? t
: optarg
);
790 int v
= atoi(optarg
);
791 volume
= v
< 0 ? 0U : (pa_volume_t
) v
;
792 volume_is_set
= TRUE
;
797 sample_spec
.channels
= (uint8_t) atoi(optarg
);
798 sample_spec_set
= TRUE
;
801 case ARG_SAMPLEFORMAT
:
802 sample_spec
.format
= pa_parse_sample_format(optarg
);
803 sample_spec_set
= TRUE
;
807 sample_spec
.rate
= (uint32_t) atoi(optarg
);
808 sample_spec_set
= TRUE
;
812 if (!pa_channel_map_parse(&channel_map
, optarg
)) {
813 pa_log(_("Invalid channel map '%s'\n"), optarg
);
817 channel_map_set
= TRUE
;
820 case ARG_FIX_CHANNELS
:
821 flags
|= PA_STREAM_FIX_CHANNELS
;
825 flags
|= PA_STREAM_FIX_RATE
;
829 flags
|= PA_STREAM_FIX_FORMAT
;
833 flags
|= PA_STREAM_NO_REMIX_CHANNELS
;
837 flags
|= PA_STREAM_NO_REMAP_CHANNELS
;
841 if (((latency
= (size_t) atoi(optarg
))) <= 0) {
842 pa_log(_("Invalid latency specification '%s'\n"), optarg
);
847 case ARG_PROCESS_TIME
:
848 if (((process_time
= (size_t) atoi(optarg
))) <= 0) {
849 pa_log(_("Invalid process time specification '%s'\n"), optarg
);
857 if (!(t
= pa_locale_to_utf8(optarg
)) ||
858 pa_proplist_setp(proplist
, t
) < 0) {
861 pa_log(_("Invalid property '%s'\n"), optarg
);
873 case ARG_FILE_FORMAT
:
877 if ((file_format
= pa_sndfile_format_from_string(optarg
)) < 0) {
878 pa_log(_("Unknown file format %s."), optarg
);
886 case ARG_LIST_FILE_FORMATS
:
887 pa_sndfile_dump_formats();
896 if (!pa_sample_spec_valid(&sample_spec
)) {
897 pa_log(_("Invalid sample specification\n"));
901 if (optind
+1 == argc
) {
904 filename
= argv
[optind
];
906 if ((fd
= open(argv
[optind
], mode
== PLAYBACK
? O_RDONLY
: O_WRONLY
|O_TRUNC
|O_CREAT
, 0666)) < 0) {
907 pa_log(_("open(): %s\n"), strerror(errno
));
911 if (dup2(fd
, mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
) < 0) {
912 pa_log(_("dup2(): %s\n"), strerror(errno
));
918 } else if (optind
+1 <= argc
) {
919 pa_log(_("Too many arguments.\n"));
927 if (mode
== RECORD
) {
928 /* This might patch up the sample spec */
929 if (pa_sndfile_write_sample_spec(&sfi
, &sample_spec
) < 0) {
930 pa_log(_("Failed to generate sample specification for file.\n"));
934 /* Transparently upgrade classic .wav to wavex for multichannel audio */
935 if (file_format
<= 0) {
936 if ((sample_spec
.channels
== 2 && (!channel_map_set
|| (channel_map
.map
[0] == PA_CHANNEL_POSITION_LEFT
&&
937 channel_map
.map
[1] == PA_CHANNEL_POSITION_RIGHT
))) ||
938 (sample_spec
.channels
== 1 && (!channel_map_set
|| (channel_map
.map
[0] == PA_CHANNEL_POSITION_MONO
))))
939 file_format
= SF_FORMAT_WAV
;
941 file_format
= SF_FORMAT_WAVEX
;
944 sfi
.format
|= file_format
;
947 if (!(sndfile
= sf_open_fd(mode
== RECORD
? STDOUT_FILENO
: STDIN_FILENO
,
948 mode
== RECORD
? SFM_WRITE
: SFM_READ
,
950 pa_log(_("Failed to open audio file.\n"));
954 if (mode
== PLAYBACK
) {
956 pa_log(_("Warning: specified sample specification will be overwritten with specification from file.\n"));
958 if (pa_sndfile_read_sample_spec(sndfile
, &sample_spec
) < 0) {
959 pa_log(_("Failed to determine sample specification from file.\n"));
962 sample_spec_set
= TRUE
;
964 if (!channel_map_set
) {
965 /* Allow the user to overwrite the channel map on the command line */
966 if (pa_sndfile_read_channel_map(sndfile
, &channel_map
) < 0) {
967 if (sample_spec
.channels
> 2)
968 pa_log(_("Warning: Failed to determine channel map from file.\n"));
970 channel_map_set
= TRUE
;
975 if (!channel_map_set
)
976 pa_channel_map_init_extend(&channel_map
, sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
);
978 if (!pa_channel_map_compatible(&channel_map
, &sample_spec
)) {
979 pa_log(_("Channel map doesn't match sample specification\n"));
986 if (mode
== PLAYBACK
)
987 readf_function
= pa_sndfile_readf_function(&sample_spec
);
989 if (pa_sndfile_write_channel_map(sndfile
, &channel_map
) < 0)
990 pa_log(_("Warning: failed to write channel map to file.\n"));
992 writef_function
= pa_sndfile_writef_function(&sample_spec
);
995 /* Fill in libsndfile prop list data */
996 sfp
= pa_proplist_new();
997 pa_sndfile_init_proplist(sndfile
, sfp
);
998 pa_proplist_update(proplist
, PA_UPDATE_MERGE
, sfp
);
999 pa_proplist_free(sfp
);
1003 char tss
[PA_SAMPLE_SPEC_SNPRINT_MAX
], tcm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
1005 pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'.\n"),
1006 mode
== RECORD
? _("recording") : _("playback"),
1007 pa_sample_spec_snprint(tss
, sizeof(tss
), &sample_spec
),
1008 pa_channel_map_snprint(tcm
, sizeof(tcm
), &channel_map
));
1011 /* Fill in client name if none was set */
1012 if (!pa_proplist_contains(proplist
, PA_PROP_APPLICATION_NAME
)) {
1015 if ((t
= pa_locale_to_utf8(bn
))) {
1016 pa_proplist_sets(proplist
, PA_PROP_APPLICATION_NAME
, t
);
1021 /* Fill in media name if none was set */
1022 if (!pa_proplist_contains(proplist
, PA_PROP_MEDIA_NAME
)) {
1025 if ((t
= filename
) ||
1026 (t
= pa_proplist_gets(proplist
, PA_PROP_APPLICATION_NAME
)))
1027 pa_proplist_sets(proplist
, PA_PROP_MEDIA_NAME
, t
);
1030 /* Set up a new main loop */
1031 if (!(m
= pa_mainloop_new())) {
1032 pa_log(_("pa_mainloop_new() failed.\n"));
1036 mainloop_api
= pa_mainloop_get_api(m
);
1038 pa_assert_se(pa_signal_init(mainloop_api
) == 0);
1039 pa_signal_new(SIGINT
, exit_signal_callback
, NULL
);
1040 pa_signal_new(SIGTERM
, exit_signal_callback
, NULL
);
1042 pa_signal_new(SIGUSR1
, sigusr1_signal_callback
, NULL
);
1044 pa_disable_sigpipe();
1047 if (!(stdio_event
= mainloop_api
->io_new(mainloop_api
,
1048 mode
== PLAYBACK
? STDIN_FILENO
: STDOUT_FILENO
,
1049 mode
== PLAYBACK
? PA_IO_EVENT_INPUT
: PA_IO_EVENT_OUTPUT
,
1050 mode
== PLAYBACK
? stdin_callback
: stdout_callback
, NULL
))) {
1051 pa_log(_("io_new() failed.\n"));
1056 /* Create a new connection context */
1057 if (!(context
= pa_context_new_with_proplist(mainloop_api
, NULL
, proplist
))) {
1058 pa_log(_("pa_context_new() failed.\n"));
1062 pa_context_set_state_callback(context
, context_state_callback
, NULL
);
1064 /* Connect the context */
1065 if (pa_context_connect(context
, server
, 0, NULL
) < 0) {
1066 pa_log(_("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context
)));
1073 pa_gettimeofday(&tv
);
1074 pa_timeval_add(&tv
, TIME_EVENT_USEC
);
1076 if (!(time_event
= mainloop_api
->time_new(mainloop_api
, &tv
, time_event_callback
, NULL
))) {
1077 pa_log(_("time_new() failed.\n"));
1082 /* Run the main loop */
1083 if (pa_mainloop_run(m
, &ret
) < 0) {
1084 pa_log(_("pa_mainloop_run() failed.\n"));
1090 pa_stream_unref(stream
);
1093 pa_context_unref(context
);
1096 pa_assert(mainloop_api
);
1097 mainloop_api
->io_free(stdio_event
);
1101 pa_assert(mainloop_api
);
1102 mainloop_api
->time_free(time_event
);
1107 pa_mainloop_free(m
);
1119 pa_proplist_free(proplist
);