JACK: fix playback glitchfest

This commit is contained in:
Andrew Kelley 2015-07-28 23:20:30 -07:00
parent 754343bba6
commit 97ee72ce5f
3 changed files with 27 additions and 12 deletions

View file

@ -241,13 +241,12 @@ view `coverage/index.html` in a browser.
## Roadmap ## Roadmap
0. JACK: input 0. Integrate into libgroove and test with Groove Basin
0. JACK: implement prebuffering
0. why does pulseaudio microphone use up all the CPU?
0. merge in/out stream structures and functions?
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
0. why does pulseaudio microphone use up all the CPU?
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 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 which is why we have to pre-fill the ring buffer with silence for
@ -282,7 +281,6 @@ view `coverage/index.html` in a browser.
0. use a documentation generator and host the docs somewhere 0. use a documentation generator and host the docs somewhere
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. Integrate into libgroove and test with Groove Basin
0. look at microphone example and determine if fewer memcpys can be done 0. look at microphone example and determine if fewer memcpys can be done
with the audio data with the audio data
- test that sending the frame count to begin read works with PulseAudio - test that sending the frame count to begin read works with PulseAudio
@ -295,6 +293,7 @@ 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

View file

@ -81,8 +81,14 @@ static void wakeup_jack(struct SoundIoPrivate *si) {
static int outstream_process_callback(jack_nframes_t nframes, void *arg) { static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub; SoundIoOutStream *outstream = &os->pub;
outstream->write_callback(outstream, nframes); osj->frames_left = nframes;
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
osj->buf_ptrs[ch] = (char*)jack_port_get_buffer(osjp->source_port, osj->frames_left);
}
outstream->write_callback(outstream, osj->frames_left);
return 0; return 0;
} }
@ -268,14 +274,11 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
{ {
SoundIoOutStream *outstream = &os->pub; SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamJack *osj = &os->backend_data.jack; SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoJack *sij = &si->backend_data.jack;
assert(*frame_count <= sij->period_size); *frame_count = min(*frame_count, osj->frames_left);
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]; osj->areas[ch].ptr = osj->buf_ptrs[ch];
if (!(osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, *frame_count)))
return SoundIoErrorStreaming;
osj->areas[ch].step = outstream->bytes_per_sample; osj->areas[ch].step = outstream->bytes_per_sample;
} }
@ -287,6 +290,17 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
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) int frame_count)
{ {
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamJack *osj = &os->backend_data.jack;
assert(frame_count <= osj->frames_left);
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;
} }

View file

@ -48,8 +48,10 @@ struct SoundIoOutStreamJackPort {
struct SoundIoOutStreamJack { struct SoundIoOutStreamJack {
jack_client_t *client; jack_client_t *client;
int period_size; int period_size;
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 {