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
このコミットが含まれているのは:
invertego 2023-11-18 05:44:36 -08:00 committed by GitHub
コミット 92c1c2ec44
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: 4AEE18F83AFDEB23
1個のファイルの変更6行の追加1行の削除

ファイルの表示

@ -78,8 +78,13 @@ struct AudioWASAPI : AudioDriver {
self.queue.count++; self.queue.count++;
if(self.queue.count >= self.bufferSize) { 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) { if(WaitForSingleObject(self.eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) {
write(); write();
} else {
self.queue.read++;
self.queue.count--;
} }
} }
} }
@ -188,7 +193,7 @@ private:
waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx; waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx;
CoTaskMemFree(waveFormatEx); CoTaskMemFree(waveFormatEx);
if(self.audioClient->GetDevicePeriod(&self.devicePeriod, nullptr)) return false; 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; if(self.audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false;
} }