audio: switch waveout backend to pull rendering

This commit is contained in:
2026-04-14 19:04:18 +08:00
parent e77dbe40b1
commit 882df1ae5a
10 changed files with 378 additions and 94 deletions

View File

@@ -64,8 +64,7 @@ bool WaveOutBackend::Initialize(const AudioConfig& config) {
const size_t bufferSampleCount = static_cast<size_t>(config.bufferSize) * config.channels;
m_audioBuffer1.assign(bufferSampleCount, 0);
m_audioBuffer2.assign(bufferSampleCount, 0);
m_pendingMixBuffer.assign(bufferSampleCount, 0.0f);
m_hasPendingMix = false;
m_renderBuffer.assign(bufferSampleCount, 0.0f);
m_buffer1Available = true;
m_buffer2Available = true;
@@ -152,7 +151,7 @@ void WaveOutBackend::Start() {
void WaveOutBackend::Stop() {
m_isRunning = false;
m_dataReadyCond.notify_all();
m_bufferReadyCond.notify_all();
if (m_hWaveOut != nullptr) {
waveOutReset(m_hWaveOut);
@@ -180,20 +179,15 @@ void WaveOutBackend::Resume() {
void WaveOutBackend::ProcessAudio(float* buffer, uint32 frameCount,
uint32 channels, uint32 sampleRate) {
(void)buffer;
(void)frameCount;
(void)channels;
(void)sampleRate;
}
if (buffer == nullptr) {
return;
}
const uint32 sampleCount = frameCount * channels;
void WaveOutBackend::SetRenderCallback(RenderCallback callback) {
std::lock_guard<std::mutex> lock(m_bufferMutex);
m_pendingMixBuffer.assign(m_pendingMixBuffer.size(), 0.0f);
for (uint32 i = 0; i < sampleCount && i < m_pendingMixBuffer.size(); ++i) {
m_pendingMixBuffer[i] = buffer[i];
}
m_hasPendingMix = true;
m_dataReadyCond.notify_one();
m_renderCallback = std::move(callback);
}
MMRESULT WaveOutBackend::InitDevice() {
@@ -269,9 +263,8 @@ DWORD WINAPI WaveOutBackend::AudioThreadProc(LPVOID lpParameter) {
void WaveOutBackend::AudioThread() {
while (m_isRunning.load()) {
std::unique_lock<std::mutex> lock(m_bufferMutex);
m_dataReadyCond.wait(lock, [this] {
return !m_isRunning.load() ||
(m_hasPendingMix && (m_buffer1Available || m_buffer2Available));
m_bufferReadyCond.wait(lock, [this] {
return !m_isRunning.load() || m_buffer1Available || m_buffer2Available;
});
if (!m_isRunning.load()) {
@@ -293,10 +286,31 @@ void WaveOutBackend::AudioThread() {
continue;
}
FillPcm16Buffer(*targetBuffer, m_pendingMixBuffer);
m_hasPendingMix = false;
RenderCallback renderCallback;
const uint32 frameCount = m_config.bufferSize;
const uint32 channels = m_config.channels;
const uint32 sampleRate = m_config.sampleRate;
const size_t sampleCount = static_cast<size_t>(frameCount) * channels;
if (targetBuffer->size() != sampleCount) {
targetBuffer->assign(sampleCount, 0);
} else {
std::fill(targetBuffer->begin(), targetBuffer->end(), 0);
}
if (m_renderBuffer.size() != sampleCount) {
m_renderBuffer.assign(sampleCount, 0.0f);
} else {
std::fill(m_renderBuffer.begin(), m_renderBuffer.end(), 0.0f);
}
renderCallback = m_renderCallback;
lock.unlock();
if (renderCallback && !m_renderBuffer.empty()) {
renderCallback(m_renderBuffer.data(), frameCount, channels, sampleRate);
}
FillPcm16Buffer(*targetBuffer, m_renderBuffer);
if (SubmitBuffer(*targetHeader, *targetBuffer) != MMSYSERR_NOERROR) {
std::lock_guard<std::mutex> restoreLock(m_bufferMutex);
if (targetHeader == &m_waveHeader1) {
@@ -304,6 +318,7 @@ void WaveOutBackend::AudioThread() {
} else {
m_buffer2Available = true;
}
m_bufferReadyCond.notify_one();
}
}
}
@@ -322,7 +337,7 @@ void WaveOutBackend::OnAudioCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstan
} else if (completedHeader == &m_waveHeader2) {
m_buffer2Available = true;
}
m_dataReadyCond.notify_one();
m_bufferReadyCond.notify_one();
}
}