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 |