AudioServer: Fix resampling math
This caused resampled audio to freeze the whole audio system after few minutes of playing (like doom)
This commit is contained in:
parent
e2ccc3026f
commit
c64159d5c3
|
|
@ -48,7 +48,8 @@ bool AudioServer::on_client_packet(int fd, long smo_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_buffer.buffer = static_cast<LibAudio::AudioBuffer*>(smo_map(smo_key));
|
audio_buffer.buffer = static_cast<LibAudio::AudioBuffer*>(smo_map(smo_key));
|
||||||
audio_buffer.sample_frames_queued = 0;
|
audio_buffer.queued_head = audio_buffer.buffer->tail;
|
||||||
|
|
||||||
if (audio_buffer.buffer == nullptr)
|
if (audio_buffer.buffer == nullptr)
|
||||||
{
|
{
|
||||||
dwarnln("Failed to map audio buffer: {}", strerror(errno));
|
dwarnln("Failed to map audio buffer: {}", strerror(errno));
|
||||||
|
|
@ -75,6 +76,8 @@ uint64_t AudioServer::update()
|
||||||
const uint32_t samples_played = m_samples_sent - kernel_samples;
|
const uint32_t samples_played = m_samples_sent - kernel_samples;
|
||||||
ASSERT(samples_played % m_channels == 0);
|
ASSERT(samples_played % m_channels == 0);
|
||||||
|
|
||||||
|
const uint32_t sample_frames_played = samples_played / m_channels;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < samples_played; i++)
|
for (uint32_t i = 0; i < samples_played; i++)
|
||||||
m_samples.pop();
|
m_samples.pop();
|
||||||
m_samples_sent -= samples_played;
|
m_samples_sent -= samples_played;
|
||||||
|
|
@ -92,25 +95,21 @@ uint64_t AudioServer::update()
|
||||||
if (buffer.buffer == nullptr)
|
if (buffer.buffer == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const sample_t sample_ratio = buffer.buffer->sample_rate / static_cast<sample_t>(m_sample_rate);
|
if (const size_t sample_frames_queued = buffer.sample_frames_queued())
|
||||||
|
|
||||||
if (buffer.sample_frames_queued)
|
|
||||||
{
|
{
|
||||||
|
const sample_t sample_ratio = buffer.buffer->sample_rate / static_cast<sample_t>(m_sample_rate);
|
||||||
const uint32_t buffer_sample_frames_played = BAN::Math::min<size_t>(
|
const uint32_t buffer_sample_frames_played = BAN::Math::min<size_t>(
|
||||||
samples_played * sample_ratio / m_channels,
|
sample_frames_played * sample_ratio,
|
||||||
buffer.sample_frames_queued
|
sample_frames_queued
|
||||||
);
|
);
|
||||||
buffer.buffer->tail = (buffer.buffer->tail + buffer_sample_frames_played * buffer.buffer->channels) % buffer.buffer->capacity;
|
buffer.buffer->tail = (buffer.buffer->tail + buffer_sample_frames_played * buffer.buffer->channels) % buffer.buffer->capacity;
|
||||||
buffer.sample_frames_queued -= buffer_sample_frames_played;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer.buffer->paused)
|
if (buffer.buffer->paused)
|
||||||
continue;
|
continue;
|
||||||
anyone_playing = true;
|
anyone_playing = true;
|
||||||
|
|
||||||
const uint32_t buffer_total_sample_frames = ((buffer.buffer->capacity + buffer.buffer->head - buffer.buffer->tail) % buffer.buffer->capacity) / buffer.buffer->channels;
|
max_sample_frames_to_queue = BAN::Math::min<size_t>(max_sample_frames_to_queue, buffer.sample_frames_available());
|
||||||
const uint32_t buffer_sample_frames_available = (buffer_total_sample_frames - buffer.sample_frames_queued) / sample_ratio;
|
|
||||||
max_sample_frames_to_queue = BAN::Math::min<size_t>(max_sample_frames_to_queue, buffer_sample_frames_available);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!anyone_playing)
|
if (!anyone_playing)
|
||||||
|
|
@ -132,13 +131,8 @@ uint64_t AudioServer::update()
|
||||||
|
|
||||||
const sample_t sample_ratio = buffer.buffer->sample_rate / static_cast<sample_t>(m_sample_rate);
|
const sample_t sample_ratio = buffer.buffer->sample_rate / static_cast<sample_t>(m_sample_rate);
|
||||||
|
|
||||||
const uint32_t buffer_total_sample_frames = ((buffer.buffer->capacity + buffer.buffer->head - buffer.buffer->tail) % buffer.buffer->capacity) / buffer.buffer->channels;
|
const size_t sample_frames_to_queue = BAN::Math::min<size_t>(max_sample_frames_to_queue, buffer.sample_frames_available() / sample_ratio);
|
||||||
const uint32_t buffer_sample_frames_available = (buffer_total_sample_frames - buffer.sample_frames_queued) / sample_ratio;
|
if (sample_frames_to_queue == 0)
|
||||||
if (buffer_sample_frames_available == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const size_t sample_frames_to_queue = BAN::Math::min<size_t>(max_sample_frames_to_queue, buffer_sample_frames_available);
|
|
||||||
if (sample_frames_to_queue < sample_frames_per_10ms)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
while (m_samples.size() < queued_samples_end + sample_frames_to_queue * m_channels)
|
while (m_samples.size() < queued_samples_end + sample_frames_to_queue * m_channels)
|
||||||
|
|
@ -146,7 +140,7 @@ uint64_t AudioServer::update()
|
||||||
|
|
||||||
const size_t min_channels = BAN::Math::min(m_channels, buffer.buffer->channels);
|
const size_t min_channels = BAN::Math::min(m_channels, buffer.buffer->channels);
|
||||||
|
|
||||||
const size_t buffer_tail = buffer.buffer->tail + buffer.sample_frames_queued * buffer.buffer->channels;
|
const size_t buffer_tail = buffer.queued_head;
|
||||||
for (size_t i = 0; i < sample_frames_to_queue; i++)
|
for (size_t i = 0; i < sample_frames_to_queue; i++)
|
||||||
{
|
{
|
||||||
const size_t buffer_frame = i * sample_ratio;
|
const size_t buffer_frame = i * sample_ratio;
|
||||||
|
|
@ -154,10 +148,8 @@ uint64_t AudioServer::update()
|
||||||
m_samples[queued_samples_end + i * m_channels + j] += buffer.buffer->samples[(buffer_tail + buffer_frame * buffer.buffer->channels + j) % buffer.buffer->capacity];
|
m_samples[queued_samples_end + i * m_channels + j] += buffer.buffer->samples[(buffer_tail + buffer_frame * buffer.buffer->channels + j) % buffer.buffer->capacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.sample_frames_queued += BAN::Math::min<uint32_t>(
|
const uint32_t buffer_sample_frames = sample_frames_to_queue * sample_ratio;
|
||||||
buffer_total_sample_frames,
|
buffer.queued_head = (buffer_tail + buffer_sample_frames * buffer.buffer->channels) % buffer.buffer->capacity;
|
||||||
BAN::Math::ceil(sample_frames_to_queue * sample_ratio)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
send_samples();
|
send_samples();
|
||||||
|
|
@ -179,19 +171,26 @@ void AudioServer::reset_kernel_buffer()
|
||||||
const uint32_t samples_played = m_samples_sent - kernel_samples;
|
const uint32_t samples_played = m_samples_sent - kernel_samples;
|
||||||
ASSERT(samples_played % m_channels == 0);
|
ASSERT(samples_played % m_channels == 0);
|
||||||
|
|
||||||
|
const uint32_t sample_frames_played = samples_played / m_channels;
|
||||||
|
|
||||||
m_samples_sent = 0;
|
m_samples_sent = 0;
|
||||||
m_samples.clear();
|
m_samples.clear();
|
||||||
|
|
||||||
for (auto& [_, buffer] : m_audio_buffers)
|
for (auto& [_, buffer] : m_audio_buffers)
|
||||||
{
|
{
|
||||||
if (buffer.buffer == nullptr || buffer.sample_frames_queued == 0)
|
if (buffer.buffer == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (const size_t sample_frames_queued = buffer.sample_frames_queued())
|
||||||
|
{
|
||||||
|
const sample_t sample_ratio = buffer.buffer->sample_rate / static_cast<sample_t>(m_sample_rate);
|
||||||
const uint32_t buffer_sample_frames_played = BAN::Math::min<size_t>(
|
const uint32_t buffer_sample_frames_played = BAN::Math::min<size_t>(
|
||||||
samples_played / m_channels,
|
sample_frames_played * sample_ratio,
|
||||||
buffer.sample_frames_queued
|
sample_frames_queued
|
||||||
);
|
);
|
||||||
buffer.buffer->tail = (buffer.buffer->tail + buffer_sample_frames_played * buffer.buffer->channels) % buffer.buffer->capacity;
|
buffer.buffer->tail = (buffer.buffer->tail + buffer_sample_frames_played * buffer.buffer->channels) % buffer.buffer->capacity;
|
||||||
buffer.sample_frames_queued = 0;
|
buffer.queued_head = buffer.buffer->tail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
@ -215,7 +214,7 @@ void AudioServer::send_samples()
|
||||||
auto sample_buffer = buffer.as_span<kernel_sample_t>();
|
auto sample_buffer = buffer.as_span<kernel_sample_t>();
|
||||||
for (size_t i = 0; i < samples_to_send; i++)
|
for (size_t i = 0; i < samples_to_send; i++)
|
||||||
{
|
{
|
||||||
sample_buffer[i] = BAN::Math::clamp<double>(
|
sample_buffer[i] = BAN::Math::clamp<sample_t>(
|
||||||
m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
|
m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
|
||||||
BAN::numeric_limits<kernel_sample_t>::min(),
|
BAN::numeric_limits<kernel_sample_t>::min(),
|
||||||
BAN::numeric_limits<kernel_sample_t>::max()
|
BAN::numeric_limits<kernel_sample_t>::max()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,17 @@ private:
|
||||||
struct ClientInfo
|
struct ClientInfo
|
||||||
{
|
{
|
||||||
LibAudio::AudioBuffer* buffer;
|
LibAudio::AudioBuffer* buffer;
|
||||||
size_t sample_frames_queued { 0 };
|
size_t queued_head { 0 };
|
||||||
|
|
||||||
|
size_t sample_frames_queued() const
|
||||||
|
{
|
||||||
|
return ((buffer->capacity + queued_head - buffer->tail) % buffer->capacity) / buffer->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sample_frames_available() const
|
||||||
|
{
|
||||||
|
return ((buffer->capacity + buffer->head - queued_head) % buffer->capacity) / buffer->channels;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using sample_t = LibAudio::AudioBuffer::sample_t;
|
using sample_t = LibAudio::AudioBuffer::sample_t;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue