From 92c1c2ec4440e5b74a31ba620448c25c13d8f7d1 Mon Sep 17 00:00:00 2001 From: invertego Date: Sat, 18 Nov 2023 05:44:36 -0800 Subject: [PATCH] ruby: queue no more than "latency" samples in wasapi driver (#1292) The WASAPI driver in ruby is a bit of an oddball. It has a fixed length circular queue for samples, and before this commit there was no logic to prevent queuing more than the requested "latency" number of samples or even to prevent the queue from overflowing entirely. In practice this wasn't much of an issue when audio or video synchronization were enabled and therefore bounding the rate of audio generation. It did not, however, play nice with the fast-forward feature, and it caused a noticeable pause after returning to normal speed as the queue drained from whatever level of fullness it had wrapped around to (effectively random but averaging over half a second). Now the length of the sample queue is (mostly) bounded to the "latency" parameter which is more consistent with the other drivers. Fixes #958 --- ruby/audio/wasapi.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ruby/audio/wasapi.cpp b/ruby/audio/wasapi.cpp index bcd7cb8e3..453270026 100644 --- a/ruby/audio/wasapi.cpp +++ b/ruby/audio/wasapi.cpp @@ -78,8 +78,13 @@ struct AudioWASAPI : AudioDriver { self.queue.count++; if(self.queue.count >= self.bufferSize) { + //this event is signaled at the device period which is no more than half of bufferSize + //(in shared mode) or equal to bufferSize (in double-buffered exclusive mode) if(WaitForSingleObject(self.eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) { write(); + } else { + self.queue.read++; + self.queue.count--; } } } @@ -188,7 +193,7 @@ private: waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx; CoTaskMemFree(waveFormatEx); if(self.audioClient->GetDevicePeriod(&self.devicePeriod, nullptr)) return false; - auto latency = max(self.devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units + auto latency = max(self.devicePeriod * 2, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units if(self.audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false; }