mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-15 07:44:10 +00:00
pulse: fill audio monitor buffer more aggressively
Previously we would wait for pulse to attempt to read from the monitor source and obs buffered at least 5ms of audio data before we tried to fill the buffer. In some cases this resulted in consistently triggering underruns in pulse. Instead we try to fill the buffer immediately as obs outputs audio data and while the pa buffer is not full. We also stop trying to grow the buffer to prevent underruns after we reach 1s of latency.
This commit is contained in:
parent
e7a4ed4067
commit
5142a7685d
|
@ -20,7 +20,6 @@ struct audio_monitor {
|
|||
|
||||
struct circlebuf new_data;
|
||||
audio_resampler_t *resampler;
|
||||
size_t buffer_size;
|
||||
size_t bytesRemaining;
|
||||
|
||||
bool ignore;
|
||||
|
@ -191,21 +190,20 @@ static void do_stream_write(void *param)
|
|||
PULSE_DATA(param);
|
||||
uint8_t *buffer = NULL;
|
||||
|
||||
while (data->new_data.size >= data->buffer_size &&
|
||||
data->bytesRemaining > 0) {
|
||||
size_t bytesToFill = data->buffer_size;
|
||||
|
||||
if (bytesToFill > data->bytesRemaining)
|
||||
while (data->new_data.size > 0 && data->bytesRemaining > 0) {
|
||||
size_t bytesToFill = data->new_data.size;
|
||||
if (data->bytesRemaining < bytesToFill)
|
||||
bytesToFill = data->bytesRemaining;
|
||||
|
||||
pulseaudio_lock();
|
||||
pa_stream_begin_write(data->stream, (void **)&buffer,
|
||||
&bytesToFill);
|
||||
pulseaudio_unlock();
|
||||
if (pa_stream_begin_write(data->stream, (void **)&buffer,
|
||||
&bytesToFill)) {
|
||||
pulseaudio_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
circlebuf_pop_front(&data->new_data, buffer, bytesToFill);
|
||||
|
||||
pulseaudio_lock();
|
||||
pa_stream_write(data->stream, buffer, bytesToFill, NULL, 0LL,
|
||||
PA_SEEK_RELATIVE);
|
||||
pulseaudio_unlock();
|
||||
|
@ -277,13 +275,30 @@ static void pulseaudio_underflow(pa_stream *p, void *userdata)
|
|||
UNUSED_PARAMETER(p);
|
||||
PULSE_DATA(userdata);
|
||||
|
||||
pthread_mutex_lock(&data->playback_mutex);
|
||||
if (obs_source_active(data->source))
|
||||
data->attr.tlength = (data->attr.tlength * 3) / 2;
|
||||
pa_sample_spec spec = {0};
|
||||
spec.format = data->format;
|
||||
spec.rate = (uint32_t)data->samples_per_sec;
|
||||
spec.channels = data->channels;
|
||||
uint64_t latency = pa_bytes_to_usec(data->attr.tlength, &spec);
|
||||
|
||||
pa_stream_set_buffer_attr(data->stream, &data->attr, NULL, NULL);
|
||||
pthread_mutex_lock(&data->playback_mutex);
|
||||
if (obs_source_active(data->source) && latency < 1000000) {
|
||||
data->attr.fragsize = (uint32_t)-1;
|
||||
data->attr.maxlength = (uint32_t)-1;
|
||||
data->attr.prebuf = (uint32_t)-1;
|
||||
data->attr.minreq = (uint32_t)-1;
|
||||
data->attr.tlength = (data->attr.tlength * 3) / 2;
|
||||
pa_stream_set_buffer_attr(data->stream, &data->attr, NULL,
|
||||
NULL);
|
||||
data->bytesRemaining = data->attr.maxlength;
|
||||
}
|
||||
pthread_mutex_unlock(&data->playback_mutex);
|
||||
|
||||
if (latency >= 1000000) {
|
||||
blog(LOG_WARNING, "source monitor reached max latency %ldms",
|
||||
latency / 1000);
|
||||
}
|
||||
|
||||
pulseaudio_signal(0);
|
||||
}
|
||||
|
||||
|
@ -473,9 +488,6 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
monitor->attr.prebuf = (uint32_t)-1;
|
||||
monitor->attr.tlength = pa_usec_to_bytes(25000, &spec);
|
||||
|
||||
monitor->buffer_size =
|
||||
monitor->bytes_per_frame * pa_usec_to_bytes(5000, &spec);
|
||||
|
||||
pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING |
|
||||
PA_STREAM_AUTO_TIMING_UPDATE;
|
||||
|
||||
|
@ -493,6 +505,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
return false;
|
||||
}
|
||||
|
||||
monitor->bytesRemaining = monitor->attr.maxlength;
|
||||
|
||||
blog(LOG_INFO, "Started Monitoring in '%s'", monitor->device);
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue