#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/sndfile-util.h>
+#include <pulsecore/core-util.h>
#define TIME_EVENT_USEC 50000
static pa_stream_flags_t flags = 0;
static size_t latency = 0, process_time = 0;
+static int32_t latency_msec = 0, process_time_msec = 0;
static pa_bool_t raw = TRUE;
static int file_format = -1;
pa_assert(sndfile);
- if (pa_stream_begin_write(s, &data, &length) < 0) {
- pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
- quit(1);
- return;
- }
+ for (;;) {
+ size_t data_length = length;
- if (readf_function) {
- size_t k = pa_frame_size(&sample_spec);
+ if (pa_stream_begin_write(s, &data, &data_length) < 0) {
+ pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context)));
+ quit(1);
+ return;
+ }
- if ((bytes = readf_function(sndfile, data, (sf_count_t) (length/k))) > 0)
- bytes *= (sf_count_t) k;
+ if (readf_function) {
+ size_t k = pa_frame_size(&sample_spec);
- } else
- bytes = sf_read_raw(sndfile, data, (sf_count_t) length);
+ if ((bytes = readf_function(sndfile, data, (sf_count_t) (data_length/k))) > 0)
+ bytes *= (sf_count_t) k;
- if (bytes > 0)
- pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE);
- else
- pa_stream_cancel_write(s);
+ } else
+ bytes = sf_read_raw(sndfile, data, (sf_count_t) data_length);
- if (bytes < (sf_count_t) length)
- start_drain();
+ if (bytes > 0)
+ pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE);
+ else
+ pa_stream_cancel_write(s);
+
+ /* EOF? */
+ if (bytes < (sf_count_t) data_length) {
+ start_drain();
+ break;
+ }
+
+ /* Request fulfilled */
+ if ((size_t) bytes >= length)
+ break;
+
+ length -= bytes;
+ }
}
}
pa_stream_set_event_callback(stream, stream_event_callback, NULL);
pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
- if (latency > 0) {
- memset(&buffer_attr, 0, sizeof(buffer_attr));
- buffer_attr.tlength = (uint32_t) latency;
- buffer_attr.minreq = (uint32_t) process_time;
- buffer_attr.maxlength = (uint32_t) -1;
- buffer_attr.prebuf = (uint32_t) -1;
- buffer_attr.fragsize = (uint32_t) latency;
+ pa_zero(buffer_attr);
+ buffer_attr.maxlength = (uint32_t) -1;
+ buffer_attr.prebuf = (uint32_t) -1;
+
+ if (latency_msec > 0) {
+ buffer_attr.fragsize = buffer_attr.tlength = pa_usec_to_bytes(latency_msec * PA_USEC_PER_MSEC, &sample_spec);
flags |= PA_STREAM_ADJUST_LATENCY;
- }
+ } else if (latency > 0) {
+ buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) latency;
+ flags |= PA_STREAM_ADJUST_LATENCY;
+ } else
+ buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) -1;
+
+ if (process_time_msec > 0) {
+ buffer_attr.minreq = pa_usec_to_bytes(process_time_msec * PA_USEC_PER_MSEC, &sample_spec);
+ } else if (process_time > 0)
+ buffer_attr.minreq = (uint32_t) process_time;
+ else
+ buffer_attr.minreq = (uint32_t) -1;
if (mode == PLAYBACK) {
pa_cvolume cv;
- if (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) {
+ if (pa_stream_connect_playback(stream, device, &buffer_attr, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL) < 0) {
pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c)));
goto fail;
}
} else {
- if (pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags) < 0) {
+ if (pa_stream_connect_record(stream, device, &buffer_attr, flags) < 0) {
pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c)));
goto fail;
}
" --no-remap Map channels by index instead of name.\n"
" --latency=BYTES Request the specified latency in bytes.\n"
" --process-time=BYTES Request the specified process time per request in bytes.\n"
+ " --latency-msec=MSEC Request the specified latency in msec.\n"
+ " --process-time-msec=MSEC Request the specified process time per request in msec.\n"
" --property=PROPERTY=VALUE Set the specified property to the specified value.\n"
" --raw Record/play raw PCM data.\n"
- " --file-format=FFORMAT Record/play formatted PCM data.\n"
+ " --passthrough passthrough data \n"
+ " --file-format[=FFORMAT] Record/play formatted PCM data.\n"
" --list-file-formats List available file formats.\n")
, argv0);
}
ARG_LATENCY,
ARG_PROCESS_TIME,
ARG_RAW,
+ ARG_PASSTHROUGH,
ARG_PROPERTY,
ARG_FILE_FORMAT,
- ARG_LIST_FILE_FORMATS
+ ARG_LIST_FILE_FORMATS,
+ ARG_LATENCY_MSEC,
+ ARG_PROCESS_TIME_MSEC
};
int main(int argc, char *argv[]) {
{"process-time", 1, NULL, ARG_PROCESS_TIME},
{"property", 1, NULL, ARG_PROPERTY},
{"raw", 0, NULL, ARG_RAW},
+ {"passthrough", 0, NULL, ARG_PASSTHROUGH},
{"file-format", 2, NULL, ARG_FILE_FORMAT},
{"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
+ {"latency-msec", 1, NULL, ARG_LATENCY_MSEC},
+ {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC},
{NULL, 0, NULL, 0}
};
}
break;
+ case ARG_LATENCY_MSEC:
+ if (((latency_msec = (int32_t) atoi(optarg))) <= 0) {
+ pa_log(_("Invalid latency specification '%s'"), optarg);
+ goto quit;
+ }
+ break;
+
+ case ARG_PROCESS_TIME_MSEC:
+ if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) {
+ pa_log(_("Invalid process time specification '%s'"), optarg);
+ goto quit;
+ }
+ break;
+
case ARG_PROPERTY: {
char *t;
raw = TRUE;
break;
+ case ARG_PASSTHROUGH:
+ flags |= PA_STREAM_PASSTHROUGH;
+ break;
+
case ARG_FILE_FORMAT:
raw = FALSE;
filename = argv[optind];
- if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
+ if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
pa_log(_("open(): %s"), strerror(errno));
goto quit;
}