Chromium Code Reviews| 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 } // 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |