period_duration instead of period_count

This commit is contained in:
Andrew Kelley 2015-07-15 23:45:21 -07:00
parent 7045cb3988
commit 454fab0ffb
5 changed files with 66 additions and 57 deletions

View file

@ -308,6 +308,20 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle,
snd_pcm_uframes_t min_frames;
snd_pcm_uframes_t max_frames;
if ((err = snd_pcm_hw_params_set_period_size_integer(handle, hwparams)) < 0)
return SoundIoErrorIncompatibleDevice;
if ((err = snd_pcm_hw_params_get_period_size_min(hwparams, &min_frames, nullptr)) < 0)
return SoundIoErrorIncompatibleDevice;
if ((err = snd_pcm_hw_params_get_period_size_max(hwparams, &max_frames, nullptr)) < 0)
return SoundIoErrorIncompatibleDevice;
device->period_duration_min = ((double)min_frames) / (double)device->sample_rate_max;
device->period_duration_max = ((double)max_frames) / (double)device->sample_rate_max;
if ((err = snd_pcm_hw_params_get_buffer_size_min(hwparams, &min_frames)) < 0)
return SoundIoErrorOpeningDevice;
if ((err = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
@ -317,26 +331,6 @@ static int probe_open_device(SoundIoDevice *device, snd_pcm_t *handle,
device->buffer_duration_min = ((double)min_frames) / (double)device->sample_rate_max;
device->buffer_duration_max = ((double)max_frames) / (double)device->sample_rate_max;
if ((err = snd_pcm_hw_params_set_periods_integer(handle, hwparams)) < 0)
return SoundIoErrorOpeningDevice;
dir = 0;
if ((err = snd_pcm_hw_params_get_periods_min(hwparams, &num, &dir)) < 0)
return SoundIoErrorOpeningDevice;
if (dir != 0)
return SoundIoErrorOpeningDevice;
device->period_count_min = num;
dir = 0;
if ((err = snd_pcm_hw_params_get_periods_max(hwparams, &num, &dir)) < 0)
return SoundIoErrorOpeningDevice;
if (dir != 0)
return SoundIoErrorOpeningDevice;
device->period_count_max = num;
snd_pcm_format_mask_t *fmt_mask;
@ -438,8 +432,8 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
if (device->buffer_duration_min == device->buffer_duration_max)
device->buffer_duration_current = device->buffer_duration_min;
if (device->period_count_min == device->period_count_max)
device->period_count_current = device->period_count_min;
if (device->period_duration_min == device->period_duration_max)
device->period_duration_current = device->period_duration_min;
// now say that resampling is OK and see what the real min and max is.
if ((err = probe_open_device(device, handle, hwparams, 1)) < 0) {
@ -993,20 +987,22 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
return SoundIoErrorOpeningDevice;
}
snd_pcm_uframes_t period_frames = ceil(outstream->period_duration * (double)outstream->sample_rate);
if ((err = snd_pcm_hw_params_set_period_size_near(osa->handle, hwparams, &period_frames, nullptr)) < 0) {
outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice;
}
outstream->period_duration = ((double)period_frames) / (double)outstream->sample_rate;
snd_pcm_uframes_t buffer_size_frames = ceil(outstream->buffer_duration * (double)outstream->sample_rate);
if ((err = snd_pcm_hw_params_set_buffer_size_near(osa->handle, hwparams, &buffer_size_frames)) < 0) {
outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice;
}
outstream->buffer_duration = ((double)buffer_size_frames) / (double)outstream->sample_rate;
unsigned int actual_periods_count = outstream->period_count;
if ((err = snd_pcm_hw_params_set_periods_near(osa->handle, hwparams, &actual_periods_count, nullptr)) < 0) {
outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice;
}
outstream->period_count = actual_periods_count;
snd_pcm_uframes_t period_size;
@ -1017,6 +1013,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
// write the hardware parameters to device
if ((err = snd_pcm_hw_params(osa->handle, hwparams)) < 0) {
//assert(err != -EINVAL);
outstream_destroy_alsa(si, os);
return SoundIoErrorOpeningDevice;
}

View file

@ -19,7 +19,6 @@ struct SoundIoOutStreamDummy {
struct SoundIoOsCond *cond;
atomic_flag abort_flag;
int buffer_size;
double period;
struct SoundIoRingBuffer ring_buffer;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
@ -44,7 +43,7 @@ static void playback_thread_run(void *arg) {
double time_per_frame = 1.0 / (double)outstream->sample_rate;
while (osd->abort_flag.test_and_set()) {
soundio_os_cond_timed_wait(osd->cond, nullptr, osd->period);
soundio_os_cond_timed_wait(osd->cond, nullptr, outstream->period_duration);
double now = soundio_os_get_time();
double total_time = now - start_time;
@ -142,7 +141,6 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
os->backend_data = osd;
osd->buffer_size = outstream->bytes_per_frame * outstream->buffer_duration;
osd->period = outstream->buffer_duration / (double)outstream->period_count;
soundio_ring_buffer_init(&osd->ring_buffer, osd->buffer_size);
@ -337,9 +335,9 @@ int soundio_dummy_init(SoundIoPrivate *si) {
device->sample_rate_min = 2;
device->sample_rate_max = 5644800;
device->sample_rate_current = 48000;
device->period_count_min = 1;
device->period_count_max = 16;
device->period_count_current = 2;
device->period_duration_min = 0.01;
device->period_duration_max = 2;
device->period_duration_current = 0.05;
device->purpose = SoundIoDevicePurposeOutput;
if (si->safe_devices_info->output_devices.append(device)) {
@ -388,9 +386,9 @@ int soundio_dummy_init(SoundIoPrivate *si) {
device->sample_rate_min = 2;
device->sample_rate_max = 5644800;
device->sample_rate_current = 48000;
device->period_count_min = 1;
device->period_count_max = 16;
device->period_count_current = 2;
device->period_duration_min = 0.01;
device->period_duration_max = 2;
device->period_duration_current = 0.05;
device->purpose = SoundIoDevicePurposeInput;
if (si->safe_devices_info->input_devices.append(device)) {

View file

@ -296,6 +296,7 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
//device->default_latency = usec_to_sec(info->configured_latency);
// TODO set min, max, current sample rate
//device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
// TODO set min, max, current period size
device->purpose = SoundIoDevicePurposeOutput;
if (sipa->current_devices_info->output_devices.append(device))
@ -330,6 +331,7 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
//device->default_latency = usec_to_sec(info->configured_latency);
// TODO set min, max, current sample rate
//device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
// TODO set min, max, current period size
device->purpose = SoundIoDevicePurposeInput;
if (sipa->current_devices_info->input_devices.append(device))
@ -623,6 +625,8 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
sample_spec.channels = outstream->layout.channel_count;
pa_channel_map channel_map = to_pulseaudio_channel_map(&outstream->layout);
// TODO handle period_duration
// TODO make this value ("SoundIo") configurable
ospa->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
if (!ospa->stream) {
@ -796,6 +800,8 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
pa_channel_map channel_map = to_pulseaudio_channel_map(&instream->layout);
// TODO handle period_duration
// TODO make this value ("SoundIo") private
ispa->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
if (!ispa->stream) {

View file

@ -385,7 +385,7 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
outstream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
outstream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max);
outstream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max);
outstream->period_count = clamp(device->period_count_min, 2, device->period_count_max);
outstream->period_duration = -1.0;
return outstream;
}
@ -394,6 +394,11 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) {
if (outstream->format <= SoundIoFormatInvalid)
return SoundIoErrorInvalid;
if (outstream->period_duration == -1.0) {
outstream->period_duration = clamp(outstream->device->period_duration_min,
outstream->buffer_duration / 2.0, outstream->device->period_duration_max);
}
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format);
@ -441,7 +446,7 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
instream->layout = soundio_device_supports_layout(device, stereo) ? *stereo : device->layouts[0];
instream->sample_rate = clamp(device->sample_rate_min, 48000, device->sample_rate_max);
instream->buffer_duration = clamp(device->buffer_duration_min, 1.0, device->buffer_duration_max);
instream->period_count = clamp(device->period_count_min, 8, device->period_count_max);
instream->period_duration = -1.0;
return instream;
}
@ -449,6 +454,12 @@ struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
int soundio_instream_open(struct SoundIoInStream *instream) {
if (instream->format <= SoundIoFormatInvalid)
return SoundIoErrorInvalid;
if (instream->period_duration == -1.0) {
instream->period_duration = clamp(instream->device->period_duration_min,
instream->buffer_duration / 8.0, instream->device->period_duration_max);
}
instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
SoundIo *soundio = instream->device->soundio;

View file

@ -249,11 +249,11 @@ struct SoundIoDevice {
double buffer_duration_max;
double buffer_duration_current;
// How many slices it is possible to cut the buffer into.
// TODO change this to duration units?
int period_count_min;
int period_count_max;
int period_count_current;
// Period duration in seconds. After this much time passes, write_callback
// is called.
double period_duration_min;
double period_duration_max;
double period_duration_current;
// Tells whether this device is an input device or an output device.
enum SoundIoDevicePurpose purpose;
@ -292,19 +292,17 @@ struct SoundIoOutStream {
struct SoundIoChannelLayout layout;
// Buffer duration in seconds.
// (buffer_duration / period_count) is the latency; how much time it takes
// for a sample put in the buffer to get played.
// After you call soundio_outstream_open this value is replaced with the
// actual duration, as near to this value as possible.
// Defaults to 1 second (and then clamped into range).
double buffer_duration;
// How many slices the buffer is cut into. The IRQ will happen every
// (buffer_frame_count / period_count) frames.
// After you call soundio_outstream_open this value is replaced with the
// actual period count, as near to this value as possible.
// Defaults to 2 (and then clamped into range).
int period_count;
// `period_duration` is the latency; how much time it takes
// for a sample put in the buffer to get played.
// After you call `soundio_outstream_open` this value is replaced with the
// actual period duration, as near to this value as possible.
// Defaults to `buffer_duration / 2` (and then clamped into range).
double period_duration;
// Defaults to NULL.
void *userdata;
@ -341,11 +339,10 @@ struct SoundIoInStream {
// Defaults to 1 second (and then clamped into range).
double buffer_duration;
// How many slices the buffer is cut into. The IRQ will happen every
// (buffer_duration / period_count) seconds, and that is the latency of the
// captured audio. This value must be a power of 2.
// Defaults to 8.
int period_count;
// The latency of the captured audio. After this many seconds pass,
// `read_callback` is called.
// Defaults to `buffer_duration / 8`.
double period_duration;
void *userdata;
void (*read_callback)(struct SoundIoInStream *);