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 <windows.h> | 5 #include <windows.h> |
| 6 #include <audioclient.h> | 6 #include <audioclient.h> |
| 7 #include <avrt.h> | 7 #include <avrt.h> |
| 8 #include <mmdeviceapi.h> | 8 #include <mmdeviceapi.h> |
| 9 #include <mmreg.h> | 9 #include <mmreg.h> |
| 10 #include <mmsystem.h> | 10 #include <mmsystem.h> |
| 11 | 11 |
| 12 #include <algorithm> | |
| 12 #include <stdlib.h> | 13 #include <stdlib.h> |
| 13 | 14 |
| 14 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
| 15 #include "base/logging.h" | 16 #include "base/logging.h" |
| 16 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
| 17 #include "base/message_loop.h" | 18 #include "base/message_loop.h" |
| 18 #include "base/timer.h" | 19 #include "base/timer.h" |
| 19 #include "base/win/scoped_co_mem.h" | 20 #include "base/win/scoped_co_mem.h" |
| 20 #include "base/win/scoped_com_initializer.h" | 21 #include "base/win/scoped_com_initializer.h" |
| 21 #include "base/win/scoped_comptr.h" | 22 #include "base/win/scoped_comptr.h" |
| 22 #include "remoting/host/audio_capturer.h" | 23 #include "remoting/host/audio_capturer.h" |
| 23 #include "remoting/proto/audio.pb.h" | 24 #include "remoting/proto/audio.pb.h" |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 const int kChannels = 2; | 27 const int kChannels = 2; |
| 27 const int kBitsPerSample = 16; | 28 const int kBitsPerSample = 16; |
| 28 const int kBitsPerByte = 8; | 29 const int kBitsPerByte = 8; |
| 29 // Conversion factor from 100ns to 1ms. | 30 // Conversion factor from 100ns to 1ms. |
| 30 const int kHnsToMs = 10000; | 31 const int kHnsToMs = 10000; |
|
Wez
2012/08/16 18:49:36
nit: I'd suggest calling this k100nsToMs, but chec
Wez
2012/08/16 18:49:36
nit: Shouldn't this be kMsTo100ns or kMillisecondI
kxing
2012/08/16 20:17:21
Done.
kxing
2012/08/16 20:17:21
Yeah, I'll name it to k100nsInMillisecond, because
| |
| 31 | 32 |
| 32 // Tolerance for catching packets of silence. If all samples have absolute | 33 // Tolerance for catching packets of silence. If all samples have absolute |
| 33 // value less than this threshold, the packet will be counted as a packet of | 34 // value less than this threshold, the packet will be counted as a packet of |
| 34 // silence. A value of 2 was chosen, because Windows can give samples of 1 and | 35 // silence. A value of 2 was chosen, because Windows can give samples of 1 and |
| 35 // -1, even when no audio is playing. | 36 // -1, even when no audio is playing. |
| 36 const int kSilenceThreshold = 2; | 37 const int kSilenceThreshold = 2; |
| 38 | |
| 39 // Lower bound for timer intervals, in milliseconds. | |
| 40 const int kMinTimerInteveral = 30; | |
|
Wez
2012/08/16 18:49:36
typo: kMinTimerInterval
kxing
2012/08/16 20:17:21
Done.
| |
| 41 | |
| 42 // Upper bound for the timer precision error, in milliseconds. | |
|
Wez
2012/08/16 18:49:36
nit: Clarify where this value comes from, even if
kxing
2012/08/16 20:17:21
Done.
| |
| 43 const int kMaxTimerLag = 30; | |
|
Wez
2012/08/16 18:49:36
nit: Consider calling this kMaxExpectedTimerLag; i
kxing
2012/08/16 20:17:21
Done.
| |
| 37 } // namespace | 44 } // namespace |
| 38 | 45 |
| 39 namespace remoting { | 46 namespace remoting { |
| 40 | 47 |
| 41 class AudioCapturerWin : public AudioCapturer { | 48 class AudioCapturerWin : public AudioCapturer { |
| 42 public: | 49 public: |
| 43 AudioCapturerWin(); | 50 AudioCapturerWin(); |
| 44 virtual ~AudioCapturerWin(); | 51 virtual ~AudioCapturerWin(); |
| 45 | 52 |
| 46 // AudioCapturer interface. | 53 // AudioCapturer interface. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 return false; | 129 return false; |
| 123 } | 130 } |
| 124 | 131 |
| 125 REFERENCE_TIME device_period; | 132 REFERENCE_TIME device_period; |
| 126 hr = audio_client_->GetDevicePeriod(&device_period, NULL); | 133 hr = audio_client_->GetDevicePeriod(&device_period, NULL); |
| 127 if (FAILED(hr)) { | 134 if (FAILED(hr)) { |
| 128 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr; | 135 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr; |
| 129 return false; | 136 return false; |
| 130 } | 137 } |
| 131 audio_device_period_ = base::TimeDelta::FromMilliseconds( | 138 audio_device_period_ = base::TimeDelta::FromMilliseconds( |
| 132 device_period / kChannels / kHnsToMs); | 139 std::max(static_cast<int>(device_period / kHnsToMs), kMinTimerInteveral)); |
|
Wez
2012/08/16 18:49:36
nit: If |device_period| is not an integer number o
kxing
2012/08/16 20:17:21
Done.
| |
| 133 | 140 |
| 134 // Get the wave format. | 141 // Get the wave format. |
| 135 hr = audio_client_->GetMixFormat(&wave_format_ex_); | 142 hr = audio_client_->GetMixFormat(&wave_format_ex_); |
| 136 if (FAILED(hr)) { | 143 if (FAILED(hr)) { |
| 137 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; | 144 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; |
| 138 return false; | 145 return false; |
| 139 } | 146 } |
| 140 | 147 |
| 141 // Set the wave format | 148 // Set the wave format |
| 142 switch (wave_format_ex_->wFormatTag) { | 149 switch (wave_format_ex_->wFormatTag) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 return false; | 193 return false; |
| 187 } | 194 } |
| 188 break; | 195 break; |
| 189 } | 196 } |
| 190 default: | 197 default: |
| 191 LOG(ERROR) << "Failed to force 16-bit PCM"; | 198 LOG(ERROR) << "Failed to force 16-bit PCM"; |
| 192 return false; | 199 return false; |
| 193 } | 200 } |
| 194 | 201 |
| 195 // Initialize the IAudioClient. | 202 // Initialize the IAudioClient. |
| 196 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, | 203 hr = audio_client_->Initialize( |
| 197 AUDCLNT_STREAMFLAGS_LOOPBACK, | 204 AUDCLNT_SHAREMODE_SHARED, |
| 198 0, | 205 AUDCLNT_STREAMFLAGS_LOOPBACK, |
| 199 0, | 206 (kMaxTimerLag + audio_device_period_.InMilliseconds()) * kHnsToMs, |
|
Wez
2012/08/16 18:49:36
You're multiplying a value in milliseconds by the
kxing
2012/08/16 20:17:21
Done.
| |
| 200 wave_format_ex_, | 207 0, |
| 201 NULL); | 208 wave_format_ex_, |
| 209 NULL); | |
| 202 if (FAILED(hr)) { | 210 if (FAILED(hr)) { |
| 203 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; | 211 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; |
| 204 return false; | 212 return false; |
| 205 } | 213 } |
| 206 | 214 |
| 207 // Get an IAudioCaptureClient. | 215 // Get an IAudioCaptureClient. |
| 208 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), | 216 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), |
| 209 audio_capture_client_.ReceiveVoid()); | 217 audio_capture_client_.ReceiveVoid()); |
| 210 if (FAILED(hr)) { | 218 if (FAILED(hr)) { |
| 211 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr; | 219 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 UINT32 frames; | 276 UINT32 frames; |
| 269 DWORD flags; | 277 DWORD flags; |
| 270 hr = audio_capture_client_->GetBuffer( | 278 hr = audio_capture_client_->GetBuffer( |
| 271 &data, &frames, &flags, NULL, NULL); | 279 &data, &frames, &flags, NULL, NULL); |
| 272 if (FAILED(hr)) { | 280 if (FAILED(hr)) { |
| 273 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; | 281 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; |
| 274 return; | 282 return; |
| 275 } | 283 } |
| 276 | 284 |
| 277 if (!IsPacketOfSilence( | 285 if (!IsPacketOfSilence( |
| 278 reinterpret_cast<const int16*>(data), | 286 reinterpret_cast<const int16*>(data), |
|
Wez
2012/08/16 18:49:36
nit: Indent reinterpret... by four spaces from the
kxing
2012/08/16 20:17:21
Done.
| |
| 279 frames * kChannels)) { | 287 frames * kChannels)) { |
|
Wez
2012/08/16 18:49:36
What's the rationale for performing the silence ch
kxing
2012/08/16 20:17:21
Yes, it's to avoid the memory copy.
| |
| 280 scoped_ptr<AudioPacket> packet = | 288 scoped_ptr<AudioPacket> packet = |
| 281 scoped_ptr<AudioPacket>(new AudioPacket()); | 289 scoped_ptr<AudioPacket>(new AudioPacket()); |
| 282 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | 290 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); |
| 283 packet->set_sampling_rate(sampling_rate_); | 291 packet->set_sampling_rate(sampling_rate_); |
| 284 packet->set_bytes_per_sample( | 292 packet->set_bytes_per_sample( |
| 285 static_cast<AudioPacket::BytesPerSample>(sizeof(int16))); | 293 static_cast<AudioPacket::BytesPerSample>(sizeof(int16))); |
| 286 packet->set_encoding(AudioPacket::ENCODING_RAW); | 294 packet->set_encoding(AudioPacket::ENCODING_RAW); |
| 287 | 295 |
| 288 callback_.Run(packet.Pass()); | 296 callback_.Run(packet.Pass()); |
| 289 } | 297 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 306 return false; | 314 return false; |
| 307 } | 315 } |
| 308 return true; | 316 return true; |
| 309 } | 317 } |
| 310 | 318 |
| 311 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 319 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
| 312 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); | 320 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); |
| 313 } | 321 } |
| 314 | 322 |
| 315 } // namespace remoting | 323 } // namespace remoting |
| OLD | NEW |