Skip to content

Commit c69e767

Browse files
committed
Let windows default audio client mix down to 1 (or 2) channels
1 parent 9a8086f commit c69e767

File tree

1 file changed

+164
-50
lines changed

1 file changed

+164
-50
lines changed

build/patches/windows_add_192k.patch

Lines changed: 164 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,165 @@
11
diff --git a/modules/audio_device/win/audio_device_core_win.cc b/modules/audio_device/win/audio_device_core_win.cc
2-
index f1cc0474fc..ffb0b159b1 100644
2+
index f1cc0474fc..f8e4f25bb9 100644
33
--- a/modules/audio_device/win/audio_device_core_win.cc
44
+++ b/modules/audio_device/win/audio_device_core_win.cc
5-
@@ -1846,7 +1846,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
5+
@@ -1845,8 +1845,8 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
6+
67
HRESULT hr = S_OK;
78
WAVEFORMATEX* pWfxOut = NULL;
8-
WAVEFORMATEX Wfx = WAVEFORMATEX();
9+
- WAVEFORMATEX Wfx = WAVEFORMATEX();
910
- WAVEFORMATEX* pWfxClosestMatch = NULL;
10-
+ WAVEFORMATEX* pInitWfxClosestMatch = NULL;
11+
+ WAVEFORMATEXTENSIBLE Wfx = WAVEFORMATEXTENSIBLE();
12+
+ WAVEFORMATEXTENSIBLE* pInitWfxClosestMatch = NULL;
1113

1214
// Create COM object with IAudioClient interface.
1315
SAFE_RELEASE(_ptrClientOut);
14-
@@ -1881,7 +1881,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
15-
Wfx.wBitsPerSample = 16;
16-
Wfx.cbSize = 0;
16+
@@ -1877,11 +1877,14 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
17+
}
18+
19+
// Set wave format
20+
- Wfx.wFormatTag = WAVE_FORMAT_PCM;
21+
- Wfx.wBitsPerSample = 16;
22+
- Wfx.cbSize = 0;
23+
+ Wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
24+
+ Wfx.Format.wBitsPerSample = 16;
25+
+ Wfx.Format.cbSize = 22;
26+
+ Wfx.dwChannelMask = 0;
27+
+ Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
28+
+ Wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1729

1830
- const int freqs[] = {48000, 44100, 16000, 96000, 32000, 8000};
1931
+ const int freqs[] = {48000, 44100, 16000, 96000, 32000, 8000, 192000};
2032
hr = S_FALSE;
2133

2234
// Iterate over frequencies and channels, in order of priority
23-
@@ -1896,6 +1896,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
35+
@@ -1889,30 +1892,38 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
36+
for (unsigned int chan = 0; chan < sizeof(_playChannelsPrioList) /
37+
sizeof(_playChannelsPrioList[0]);
38+
chan++) {
39+
- Wfx.nChannels = _playChannelsPrioList[chan];
40+
- Wfx.nSamplesPerSec = freqs[freq];
41+
- Wfx.nBlockAlign = Wfx.nChannels * Wfx.wBitsPerSample / 8;
42+
- Wfx.nAvgBytesPerSec = Wfx.nSamplesPerSec * Wfx.nBlockAlign;
43+
+ Wfx.Format.nChannels = _playChannelsPrioList[chan];
44+
+ Wfx.Format.nSamplesPerSec = freqs[freq];
45+
+ Wfx.Format.nBlockAlign =
46+
+ Wfx.Format.nChannels * Wfx.Format.wBitsPerSample / 8;
47+
+ Wfx.Format.nAvgBytesPerSec =
48+
+ Wfx.Format.nSamplesPerSec * Wfx.Format.nBlockAlign;
2449
// If the method succeeds and the audio endpoint device supports the
2550
// specified stream format, it returns S_OK. If the method succeeds and
2651
// provides a closest match to the specified format, it returns S_FALSE.
27-
+ WAVEFORMATEX* pWfxClosestMatch = NULL;
28-
hr = _ptrClientOut->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &Wfx,
29-
&pWfxClosestMatch);
52+
- hr = _ptrClientOut->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &Wfx,
53+
- &pWfxClosestMatch);
54+
+ WAVEFORMATEXTENSIBLE* pWfxClosestMatch = NULL;
55+
+ hr = _ptrClientOut->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
56+
+ (WAVEFORMATEX*)&Wfx,
57+
+ (WAVEFORMATEX**)&pWfxClosestMatch);
3058
if (hr == S_OK) {
31-
@@ -1908,8 +1909,12 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
59+
break;
60+
} else {
61+
if (pWfxClosestMatch) {
62+
- RTC_LOG(LS_INFO) << "nChannels=" << Wfx.nChannels
63+
- << ", nSamplesPerSec=" << Wfx.nSamplesPerSec
64+
+ RTC_LOG(LS_INFO) << "nChannels=" << Wfx.Format.nChannels
65+
+ << ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
66+
<< " is not supported. Closest match: "
3267
"nChannels="
33-
<< pWfxClosestMatch->nChannels << ", nSamplesPerSec="
34-
<< pWfxClosestMatch->nSamplesPerSec;
68+
- << pWfxClosestMatch->nChannels << ", nSamplesPerSec="
69+
- << pWfxClosestMatch->nSamplesPerSec;
3570
- CoTaskMemFree(pWfxClosestMatch);
3671
- pWfxClosestMatch = NULL;
72+
+ << pWfxClosestMatch->Format.nChannels << ", nSamplesPerSec="
73+
+ << pWfxClosestMatch->Format.nSamplesPerSec;
3774
+
3875
+ if (pInitWfxClosestMatch) {
3976
+ CoTaskMemFree(pWfxClosestMatch);
4077
+ } else {
4178
+ pInitWfxClosestMatch = pWfxClosestMatch;
4279
+ }
4380
} else {
44-
RTC_LOG(LS_INFO) << "nChannels=" << Wfx.nChannels
45-
<< ", nSamplesPerSec=" << Wfx.nSamplesPerSec
46-
@@ -1924,6 +1929,18 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
81+
- RTC_LOG(LS_INFO) << "nChannels=" << Wfx.nChannels
82+
- << ", nSamplesPerSec=" << Wfx.nSamplesPerSec
83+
+ RTC_LOG(LS_INFO) << "nChannels=" << Wfx.Format.nChannels
84+
+ << ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
85+
<< " is not supported. No closest match.";
86+
}
87+
}
88+
@@ -1924,26 +1935,42 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
4789
// TODO(andrew): what happens in the event of failure in the above loop?
4890
// Is _ptrClientOut->Initialize expected to fail?
4991
// Same in InitRecording().
5092
+
5193
+ if (pInitWfxClosestMatch) {
5294
+ // Set up the closest match, and rely on the voice engine to resample. (roxanneskelly)
53-
+ Wfx.wFormatTag = WAVE_FORMAT_PCM;
54-
+ Wfx.wBitsPerSample = 16;
55-
+ Wfx.cbSize = 0;
56-
+ Wfx.nChannels = pInitWfxClosestMatch->nChannels;
57-
+ Wfx.nSamplesPerSec = pInitWfxClosestMatch->nSamplesPerSec;
58-
+ Wfx.nBlockAlign = pInitWfxClosestMatch->nBlockAlign;
59-
+ Wfx.nAvgBytesPerSec = pInitWfxClosestMatch->nAvgBytesPerSec;
95+
+ CopyMemory(&Wfx, pInitWfxClosestMatch, sizeof(Wfx));
96+
+ Wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
97+
+ Wfx.Format.wBitsPerSample = 16; // force it to 16 bits per sample
98+
+ Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
99+
+ Wfx.Format.nChannels = 2;
100+
+ Wfx.Format.nBlockAlign =
101+
+ Wfx.Format.nChannels * Wfx.Format.wBitsPerSample / 8;
102+
+ Wfx.Format.nAvgBytesPerSec =
103+
+ Wfx.Format.nSamplesPerSec * Wfx.Format.nBlockAlign;
60104
+ hr = S_OK;
61105
+ }
62106
if (hr == S_OK) {
63-
_playAudioFrameSize = Wfx.nBlockAlign;
107+
- _playAudioFrameSize = Wfx.nBlockAlign;
108+
+ _playAudioFrameSize = Wfx.Format.nBlockAlign;
64109
// Block size is the number of samples each channel in 10ms.
65-
@@ -2031,7 +2048,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
110+
- _playBlockSize = Wfx.nSamplesPerSec / 100;
111+
- _playSampleRate = Wfx.nSamplesPerSec;
112+
+ _playBlockSize = Wfx.Format.nSamplesPerSec / 100;
113+
+ _playSampleRate = Wfx.Format.nSamplesPerSec;
114+
_devicePlaySampleRate =
115+
- Wfx.nSamplesPerSec; // The device itself continues to run at 44.1 kHz.
116+
- _devicePlayBlockSize = Wfx.nSamplesPerSec / 100;
117+
- _playChannels = Wfx.nChannels;
118+
+ Wfx.Format
119+
+ .nSamplesPerSec; // The device itself continues to run at 44.1 kHz.
120+
+ _devicePlayBlockSize = Wfx.Format.nSamplesPerSec / 100;
121+
+ _playChannels = Wfx.Format.nChannels;
122+
123+
RTC_LOG(LS_VERBOSE) << "VoE selected this rendering format:";
124+
RTC_LOG(LS_VERBOSE) << "wFormatTag : 0x"
125+
- << webrtc::ToHex(Wfx.wFormatTag) << " ("
126+
- << Wfx.wFormatTag << ")";
127+
- RTC_LOG(LS_VERBOSE) << "nChannels : " << Wfx.nChannels;
128+
- RTC_LOG(LS_VERBOSE) << "nSamplesPerSec : " << Wfx.nSamplesPerSec;
129+
- RTC_LOG(LS_VERBOSE) << "nAvgBytesPerSec : " << Wfx.nAvgBytesPerSec;
130+
- RTC_LOG(LS_VERBOSE) << "nBlockAlign : " << Wfx.nBlockAlign;
131+
- RTC_LOG(LS_VERBOSE) << "wBitsPerSample : " << Wfx.wBitsPerSample;
132+
- RTC_LOG(LS_VERBOSE) << "cbSize : " << Wfx.cbSize;
133+
+ << webrtc::ToHex(Wfx.Format.wFormatTag) << " ("
134+
+ << Wfx.Format.wFormatTag << ")";
135+
+ RTC_LOG(LS_VERBOSE) << "nChannels : " << Wfx.Format.nChannels;
136+
+ RTC_LOG(LS_VERBOSE) << "nSamplesPerSec : " << Wfx.Format.nSamplesPerSec;
137+
+ RTC_LOG(LS_VERBOSE) << "nAvgBytesPerSec : "
138+
+ << Wfx.Format.nAvgBytesPerSec;
139+
+ RTC_LOG(LS_VERBOSE) << "nBlockAlign : " << Wfx.Format.nBlockAlign;
140+
+ RTC_LOG(LS_VERBOSE) << "wBitsPerSample : " << Wfx.Format.wBitsPerSample;
141+
+ RTC_LOG(LS_VERBOSE) << "cbSize : " << Wfx.Format.cbSize;
142+
RTC_LOG(LS_VERBOSE) << "Additional settings:";
143+
RTC_LOG(LS_VERBOSE) << "_playAudioFrameSize: " << _playAudioFrameSize;
144+
RTC_LOG(LS_VERBOSE) << "_playBlockSize : " << _playBlockSize;
145+
@@ -1980,12 +2007,14 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
146+
}
147+
hr = _ptrClientOut->Initialize(
148+
AUDCLNT_SHAREMODE_SHARED, // share Audio Engine with other applications
149+
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, // processing of the audio buffer by
150+
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | // processing of the audio buffer by
151+
// the client will be event driven
152+
+ AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
153+
+ AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
154+
hnsBufferDuration, // requested buffer capacity as a time value (in
155+
// 100-nanosecond units)
156+
0, // periodicity
157+
- &Wfx, // selected wave format
158+
+ (WAVEFORMATEX *)&Wfx, // selected wave format
159+
NULL); // session GUID
160+
161+
if (FAILED(hr)) {
162+
@@ -2031,7 +2060,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
66163
_playIsInitialized = true;
67164

68165
CoTaskMemFree(pWfxOut);
@@ -71,7 +168,7 @@ index f1cc0474fc..ffb0b159b1 100644
71168

72169
RTC_LOG(LS_VERBOSE) << "render side is now initialized";
73170
return 0;
74-
@@ -2039,7 +2056,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
171+
@@ -2039,7 +2068,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
75172
Exit:
76173
_TraceCOMError(hr);
77174
CoTaskMemFree(pWfxOut);
@@ -80,16 +177,16 @@ index f1cc0474fc..ffb0b159b1 100644
80177
SAFE_RELEASE(_ptrClientOut);
81178
SAFE_RELEASE(_ptrRenderClient);
82179
return -1;
83-
@@ -2163,7 +2180,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
180+
@@ -2163,7 +2192,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
84181
HRESULT hr = S_OK;
85182
WAVEFORMATEX* pWfxIn = NULL;
86183
WAVEFORMATEXTENSIBLE Wfx = WAVEFORMATEXTENSIBLE();
87184
- WAVEFORMATEX* pWfxClosestMatch = NULL;
88-
+ WAVEFORMATEX* pInitWfxClosestMatch = NULL;
185+
+ WAVEFORMATEXTENSIBLE* pInitWfxClosestMatch = NULL;
89186

90187
// Create COM object with IAudioClient interface.
91188
SAFE_RELEASE(_ptrClientIn);
92-
@@ -2201,7 +2218,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
189+
@@ -2201,7 +2230,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
93190
Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
94191
Wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
95192

@@ -98,20 +195,30 @@ index f1cc0474fc..ffb0b159b1 100644
98195
hr = S_FALSE;
99196

100197
// Iterate over frequencies and channels, in order of priority
101-
@@ -2218,6 +2235,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
198+
@@ -2218,8 +2247,10 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
102199
// If the method succeeds and the audio endpoint device supports the
103200
// specified stream format, it returns S_OK. If the method succeeds and
104201
// provides a closest match to the specified format, it returns S_FALSE.
105-
+ WAVEFORMATEX* pWfxClosestMatch = NULL;
106-
hr = _ptrClientIn->IsFormatSupported(
107-
AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&Wfx, &pWfxClosestMatch);
202+
- hr = _ptrClientIn->IsFormatSupported(
203+
- AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&Wfx, &pWfxClosestMatch);
204+
+ WAVEFORMATEXTENSIBLE* pWfxClosestMatch = NULL;
205+
+ hr = _ptrClientIn->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
206+
+ (WAVEFORMATEX*)&Wfx,
207+
+ (WAVEFORMATEX**)&pWfxClosestMatch);
108208
if (hr == S_OK) {
109-
@@ -2230,8 +2248,11 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
209+
break;
210+
} else {
211+
@@ -2228,10 +2259,14 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
212+
<< ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
213+
<< " is not supported. Closest match: "
110214
"nChannels="
111-
<< pWfxClosestMatch->nChannels << ", nSamplesPerSec="
112-
<< pWfxClosestMatch->nSamplesPerSec;
215+
- << pWfxClosestMatch->nChannels << ", nSamplesPerSec="
216+
- << pWfxClosestMatch->nSamplesPerSec;
113217
- CoTaskMemFree(pWfxClosestMatch);
114218
- pWfxClosestMatch = NULL;
219+
+ << pWfxClosestMatch->Format.nChannels
220+
+ << ", nSamplesPerSec="
221+
+ << pWfxClosestMatch->Format.nSamplesPerSec;
115222
+ if (pInitWfxClosestMatch) {
116223
+ CoTaskMemFree(pWfxClosestMatch);
117224
+ } else {
@@ -120,31 +227,38 @@ index f1cc0474fc..ffb0b159b1 100644
120227
} else {
121228
RTC_LOG(LS_INFO) << "nChannels=" << Wfx.Format.nChannels
122229
<< ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
123-
@@ -2242,7 +2263,22 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
230+
@@ -2242,7 +2277,20 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
124231
if (hr == S_OK)
125232
break;
126233
}
127234
-
128235
+ if (pInitWfxClosestMatch) {
129236
+ // Set up the closest match, and rely on the voice engine to resample.
130237
+ // (roxanneskelly)
131-
+ Wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
132-
+ Wfx.Format.wBitsPerSample = 16;
133-
+ Wfx.Format.cbSize = 22;
134-
+ Wfx.dwChannelMask = 0;
135-
+ Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
238+
+ CopyMemory(&Wfx, pInitWfxClosestMatch, sizeof(Wfx));
136239
+ Wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
137-
+
138-
+ Wfx.Format.nChannels = pInitWfxClosestMatch->nChannels;
139-
+ Wfx.Format.nSamplesPerSec = pInitWfxClosestMatch->nSamplesPerSec;
140-
+ Wfx.Format.nBlockAlign = pInitWfxClosestMatch->nBlockAlign;
141-
+ Wfx.Format.nAvgBytesPerSec = pInitWfxClosestMatch->nAvgBytesPerSec;
240+
+ Wfx.Format.wBitsPerSample = 16; // force it to 16 bits per sample
241+
+ Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
242+
+ Wfx.Format.nChannels = 1;
243+
+ Wfx.Format.nBlockAlign =
244+
+ Wfx.Format.nChannels * Wfx.Format.wBitsPerSample / 8;
245+
+ Wfx.Format.nAvgBytesPerSec =
246+
+ Wfx.Format.nSamplesPerSec * Wfx.Format.nBlockAlign;
142247
+ hr = S_OK;
143248
+ }
144249
if (hr == S_OK) {
145250
_recAudioFrameSize = Wfx.Format.nBlockAlign;
146251
_recSampleRate = Wfx.Format.nSamplesPerSec;
147-
@@ -2321,7 +2357,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
252+
@@ -2270,6 +2318,8 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
253+
AUDCLNT_SHAREMODE_SHARED, // share Audio Engine with other applications
254+
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | // processing of the audio buffer by
255+
// the client will be event driven
256+
+ AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
257+
+ AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
258+
AUDCLNT_STREAMFLAGS_NOPERSIST, // volume and mute settings for an
259+
// audio session will not persist
260+
// across system restarts
261+
@@ -2321,7 +2371,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
148262
_recIsInitialized = true;
149263

150264
CoTaskMemFree(pWfxIn);
@@ -153,7 +267,7 @@ index f1cc0474fc..ffb0b159b1 100644
153267

154268
RTC_LOG(LS_VERBOSE) << "capture side is now initialized";
155269
return 0;
156-
@@ -2329,7 +2365,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
270+
@@ -2329,7 +2379,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
157271
Exit:
158272
_TraceCOMError(hr);
159273
CoTaskMemFree(pWfxIn);

0 commit comments

Comments
 (0)