Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: remoting/host/audio_capturer_win.cc

Issue 2903153004: [Chromoting] Implement down mixing in AudioPump (Closed)
Patch Set: Resolve review comments Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/audio_capturer_win.h" 5 #include "remoting/host/audio_capturer_win.h"
6 6
7 #include <avrt.h> 7 #include <avrt.h>
8 #include <mmreg.h> 8 #include <mmreg.h>
9 #include <mmsystem.h> 9 #include <mmsystem.h>
10 #include <objbase.h> 10 #include <objbase.h>
11 #include <stdint.h> 11 #include <stdint.h>
12 #include <stdlib.h> 12 #include <stdlib.h>
13 #include <windows.h> 13 #include <windows.h>
14 14
15 #include <algorithm> 15 #include <algorithm>
16 #include <utility> 16 #include <utility>
17 17
18 #include "base/logging.h" 18 #include "base/logging.h"
19 #include "base/memory/ptr_util.h" 19 #include "base/memory/ptr_util.h"
20 #include "base/synchronization/lock.h" 20 #include "base/synchronization/lock.h"
21 #include "remoting/host/win/default_audio_device_change_detector.h" 21 #include "remoting/host/win/default_audio_device_change_detector.h"
22 22
23 namespace { 23 namespace {
24 const int kChannels = 2;
25 const int kBytesPerSample = 2; 24 const int kBytesPerSample = 2;
26 const int kBitsPerSample = kBytesPerSample * 8; 25 const int kBitsPerSample = kBytesPerSample * 8;
27 // Conversion factor from 100ns to 1ms. 26 // Conversion factor from 100ns to 1ms.
28 const int k100nsPerMillisecond = 10000; 27 const int k100nsPerMillisecond = 10000;
29 28
30 // Tolerance for catching packets of silence. If all samples have absolute 29 // Tolerance for catching packets of silence. If all samples have absolute
31 // value less than this threshold, the packet will be counted as a packet of 30 // value less than this threshold, the packet will be counted as a packet of
32 // silence. A value of 2 was chosen, because Windows can give samples of 1 and 31 // silence. A value of 2 was chosen, because Windows can give samples of 1 and
33 // -1, even when no audio is playing. 32 // -1, even when no audio is playing.
34 const int kSilenceThreshold = 2; 33 const int kSilenceThreshold = 2;
35 34
36 // Lower bound for timer intervals, in milliseconds. 35 // Lower bound for timer intervals, in milliseconds.
37 const int kMinTimerInterval = 30; 36 const int kMinTimerInterval = 30;
38 37
39 // Upper bound for the timer precision error, in milliseconds. 38 // Upper bound for the timer precision error, in milliseconds.
40 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. 39 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe.
41 const int kMaxExpectedTimerLag = 30; 40 const int kMaxExpectedTimerLag = 30;
41
42 } // namespace 42 } // namespace
43 43
44 namespace remoting { 44 namespace remoting {
45 45
46 AudioCapturerWin::AudioCapturerWin() 46 AudioCapturerWin::AudioCapturerWin()
47 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), 47 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
48 volume_filter_(kSilenceThreshold), 48 volume_filter_(kSilenceThreshold),
49 last_capture_error_(S_OK) { 49 last_capture_error_(S_OK) {
50 thread_checker_.DetachFromThread(); 50 thread_checker_.DetachFromThread();
51 } 51 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 audio_device_period_ = base::TimeDelta::FromMilliseconds( 143 audio_device_period_ = base::TimeDelta::FromMilliseconds(
144 std::max(device_period_in_milliseconds, kMinTimerInterval)); 144 std::max(device_period_in_milliseconds, kMinTimerInterval));
145 145
146 // Get the wave format. 146 // Get the wave format.
147 hr = audio_client_->GetMixFormat(&wave_format_ex_); 147 hr = audio_client_->GetMixFormat(&wave_format_ex_);
148 if (FAILED(hr)) { 148 if (FAILED(hr)) {
149 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; 149 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr;
150 return false; 150 return false;
151 } 151 }
152 152
153 // Set the wave format 153 if (wave_format_ex_->wFormatTag != WAVE_FORMAT_IEEE_FLOAT &&
154 switch (wave_format_ex_->wFormatTag) { 154 wave_format_ex_->wFormatTag != WAVE_FORMAT_PCM &&
155 case WAVE_FORMAT_IEEE_FLOAT: 155 wave_format_ex_->wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
156 // Intentional fall-through. 156 LOG(ERROR) << "Failed to force 16-bit PCM";
157 case WAVE_FORMAT_PCM: 157 return false;
158 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) { 158 }
159 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
160 return false;
161 }
162 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
163 wave_format_ex_->nSamplesPerSec);
164 159
165 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM; 160 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) {
166 wave_format_ex_->nChannels = kChannels; 161 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz. "
167 wave_format_ex_->wBitsPerSample = kBitsPerSample; 162 << wave_format_ex_->nSamplesPerSec;
168 wave_format_ex_->nBlockAlign = kChannels * kBytesPerSample; 163 return false;
169 wave_format_ex_->nAvgBytesPerSec = 164 }
170 sampling_rate_ * kChannels * kBytesPerSample;
171 break;
172 case WAVE_FORMAT_EXTENSIBLE: {
173 PWAVEFORMATEXTENSIBLE wave_format_extensible =
174 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
175 static_cast<WAVEFORMATEX*>(wave_format_ex_));
176 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
177 wave_format_extensible->SubFormat)) {
178 if (!AudioCapturer::IsValidSampleRate(
179 wave_format_extensible->Format.nSamplesPerSec)) {
180 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
181 return false;
182 }
183 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
184 wave_format_extensible->Format.nSamplesPerSec);
185 165
186 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 166 // We support from mono to 7.1. This check should be consistent with
187 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample; 167 // AudioPacket::Channels.
168 if (wave_format_ex_->nChannels > 8 || wave_format_ex_->nChannels <= 0) {
169 LOG(ERROR) << "Unsupported channels " << wave_format_ex_->nChannels;
170 return false;
171 }
188 172
189 wave_format_extensible->Format.nChannels = kChannels; 173 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
190 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_; 174 wave_format_ex_->nSamplesPerSec);
191 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample; 175
192 wave_format_extensible->Format.nBlockAlign = 176 wave_format_ex_->wBitsPerSample = kBitsPerSample;
193 kChannels * kBytesPerSample; 177 wave_format_ex_->nBlockAlign = wave_format_ex_->nChannels * kBytesPerSample;
194 wave_format_extensible->Format.nAvgBytesPerSec = 178 wave_format_ex_->nAvgBytesPerSec =
195 sampling_rate_ * kChannels * kBytesPerSample; 179 sampling_rate_ * wave_format_ex_->nBlockAlign;
196 } else { 180
197 LOG(ERROR) << "Failed to force 16-bit samples"; 181 if (wave_format_ex_->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
198 return false; 182 PWAVEFORMATEXTENSIBLE wave_format_extensible =
199 } 183 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
200 break; 184 static_cast<WAVEFORMATEX*>(wave_format_ex_));
185 if (!IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
186 wave_format_extensible->SubFormat) &&
187 !IsEqualGUID(KSDATAFORMAT_SUBTYPE_PCM,
188 wave_format_extensible->SubFormat)) {
189 LOG(ERROR) << "Failed to force 16-bit samples";
190 return false;
201 } 191 }
202 default: 192
203 LOG(ERROR) << "Failed to force 16-bit PCM"; 193 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
204 return false; 194 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample;
195 } else {
196 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM;
205 } 197 }
206 198
207 // Initialize the IAudioClient. 199 // Initialize the IAudioClient.
208 hr = audio_client_->Initialize( 200 hr = audio_client_->Initialize(
209 AUDCLNT_SHAREMODE_SHARED, 201 AUDCLNT_SHAREMODE_SHARED,
210 AUDCLNT_STREAMFLAGS_LOOPBACK, 202 AUDCLNT_STREAMFLAGS_LOOPBACK,
211 (kMaxExpectedTimerLag + audio_device_period_.InMilliseconds()) * 203 (kMaxExpectedTimerLag + audio_device_period_.InMilliseconds()) *
212 k100nsPerMillisecond, 204 k100nsPerMillisecond,
213 0, 205 0,
214 wave_format_ex_, 206 wave_format_ex_,
(...skipping 11 matching lines...) Expand all
226 } 218 }
227 219
228 // Start the IAudioClient. 220 // Start the IAudioClient.
229 hr = audio_client_->Start(); 221 hr = audio_client_->Start();
230 if (FAILED(hr)) { 222 if (FAILED(hr)) {
231 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; 223 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr;
232 return false; 224 return false;
233 } 225 }
234 226
235 volume_filter_.ActivateBy(mm_device_.Get()); 227 volume_filter_.ActivateBy(mm_device_.Get());
236 volume_filter_.Initialize(sampling_rate_, kChannels); 228 volume_filter_.Initialize(sampling_rate_, wave_format_ex_->nChannels);
237 229
238 return true; 230 return true;
239 } 231 }
240 232
241 bool AudioCapturerWin::is_initialized() const { 233 bool AudioCapturerWin::is_initialized() const {
242 // All Com components should be initialized / deinitialized together. 234 // All Com components should be initialized / deinitialized together.
243 return !!audio_client_; 235 return !!audio_client_;
244 } 236 }
245 237
246 void AudioCapturerWin::DoCapture() { 238 void AudioCapturerWin::DoCapture() {
(...skipping 26 matching lines...) Expand all
273 nullptr); 265 nullptr);
274 if (FAILED(hr)) 266 if (FAILED(hr))
275 break; 267 break;
276 268
277 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) { 269 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) {
278 std::unique_ptr<AudioPacket> packet(new AudioPacket()); 270 std::unique_ptr<AudioPacket> packet(new AudioPacket());
279 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); 271 packet->add_data(data, frames * wave_format_ex_->nBlockAlign);
280 packet->set_encoding(AudioPacket::ENCODING_RAW); 272 packet->set_encoding(AudioPacket::ENCODING_RAW);
281 packet->set_sampling_rate(sampling_rate_); 273 packet->set_sampling_rate(sampling_rate_);
282 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); 274 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
283 packet->set_channels(AudioPacket::CHANNELS_STEREO); 275 // Only the count of channels is taken into account now, we should also
276 // consider dwChannelMask.
chcunningham 2017/06/08 16:39:45 as-is, what happens if you have a some mask (that
DaleCurtis 2017/06/08 17:05:47 I don't remember the details around channel masks,
Sergey Ulanov 2017/06/08 18:27:59 We do take into account nChannels, and number of b
Hzj_jie 2017/06/08 19:07:48 Thank you for the suggestion, but we do not always
chcunningham 2017/06/09 19:25:28 This is a key insight that I overlooked. I now app
Hzj_jie 2017/06/09 21:33:47 Done.
277 // TODO(zijiehe): Support also layouts.
chcunningham 2017/06/08 16:39:45 Not sure what this TODO means. Do you mean "Suppor
Hzj_jie 2017/06/08 19:07:48 Yes. Updated.
278 packet->set_channels(static_cast<AudioPacket::Channels>(
279 wave_format_ex_->nChannels));
284 280
285 callback_.Run(std::move(packet)); 281 callback_.Run(std::move(packet));
286 } 282 }
287 283
288 hr = audio_capture_client_->ReleaseBuffer(frames); 284 hr = audio_capture_client_->ReleaseBuffer(frames);
289 if (FAILED(hr)) 285 if (FAILED(hr))
290 break; 286 break;
291 } 287 }
292 288
293 // There is nothing to capture if the audio endpoint device has been unplugged 289 // There is nothing to capture if the audio endpoint device has been unplugged
(...skipping 11 matching lines...) Expand all
305 301
306 bool AudioCapturer::IsSupported() { 302 bool AudioCapturer::IsSupported() {
307 return true; 303 return true;
308 } 304 }
309 305
310 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { 306 std::unique_ptr<AudioCapturer> AudioCapturer::Create() {
311 return base::WrapUnique(new AudioCapturerWin()); 307 return base::WrapUnique(new AudioCapturerWin());
312 } 308 }
313 309
314 } // namespace remoting 310 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698