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 "content/renderer/media/webrtc_audio_capturer.h" | 5 #include "content/renderer/media/webrtc_audio_capturer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 } | 56 } |
57 | 57 |
58 void SetCaptureFormat(const media::AudioParameters& params) { | 58 void SetCaptureFormat(const media::AudioParameters& params) { |
59 base::AutoLock lock(lock_); | 59 base::AutoLock lock(lock_); |
60 if (delegate_) | 60 if (delegate_) |
61 delegate_->SetCaptureFormat(params); | 61 delegate_->SetCaptureFormat(params); |
62 } | 62 } |
63 | 63 |
64 void Reset() { | 64 void Reset() { |
65 base::AutoLock lock(lock_); | 65 base::AutoLock lock(lock_); |
| 66 if (delegate_) |
| 67 delegate_->Stop(); |
66 delegate_ = NULL; | 68 delegate_ = NULL; |
67 } | 69 } |
68 | 70 |
69 // Wrapper which allows to use std::find_if() when adding and removing | 71 // Wrapper which allows to use std::find_if() when adding and removing |
70 // sinks to/from the list. | 72 // sinks to/from the list. |
71 struct TrackWrapper { | 73 struct TrackWrapper { |
72 TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {} | 74 TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {} |
73 bool operator()( | 75 bool operator()( |
74 const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) { | 76 const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) { |
75 return owner->IsEqual(track_); | 77 return owner->IsEqual(track_); |
(...skipping 18 matching lines...) Expand all Loading... |
94 | 96 |
95 DISALLOW_COPY_AND_ASSIGN(TrackOwner); | 97 DISALLOW_COPY_AND_ASSIGN(TrackOwner); |
96 }; | 98 }; |
97 | 99 |
98 // static | 100 // static |
99 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { | 101 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { |
100 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); | 102 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); |
101 return capturer; | 103 return capturer; |
102 } | 104 } |
103 | 105 |
104 void WebRtcAudioCapturer::Reconfigure(int sample_rate, | 106 void WebRtcAudioCapturer::Reconfigure( |
105 media::ChannelLayout channel_layout) { | 107 int sample_rate, |
| 108 media::ChannelLayout channel_layout) { |
106 DCHECK(thread_checker_.CalledOnValidThread()); | 109 DCHECK(thread_checker_.CalledOnValidThread()); |
107 int buffer_size = GetBufferSize(sample_rate); | 110 int buffer_size = GetBufferSize(sample_rate); |
108 DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size; | 111 DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size; |
109 | 112 |
110 media::AudioParameters::Format format = | 113 media::AudioParameters::Format format = |
111 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; | 114 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; |
112 | 115 |
113 // bits_per_sample is always 16 for now. | 116 // bits_per_sample is always 16 for now. |
114 int bits_per_sample = 16; | 117 int bits_per_sample = 16; |
115 media::AudioParameters params(format, channel_layout, sample_rate, | 118 media::AudioParameters params(format, channel_layout, sample_rate, |
116 bits_per_sample, buffer_size); | 119 bits_per_sample, buffer_size); |
| 120 DCHECK(params.IsValid()); |
117 | 121 |
118 TrackList tracks; | 122 TrackList tracks; |
119 { | 123 { |
120 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
121 tracks = tracks_; | 125 tracks = tracks_; |
122 params_ = params; | 126 params_ = params; |
123 } | 127 } |
124 | 128 |
125 // Tell all audio_tracks which format we use. | 129 // Tell all audio_tracks which format we use. |
126 for (TrackList::const_iterator it = tracks.begin(); | 130 for (TrackList::const_iterator it = tracks.begin(); |
127 it != tracks.end(); ++it) | 131 it != tracks.end(); ++it) |
128 (*it)->SetCaptureFormat(params); | 132 (*it)->SetCaptureFormat(params); |
129 } | 133 } |
130 | 134 |
131 bool WebRtcAudioCapturer::Initialize(int render_view_id, | 135 bool WebRtcAudioCapturer::Initialize( |
132 media::ChannelLayout channel_layout, | 136 int render_view_id, |
133 int sample_rate, | 137 media::ChannelLayout channel_layout, |
134 int buffer_size, | 138 int sample_rate, |
135 int session_id, | 139 int buffer_size, |
136 const std::string& device_id, | 140 int session_id, |
137 int paired_output_sample_rate, | 141 const std::string& device_id, |
138 int paired_output_frames_per_buffer) { | 142 int paired_output_sample_rate, |
| 143 int paired_output_frames_per_buffer) { |
139 DCHECK(thread_checker_.CalledOnValidThread()); | 144 DCHECK(thread_checker_.CalledOnValidThread()); |
140 DCHECK_GE(render_view_id, 0); | 145 DCHECK_GE(render_view_id, 0); |
141 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | 146 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; |
142 | 147 |
143 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; | 148 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; |
144 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | 149 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
145 channel_layout, media::CHANNEL_LAYOUT_MAX); | 150 channel_layout, media::CHANNEL_LAYOUT_MAX); |
146 | 151 |
147 render_view_id_ = render_view_id; | 152 render_view_id_ = render_view_id; |
148 session_id_ = session_id; | 153 session_id_ = session_id; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 &kValidInputRates[0] + arraysize(kValidInputRates), | 185 &kValidInputRates[0] + arraysize(kValidInputRates), |
181 sample_rate) == | 186 sample_rate) == |
182 &kValidInputRates[arraysize(kValidInputRates)]) { | 187 &kValidInputRates[arraysize(kValidInputRates)]) { |
183 DLOG(ERROR) << sample_rate << " is not a supported input rate."; | 188 DLOG(ERROR) << sample_rate << " is not a supported input rate."; |
184 return false; | 189 return false; |
185 } | 190 } |
186 | 191 |
187 // Create and configure the default audio capturing source. The |source_| | 192 // Create and configure the default audio capturing source. The |source_| |
188 // will be overwritten if an external client later calls SetCapturerSource() | 193 // will be overwritten if an external client later calls SetCapturerSource() |
189 // providing an alternative media::AudioCapturerSource. | 194 // providing an alternative media::AudioCapturerSource. |
190 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), | 195 InitializeCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), |
191 channel_layout, | 196 channel_layout, |
192 static_cast<float>(sample_rate)); | 197 static_cast<float>(sample_rate)); |
193 | 198 |
194 return true; | 199 return true; |
195 } | 200 } |
196 | 201 |
197 WebRtcAudioCapturer::WebRtcAudioCapturer() | 202 WebRtcAudioCapturer::WebRtcAudioCapturer() |
198 : source_(NULL), | 203 : source_(NULL), |
199 running_(false), | 204 running_(false), |
200 agc_is_enabled_(false), | 205 agc_is_enabled_(false), |
201 render_view_id_(-1), | 206 render_view_id_(-1), |
202 hardware_buffer_size_(0), | 207 hardware_buffer_size_(0), |
203 session_id_(0), | 208 session_id_(0), |
204 volume_(0), | 209 volume_(0), |
205 source_provider_(new WebRtcLocalAudioSourceProvider()), | |
206 peer_connection_mode_(false), | 210 peer_connection_mode_(false), |
207 output_sample_rate_(0), | 211 output_sample_rate_(0), |
208 output_frames_per_buffer_(0) { | 212 output_frames_per_buffer_(0), |
209 DCHECK(source_provider_.get()); | 213 audio_delay_ms_(0), |
| 214 key_pressed_(false) { |
210 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | 215 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; |
211 } | 216 } |
212 | 217 |
213 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 218 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
214 DCHECK(thread_checker_.CalledOnValidThread()); | 219 DCHECK(thread_checker_.CalledOnValidThread()); |
215 DCHECK(tracks_.empty()); | 220 DCHECK(tracks_.empty()); |
216 DCHECK(!running_); | 221 DCHECK(!running_); |
217 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | 222 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; |
218 } | 223 } |
219 | 224 |
220 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) { | 225 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) { |
221 DCHECK(track); | 226 DCHECK(track); |
222 DVLOG(1) << "WebRtcAudioCapturer::AddTrack()"; | 227 DVLOG(1) << "WebRtcAudioCapturer::AddTrack()"; |
223 | 228 |
224 // Start the source if the first audio track is connected to the capturer. | 229 // Start the source if the first audio track is connected to the capturer. |
225 // Start() will do nothing if the capturer has already been started. | 230 // Start() will do nothing if the capturer has already been started. |
226 Start(); | 231 Start(); |
227 | 232 |
228 base::AutoLock auto_lock(lock_); | 233 base::AutoLock auto_lock(lock_); |
229 // Verify that |track| is not already added to the list. | 234 // Verify that |track| is not already added to the list. |
230 DCHECK(std::find_if(tracks_.begin(), tracks_.end(), | 235 DCHECK(std::find_if(tracks_.begin(), tracks_.end(), |
231 TrackOwner::TrackWrapper(track)) == tracks_.end()); | 236 TrackOwner::TrackWrapper(track)) == tracks_.end()); |
232 | 237 |
233 track->SetCaptureFormat(params_); | 238 if (params_.IsValid()) |
| 239 track->SetCaptureFormat(params_); |
| 240 |
234 tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track)); | 241 tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track)); |
235 } | 242 } |
236 | 243 |
237 void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) { | 244 void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) { |
238 DCHECK(thread_checker_.CalledOnValidThread()); | 245 DCHECK(thread_checker_.CalledOnValidThread()); |
239 | 246 |
240 bool stop_source = false; | 247 bool stop_source = false; |
241 { | 248 { |
242 base::AutoLock auto_lock(lock_); | 249 base::AutoLock auto_lock(lock_); |
243 // Get iterator to the first element for which WrapsSink(track) returns | 250 // Get iterator to the first element for which WrapsSink(track) returns |
244 // true. | 251 // true. |
245 TrackList::iterator it = std::find_if( | 252 TrackList::iterator it = std::find_if( |
246 tracks_.begin(), tracks_.end(), TrackOwner::TrackWrapper(track)); | 253 tracks_.begin(), tracks_.end(), TrackOwner::TrackWrapper(track)); |
247 if (it != tracks_.end()) { | 254 if (it != tracks_.end()) { |
248 // Clear the delegate to ensure that no more capture callbacks will | 255 // Clear the delegate to ensure that no more capture callbacks will |
249 // be sent to this sink. Also avoids a possible crash which can happen | 256 // be sent to this sink. Also avoids a possible crash which can happen |
250 // if this method is called while capturing is active. | 257 // if this method is called while capturing is active. |
251 (*it)->Reset(); | 258 (*it)->Reset(); |
252 tracks_.erase(it); | 259 tracks_.erase(it); |
253 } | 260 } |
254 | 261 |
255 // Stop the source if the last audio track is going away. | 262 // Stop the source if the last audio track is going away. |
256 stop_source = tracks_.empty(); | 263 stop_source = tracks_.empty(); |
257 } | 264 } |
258 | 265 |
259 if (stop_source) | 266 if (stop_source) |
260 Stop(); | 267 Stop(); |
261 } | 268 } |
262 | 269 |
263 void WebRtcAudioCapturer::SetCapturerSource( | 270 void WebRtcAudioCapturer::InitializeCapturerSource( |
264 const scoped_refptr<media::AudioCapturerSource>& source, | 271 const scoped_refptr<media::AudioCapturerSource>& source, |
265 media::ChannelLayout channel_layout, | 272 media::ChannelLayout channel_layout, |
266 float sample_rate) { | 273 float sample_rate) { |
267 DCHECK(thread_checker_.CalledOnValidThread()); | 274 DCHECK(thread_checker_.CalledOnValidThread()); |
268 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," | 275 DVLOG(1) << "InitializeCapturerSource(channel_layout=" << channel_layout |
269 << "sample_rate=" << sample_rate << ")"; | 276 << "," << "sample_rate=" << sample_rate << ")"; |
270 scoped_refptr<media::AudioCapturerSource> old_source; | 277 scoped_refptr<media::AudioCapturerSource> old_source; |
271 bool restart_source = false; | 278 bool restart_source = false; |
272 { | 279 { |
273 base::AutoLock auto_lock(lock_); | 280 base::AutoLock auto_lock(lock_); |
274 if (source_.get() == source.get()) | 281 if (source_.get() == source.get()) |
275 return; | 282 return; |
276 | 283 |
277 source_.swap(old_source); | 284 source_.swap(old_source); |
278 source_ = source; | 285 source_ = source; |
279 | 286 |
280 // Reset the flag to allow starting the new source. | 287 // Reset the flag to allow starting the new source. |
281 restart_source = running_; | 288 restart_source = running_; |
282 running_ = false; | 289 running_ = false; |
283 } | 290 } |
284 | 291 |
285 DVLOG(1) << "Switching to a new capture source."; | 292 DVLOG(1) << "Switching to a new capture source."; |
286 if (old_source.get()) | 293 if (old_source.get()) |
287 old_source->Stop(); | 294 old_source->Stop(); |
288 | 295 |
289 // Dispatch the new parameters both to the sink(s) and to the new source. | 296 // Dispatch the new parameters both to the sink(s) and to the new source. |
290 // The idea is to get rid of any dependency of the microphone parameters | 297 // The idea is to get rid of any dependency of the microphone parameters |
291 // which would normally be used by default. | 298 // which would normally be used by default. |
292 Reconfigure(sample_rate, channel_layout); | 299 Reconfigure(sample_rate, channel_layout); |
293 | 300 |
294 // Make sure to grab the new parameters in case they were reconfigured. | 301 // Make sure to grab the new parameters in case they were reconfigured. |
295 media::AudioParameters params = audio_parameters(); | 302 media::AudioParameters params = audio_parameters(); |
296 source_provider_->Initialize(params); | |
297 if (source.get()) | 303 if (source.get()) |
298 source->Initialize(params, this, session_id_); | 304 source->Initialize(params, this, session_id_); |
299 | 305 |
300 if (restart_source) | 306 if (restart_source) |
301 Start(); | 307 Start(); |
302 } | 308 } |
303 | 309 |
304 void WebRtcAudioCapturer::EnablePeerConnectionMode() { | 310 void WebRtcAudioCapturer::EnablePeerConnectionMode() { |
305 DCHECK(thread_checker_.CalledOnValidThread()); | 311 DCHECK(thread_checker_.CalledOnValidThread()); |
306 DVLOG(1) << "EnablePeerConnectionMode"; | 312 DVLOG(1) << "EnablePeerConnectionMode"; |
(...skipping 13 matching lines...) Expand all Loading... |
320 render_view_id = render_view_id_; | 326 render_view_id = render_view_id_; |
321 } | 327 } |
322 | 328 |
323 // Do nothing if the current buffer size is the WebRtc native buffer size. | 329 // Do nothing if the current buffer size is the WebRtc native buffer size. |
324 media::AudioParameters params = audio_parameters(); | 330 media::AudioParameters params = audio_parameters(); |
325 if (GetBufferSize(params.sample_rate()) == params.frames_per_buffer()) | 331 if (GetBufferSize(params.sample_rate()) == params.frames_per_buffer()) |
326 return; | 332 return; |
327 | 333 |
328 // Create a new audio stream as source which will open the hardware using | 334 // Create a new audio stream as source which will open the hardware using |
329 // WebRtc native buffer size. | 335 // WebRtc native buffer size. |
330 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), | 336 InitializeCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), |
331 params.channel_layout(), | 337 params.channel_layout(), |
332 static_cast<float>(params.sample_rate())); | 338 static_cast<float>(params.sample_rate())); |
333 } | 339 } |
334 | 340 |
335 void WebRtcAudioCapturer::Start() { | 341 void WebRtcAudioCapturer::Start() { |
336 DVLOG(1) << "WebRtcAudioCapturer::Start()"; | 342 DVLOG(1) << "WebRtcAudioCapturer::Start()"; |
337 base::AutoLock auto_lock(lock_); | 343 base::AutoLock auto_lock(lock_); |
338 if (running_) | 344 if (running_) |
339 return; | 345 return; |
340 | 346 |
341 // Start the data source, i.e., start capturing data from the current source. | 347 // Start the data source, i.e., start capturing data from the current source. |
342 // Note that, the source does not have to be a microphone. | 348 // Note that, the source does not have to be a microphone. |
343 if (source_.get()) { | 349 if (source_.get()) { |
344 // We need to set the AGC control before starting the stream. | 350 // We need to set the AGC control before starting the stream. |
345 source_->SetAutomaticGainControl(agc_is_enabled_); | 351 source_->SetAutomaticGainControl(agc_is_enabled_); |
346 source_->Start(); | 352 source_->Start(); |
347 } | 353 } |
348 | 354 |
349 running_ = true; | 355 running_ = true; |
350 } | 356 } |
351 | 357 |
352 void WebRtcAudioCapturer::Stop() { | 358 void WebRtcAudioCapturer::Stop() { |
353 DVLOG(1) << "WebRtcAudioCapturer::Stop()"; | 359 DVLOG(1) << "WebRtcAudioCapturer::Stop()"; |
354 scoped_refptr<media::AudioCapturerSource> source; | 360 scoped_refptr<media::AudioCapturerSource> source; |
| 361 TrackList tracks; |
355 { | 362 { |
356 base::AutoLock auto_lock(lock_); | 363 base::AutoLock auto_lock(lock_); |
357 if (!running_) | 364 if (!running_) |
358 return; | 365 return; |
359 | 366 |
360 source = source_; | 367 source = source_; |
| 368 tracks = tracks_; |
361 running_ = false; | 369 running_ = false; |
362 } | 370 } |
363 | 371 |
364 if (source.get()) | 372 if (source.get()) |
365 source->Stop(); | 373 source->Stop(); |
| 374 |
| 375 for (TrackList::const_iterator it = tracks.begin(); it != tracks.end(); ++it) |
| 376 (*it)->Reset(); |
366 } | 377 } |
367 | 378 |
368 void WebRtcAudioCapturer::SetVolume(int volume) { | 379 void WebRtcAudioCapturer::SetVolume(int volume) { |
369 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; | 380 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; |
370 DCHECK_LE(volume, MaxVolume()); | 381 DCHECK_LE(volume, MaxVolume()); |
371 double normalized_volume = static_cast<double>(volume) / MaxVolume(); | 382 double normalized_volume = static_cast<double>(volume) / MaxVolume(); |
372 base::AutoLock auto_lock(lock_); | 383 base::AutoLock auto_lock(lock_); |
373 if (source_.get()) | 384 if (source_.get()) |
374 source_->SetVolume(normalized_volume); | 385 source_->SetVolume(normalized_volume); |
375 } | 386 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 return; | 430 return; |
420 | 431 |
421 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the | 432 // Map internal volume range of [0.0, 1.0] into [0, 255] used by the |
422 // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the | 433 // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the |
423 // volume is higher than 255. | 434 // volume is higher than 255. |
424 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); | 435 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); |
425 current_volume = volume_; | 436 current_volume = volume_; |
426 tracks = tracks_; | 437 tracks = tracks_; |
427 } | 438 } |
428 | 439 |
429 // Deliver captured data to source provider, which stores the data into FIFO | |
430 // for WebAudio to fetch. | |
431 source_provider_->DeliverData(audio_source, audio_delay_milliseconds, | |
432 current_volume, key_pressed); | |
433 | |
434 // Feed the data to the tracks. | 440 // Feed the data to the tracks. |
435 for (TrackList::const_iterator it = tracks.begin(); | 441 for (TrackList::const_iterator it = tracks.begin(); |
436 it != tracks.end(); | 442 it != tracks.end(); |
437 ++it) { | 443 ++it) { |
438 (*it)->Capture(audio_source, audio_delay_milliseconds, | 444 (*it)->Capture(audio_source, audio_delay_milliseconds, |
439 current_volume, key_pressed); | 445 current_volume, key_pressed); |
440 } | 446 } |
441 } | 447 } |
442 | 448 |
443 void WebRtcAudioCapturer::OnCaptureError() { | 449 void WebRtcAudioCapturer::OnCaptureError() { |
(...skipping 27 matching lines...) Expand all Loading... |
471 // Use the native hardware buffer size in non peer connection mode on Mac. | 477 // Use the native hardware buffer size in non peer connection mode on Mac. |
472 if (!peer_connection_mode_ && hardware_buffer_size_) | 478 if (!peer_connection_mode_ && hardware_buffer_size_) |
473 return hardware_buffer_size_; | 479 return hardware_buffer_size_; |
474 #endif | 480 #endif |
475 | 481 |
476 // WebRtc is running at a buffer size of 10ms data. Use a multiple of 10ms | 482 // WebRtc is running at a buffer size of 10ms data. Use a multiple of 10ms |
477 // as the buffer size to achieve the best performance for WebRtc. | 483 // as the buffer size to achieve the best performance for WebRtc. |
478 return (sample_rate / 100); | 484 return (sample_rate / 100); |
479 } | 485 } |
480 | 486 |
| 487 void WebRtcAudioCapturer::GetAudioProcessingParams( |
| 488 int* delay_ms, int* volume, bool* key_pressed) { |
| 489 base::AutoLock auto_lock(lock_); |
| 490 *delay_ms = audio_delay_ms_; |
| 491 *volume = volume_; |
| 492 *key_pressed = key_pressed_; |
| 493 } |
| 494 |
481 } // namespace content | 495 } // namespace content |
OLD | NEW |