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 k100nsInMillisecond = 10000; |
Wez
2012/08/16 20:20:20
nit: k100nsPerMillisecond, to avoid ambiguity over
kxing
2012/08/16 20:38:46
Done.
| |
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 kMinTimerInterval = 30; | |
41 | |
42 // Upper bound for the timer precision error, in milliseconds. | |
43 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. | |
44 const int kMaxExpectedTimerLag = 30; | |
37 } // namespace | 45 } // namespace |
38 | 46 |
39 namespace remoting { | 47 namespace remoting { |
40 | 48 |
41 class AudioCapturerWin : public AudioCapturer { | 49 class AudioCapturerWin : public AudioCapturer { |
42 public: | 50 public: |
43 AudioCapturerWin(); | 51 AudioCapturerWin(); |
44 virtual ~AudioCapturerWin(); | 52 virtual ~AudioCapturerWin(); |
45 | 53 |
46 // AudioCapturer interface. | 54 // AudioCapturer interface. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 LOG(ERROR) << "Failed to get an IAudioClient. Error " << hr; | 129 LOG(ERROR) << "Failed to get an IAudioClient. Error " << hr; |
122 return false; | 130 return false; |
123 } | 131 } |
124 | 132 |
125 REFERENCE_TIME device_period; | 133 REFERENCE_TIME device_period; |
126 hr = audio_client_->GetDevicePeriod(&device_period, NULL); | 134 hr = audio_client_->GetDevicePeriod(&device_period, NULL); |
127 if (FAILED(hr)) { | 135 if (FAILED(hr)) { |
128 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr; | 136 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr; |
129 return false; | 137 return false; |
130 } | 138 } |
139 // We round up, if |device_period| / |k100nsInMillisecond| | |
140 // is not a whole number. | |
141 int device_period_in_milliseconds = | |
142 1 + (device_period - 1) / k100nsInMillisecond; | |
Wez
2012/08/16 20:20:20
nit: Bracket the division to make it clear to the
kxing
2012/08/16 20:38:46
Done.
| |
131 audio_device_period_ = base::TimeDelta::FromMilliseconds( | 143 audio_device_period_ = base::TimeDelta::FromMilliseconds( |
132 device_period / kChannels / kHnsToMs); | 144 std::max(device_period_in_milliseconds, kMinTimerInterval)); |
133 | 145 |
134 // Get the wave format. | 146 // Get the wave format. |
135 hr = audio_client_->GetMixFormat(&wave_format_ex_); | 147 hr = audio_client_->GetMixFormat(&wave_format_ex_); |
136 if (FAILED(hr)) { | 148 if (FAILED(hr)) { |
137 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; | 149 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; |
138 return false; | 150 return false; |
139 } | 151 } |
140 | 152 |
141 // Set the wave format | 153 // Set the wave format |
142 switch (wave_format_ex_->wFormatTag) { | 154 switch (wave_format_ex_->wFormatTag) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
186 return false; | 198 return false; |
187 } | 199 } |
188 break; | 200 break; |
189 } | 201 } |
190 default: | 202 default: |
191 LOG(ERROR) << "Failed to force 16-bit PCM"; | 203 LOG(ERROR) << "Failed to force 16-bit PCM"; |
192 return false; | 204 return false; |
193 } | 205 } |
194 | 206 |
195 // Initialize the IAudioClient. | 207 // Initialize the IAudioClient. |
196 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, | 208 hr = audio_client_->Initialize( |
197 AUDCLNT_STREAMFLAGS_LOOPBACK, | 209 AUDCLNT_SHAREMODE_SHARED, |
198 0, | 210 AUDCLNT_STREAMFLAGS_LOOPBACK, |
199 0, | 211 (kMaxExpectedTimerLag + audio_device_period_.InMilliseconds()) * |
200 wave_format_ex_, | 212 k100nsInMillisecond, |
201 NULL); | 213 0, |
214 wave_format_ex_, | |
215 NULL); | |
202 if (FAILED(hr)) { | 216 if (FAILED(hr)) { |
203 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; | 217 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; |
204 return false; | 218 return false; |
205 } | 219 } |
206 | 220 |
207 // Get an IAudioCaptureClient. | 221 // Get an IAudioCaptureClient. |
208 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), | 222 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), |
209 audio_capture_client_.ReceiveVoid()); | 223 audio_capture_client_.ReceiveVoid()); |
210 if (FAILED(hr)) { | 224 if (FAILED(hr)) { |
211 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr; | 225 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; | 282 UINT32 frames; |
269 DWORD flags; | 283 DWORD flags; |
270 hr = audio_capture_client_->GetBuffer( | 284 hr = audio_capture_client_->GetBuffer( |
271 &data, &frames, &flags, NULL, NULL); | 285 &data, &frames, &flags, NULL, NULL); |
272 if (FAILED(hr)) { | 286 if (FAILED(hr)) { |
273 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; | 287 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; |
274 return; | 288 return; |
275 } | 289 } |
276 | 290 |
277 if (!IsPacketOfSilence( | 291 if (!IsPacketOfSilence( |
278 reinterpret_cast<const int16*>(data), | 292 reinterpret_cast<const int16*>(data), |
279 frames * kChannels)) { | 293 frames * kChannels)) { |
280 scoped_ptr<AudioPacket> packet = | 294 scoped_ptr<AudioPacket> packet = |
281 scoped_ptr<AudioPacket>(new AudioPacket()); | 295 scoped_ptr<AudioPacket>(new AudioPacket()); |
282 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | 296 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); |
283 packet->set_sampling_rate(sampling_rate_); | 297 packet->set_sampling_rate(sampling_rate_); |
284 packet->set_bytes_per_sample( | 298 packet->set_bytes_per_sample( |
285 static_cast<AudioPacket::BytesPerSample>(sizeof(int16))); | 299 static_cast<AudioPacket::BytesPerSample>(sizeof(int16))); |
286 packet->set_encoding(AudioPacket::ENCODING_RAW); | 300 packet->set_encoding(AudioPacket::ENCODING_RAW); |
287 | 301 |
288 callback_.Run(packet.Pass()); | 302 callback_.Run(packet.Pass()); |
289 } | 303 } |
(...skipping 16 matching lines...) Expand all Loading... | |
306 return false; | 320 return false; |
307 } | 321 } |
308 return true; | 322 return true; |
309 } | 323 } |
310 | 324 |
311 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 325 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
312 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); | 326 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); |
313 } | 327 } |
314 | 328 |
315 } // namespace remoting | 329 } // namespace remoting |
OLD | NEW |