From 30cbbd98e7159de08bb71ab4332dbd0bab19eba5 Mon Sep 17 00:00:00 2001
From: Val Doroshchuk <valentyn.doroshchuk@qt.io>
Date: Tue, 16 Oct 2018 09:12:19 +0200
Subject: [PATCH] WindowsAudioOutput: Introduce QT_WAVE_BUFFERS env var

Currently by default 5 wave buffers are created where each buffer
contains buffer_size/5 bytes.
If total buffer size is small enough, playing of these wave buffers might be
finished before refilling them.
Which leads crackling and another noise.

Introduced QT_WAVE_BUFFERS env var which contains number of wave
buffers. Must not be less than 5.

If number of wave buffers is big enough, it ensures that there is
always data to play.

Task-number: QTBUG-45174
Change-Id: I66bf997411f858fbff822394bb748dea2086060e
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
---
 .../windowsaudio/qwindowsaudiooutput.cpp      | 33 ++++++++++++-------
 .../windowsaudio/qwindowsaudiooutput.h        |  1 +
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
index 26eecb768..f39e1694b 100644
--- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
+++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
@@ -74,6 +74,7 @@ QWindowsAudioOutput::QWindowsAudioOutput(const QByteArray &device)
     pullMode = true;
     finished = false;
     volumeCache = qreal(1.0);
+    blocks_count = 5;
 }
 
 QWindowsAudioOutput::~QWindowsAudioOutput()
@@ -110,8 +111,9 @@ void CALLBACK QWindowsAudioOutput::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
                 return;
             }
             qAudio->waveFreeBlockCount++;
-            if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size)
-                qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size;
+            if (qAudio->waveFreeBlockCount >= qAudio->blocks_count)
+                qAudio->waveFreeBlockCount = qAudio->blocks_count;
+
             qAudio->feedback();
             break;
         default:
@@ -144,10 +146,7 @@ WAVEHDR* QWindowsAudioOutput::allocateBlocks(int size, int count)
 void QWindowsAudioOutput::freeBlocks(WAVEHDR* blockArray)
 {
     WAVEHDR* blocks = blockArray;
-
-    int count = buffer_size/period_size;
-
-    for(int i = 0; i < count; i++) {
+    for (int i = 0; i < blocks_count; ++i) {
         waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR));
         blocks++;
     }
@@ -252,16 +251,26 @@ bool QWindowsAudioOutput::open()
         return false;
     }
 
-    waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
+    const int periods = buffer_size / period_size;
+    bool ok = false;
+    static int wave_buffers = qEnvironmentVariableIntValue("QT_WAVE_BUFFERS", &ok);
+    if (wave_buffers < periods) {
+        if (ok)
+            qWarning("Number of WAVE buffers (QT_WAVE_BUFFERS=%d) cannot be less than %d.", wave_buffers, periods);
+        wave_buffers = periods;
+    }
+
+    blocks_count = wave_buffers;
+    waveBlocks = allocateBlocks(period_size, blocks_count);
 
     mutex.lock();
-    waveFreeBlockCount = buffer_size/period_size;
+    waveFreeBlockCount = blocks_count;
     mutex.unlock();
 
     waveCurrentBlock = 0;
 
     if(audioBuffer == 0)
-        audioBuffer = new char[buffer_size];
+        audioBuffer = new char[blocks_count * period_size];
 
     timeStamp.restart();
     elapsedTimeOffset = 0;
@@ -440,7 +449,7 @@ qint64 QWindowsAudioOutput::write( const char *data, qint64 len )
 
         totalTimeValue += current->dwBufferLength;
         waveCurrentBlock++;
-        waveCurrentBlock %= buffer_size/period_size;
+        waveCurrentBlock %= blocks_count;
         current = &waveBlocks[waveCurrentBlock];
         current->dwUser = 0;
         errorState = QAudio::NoError;
@@ -547,7 +556,7 @@ bool QWindowsAudioOutput::deviceReady()
             check = waveFreeBlockCount;
             mutex.unlock();
 
-            if(check == buffer_size/period_size) {
+            if (check == blocks_count) {
                 if (deviceState != QAudio::IdleState) {
                     errorState = QAudio::UnderrunError;
                     deviceState = QAudio::IdleState;
@@ -567,7 +576,7 @@ bool QWindowsAudioOutput::deviceReady()
         buffered = waveFreeBlockCount;
         mutex.unlock();
 
-        if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) {
+        if (buffered >= blocks_count && deviceState == QAudio::ActiveState) {
             if (deviceState != QAudio::IdleState) {
                 errorState = QAudio::UnderrunError;
                 deviceState = QAudio::IdleState;
diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.h b/src/plugins/windowsaudio/qwindowsaudiooutput.h
index b71f00e98..30ee1defe 100644
--- a/src/plugins/windowsaudio/qwindowsaudiooutput.h
+++ b/src/plugins/windowsaudio/qwindowsaudiooutput.h
@@ -123,6 +123,7 @@ private:
     QTime timeStampOpened;
     qint32 buffer_size;
     qint32 period_size;
+    qint32 blocks_count;
     qint64 totalTimeValue;
     bool pullMode;
     int intervalTime;
-- 
GitLab