mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 13:45:41 +00:00
Delete the concept of prebuffering
This commit is contained in:
parent
d3cf8f02db
commit
44569708a0
|
@ -20,10 +20,10 @@ behavior on every platform.
|
||||||
## Features and Limitations
|
## Features and Limitations
|
||||||
|
|
||||||
* Supported backends:
|
* Supported backends:
|
||||||
|
- [JACK](http://jackaudio.org/)
|
||||||
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||||
- [ALSA](http://www.alsa-project.org/)
|
- [ALSA](http://www.alsa-project.org/)
|
||||||
- Dummy (silence)
|
- Dummy (silence)
|
||||||
- [JACK](http://jackaudio.org/)
|
|
||||||
- (planned) [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
- (planned) [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
||||||
- (planned) [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx)
|
- (planned) [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx)
|
||||||
- (planned) [ASIO](http://www.asio4all.com/)
|
- (planned) [ASIO](http://www.asio4all.com/)
|
||||||
|
@ -245,19 +245,15 @@ view `coverage/index.html` in a browser.
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
0. implement CoreAudio (OSX) backend, get examples working
|
||||||
0. implement WASAPI (Windows) backend, get examples working
|
0. implement WASAPI (Windows) backend, get examples working
|
||||||
0. implement ASIO (Windows) backend, get examples working
|
0. implement ASIO (Windows) backend, get examples working
|
||||||
0. JACK: implement prebuffering ...or delete prebuffering as a concept
|
|
||||||
0. Avoid calling `soundio_panic` in PulseAudio.
|
0. Avoid calling `soundio_panic` in PulseAudio.
|
||||||
0. Figure out a way to test prebuf. I suspect prebuf not working for ALSA
|
|
||||||
which is why we have to pre-fill the ring buffer with silence for
|
|
||||||
the microphone example.
|
|
||||||
0. PulseAudio: when prebuf gets set to 0 need to pass `PA_STREAM_START_CORKED`.
|
0. PulseAudio: when prebuf gets set to 0 need to pass `PA_STREAM_START_CORKED`.
|
||||||
|
0. clear buffer maybe could take an argument to say how many frames to not clear
|
||||||
0. In ALSA do we need to wake up the poll when destroying the in or out stream?
|
0. In ALSA do we need to wake up the poll when destroying the in or out stream?
|
||||||
0. Verify that JACK xrun callback context is the same as process callback.
|
0. Verify that JACK xrun callback context is the same as process callback.
|
||||||
If not, might need to hav xrun callback set a flag and have process callback
|
If not, might need to hav xrun callback set a flag and have process callback
|
||||||
call the underflow callback.
|
call the underflow callback.
|
||||||
0. Detect PulseAudio server going offline and emit `on_backend_disconnect`.
|
0. Detect PulseAudio server going offline and emit `on_backend_disconnect`.
|
||||||
0. Instead fo open(), start(), pause(), open() starts it and it starts paused.
|
0. Instead fo open(), start(), pause(), open() starts it and it starts paused.
|
||||||
0. Create a test for clearing the playback buffer and prebuffering.
|
|
||||||
0. Create a test for pausing and resuming input and output streams.
|
0. Create a test for pausing and resuming input and output streams.
|
||||||
0. Create a test for the latency / synchronization API.
|
0. Create a test for the latency / synchronization API.
|
||||||
- Input is an audio file and some events indexed at particular frame - when
|
- Input is an audio file and some events indexed at particular frame - when
|
||||||
|
@ -290,7 +286,6 @@ view `coverage/index.html` in a browser.
|
||||||
0. make rtprio warning a callback and have existing behavior be the default callback
|
0. make rtprio warning a callback and have existing behavior be the default callback
|
||||||
0. write detailed docs on buffer underflows explaining when they occur, what state
|
0. write detailed docs on buffer underflows explaining when they occur, what state
|
||||||
changes are related to them, and how to recover from them.
|
changes are related to them, and how to recover from them.
|
||||||
0. API to trigger playback even if prebuf condition isn't met yet.
|
|
||||||
0. Consider testing on FreeBSD
|
0. Consider testing on FreeBSD
|
||||||
|
|
||||||
## Planned Uses for libsoundio
|
## Planned Uses for libsoundio
|
||||||
|
|
|
@ -61,7 +61,6 @@ static void read_callback(struct SoundIoInStream *instream, int available_frame_
|
||||||
int write_count = min_int(available_frame_count, free_count);
|
int write_count = min_int(available_frame_count, free_count);
|
||||||
int frames_left = write_count;
|
int frames_left = write_count;
|
||||||
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int frame_count = frames_left;
|
int frame_count = frames_left;
|
||||||
|
|
||||||
|
@ -148,7 +147,7 @@ static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usage(char *exe) {
|
static int usage(char *exe) {
|
||||||
fprintf(stderr, "Usage: %s [--dummy] [--alsa] [--pulseaudio] [--in-device name] [--out-device name]\n", exe);
|
fprintf(stderr, "Usage: %s [--dummy] [--alsa] [--pulseaudio] [--jack] [--in-device name] [--out-device name]\n", exe);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +164,8 @@ int main(int argc, char **argv) {
|
||||||
backend = SoundIoBackendAlsa;
|
backend = SoundIoBackendAlsa;
|
||||||
} else if (strcmp("--pulseaudio", arg) == 0) {
|
} else if (strcmp("--pulseaudio", arg) == 0) {
|
||||||
backend = SoundIoBackendPulseAudio;
|
backend = SoundIoBackendPulseAudio;
|
||||||
|
} else if (strcmp("--jack", arg) == 0) {
|
||||||
|
backend = SoundIoBackendJack;
|
||||||
} else if (strcmp("--in-device", arg) == 0) {
|
} else if (strcmp("--in-device", arg) == 0) {
|
||||||
if (++i >= argc) {
|
if (++i >= argc) {
|
||||||
return usage(exe);
|
return usage(exe);
|
||||||
|
@ -290,7 +291,6 @@ int main(int argc, char **argv) {
|
||||||
outstream->period_duration = 0.1;
|
outstream->period_duration = 0.1;
|
||||||
outstream->write_callback = write_callback;
|
outstream->write_callback = write_callback;
|
||||||
outstream->underflow_callback = underflow_callback;
|
outstream->underflow_callback = underflow_callback;
|
||||||
outstream->prebuf_duration = 0.0;
|
|
||||||
|
|
||||||
if ((err = soundio_outstream_open(outstream)))
|
if ((err = soundio_outstream_open(outstream)))
|
||||||
panic("unable to open output stream: %s", soundio_strerror(err));
|
panic("unable to open output stream: %s", soundio_strerror(err));
|
||||||
|
|
20
src/alsa.cpp
20
src/alsa.cpp
|
@ -1086,8 +1086,6 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
outstream->period_duration = clamp(device->period_duration_min,
|
outstream->period_duration = clamp(device->period_duration_min,
|
||||||
outstream->buffer_duration / 2.0, device->period_duration_max);
|
outstream->buffer_duration / 2.0, device->period_duration_max);
|
||||||
}
|
}
|
||||||
if (outstream->prebuf_duration == -1.0)
|
|
||||||
outstream->prebuf_duration = outstream->buffer_duration;
|
|
||||||
|
|
||||||
int ch_count = outstream->layout.channel_count;
|
int ch_count = outstream->layout.channel_count;
|
||||||
|
|
||||||
|
@ -1196,8 +1194,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_uframes_t prebuf_frames = ceil(outstream->prebuf_duration * (double)outstream->sample_rate);
|
if ((err = snd_pcm_sw_params_set_start_threshold(osa->handle, swparams, 0)) < 0) {
|
||||||
if ((err = snd_pcm_sw_params_set_start_threshold(osa->handle, swparams, prebuf_frames)) < 0) {
|
|
||||||
outstream_destroy_alsa(si, os);
|
outstream_destroy_alsa(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
@ -1243,16 +1240,23 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
assert(!osa->thread);
|
assert(!osa->thread);
|
||||||
|
|
||||||
osa->thread_exit_flag.test_and_set();
|
// Give the API user a chance to fill the buffer before playback commences.
|
||||||
|
snd_pcm_sframes_t avail = snd_pcm_avail_update(osa->handle);
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_thread_create(outstream_thread_run, os, true, &osa->thread))) {
|
if (avail < 0) {
|
||||||
outstream_destroy_alsa(si, os);
|
if ((err = xrun_recovery(os, avail)) < 0)
|
||||||
return err;
|
return SoundIoErrorStreaming;
|
||||||
}
|
}
|
||||||
|
outstream->write_callback(outstream, avail);
|
||||||
|
|
||||||
|
osa->thread_exit_flag.test_and_set();
|
||||||
|
if ((err = soundio_os_thread_create(outstream_thread_run, os, true, &osa->thread)))
|
||||||
|
return err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,12 @@ static void playback_thread_run(void *arg) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
double start_time = soundio_os_get_time();
|
|
||||||
osd->playback_start_time = start_time;
|
|
||||||
osd->frames_consumed = 0;
|
|
||||||
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
int fill_bytes = soundio_ring_buffer_fill_count(&osd->ring_buffer);
|
||||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
||||||
int fill_frames = fill_bytes / outstream->bytes_per_frame;
|
|
||||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||||
osd->prebuf_frames_left = osd->prebuf_frame_count - fill_frames;
|
|
||||||
outstream->write_callback(outstream, free_frames);
|
outstream->write_callback(outstream, free_frames);
|
||||||
|
double start_time = soundio_os_get_time();
|
||||||
|
long frames_consumed = 0;
|
||||||
|
|
||||||
while (osd->abort_flag.test_and_set()) {
|
while (osd->abort_flag.test_and_set()) {
|
||||||
double now = soundio_os_get_time();
|
double now = soundio_os_get_time();
|
||||||
|
@ -39,22 +36,20 @@ static void playback_thread_run(void *arg) {
|
||||||
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
int free_bytes = soundio_ring_buffer_capacity(&osd->ring_buffer) - fill_bytes;
|
||||||
int fill_frames = fill_bytes / outstream->bytes_per_frame;
|
int fill_frames = fill_bytes / outstream->bytes_per_frame;
|
||||||
int free_frames = free_bytes / outstream->bytes_per_frame;
|
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||||
if (osd->prebuf_frames_left > 0) {
|
|
||||||
outstream->write_callback(outstream, free_frames);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
double total_time = soundio_os_get_time() - osd->playback_start_time;
|
double total_time = soundio_os_get_time() - start_time;
|
||||||
long total_frames = total_time * outstream->sample_rate;
|
long total_frames = total_time * outstream->sample_rate;
|
||||||
int frames_to_kill = total_frames - osd->frames_consumed;
|
int frames_to_kill = total_frames - frames_consumed;
|
||||||
int read_count = min(frames_to_kill, fill_frames);
|
int read_count = min(frames_to_kill, fill_frames);
|
||||||
int byte_count = read_count * outstream->bytes_per_frame;
|
int byte_count = read_count * outstream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&osd->ring_buffer, byte_count);
|
||||||
osd->frames_consumed += read_count;
|
frames_consumed += read_count;
|
||||||
|
|
||||||
if (frames_to_kill > read_count) {
|
if (frames_to_kill > fill_frames) {
|
||||||
osd->prebuf_frames_left = osd->prebuf_frame_count;
|
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
|
outstream->write_callback(outstream, free_frames);
|
||||||
|
frames_consumed = 0;
|
||||||
|
start_time = soundio_os_get_time();
|
||||||
} else if (free_frames > 0) {
|
} else if (free_frames > 0) {
|
||||||
outstream->write_callback(outstream, free_frames);
|
outstream->write_callback(outstream, free_frames);
|
||||||
}
|
}
|
||||||
|
@ -70,26 +65,33 @@ static void capture_thread_run(void *arg) {
|
||||||
double start_time = soundio_os_get_time();
|
double start_time = soundio_os_get_time();
|
||||||
while (isd->abort_flag.test_and_set()) {
|
while (isd->abort_flag.test_and_set()) {
|
||||||
double now = soundio_os_get_time();
|
double now = soundio_os_get_time();
|
||||||
double total_time = now - start_time;
|
|
||||||
long total_frames = total_time * instream->sample_rate;
|
|
||||||
int frames_to_kill = total_frames - frames_consumed;
|
|
||||||
int free_bytes = soundio_ring_buffer_free_count(&isd->ring_buffer);
|
|
||||||
int free_frames = free_bytes / instream->bytes_per_frame;
|
|
||||||
int write_count = min(frames_to_kill, free_frames);
|
|
||||||
int frames_left = max(frames_to_kill - write_count, 0);
|
|
||||||
int byte_count = write_count * instream->bytes_per_frame;
|
|
||||||
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
|
||||||
frames_consumed += write_count;
|
|
||||||
|
|
||||||
isd->hole_size += frames_left;
|
|
||||||
if (write_count > 0)
|
|
||||||
instream->read_callback(instream, write_count);
|
|
||||||
now = soundio_os_get_time();
|
|
||||||
double time_passed = now - start_time;
|
double time_passed = now - start_time;
|
||||||
double next_period = start_time +
|
double next_period = start_time +
|
||||||
ceil(time_passed / instream->period_duration) * instream->period_duration;
|
ceil(time_passed / instream->period_duration) * instream->period_duration;
|
||||||
double relative_time = next_period - now;
|
double relative_time = next_period - now;
|
||||||
soundio_os_cond_timed_wait(isd->cond, nullptr, relative_time);
|
soundio_os_cond_timed_wait(isd->cond, nullptr, relative_time);
|
||||||
|
|
||||||
|
int fill_bytes = soundio_ring_buffer_fill_count(&isd->ring_buffer);
|
||||||
|
int free_bytes = soundio_ring_buffer_capacity(&isd->ring_buffer) - fill_bytes;
|
||||||
|
int fill_frames = fill_bytes / instream->bytes_per_frame;
|
||||||
|
int free_frames = free_bytes / instream->bytes_per_frame;
|
||||||
|
|
||||||
|
double total_time = soundio_os_get_time() - start_time;
|
||||||
|
long total_frames = total_time * instream->sample_rate;
|
||||||
|
int frames_to_kill = total_frames - frames_consumed;
|
||||||
|
int write_count = min(frames_to_kill, free_frames);
|
||||||
|
int byte_count = write_count * instream->bytes_per_frame;
|
||||||
|
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
||||||
|
frames_consumed += write_count;
|
||||||
|
|
||||||
|
if (frames_to_kill > free_frames) {
|
||||||
|
// TODO overflow callback
|
||||||
|
frames_consumed = 0;
|
||||||
|
start_time = soundio_os_get_time();
|
||||||
|
}
|
||||||
|
if (fill_frames > 0) {
|
||||||
|
instream->read_callback(instream, fill_frames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,11 +162,6 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
osd->buffer_frame_count = actual_capacity / outstream->bytes_per_frame;
|
osd->buffer_frame_count = actual_capacity / outstream->bytes_per_frame;
|
||||||
outstream->buffer_duration = osd->buffer_frame_count / (double) outstream->sample_rate;
|
outstream->buffer_duration = osd->buffer_frame_count / (double) outstream->sample_rate;
|
||||||
|
|
||||||
if (outstream->prebuf_duration == -1.0)
|
|
||||||
outstream->prebuf_duration = outstream->buffer_duration;
|
|
||||||
outstream->prebuf_duration = min(outstream->prebuf_duration, outstream->buffer_duration);
|
|
||||||
osd->prebuf_frame_count = ceil(outstream->prebuf_duration * (double) outstream->sample_rate);
|
|
||||||
|
|
||||||
osd->cond = soundio_os_cond_create();
|
osd->cond = soundio_os_cond_create();
|
||||||
if (!osd->cond) {
|
if (!osd->cond) {
|
||||||
outstream_destroy_dummy(si, os);
|
outstream_destroy_dummy(si, os);
|
||||||
|
@ -231,20 +228,12 @@ static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
int byte_count = frame_count * outstream->bytes_per_frame;
|
int byte_count = frame_count * outstream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
||||||
if (osd->prebuf_frames_left > 0) {
|
|
||||||
osd->prebuf_frames_left -= frame_count;
|
|
||||||
if (osd->prebuf_frames_left <= 0) {
|
|
||||||
osd->playback_start_time = soundio_os_get_time();
|
|
||||||
osd->frames_consumed = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||||
osd->prebuf_frames_left = osd->prebuf_frame_count;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,13 +318,6 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
|
||||||
assert(*frame_count >= 0);
|
assert(*frame_count >= 0);
|
||||||
assert(*frame_count <= isd->buffer_frame_count);
|
assert(*frame_count <= isd->buffer_frame_count);
|
||||||
|
|
||||||
if (isd->hole_size > 0) {
|
|
||||||
*out_areas = nullptr;
|
|
||||||
isd->read_frame_count = min(isd->hole_size, *frame_count);
|
|
||||||
*frame_count = isd->read_frame_count;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fill_byte_count = soundio_ring_buffer_fill_count(&isd->ring_buffer);
|
int fill_byte_count = soundio_ring_buffer_fill_count(&isd->ring_buffer);
|
||||||
int fill_frame_count = fill_byte_count / instream->bytes_per_frame;
|
int fill_frame_count = fill_byte_count / instream->bytes_per_frame;
|
||||||
isd->read_frame_count = min(*frame_count, fill_frame_count);
|
isd->read_frame_count = min(*frame_count, fill_frame_count);
|
||||||
|
@ -357,14 +339,8 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
|
||||||
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if (isd->hole_size > 0) {
|
|
||||||
isd->hole_size -= isd->read_frame_count;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(&isd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +469,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->name = strdup("dummy-in");
|
device->name = strdup("dummy-in");
|
||||||
device->description = strdup("Dummy input device");
|
device->description = strdup("Dummy Input Device");
|
||||||
if (!device->name || !device->description) {
|
if (!device->name || !device->description) {
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
|
|
|
@ -31,9 +31,6 @@ struct SoundIoOutStreamDummy {
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
int buffer_frame_count;
|
int buffer_frame_count;
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
int prebuf_frame_count;
|
|
||||||
int prebuf_frames_left;
|
|
||||||
long frames_consumed;
|
|
||||||
double playback_start_time;
|
double playback_start_time;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
@ -45,7 +42,6 @@ struct SoundIoInStreamDummy {
|
||||||
int read_frame_count;
|
int read_frame_count;
|
||||||
int buffer_frame_count;
|
int buffer_frame_count;
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
int hole_size;
|
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -428,7 +428,6 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
|
|
||||||
outstream->buffer_duration = 0.0;
|
outstream->buffer_duration = 0.0;
|
||||||
outstream->period_duration = device->period_duration_current;
|
outstream->period_duration = device->period_duration_current;
|
||||||
outstream->prebuf_duration = 0.0;
|
|
||||||
osj->period_size = sij->period_size;
|
osj->period_size = sij->period_size;
|
||||||
|
|
||||||
jack_status_t status;
|
jack_status_t status;
|
||||||
|
@ -573,8 +572,6 @@ static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOut
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
// JACK does not support `prebuf` which is the same as a `prebuf` value of 0,
|
|
||||||
// which means that clearing the buffer is always successful and does nothing.
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -637,7 +637,7 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
|
||||||
ospa->buffer_attr.maxlength = UINT32_MAX;
|
ospa->buffer_attr.maxlength = UINT32_MAX;
|
||||||
ospa->buffer_attr.tlength = UINT32_MAX;
|
ospa->buffer_attr.tlength = UINT32_MAX;
|
||||||
ospa->buffer_attr.prebuf = UINT32_MAX;
|
ospa->buffer_attr.prebuf = 0;
|
||||||
ospa->buffer_attr.minreq = UINT32_MAX;
|
ospa->buffer_attr.minreq = UINT32_MAX;
|
||||||
ospa->buffer_attr.fragsize = UINT32_MAX;
|
ospa->buffer_attr.fragsize = UINT32_MAX;
|
||||||
|
|
||||||
|
@ -649,12 +649,6 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
ospa->buffer_attr.maxlength = buffer_length;
|
ospa->buffer_attr.maxlength = buffer_length;
|
||||||
ospa->buffer_attr.tlength = buffer_length;
|
ospa->buffer_attr.tlength = buffer_length;
|
||||||
}
|
}
|
||||||
if (outstream->prebuf_duration >= 0.0) {
|
|
||||||
int prebuf_length = outstream->bytes_per_frame *
|
|
||||||
ceil(outstream->prebuf_duration * bytes_per_second / (double)outstream->bytes_per_frame);
|
|
||||||
|
|
||||||
ospa->buffer_attr.prebuf = prebuf_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -684,8 +678,6 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
const pa_buffer_attr *attr = pa_stream_get_buffer_attr(ospa->stream);
|
const pa_buffer_attr *attr = pa_stream_get_buffer_attr(ospa->stream);
|
||||||
outstream->buffer_duration = (attr->maxlength /
|
outstream->buffer_duration = (attr->maxlength /
|
||||||
(double)outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
(double)outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
||||||
outstream->prebuf_duration = (attr->prebuf /
|
|
||||||
(double)outstream->bytes_per_frame) / (double)outstream->sample_rate;
|
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -842,7 +834,7 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
|
||||||
ispa->buffer_attr.maxlength = UINT32_MAX;
|
ispa->buffer_attr.maxlength = UINT32_MAX;
|
||||||
ispa->buffer_attr.tlength = UINT32_MAX;
|
ispa->buffer_attr.tlength = UINT32_MAX;
|
||||||
ispa->buffer_attr.prebuf = UINT32_MAX;
|
ispa->buffer_attr.prebuf = 0;
|
||||||
ispa->buffer_attr.minreq = UINT32_MAX;
|
ispa->buffer_attr.minreq = UINT32_MAX;
|
||||||
ispa->buffer_attr.fragsize = UINT32_MAX;
|
ispa->buffer_attr.fragsize = UINT32_MAX;
|
||||||
|
|
||||||
|
|
|
@ -359,8 +359,6 @@ struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device)
|
||||||
outstream->error_callback = default_outstream_error_callback;
|
outstream->error_callback = default_outstream_error_callback;
|
||||||
outstream->underflow_callback = default_underflow_callback;
|
outstream->underflow_callback = default_underflow_callback;
|
||||||
|
|
||||||
outstream->prebuf_duration = -1.0;
|
|
||||||
|
|
||||||
return outstream;
|
return outstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,14 +357,6 @@ struct SoundIoOutStream {
|
||||||
// sets `PA_STREAM_ADJUST_LATENCY` and is the value used for `fragsize`.
|
// sets `PA_STREAM_ADJUST_LATENCY` and is the value used for `fragsize`.
|
||||||
double period_duration;
|
double period_duration;
|
||||||
|
|
||||||
// How many seconds need to be in the buffer before playback will commence.
|
|
||||||
// If a buffer underflow occurs, this prebuffering will be again enabled.
|
|
||||||
// This value defaults to being the same as `buffer_duration`.
|
|
||||||
// After you call `soundio_outstream_open` this value is replaced with the
|
|
||||||
// actual `prebuf_duration`, as near to this value as possible.
|
|
||||||
// JACK does not support prebuffering; `prebuf_duration` is effectively 0.
|
|
||||||
double prebuf_duration;
|
|
||||||
|
|
||||||
// Defaults to NULL. Put whatever you want here.
|
// Defaults to NULL. Put whatever you want here.
|
||||||
void *userdata;
|
void *userdata;
|
||||||
// In this callback, you call `soundio_outstream_begin_write` and
|
// In this callback, you call `soundio_outstream_begin_write` and
|
||||||
|
@ -619,12 +611,15 @@ bool soundio_device_supports_layout(struct SoundIoDevice *device,
|
||||||
// Allocates memory and sets defaults. Next you should fill out the struct fields
|
// Allocates memory and sets defaults. Next you should fill out the struct fields
|
||||||
// and then call `soundio_outstream_open`.
|
// and then call `soundio_outstream_open`.
|
||||||
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device);
|
struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device);
|
||||||
|
|
||||||
int soundio_outstream_open(struct SoundIoOutStream *outstream);
|
|
||||||
|
|
||||||
// You may not call this function from the `write_callback` thread context.
|
// You may not call this function from the `write_callback` thread context.
|
||||||
void soundio_outstream_destroy(struct SoundIoOutStream *outstream);
|
void soundio_outstream_destroy(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
|
// After you call this function, `buffer_duration` and `period_duration` are
|
||||||
|
// set to the correct values, if available.
|
||||||
|
// The next thing to do is call `soundio_instream_start`.
|
||||||
|
int soundio_outstream_open(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
|
// After you call this function, `write_callback` will be called.
|
||||||
int soundio_outstream_start(struct SoundIoOutStream *outstream);
|
int soundio_outstream_start(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
// Call this function when you are ready to begin writing to the device buffer.
|
// Call this function when you are ready to begin writing to the device buffer.
|
||||||
|
@ -646,7 +641,7 @@ int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||||
// You must call this function only from the `write_callback` thread context.
|
// You must call this function only from the `write_callback` thread context.
|
||||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream, int frame_count);
|
int soundio_outstream_end_write(struct SoundIoOutStream *outstream, int frame_count);
|
||||||
|
|
||||||
// Clears the output stream buffer and the stream goes into prebuffering mode.
|
// Clears the output stream buffer.
|
||||||
// You must call this function only from the `write_callback` thread context.
|
// You must call this function only from the `write_callback` thread context.
|
||||||
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
|
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
|
@ -663,11 +658,15 @@ int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);
|
||||||
// Allocates memory and sets defaults. Next you should fill out the struct fields
|
// Allocates memory and sets defaults. Next you should fill out the struct fields
|
||||||
// and then call `soundio_instream_open`.
|
// and then call `soundio_instream_open`.
|
||||||
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device);
|
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device);
|
||||||
// You must not call this function from `read_callback`.
|
// You may not call this function from `read_callback`.
|
||||||
void soundio_instream_destroy(struct SoundIoInStream *instream);
|
void soundio_instream_destroy(struct SoundIoInStream *instream);
|
||||||
|
|
||||||
|
// After you call this function, `buffer_duration` and `period_duration` are
|
||||||
|
// set to the correct values, if available.
|
||||||
|
// The next thing to do is call `soundio_instream_start`.
|
||||||
int soundio_instream_open(struct SoundIoInStream *instream);
|
int soundio_instream_open(struct SoundIoInStream *instream);
|
||||||
|
|
||||||
|
// After you call this function, `read_callback` will be called.
|
||||||
int soundio_instream_start(struct SoundIoInStream *instream);
|
int soundio_instream_start(struct SoundIoInStream *instream);
|
||||||
|
|
||||||
// Call this function when you are ready to begin reading from the device
|
// Call this function when you are ready to begin reading from the device
|
||||||
|
|
Loading…
Reference in a new issue