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 <stdint.h> | 10 #include <stdint.h> |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 } | 47 } |
48 | 48 |
49 AudioCapturerWin::~AudioCapturerWin() { | 49 AudioCapturerWin::~AudioCapturerWin() { |
50 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
51 } | 51 } |
52 | 52 |
53 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { | 53 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { |
54 DCHECK(!audio_capture_client_.get()); | 54 DCHECK(!audio_capture_client_.get()); |
55 DCHECK(!audio_client_.get()); | 55 DCHECK(!audio_client_.get()); |
56 DCHECK(!mm_device_.get()); | 56 DCHECK(!mm_device_.get()); |
57 DCHECK(!audio_volume_.get()); | |
57 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); | 58 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); |
58 DCHECK(thread_checker_.CalledOnValidThread()); | 59 DCHECK(thread_checker_.CalledOnValidThread()); |
59 | 60 |
60 callback_ = callback; | 61 callback_ = callback; |
61 | 62 |
62 // Initialize the capture timer. | 63 // Initialize the capture timer. |
63 capture_timer_.reset(new base::RepeatingTimer()); | 64 capture_timer_.reset(new base::RepeatingTimer()); |
64 | 65 |
65 HRESULT hr = S_OK; | 66 HRESULT hr = S_OK; |
66 | 67 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
186 return false; | 187 return false; |
187 } | 188 } |
188 | 189 |
189 // Start the IAudioClient. | 190 // Start the IAudioClient. |
190 hr = audio_client_->Start(); | 191 hr = audio_client_->Start(); |
191 if (FAILED(hr)) { | 192 if (FAILED(hr)) { |
192 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 193 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
193 return false; | 194 return false; |
194 } | 195 } |
195 | 196 |
197 // Initialize ISimpleAudioVolume. | |
198 // TODO(zijiehe): Do we need to control per process volume? | |
199 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | |
200 audio_volume_.ReceiveVoid()); | |
201 if (FAILED(hr)) { | |
202 LOG(ERROR) << "Failed to get an ISimpleAudioVolume. Error " << hr; | |
203 return false; | |
204 } | |
205 | |
196 silence_detector_.Reset(sampling_rate_, kChannels); | 206 silence_detector_.Reset(sampling_rate_, kChannels); |
197 | 207 |
198 // Start capturing. | 208 // Start capturing. |
199 capture_timer_->Start(FROM_HERE, | 209 capture_timer_->Start(FROM_HERE, |
200 audio_device_period_, | 210 audio_device_period_, |
201 this, | 211 this, |
202 &AudioCapturerWin::DoCapture); | 212 &AudioCapturerWin::DoCapture); |
203 return true; | 213 return true; |
204 } | 214 } |
205 | 215 |
216 float AudioCapturerWin::GetAudioLevel() { | |
217 BOOL mute; | |
218 HRESULT hr = audio_volume_->GetMute(&mute); | |
219 if (FAILED(hr)) { | |
220 return 1; | |
221 } | |
222 if (mute) { | |
223 return 0; | |
224 } | |
225 | |
226 float level; | |
227 hr = audio_volume_->GetMasterVolume(&level); | |
228 if (FAILED(hr) || level > 1) { | |
229 return 1; | |
230 } | |
231 if (level < 0) { | |
232 return 0; | |
233 } | |
234 return level; | |
235 } | |
236 | |
237 void AudioCapturerWin::ProcessSamples(uint8_t* data, | |
238 size_t frames, | |
239 int32_t flags) { | |
240 if (frames == 0) { | |
241 return; | |
242 } | |
243 | |
244 if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == 0) { | |
245 return; | |
246 } | |
247 | |
248 float level = GetAudioLevel(); | |
249 if (level == 0) { | |
250 return; | |
251 } | |
252 | |
253 int16_t* samples = reinterpret_cast<int16_t*>(data); | |
254 static_assert(sizeof(samples[0]) == kBytesPerSample, | |
255 "expect 16 bits per sample"); | |
256 size_t sample_count = frames * kChannels; | |
Sergey Ulanov
2016/03/10 06:04:28
nit: move samples and sample_count inside the if b
Hzj_jie
2016/03/10 18:30:41
Both silence_detector_.IsSilence and following log
| |
257 if (silence_detector_.IsSilence(samples, sample_count)) { | |
Sergey Ulanov
2016/03/10 06:04:28
nit: move this above GetAudioLevel() call to avoid
Hzj_jie
2016/03/10 18:30:41
Done.
| |
258 return; | |
259 } | |
260 | |
261 if (level < 1) { | |
262 // Windows API does not provide volume adjusted audio sample as Linux does. | |
263 // So we need to manually append volume signal to the samples. | |
264 int32_t level_int = static_cast<int32_t>(level * 65536); | |
265 for (size_t i = 0; i < sample_count; i++) { | |
266 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16; | |
267 } | |
268 } | |
269 | |
270 scoped_ptr<AudioPacket> packet(new AudioPacket()); | |
271 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | |
272 packet->set_encoding(AudioPacket::ENCODING_RAW); | |
273 packet->set_sampling_rate(sampling_rate_); | |
274 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | |
275 packet->set_channels(AudioPacket::CHANNELS_STEREO); | |
276 | |
277 callback_.Run(std::move(packet)); | |
278 } | |
279 | |
206 void AudioCapturerWin::DoCapture() { | 280 void AudioCapturerWin::DoCapture() { |
207 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); | 281 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); |
208 DCHECK(thread_checker_.CalledOnValidThread()); | 282 DCHECK(thread_checker_.CalledOnValidThread()); |
209 | 283 |
210 // Fetch all packets from the audio capture endpoint buffer. | 284 // Fetch all packets from the audio capture endpoint buffer. |
211 HRESULT hr = S_OK; | 285 HRESULT hr = S_OK; |
212 while (true) { | 286 while (true) { |
213 UINT32 next_packet_size; | 287 UINT32 next_packet_size; |
214 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); | 288 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); |
215 if (FAILED(hr)) | 289 if (FAILED(hr)) |
216 break; | 290 break; |
217 | 291 |
218 if (next_packet_size <= 0) { | 292 if (next_packet_size <= 0) { |
219 return; | 293 return; |
220 } | 294 } |
221 | 295 |
222 BYTE* data; | 296 BYTE* data; |
223 UINT32 frames; | 297 UINT32 frames; |
224 DWORD flags; | 298 DWORD flags; |
225 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, | 299 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, |
226 nullptr); | 300 nullptr); |
227 if (FAILED(hr)) | 301 if (FAILED(hr)) |
228 break; | 302 break; |
229 | 303 |
230 if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == 0 && | 304 ProcessSamples(data, frames, flags); |
231 !silence_detector_.IsSilence(reinterpret_cast<const int16_t*>(data), | |
232 frames * kChannels)) { | |
233 scoped_ptr<AudioPacket> packet(new AudioPacket()); | |
234 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | |
235 packet->set_encoding(AudioPacket::ENCODING_RAW); | |
236 packet->set_sampling_rate(sampling_rate_); | |
237 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | |
238 packet->set_channels(AudioPacket::CHANNELS_STEREO); | |
239 | |
240 callback_.Run(std::move(packet)); | |
241 } | |
242 | 305 |
243 hr = audio_capture_client_->ReleaseBuffer(frames); | 306 hr = audio_capture_client_->ReleaseBuffer(frames); |
244 if (FAILED(hr)) | 307 if (FAILED(hr)) |
245 break; | 308 break; |
246 } | 309 } |
247 | 310 |
248 // There is nothing to capture if the audio endpoint device has been unplugged | 311 // There is nothing to capture if the audio endpoint device has been unplugged |
249 // or disabled. | 312 // or disabled. |
250 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) | 313 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) |
251 return; | 314 return; |
252 | 315 |
253 // Avoid reporting the same error multiple times. | 316 // Avoid reporting the same error multiple times. |
254 if (FAILED(hr) && hr != last_capture_error_) { | 317 if (FAILED(hr) && hr != last_capture_error_) { |
255 last_capture_error_ = hr; | 318 last_capture_error_ = hr; |
256 LOG(ERROR) << "Failed to capture an audio packet: 0x" | 319 LOG(ERROR) << "Failed to capture an audio packet: 0x" |
257 << std::hex << hr << std::dec << "."; | 320 << std::hex << hr << std::dec << "."; |
258 } | 321 } |
259 } | 322 } |
260 | 323 |
261 bool AudioCapturer::IsSupported() { | 324 bool AudioCapturer::IsSupported() { |
262 return true; | 325 return true; |
263 } | 326 } |
264 | 327 |
265 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 328 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
266 return make_scoped_ptr(new AudioCapturerWin()); | 329 return make_scoped_ptr(new AudioCapturerWin()); |
267 } | 330 } |
268 | 331 |
269 } // namespace remoting | 332 } // namespace remoting |
OLD | NEW |