OLD | NEW |
---|---|
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 int ChooseChannels(int channel_count) { | |
joedow
2017/05/26 16:01:50
This function doesn't choose a channel, it convert
Hzj_jie
2017/05/26 20:08:03
Before this change, we always select stereo. But t
Sergey Ulanov
2017/05/26 22:24:45
If I understand correctly this function defines ch
Hzj_jie
2017/05/28 20:58:58
IMO, it's still worthy to have a shot: it won't wa
Sergey Ulanov
2017/06/05 18:03:19
I still don't think this is necessary. The problem
Hzj_jie
2017/06/06 03:21:42
Then I would prefer to rewrite the wave_format_ex_
chcunningham
2017/06/09 19:25:28
This is fine for this CL, but we have seen more th
Hzj_jie
2017/06/09 21:33:47
IMO, a long-term solution is to migrate to AudioIn
| |
43 using remoting::AudioPacket; | |
44 // The condition should match AudioPacket::Channels enum in audio.proto. | |
45 if (channel_count == AudioPacket::CHANNELS_MONO || | |
46 channel_count == AudioPacket::CHANNELS_STEREO || | |
47 channel_count == AudioPacket::CHANNELS_5_1 || | |
48 channel_count == AudioPacket::CHANNELS_6_1 || | |
49 channel_count == AudioPacket::CHANNELS_7_1) { | |
50 return channel_count; | |
51 } | |
52 return AudioPacket::CHANNELS_STEREO; | |
53 } | |
54 | |
42 } // namespace | 55 } // namespace |
43 | 56 |
44 namespace remoting { | 57 namespace remoting { |
45 | 58 |
46 AudioCapturerWin::AudioCapturerWin() | 59 AudioCapturerWin::AudioCapturerWin() |
47 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), | 60 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), |
48 volume_filter_(kSilenceThreshold), | 61 volume_filter_(kSilenceThreshold), |
49 last_capture_error_(S_OK) { | 62 last_capture_error_(S_OK) { |
50 thread_checker_.DetachFromThread(); | 63 thread_checker_.DetachFromThread(); |
51 } | 64 } |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 // Intentional fall-through. | 169 // Intentional fall-through. |
157 case WAVE_FORMAT_PCM: | 170 case WAVE_FORMAT_PCM: |
158 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) { | 171 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) { |
159 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz."; | 172 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz."; |
160 return false; | 173 return false; |
161 } | 174 } |
162 sampling_rate_ = static_cast<AudioPacket::SamplingRate>( | 175 sampling_rate_ = static_cast<AudioPacket::SamplingRate>( |
163 wave_format_ex_->nSamplesPerSec); | 176 wave_format_ex_->nSamplesPerSec); |
164 | 177 |
165 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM; | 178 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM; |
166 wave_format_ex_->nChannels = kChannels; | 179 wave_format_ex_->nChannels = ChooseChannels(wave_format_ex_->nChannels); |
167 wave_format_ex_->wBitsPerSample = kBitsPerSample; | 180 wave_format_ex_->wBitsPerSample = kBitsPerSample; |
168 wave_format_ex_->nBlockAlign = kChannels * kBytesPerSample; | 181 wave_format_ex_->nBlockAlign = |
182 wave_format_ex_->nChannels * kBytesPerSample; | |
169 wave_format_ex_->nAvgBytesPerSec = | 183 wave_format_ex_->nAvgBytesPerSec = |
170 sampling_rate_ * kChannels * kBytesPerSample; | 184 sampling_rate_ * wave_format_ex_->nChannels * kBytesPerSample; |
171 break; | 185 break; |
172 case WAVE_FORMAT_EXTENSIBLE: { | 186 case WAVE_FORMAT_EXTENSIBLE: { |
173 PWAVEFORMATEXTENSIBLE wave_format_extensible = | 187 PWAVEFORMATEXTENSIBLE wave_format_extensible = |
174 reinterpret_cast<WAVEFORMATEXTENSIBLE*>( | 188 reinterpret_cast<WAVEFORMATEXTENSIBLE*>( |
175 static_cast<WAVEFORMATEX*>(wave_format_ex_)); | 189 static_cast<WAVEFORMATEX*>(wave_format_ex_)); |
176 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, | 190 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, |
177 wave_format_extensible->SubFormat)) { | 191 wave_format_extensible->SubFormat)) { |
178 if (!AudioCapturer::IsValidSampleRate( | 192 if (!AudioCapturer::IsValidSampleRate( |
179 wave_format_extensible->Format.nSamplesPerSec)) { | 193 wave_format_extensible->Format.nSamplesPerSec)) { |
180 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz."; | 194 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz."; |
181 return false; | 195 return false; |
182 } | 196 } |
183 sampling_rate_ = static_cast<AudioPacket::SamplingRate>( | 197 sampling_rate_ = static_cast<AudioPacket::SamplingRate>( |
184 wave_format_extensible->Format.nSamplesPerSec); | 198 wave_format_extensible->Format.nSamplesPerSec); |
185 | 199 |
186 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | 200 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; |
187 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample; | 201 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample; |
188 | 202 |
189 wave_format_extensible->Format.nChannels = kChannels; | 203 wave_format_extensible->Format.nChannels = |
204 ChooseChannels(wave_format_extensible->Format.nChannels); | |
Sergey Ulanov
2017/05/26 22:24:45
If you change number of channels here then you pro
Hzj_jie
2017/05/28 20:58:59
According to MSDN, https://social.msdn.microsoft.c
Sergey Ulanov
2017/05/30 19:18:19
My point was that, if the API will never downmix t
Hzj_jie
2017/05/31 00:12:08
Got you. I will update both nChannels and dwChanne
Sergey Ulanov
2017/05/31 00:44:43
Is this useful given that we know that windows wil
Hzj_jie
2017/05/31 02:49:28
Trying to initialize in stereo does not really was
Sergey Ulanov
2017/06/05 18:03:19
I don't think it can cause any problems. It's reas
Hzj_jie
2017/06/06 03:21:42
Done.
| |
190 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_; | 205 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_; |
191 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample; | 206 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample; |
192 wave_format_extensible->Format.nBlockAlign = | 207 wave_format_extensible->Format.nBlockAlign = |
193 kChannels * kBytesPerSample; | 208 wave_format_extensible->Format.nChannels * kBytesPerSample; |
194 wave_format_extensible->Format.nAvgBytesPerSec = | 209 wave_format_extensible->Format.nAvgBytesPerSec = |
195 sampling_rate_ * kChannels * kBytesPerSample; | 210 sampling_rate_ * wave_format_extensible->Format.nChannels * |
211 kBytesPerSample; | |
196 } else { | 212 } else { |
197 LOG(ERROR) << "Failed to force 16-bit samples"; | 213 LOG(ERROR) << "Failed to force 16-bit samples"; |
198 return false; | 214 return false; |
199 } | 215 } |
200 break; | 216 break; |
201 } | 217 } |
202 default: | 218 default: |
203 LOG(ERROR) << "Failed to force 16-bit PCM"; | 219 LOG(ERROR) << "Failed to force 16-bit PCM"; |
204 return false; | 220 return false; |
205 } | 221 } |
(...skipping 20 matching lines...) Expand all Loading... | |
226 } | 242 } |
227 | 243 |
228 // Start the IAudioClient. | 244 // Start the IAudioClient. |
229 hr = audio_client_->Start(); | 245 hr = audio_client_->Start(); |
230 if (FAILED(hr)) { | 246 if (FAILED(hr)) { |
231 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 247 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
232 return false; | 248 return false; |
233 } | 249 } |
234 | 250 |
235 volume_filter_.ActivateBy(mm_device_.Get()); | 251 volume_filter_.ActivateBy(mm_device_.Get()); |
236 volume_filter_.Initialize(sampling_rate_, kChannels); | 252 volume_filter_.Initialize(sampling_rate_, wave_format_ex_->nChannels); |
237 | 253 |
238 return true; | 254 return true; |
239 } | 255 } |
240 | 256 |
241 bool AudioCapturerWin::is_initialized() const { | 257 bool AudioCapturerWin::is_initialized() const { |
242 // All Com components should be initialized / deinitialized together. | 258 // All Com components should be initialized / deinitialized together. |
243 return !!audio_client_; | 259 return !!audio_client_; |
244 } | 260 } |
245 | 261 |
246 void AudioCapturerWin::DoCapture() { | 262 void AudioCapturerWin::DoCapture() { |
(...skipping 26 matching lines...) Expand all Loading... | |
273 nullptr); | 289 nullptr); |
274 if (FAILED(hr)) | 290 if (FAILED(hr)) |
275 break; | 291 break; |
276 | 292 |
277 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) { | 293 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) { |
278 std::unique_ptr<AudioPacket> packet(new AudioPacket()); | 294 std::unique_ptr<AudioPacket> packet(new AudioPacket()); |
279 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | 295 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); |
280 packet->set_encoding(AudioPacket::ENCODING_RAW); | 296 packet->set_encoding(AudioPacket::ENCODING_RAW); |
281 packet->set_sampling_rate(sampling_rate_); | 297 packet->set_sampling_rate(sampling_rate_); |
282 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | 298 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); |
283 packet->set_channels(AudioPacket::CHANNELS_STEREO); | 299 packet->set_channels(static_cast<AudioPacket::Channels>( |
300 wave_format_ex_->nChannels)); | |
284 | 301 |
285 callback_.Run(std::move(packet)); | 302 callback_.Run(std::move(packet)); |
286 } | 303 } |
287 | 304 |
288 hr = audio_capture_client_->ReleaseBuffer(frames); | 305 hr = audio_capture_client_->ReleaseBuffer(frames); |
289 if (FAILED(hr)) | 306 if (FAILED(hr)) |
290 break; | 307 break; |
291 } | 308 } |
292 | 309 |
293 // There is nothing to capture if the audio endpoint device has been unplugged | 310 // There is nothing to capture if the audio endpoint device has been unplugged |
(...skipping 11 matching lines...) Expand all Loading... | |
305 | 322 |
306 bool AudioCapturer::IsSupported() { | 323 bool AudioCapturer::IsSupported() { |
307 return true; | 324 return true; |
308 } | 325 } |
309 | 326 |
310 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { | 327 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { |
311 return base::WrapUnique(new AudioCapturerWin()); | 328 return base::WrapUnique(new AudioCapturerWin()); |
312 } | 329 } |
313 | 330 |
314 } // namespace remoting | 331 } // namespace remoting |
OLD | NEW |