mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 04:35:35 +00:00
write and read functions no longer allow setting frame count
CoreAudio and JACK both have this limitation
This commit is contained in:
parent
df0ca8a772
commit
f87961275d
|
@ -23,7 +23,7 @@ behavior on every platform.
|
||||||
- [JACK](http://jackaudio.org/)
|
- [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/)
|
||||||
- (planned) [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
- [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
||||||
- Dummy (silence)
|
- Dummy (silence)
|
||||||
- (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/)
|
||||||
|
@ -242,6 +242,9 @@ view `coverage/index.html` in a browser.
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
0. implement CoreAudio (OSX) backend, get examples working
|
||||||
|
- microphone example
|
||||||
|
- underflow example
|
||||||
|
0. ALSA backend for microphone example is broken
|
||||||
0. Add some builtin channel layouts from
|
0. Add some builtin channel layouts from
|
||||||
https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Channel_Layout_Tags
|
https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Channel_Layout_Tags
|
||||||
0. Make sure sending bogus device id results in "SoundIoErrorNoSuchDevice" on each backend
|
0. Make sure sending bogus device id results in "SoundIoErrorNoSuchDevice" on each backend
|
||||||
|
@ -251,6 +254,7 @@ view `coverage/index.html` in a browser.
|
||||||
should do the same.
|
should do the same.
|
||||||
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. Do we really want `period_duration` in the API?
|
||||||
0. Integrate into libgroove and test with Groove Basin
|
0. Integrate into libgroove and test with Groove Basin
|
||||||
0. clear buffer maybe could take an argument to say how many frames to not clear
|
0. clear buffer maybe could take an argument to say how many frames to not clear
|
||||||
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.
|
||||||
|
@ -275,7 +279,7 @@ view `coverage/index.html` in a browser.
|
||||||
0. -fvisibility=hidden and then explicitly export stuff, or
|
0. -fvisibility=hidden and then explicitly export stuff, or
|
||||||
explicitly make the unexported stuff private
|
explicitly make the unexported stuff private
|
||||||
0. add len arguments to APIs that have char *
|
0. add len arguments to APIs that have char *
|
||||||
- replace strdup with soundio_str_dupe
|
- replace strdup with `soundio_str_dupe`
|
||||||
0. Support PulseAudio proplist properties for main context and streams
|
0. Support PulseAudio proplist properties for main context and streams
|
||||||
0. Expose JACK options in `jack_client_open`
|
0. Expose JACK options in `jack_client_open`
|
||||||
0. custom allocator support
|
0. custom allocator support
|
||||||
|
|
|
@ -51,26 +51,24 @@ static void panic(const char *format, ...) {
|
||||||
|
|
||||||
struct SoundIoRingBuffer *ring_buffer = NULL;
|
struct SoundIoRingBuffer *ring_buffer = NULL;
|
||||||
|
|
||||||
static int min_int(int a, int b) {
|
|
||||||
return (a < b) ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_callback(struct SoundIoInStream *instream, int available_frame_count) {
|
static void read_callback(struct SoundIoInStream *instream, int available_frame_count) {
|
||||||
|
struct SoundIoChannelArea *areas;
|
||||||
|
int frame_count;
|
||||||
int err;
|
int err;
|
||||||
char *write_ptr = soundio_ring_buffer_write_ptr(ring_buffer);
|
char *write_ptr = soundio_ring_buffer_write_ptr(ring_buffer);
|
||||||
int free_bytes = soundio_ring_buffer_free_count(ring_buffer);
|
int free_bytes = soundio_ring_buffer_free_count(ring_buffer);
|
||||||
int free_count = free_bytes / instream->bytes_per_frame;
|
int free_count = free_bytes / instream->bytes_per_frame;
|
||||||
int write_count = min_int(available_frame_count, free_count);
|
|
||||||
int frames_left = write_count;
|
//fprintf(stderr, "read_callback %d free %d\n", available_frame_count, free_count);
|
||||||
|
|
||||||
|
if (available_frame_count > free_count)
|
||||||
|
panic("ring buffer overflow");
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int frame_count = frames_left;
|
|
||||||
|
|
||||||
struct SoundIoChannelArea *areas;
|
|
||||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
||||||
panic("begin read error: %s", soundio_strerror(err));
|
panic("begin read error: %s", soundio_strerror(err));
|
||||||
|
|
||||||
if (frame_count <= 0)
|
if (!frame_count)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!areas) {
|
if (!areas) {
|
||||||
|
@ -90,36 +88,42 @@ static void read_callback(struct SoundIoInStream *instream, int available_frame_
|
||||||
|
|
||||||
if ((err = soundio_instream_end_read(instream)))
|
if ((err = soundio_instream_end_read(instream)))
|
||||||
panic("end read error: %s", soundio_strerror(err));
|
panic("end read error: %s", soundio_strerror(err));
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
|
|
||||||
if (frames_left <= 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int advance_bytes = write_count * instream->bytes_per_frame;
|
int advance_bytes = available_frame_count * instream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(ring_buffer, advance_bytes);
|
soundio_ring_buffer_advance_write_ptr(ring_buffer, advance_bytes);
|
||||||
|
|
||||||
int dropped_frames = available_frame_count - write_count;
|
|
||||||
if (dropped_frames > 0)
|
|
||||||
fprintf(stderr, "Dropped %d frames due to overflow\n", dropped_frames);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
||||||
int err;
|
|
||||||
struct SoundIoChannelArea *areas;
|
struct SoundIoChannelArea *areas;
|
||||||
|
int frame_count;
|
||||||
|
int err;
|
||||||
|
|
||||||
char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
|
char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
|
||||||
int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
|
int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
|
||||||
int fill_count = fill_bytes / outstream->bytes_per_frame;
|
int fill_count = fill_bytes / outstream->bytes_per_frame;
|
||||||
int read_frames = min_int(requested_frame_count, fill_count);
|
|
||||||
int frames_left = read_frames;
|
//fprintf(stderr, "write_callback %d fill %d\n", requested_frame_count, fill_count);
|
||||||
|
|
||||||
|
if (requested_frame_count > fill_count) {
|
||||||
|
// Ring buffer does not have enough data, fill with zeroes.
|
||||||
|
for (;;) {
|
||||||
|
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||||
|
panic("begin write error: %s", soundio_strerror(err));
|
||||||
|
if (frame_count <= 0)
|
||||||
|
return;
|
||||||
|
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||||
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
memset(areas[ch].ptr, 0, outstream->bytes_per_sample);
|
||||||
|
areas[ch].ptr += areas[ch].step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((err = soundio_outstream_end_write(outstream)))
|
||||||
|
panic("end write error: %s", soundio_strerror(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int frame_count = frames_left;
|
|
||||||
|
|
||||||
if (frame_count <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||||
panic("begin write error: %s", soundio_strerror(err));
|
panic("begin write error: %s", soundio_strerror(err));
|
||||||
|
|
||||||
|
@ -134,13 +138,11 @@ static void write_callback(struct SoundIoOutStream *outstream, int requested_fra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = soundio_outstream_end_write(outstream, frame_count)))
|
if ((err = soundio_outstream_end_write(outstream)))
|
||||||
panic("end write error: %s", soundio_strerror(err));
|
panic("end write error: %s", soundio_strerror(err));
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
soundio_ring_buffer_advance_read_ptr(ring_buffer, read_frames * outstream->bytes_per_frame);
|
soundio_ring_buffer_advance_read_ptr(ring_buffer, requested_frame_count * outstream->bytes_per_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
static void underflow_callback(struct SoundIoOutStream *outstream) {
|
||||||
|
|
|
@ -35,11 +35,11 @@ static float seconds_offset = 0.0f;
|
||||||
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
||||||
float float_sample_rate = outstream->sample_rate;
|
float float_sample_rate = outstream->sample_rate;
|
||||||
float seconds_per_frame = 1.0f / float_sample_rate;
|
float seconds_per_frame = 1.0f / float_sample_rate;
|
||||||
|
int frame_count;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
int frame_count = requested_frame_count;
|
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
struct SoundIoChannelArea *areas;
|
struct SoundIoChannelArea *areas;
|
||||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||||
panic("%s", soundio_strerror(err));
|
panic("%s", soundio_strerror(err));
|
||||||
|
@ -60,15 +60,11 @@ static void write_callback(struct SoundIoOutStream *outstream, int requested_fra
|
||||||
}
|
}
|
||||||
seconds_offset += seconds_per_frame * frame_count;
|
seconds_offset += seconds_per_frame * frame_count;
|
||||||
|
|
||||||
if ((err = soundio_outstream_end_write(outstream, frame_count))) {
|
if ((err = soundio_outstream_end_write(outstream))) {
|
||||||
if (err == SoundIoErrorUnderflow)
|
if (err == SoundIoErrorUnderflow)
|
||||||
return;
|
return;
|
||||||
panic("%s", soundio_strerror(err));
|
panic("%s", soundio_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_frame_count -= frame_count;
|
|
||||||
if (requested_frame_count <= 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -417,8 +417,11 @@ struct SoundIoOutStream {
|
||||||
// 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
|
||||||
// `soundio_outstream_end_write`. `requested_frame_count` will always be
|
// `soundio_outstream_end_write` as many times as necessary to write
|
||||||
// greater than 0.
|
// exactly `requested_frame_count` frames. `requested_frame_count` will
|
||||||
|
// always be greater than 0. To be compatible with all backends, you must
|
||||||
|
// write exactly `requested_frame_count` frames during the callback,
|
||||||
|
// otherwise a buffer underrun will occur.
|
||||||
void (*write_callback)(struct SoundIoOutStream *, int requested_frame_count);
|
void (*write_callback)(struct SoundIoOutStream *, int requested_frame_count);
|
||||||
// This optional callback happens when the sound device runs out of buffered
|
// This optional callback happens when the sound device runs out of buffered
|
||||||
// audio data to play. After this occurs, the outstream waits until the
|
// audio data to play. After this occurs, the outstream waits until the
|
||||||
|
@ -712,21 +715,20 @@ int soundio_outstream_start(struct SoundIoOutStream *outstream);
|
||||||
// * `outstream` - (in) The output stream you want to write to.
|
// * `outstream` - (in) The output stream you want to write to.
|
||||||
// * `areas` - (out) The memory addresses you can write data to. It is OK to
|
// * `areas` - (out) The memory addresses you can write data to. It is OK to
|
||||||
// modify the pointers if that helps you iterate.
|
// modify the pointers if that helps you iterate.
|
||||||
// * `frame_count` - (in/out) Provide the number of frames you want to write.
|
// * `frame_count` - (out) Returns the number of frames you actually can write.
|
||||||
// Returned will be the number of frames you actually can write. Must be
|
|
||||||
// greater than 0 frames.
|
|
||||||
// It is your responsibility to call this function no more and no fewer than the
|
// It is your responsibility to call this function no more and no fewer than the
|
||||||
// correct number of times as determined by `requested_frame_count` from
|
// correct number of times as determined by `requested_frame_count` from
|
||||||
// `write_callback`. See sio_sine.c for an example.
|
// `write_callback`. See sio_sine.c for an example.
|
||||||
// You must call this function only from the `write_callback` thread context.
|
// You must call this function only from the `write_callback` thread context.
|
||||||
// After calling this function, write data to `areas` and then call `soundio_outstream_end_write`.
|
// After calling this function, write data to `areas` and then call
|
||||||
|
// `soundio_outstream_end_write`.
|
||||||
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||||
struct SoundIoChannelArea **areas, int *frame_count);
|
struct SoundIoChannelArea **areas, int *frame_count);
|
||||||
|
|
||||||
// Commits the write that you began with `soundio_outstream_begin_write`.
|
// Commits the write that you began with `soundio_outstream_begin_write`.
|
||||||
// You must call this function only from the `write_callback` thread context.
|
// You must call this function only from the `write_callback` thread context.
|
||||||
// This function might return `SoundIoErrorUnderflow` but don't count on it.
|
// This function might return `SoundIoErrorUnderflow` but don't count on it.
|
||||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream, int frame_count);
|
int soundio_outstream_end_write(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
// Clears the output stream buffer.
|
// 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.
|
||||||
|
@ -760,12 +762,11 @@ int soundio_instream_start(struct SoundIoInStream *instream);
|
||||||
// buffer.
|
// buffer.
|
||||||
// * `instream` - (in) The input stream you want to read from.
|
// * `instream` - (in) The input stream you want to read from.
|
||||||
// * `areas` - (out) The memory addresses you can read data from. It is OK
|
// * `areas` - (out) The memory addresses you can read data from. It is OK
|
||||||
// to modify the pointers if that helps you iterate. If a buffer overflow
|
// to modify the pointers if that helps you iterate. There might be a "hole"
|
||||||
// occurred, there will be a "hole" in the buffer. To indicate this,
|
// in the buffer. To indicate this, `areas` will be `NULL` and `frame_count`
|
||||||
// `areas` will be `NULL` and `frame_count` tells how big the hole is in
|
// tells how big the hole is in frames.
|
||||||
// frames.
|
// * `frame_count` - (out) - Returns the number of frames you can actually
|
||||||
// * `frame_count` - (in/out) - Provide the number of frames you want to read.
|
// read.
|
||||||
// Returned will be the number of frames you can actually read.
|
|
||||||
// It is your responsibility to call this function no more and no fewer than the
|
// It is your responsibility to call this function no more and no fewer than the
|
||||||
// correct number of times as determined by `available_frame_count` from
|
// correct number of times as determined by `available_frame_count` from
|
||||||
// `read_callback`. See sio_microphone.c for an example.
|
// `read_callback`. See sio_microphone.c for an example.
|
||||||
|
|
53
src/alsa.cpp
53
src/alsa.cpp
|
@ -1013,6 +1013,7 @@ void outstream_thread_run(void *arg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osa->frames_left = avail;
|
||||||
outstream->write_callback(outstream, avail);
|
outstream->write_callback(outstream, avail);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1080,6 +1081,7 @@ static void instream_thread_run(void *arg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isa->frames_left = avail;
|
||||||
instream->read_callback(instream, avail);
|
instream->read_callback(instream, avail);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1283,7 +1285,7 @@ static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
}
|
}
|
||||||
|
|
||||||
int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
||||||
struct SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
@ -1295,17 +1297,19 @@ int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
||||||
osa->areas[ch].step = outstream->bytes_per_frame;
|
osa->areas[ch].step = outstream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
*frame_count = min(*frame_count, osa->period_size);
|
osa->frames_to_write = min(osa->frames_left, osa->period_size);
|
||||||
|
*out_frame_count = osa->frames_to_write;
|
||||||
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
osa->areas[ch].ptr = osa->sample_buffer + ch * outstream->bytes_per_sample * osa->period_size;
|
osa->areas[ch].ptr = osa->sample_buffer + ch * outstream->bytes_per_sample * osa->period_size;
|
||||||
osa->areas[ch].step = outstream->bytes_per_sample;
|
osa->areas[ch].step = outstream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
*frame_count = min(*frame_count, osa->period_size);
|
osa->frames_to_write = min(osa->frames_left, osa->period_size);
|
||||||
|
*out_frame_count = osa->frames_to_write;
|
||||||
} else {
|
} else {
|
||||||
const snd_pcm_channel_area_t *areas;
|
const snd_pcm_channel_area_t *areas;
|
||||||
snd_pcm_uframes_t frames = *frame_count;
|
snd_pcm_uframes_t frames = osa->frames_left;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = snd_pcm_mmap_begin(osa->handle, &areas, &osa->offset, &frames)) < 0) {
|
if ((err = snd_pcm_mmap_begin(osa->handle, &areas, &osa->offset, &frames)) < 0) {
|
||||||
|
@ -1323,37 +1327,40 @@ int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
||||||
(osa->areas[ch].step * osa->offset);
|
(osa->areas[ch].step * osa->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
*frame_count = frames;
|
osa->frames_to_write = frames;
|
||||||
|
*out_frame_count = osa->frames_to_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_areas = osa->areas;
|
*out_areas = osa->areas;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
|
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres;
|
snd_pcm_sframes_t commitres;
|
||||||
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
commitres = snd_pcm_writei(osa->handle, osa->sample_buffer, frame_count);
|
commitres = snd_pcm_writei(osa->handle, osa->sample_buffer, osa->frames_to_write);
|
||||||
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
} else if (osa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
char *ptrs[SOUNDIO_MAX_CHANNELS];
|
char *ptrs[SOUNDIO_MAX_CHANNELS];
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
ptrs[ch] = osa->sample_buffer + ch * outstream->bytes_per_sample * osa->period_size;
|
ptrs[ch] = osa->sample_buffer + ch * outstream->bytes_per_sample * osa->period_size;
|
||||||
}
|
}
|
||||||
commitres = snd_pcm_writen(osa->handle, (void**)ptrs, frame_count);
|
commitres = snd_pcm_writen(osa->handle, (void**)ptrs, osa->frames_to_write);
|
||||||
} else {
|
} else {
|
||||||
commitres = snd_pcm_mmap_commit(osa->handle, osa->offset, frame_count);
|
commitres = snd_pcm_mmap_commit(osa->handle, osa->offset, osa->frames_to_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commitres < 0 || commitres != frame_count) {
|
if (commitres < 0 || commitres != osa->frames_to_write) {
|
||||||
int err = (commitres >= 0) ? -EPIPE : commitres;
|
int err = (commitres >= 0) ? -EPIPE : commitres;
|
||||||
if (err == -EPIPE || err == -ESTRPIPE)
|
if (err == -EPIPE || err == -ESTRPIPE)
|
||||||
return SoundIoErrorUnderflow;
|
return SoundIoErrorUnderflow;
|
||||||
else
|
else
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
}
|
}
|
||||||
|
osa->frames_left -= osa->frames_to_write;
|
||||||
|
assert(osa->frames_left >= 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1560,7 +1567,7 @@ static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_alsa(SoundIoPrivate *si,
|
static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
@ -1572,10 +1579,11 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
isa->areas[ch].step = instream->bytes_per_frame;
|
isa->areas[ch].step = instream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->read_frame_count = min(*frame_count, isa->period_size);
|
isa->read_frame_count = min(isa->frames_left, isa->period_size);
|
||||||
*frame_count = isa->read_frame_count;
|
*out_frame_count = isa->read_frame_count;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count);
|
snd_pcm_sframes_t commitres = snd_pcm_readi(isa->handle, isa->sample_buffer, isa->read_frame_count);
|
||||||
if (commitres < 0 || commitres != *frame_count) {
|
if (commitres < 0 || commitres != isa->read_frame_count) {
|
||||||
int err = (commitres >= 0) ? -EPIPE : commitres;
|
int err = (commitres >= 0) ? -EPIPE : commitres;
|
||||||
if ((err = instream_xrun_recovery(is, err)) < 0)
|
if ((err = instream_xrun_recovery(is, err)) < 0)
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
@ -1588,17 +1596,18 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
ptrs[ch] = isa->areas[ch].ptr;
|
ptrs[ch] = isa->areas[ch].ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->read_frame_count = min(*frame_count, isa->period_size);
|
isa->read_frame_count = min(isa->frames_left, isa->period_size);
|
||||||
*frame_count = isa->read_frame_count;
|
*out_frame_count = isa->read_frame_count;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count);
|
snd_pcm_sframes_t commitres = snd_pcm_readn(isa->handle, (void**)ptrs, isa->read_frame_count);
|
||||||
if (commitres < 0 || commitres != *frame_count) {
|
if (commitres < 0 || commitres != isa->read_frame_count) {
|
||||||
int err = (commitres >= 0) ? -EPIPE : commitres;
|
int err = (commitres >= 0) ? -EPIPE : commitres;
|
||||||
if ((err = instream_xrun_recovery(is, err)) < 0)
|
if ((err = instream_xrun_recovery(is, err)) < 0)
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const snd_pcm_channel_area_t *areas;
|
const snd_pcm_channel_area_t *areas;
|
||||||
snd_pcm_uframes_t frames = *frame_count;
|
snd_pcm_uframes_t frames = isa->frames_left;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = snd_pcm_mmap_begin(isa->handle, &areas, &isa->offset, &frames)) < 0) {
|
if ((err = snd_pcm_mmap_begin(isa->handle, &areas, &isa->offset, &frames)) < 0) {
|
||||||
|
@ -1615,7 +1624,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
}
|
}
|
||||||
|
|
||||||
isa->read_frame_count = frames;
|
isa->read_frame_count = frames;
|
||||||
*frame_count = isa->read_frame_count;
|
*out_frame_count = isa->read_frame_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_areas = isa->areas;
|
*out_areas = isa->areas;
|
||||||
|
@ -1626,9 +1635,9 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
|
||||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
return 0;
|
// nothing to do
|
||||||
} else if (isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
} else if (isa->access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
|
||||||
return 0;
|
// nothing to do
|
||||||
} else {
|
} else {
|
||||||
snd_pcm_sframes_t commitres = snd_pcm_mmap_commit(isa->handle, isa->offset, isa->read_frame_count);
|
snd_pcm_sframes_t commitres = snd_pcm_mmap_commit(isa->handle, isa->offset, isa->read_frame_count);
|
||||||
if (commitres < 0 || commitres != isa->read_frame_count) {
|
if (commitres < 0 || commitres != isa->read_frame_count) {
|
||||||
|
@ -1638,6 +1647,8 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isa->frames_left -= isa->read_frame_count;
|
||||||
|
assert(isa->frames_left >= 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ struct SoundIoOutStreamAlsa {
|
||||||
SoundIoOsThread *thread;
|
SoundIoOsThread *thread;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
int period_size;
|
int period_size;
|
||||||
|
int frames_left;
|
||||||
|
int frames_to_write;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,6 +67,7 @@ struct SoundIoInStreamAlsa {
|
||||||
SoundIoOsThread *thread;
|
SoundIoOsThread *thread;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
int period_size;
|
int period_size;
|
||||||
|
int frames_left;
|
||||||
int read_frame_count;
|
int read_frame_count;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
|
@ -865,8 +865,7 @@ static int outstream_begin_write_ca(struct SoundIoPrivate *si, struct SoundIoOut
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, int)
|
static int outstream_end_write_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
{
|
|
||||||
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
|
||||||
osca->buffer_index += 1;
|
osca->buffer_index += 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -20,6 +20,7 @@ static void playback_thread_run(void *arg) {
|
||||||
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 free_frames = free_bytes / outstream->bytes_per_frame;
|
int free_frames = free_bytes / outstream->bytes_per_frame;
|
||||||
|
osd->frames_left = free_frames;
|
||||||
outstream->write_callback(outstream, free_frames);
|
outstream->write_callback(outstream, free_frames);
|
||||||
double start_time = soundio_os_get_time();
|
double start_time = soundio_os_get_time();
|
||||||
long frames_consumed = 0;
|
long frames_consumed = 0;
|
||||||
|
@ -47,10 +48,12 @@ static void playback_thread_run(void *arg) {
|
||||||
|
|
||||||
if (frames_to_kill > fill_frames) {
|
if (frames_to_kill > fill_frames) {
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
|
osd->frames_left = free_frames;
|
||||||
outstream->write_callback(outstream, free_frames);
|
outstream->write_callback(outstream, free_frames);
|
||||||
frames_consumed = 0;
|
frames_consumed = 0;
|
||||||
start_time = soundio_os_get_time();
|
start_time = soundio_os_get_time();
|
||||||
} else if (free_frames > 0) {
|
} else if (free_frames > 0) {
|
||||||
|
osd->frames_left = free_frames;
|
||||||
outstream->write_callback(outstream, free_frames);
|
outstream->write_callback(outstream, free_frames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +93,7 @@ static void capture_thread_run(void *arg) {
|
||||||
start_time = soundio_os_get_time();
|
start_time = soundio_os_get_time();
|
||||||
}
|
}
|
||||||
if (fill_frames > 0) {
|
if (fill_frames > 0) {
|
||||||
|
isd->frames_left = fill_frames;
|
||||||
instream->read_callback(instream, fill_frames);
|
instream->read_callback(instream, fill_frames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,37 +201,28 @@ static int outstream_start_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_dummy(SoundIoPrivate *si,
|
static int outstream_begin_write_dummy(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
|
||||||
|
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
assert(*frame_count >= 0);
|
char *write_ptr = soundio_ring_buffer_write_ptr(&osd->ring_buffer);
|
||||||
assert(*frame_count <= osd->buffer_frame_count);
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
osd->areas[ch].ptr = write_ptr + outstream->bytes_per_sample * ch;
|
||||||
int free_byte_count = soundio_ring_buffer_free_count(&osd->ring_buffer);
|
osd->areas[ch].step = outstream->bytes_per_frame;
|
||||||
int free_frame_count = free_byte_count / outstream->bytes_per_frame;
|
|
||||||
*frame_count = min(*frame_count, free_frame_count);
|
|
||||||
|
|
||||||
if (free_frame_count) {
|
|
||||||
char *write_ptr = soundio_ring_buffer_write_ptr(&osd->ring_buffer);
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
|
||||||
osd->areas[ch].ptr = write_ptr + outstream->bytes_per_sample * ch;
|
|
||||||
osd->areas[ch].step = outstream->bytes_per_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_areas = osd->areas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*out_frame_count = osd->frames_left;
|
||||||
|
*out_areas = osd->areas;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
|
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
int byte_count = frame_count * outstream->bytes_per_frame;
|
int byte_count = osd->frames_left * 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);
|
||||||
|
osd->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,37 +305,29 @@ static int instream_start_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_dummy(SoundIoPrivate *si,
|
static int instream_begin_read_dummy(SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
assert(*frame_count >= 0);
|
char *read_ptr = soundio_ring_buffer_read_ptr(&isd->ring_buffer);
|
||||||
assert(*frame_count <= isd->buffer_frame_count);
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
|
isd->areas[ch].ptr = read_ptr + instream->bytes_per_sample * ch;
|
||||||
int fill_byte_count = soundio_ring_buffer_fill_count(&isd->ring_buffer);
|
isd->areas[ch].step = 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);
|
|
||||||
*frame_count = isd->read_frame_count;
|
|
||||||
|
|
||||||
if (fill_frame_count) {
|
|
||||||
char *read_ptr = soundio_ring_buffer_read_ptr(&isd->ring_buffer);
|
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
|
||||||
isd->areas[ch].ptr = read_ptr + instream->bytes_per_sample * ch;
|
|
||||||
isd->areas[ch].step = instream->bytes_per_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_areas = isd->areas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*out_frame_count = isd->frames_left;
|
||||||
|
*out_areas = isd->areas;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
int byte_count = isd->read_frame_count * instream->bytes_per_frame;
|
int byte_count = isd->frames_left * instream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
soundio_ring_buffer_advance_read_ptr(&isd->ring_buffer, byte_count);
|
||||||
|
isd->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ struct SoundIoOutStreamDummy {
|
||||||
struct SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
int buffer_frame_count;
|
int buffer_frame_count;
|
||||||
|
int frames_left;
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
double playback_start_time;
|
double playback_start_time;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
|
@ -39,7 +40,7 @@ struct SoundIoInStreamDummy {
|
||||||
struct SoundIoOsThread *thread;
|
struct SoundIoOsThread *thread;
|
||||||
struct SoundIoOsCond *cond;
|
struct SoundIoOsCond *cond;
|
||||||
atomic_flag abort_flag;
|
atomic_flag abort_flag;
|
||||||
int read_frame_count;
|
int frames_left;
|
||||||
int buffer_frame_count;
|
int buffer_frame_count;
|
||||||
struct SoundIoRingBuffer ring_buffer;
|
struct SoundIoRingBuffer ring_buffer;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
|
|
54
src/jack.cpp
54
src/jack.cpp
|
@ -342,7 +342,8 @@ static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
osj->frames_left = nframes;
|
osj->frames_left = nframes;
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
osj->buf_ptrs[ch] = (char*)jack_port_get_buffer(osjp->source_port, osj->frames_left);
|
osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, nframes);
|
||||||
|
osj->areas[ch].step = outstream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
outstream->write_callback(outstream, osj->frames_left);
|
outstream->write_callback(outstream, osj->frames_left);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -525,37 +526,19 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
|
|
||||||
*frame_count = min(*frame_count, osj->frames_left);
|
*out_frame_count = osj->frames_left;
|
||||||
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
|
||||||
osj->areas[ch].ptr = osj->buf_ptrs[ch];
|
|
||||||
osj->areas[ch].step = outstream->bytes_per_sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_areas = osj->areas;
|
*out_areas = osj->areas;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
int frame_count)
|
|
||||||
{
|
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
assert(frame_count <= osj->frames_left);
|
osj->frames_left = 0;
|
||||||
|
|
||||||
osj->frames_left -= frame_count;
|
|
||||||
if (osj->frames_left > 0) {
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
|
||||||
osj->buf_ptrs[ch] += frame_count * outstream->bytes_per_sample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,7 +594,14 @@ static void instream_shutdown_callback(void *arg) {
|
||||||
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
instream->read_callback(instream, nframes);
|
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
|
isj->frames_left = nframes;
|
||||||
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
|
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||||
|
isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, nframes);
|
||||||
|
isj->areas[ch].step = instream->bytes_per_sample;
|
||||||
|
}
|
||||||
|
instream->read_callback(instream, isj->frames_left);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,27 +726,19 @@ static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
|
||||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
|
||||||
assert(*frame_count <= sij->period_size);
|
|
||||||
|
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
|
||||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
|
||||||
if (!(isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, *frame_count)))
|
|
||||||
return SoundIoErrorStreaming;
|
|
||||||
|
|
||||||
isj->areas[ch].step = instream->bytes_per_sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
*out_frame_count = isj->frames_left;
|
||||||
*out_areas = isj->areas;
|
*out_areas = isj->areas;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
|
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||||
|
isj->frames_left = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ struct SoundIoOutStreamJack {
|
||||||
int frames_left;
|
int frames_left;
|
||||||
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamJackPort {
|
struct SoundIoInStreamJackPort {
|
||||||
|
@ -62,8 +61,10 @@ struct SoundIoInStreamJackPort {
|
||||||
struct SoundIoInStreamJack {
|
struct SoundIoInStreamJack {
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
int period_size;
|
int period_size;
|
||||||
|
int frames_left;
|
||||||
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
|
char *buf_ptrs[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -641,8 +641,11 @@ static void playback_stream_underflow_callback(pa_stream *stream, void *userdata
|
||||||
}
|
}
|
||||||
|
|
||||||
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
||||||
SoundIoOutStream *outstream = (SoundIoOutStream*)(userdata);
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate*)(userdata);
|
||||||
int frame_count = ((int)nbytes) / outstream->bytes_per_frame;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
ospa->bytes_left = nbytes;
|
||||||
|
int frame_count = ospa->bytes_left / outstream->bytes_per_frame;
|
||||||
outstream->write_callback(outstream, frame_count);
|
outstream->write_callback(outstream, frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,17 +753,23 @@ static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_pa(SoundIoPrivate *si,
|
static int outstream_begin_write_pa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoOutStreamPrivate *os, SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
|
||||||
|
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
|
|
||||||
size_t byte_count = *frame_count * outstream->bytes_per_frame;
|
if (ospa->bytes_left <= 0) {
|
||||||
|
*out_frame_count = 0;
|
||||||
|
*out_areas = nullptr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (pa_stream_begin_write(stream, (void**)&ospa->write_ptr, &byte_count))
|
// PulseAudio docs recommend setting this to (size_t) -1 but I have found
|
||||||
|
// that this causes a too small buffer to be returned.
|
||||||
|
ospa->byte_count = ospa->bytes_left;
|
||||||
|
|
||||||
|
if (pa_stream_begin_write(stream, (void**)&ospa->write_ptr, &ospa->byte_count))
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
@ -768,21 +777,18 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
|
||||||
ospa->areas[ch].step = outstream->bytes_per_frame;
|
ospa->areas[ch].step = outstream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
*frame_count = byte_count / outstream->bytes_per_frame;
|
*out_frame_count = ospa->byte_count / outstream->bytes_per_frame;
|
||||||
*out_areas = ospa->areas;
|
*out_areas = ospa->areas;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
|
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
|
||||||
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
assert(frame_count >= 0);
|
if (pa_stream_write(stream, ospa->write_ptr, ospa->byte_count, nullptr, 0, PA_SEEK_RELATIVE))
|
||||||
size_t byte_count = frame_count * outstream->bytes_per_frame;
|
|
||||||
assert(byte_count < 1 * 1024 * 1024 * 1024); // attempting to write > 1GB is certainly a mistake
|
|
||||||
if (pa_stream_write(stream, ospa->write_ptr, byte_count, NULL, 0, PA_SEEK_RELATIVE))
|
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
ospa->bytes_left -= ospa->byte_count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,9 +850,11 @@ static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, void *userdata) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
assert(nbytes % instream->bytes_per_frame == 0);
|
assert(nbytes % instream->bytes_per_frame == 0);
|
||||||
assert(nbytes > 0);
|
assert(nbytes > 0);
|
||||||
int available_frame_count = nbytes / instream->bytes_per_frame;
|
ispa->bytes_left = nbytes;
|
||||||
|
int available_frame_count = ispa->bytes_left / instream->bytes_per_frame;
|
||||||
instream->read_callback(instream, available_frame_count);
|
instream->read_callback(instream, available_frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,6 +908,7 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
|
||||||
pa_stream_set_state_callback(stream, recording_stream_state_callback, is);
|
pa_stream_set_state_callback(stream, recording_stream_state_callback, is);
|
||||||
pa_stream_set_read_callback(stream, recording_stream_read_callback, is);
|
pa_stream_set_read_callback(stream, recording_stream_read_callback, is);
|
||||||
|
// TODO handle overflow callback
|
||||||
|
|
||||||
ispa->buffer_attr.maxlength = UINT32_MAX;
|
ispa->buffer_attr.maxlength = UINT32_MAX;
|
||||||
ispa->buffer_attr.tlength = UINT32_MAX;
|
ispa->buffer_attr.tlength = UINT32_MAX;
|
||||||
|
@ -955,7 +964,7 @@ static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_pa(SoundIoPrivate *si,
|
static int instream_begin_read_pa(SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *out_frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
|
@ -963,24 +972,30 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
|
||||||
|
|
||||||
assert(ispa->stream_ready);
|
assert(ispa->stream_ready);
|
||||||
|
|
||||||
char *data;
|
if (ispa->bytes_left <= 0) {
|
||||||
size_t nbytes = *frame_count * instream->bytes_per_frame;
|
*out_frame_count = 0;
|
||||||
if (pa_stream_peek(stream, (const void **)&data, &nbytes)) {
|
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
*frame_count = 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *data;
|
||||||
|
ispa->byte_count = (size_t)-1;
|
||||||
|
if (pa_stream_peek(stream, (const void **)&data, &ispa->byte_count)) {
|
||||||
|
*out_areas = nullptr;
|
||||||
|
*out_frame_count = 0;
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*out_frame_count = ispa->byte_count / instream->bytes_per_frame;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
ispa->areas[ch].ptr = data + instream->bytes_per_sample * ch;
|
ispa->areas[ch].ptr = data + instream->bytes_per_sample * ch;
|
||||||
ispa->areas[ch].step = instream->bytes_per_frame;
|
ispa->areas[ch].step = instream->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
*frame_count = nbytes / instream->bytes_per_frame;
|
|
||||||
*out_areas = ispa->areas;
|
*out_areas = ispa->areas;
|
||||||
} else {
|
} else {
|
||||||
*frame_count = nbytes / instream->bytes_per_frame;
|
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,7 +1007,7 @@ static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
if (pa_stream_drop(stream))
|
if (pa_stream_drop(stream))
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
ispa->bytes_left -= ispa->byte_count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
|
|
||||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDevicePulseAudio {
|
struct SoundIoDevicePulseAudio { };
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SoundIoPulseAudio {
|
struct SoundIoPulseAudio {
|
||||||
int connection_err;
|
int connection_err;
|
||||||
|
@ -50,6 +48,8 @@ struct SoundIoOutStreamPulseAudio {
|
||||||
atomic_bool stream_ready;
|
atomic_bool stream_ready;
|
||||||
pa_buffer_attr buffer_attr;
|
pa_buffer_attr buffer_attr;
|
||||||
char *write_ptr;
|
char *write_ptr;
|
||||||
|
size_t byte_count;
|
||||||
|
int bytes_left;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@ struct SoundIoInStreamPulseAudio {
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
atomic_bool stream_ready;
|
atomic_bool stream_ready;
|
||||||
pa_buffer_attr buffer_attr;
|
pa_buffer_attr buffer_attr;
|
||||||
|
size_t byte_count;
|
||||||
|
int bytes_left;
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -352,15 +352,14 @@ int soundio_outstream_begin_write(struct SoundIoOutStream *outstream,
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
||||||
assert(*frame_count > 0);
|
|
||||||
return si->outstream_begin_write(si, os, areas, frame_count);
|
return si->outstream_begin_write(si, os, areas, frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_outstream_end_write(struct SoundIoOutStream *outstream, int frame_count) {
|
int soundio_outstream_end_write(struct SoundIoOutStream *outstream) {
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
||||||
return si->outstream_end_write(si, os, frame_count);
|
return si->outstream_end_write(si, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_outstream_error_callback(struct SoundIoOutStream *os, int err) {
|
static void default_outstream_error_callback(struct SoundIoOutStream *os, int err) {
|
||||||
|
|
|
@ -126,8 +126,8 @@ struct SoundIoPrivate {
|
||||||
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
int (*outstream_start)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
int (*outstream_begin_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count);
|
SoundIoChannelArea **out_areas, int *out_frame_count);
|
||||||
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count);
|
int (*outstream_end_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||||
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ struct SoundIoPrivate {
|
||||||
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
int (*instream_start)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
int (*instream_begin_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
int (*instream_begin_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count);
|
SoundIoChannelArea **out_areas, int *out_frame_count);
|
||||||
int (*instream_end_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
int (*instream_end_read)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||||
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ static float seconds_end = 9.0f;
|
||||||
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
static void write_callback(struct SoundIoOutStream *outstream, int requested_frame_count) {
|
||||||
float float_sample_rate = outstream->sample_rate;
|
float float_sample_rate = outstream->sample_rate;
|
||||||
float seconds_per_frame = 1.0f / float_sample_rate;
|
float seconds_per_frame = 1.0f / float_sample_rate;
|
||||||
|
struct SoundIoChannelArea *areas;
|
||||||
|
int frame_count;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!caused_underflow && seconds_offset >= 3.0f) {
|
if (!caused_underflow && seconds_offset >= 3.0f) {
|
||||||
|
@ -54,9 +56,6 @@ static void write_callback(struct SoundIoOutStream *outstream, int requested_fra
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int frame_count = requested_frame_count;
|
|
||||||
|
|
||||||
struct SoundIoChannelArea *areas;
|
|
||||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
||||||
panic("%s", soundio_strerror(err));
|
panic("%s", soundio_strerror(err));
|
||||||
|
|
||||||
|
@ -76,15 +75,11 @@ static void write_callback(struct SoundIoOutStream *outstream, int requested_fra
|
||||||
}
|
}
|
||||||
seconds_offset += seconds_per_frame * frame_count;
|
seconds_offset += seconds_per_frame * frame_count;
|
||||||
|
|
||||||
if ((err = soundio_outstream_end_write(outstream, frame_count))) {
|
if ((err = soundio_outstream_end_write(outstream))) {
|
||||||
if (err == SoundIoErrorUnderflow)
|
if (err == SoundIoErrorUnderflow)
|
||||||
return;
|
return;
|
||||||
panic("%s", soundio_strerror(err));
|
panic("%s", soundio_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_frame_count -= frame_count;
|
|
||||||
if (requested_frame_count <= 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +119,8 @@ int main(int argc, char **argv) {
|
||||||
if (err)
|
if (err)
|
||||||
panic("error connecting: %s", soundio_strerror(err));
|
panic("error connecting: %s", soundio_strerror(err));
|
||||||
|
|
||||||
|
soundio_flush_events(soundio);
|
||||||
|
|
||||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||||
if (default_out_device_index < 0)
|
if (default_out_device_index < 0)
|
||||||
panic("no output device found");
|
panic("no output device found");
|
||||||
|
|
Loading…
Reference in a new issue