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> |
(...skipping 16 matching lines...) Expand all Loading... | |
27 const int kBitsPerSample = 16; | 27 const int kBitsPerSample = 16; |
28 const int kBitsPerByte = 8; | 28 const int kBitsPerByte = 8; |
29 // Conversion factor from 100ns to 1ms. | 29 // Conversion factor from 100ns to 1ms. |
30 const int kHnsToMs = 10000; | 30 const int kHnsToMs = 10000; |
31 | 31 |
32 // Tolerance for catching packets of silence. If all samples have absolute | 32 // 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 | 33 // 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 | 34 // silence. A value of 2 was chosen, because Windows can give samples of 1 and |
35 // -1, even when no audio is playing. | 35 // -1, even when no audio is playing. |
36 const int kSilenceThreshold = 2; | 36 const int kSilenceThreshold = 2; |
37 | |
38 // Number of packets that can be stored in the Windows capture buffer. | |
39 // Even if we capture once every |audio_device_period_| * |kWindowsBufferSize|, | |
40 // we will buffer enough to avoid glitches. | |
41 const int kWindowsBufferSize = 10; | |
Wez
2012/08/15 21:32:29
Why 10? Surely we want to configure things to cope
kxing
2012/08/16 17:30:57
Done.
| |
37 } // namespace | 42 } // namespace |
38 | 43 |
39 namespace remoting { | 44 namespace remoting { |
40 | 45 |
41 class AudioCapturerWin : public AudioCapturer { | 46 class AudioCapturerWin : public AudioCapturer { |
42 public: | 47 public: |
43 AudioCapturerWin(); | 48 AudioCapturerWin(); |
44 virtual ~AudioCapturerWin(); | 49 virtual ~AudioCapturerWin(); |
45 | 50 |
46 // AudioCapturer interface. | 51 // AudioCapturer interface. |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 break; | 193 break; |
189 } | 194 } |
190 default: | 195 default: |
191 LOG(ERROR) << "Failed to force 16-bit PCM"; | 196 LOG(ERROR) << "Failed to force 16-bit PCM"; |
192 return false; | 197 return false; |
193 } | 198 } |
194 | 199 |
195 // Initialize the IAudioClient. | 200 // Initialize the IAudioClient. |
196 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, | 201 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, |
197 AUDCLNT_STREAMFLAGS_LOOPBACK, | 202 AUDCLNT_STREAMFLAGS_LOOPBACK, |
198 0, | 203 device_period * kWindowsBufferSize, |
Sergey Ulanov
2012/08/15 21:43:22
Does this have to be multiple of device_period? Ca
kxing
2012/08/16 17:30:57
Done.
| |
199 0, | 204 0, |
200 wave_format_ex_, | 205 wave_format_ex_, |
201 NULL); | 206 NULL); |
202 if (FAILED(hr)) { | 207 if (FAILED(hr)) { |
203 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; | 208 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr; |
204 return false; | 209 return false; |
205 } | 210 } |
206 | 211 |
207 // Get an IAudioCaptureClient. | 212 // Get an IAudioCaptureClient. |
208 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), | 213 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient), |
209 audio_capture_client_.ReceiveVoid()); | 214 audio_capture_client_.ReceiveVoid()); |
210 if (FAILED(hr)) { | 215 if (FAILED(hr)) { |
211 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr; | 216 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr; |
212 return false; | 217 return false; |
213 } | 218 } |
214 | 219 |
215 // Start the IAudioClient. | 220 // Start the IAudioClient. |
216 hr = audio_client_->Start(); | 221 hr = audio_client_->Start(); |
217 if (FAILED(hr)) { | 222 if (FAILED(hr)) { |
218 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 223 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
219 return false; | 224 return false; |
220 } | 225 } |
221 | 226 |
222 // Start capturing. | 227 // Start capturing. |
223 capture_timer_->Start(FROM_HERE, | 228 capture_timer_->Start(FROM_HERE, |
224 audio_device_period_, | 229 audio_device_period_, |
Sergey Ulanov
2012/08/15 21:43:22
why do we need timer to be scheduled with device_p
Wez
2012/08/15 21:55:30
We need to cope with the case where the device per
kxing
2012/08/16 17:30:57
Done.
kxing
2012/08/16 17:30:57
Done.
| |
225 this, | 230 this, |
226 &AudioCapturerWin::DoCapture); | 231 &AudioCapturerWin::DoCapture); |
227 return true; | 232 return true; |
228 } | 233 } |
229 | 234 |
230 void AudioCapturerWin::Stop() { | 235 void AudioCapturerWin::Stop() { |
231 DCHECK(thread_checker_.CalledOnValidThread()); | 236 DCHECK(thread_checker_.CalledOnValidThread()); |
232 DCHECK(IsRunning()); | 237 DCHECK(IsRunning()); |
233 | 238 |
234 capture_timer_.reset(); | 239 capture_timer_.reset(); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
306 return false; | 311 return false; |
307 } | 312 } |
308 return true; | 313 return true; |
309 } | 314 } |
310 | 315 |
311 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 316 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
312 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); | 317 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); |
313 } | 318 } |
314 | 319 |
315 } // namespace remoting | 320 } // namespace remoting |
OLD | NEW |