| 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 } | 101 } |
| 102 | 102 |
| 103 // Do NOT reference count the |delegate_| to avoid cyclic reference counting. | 103 // Do NOT reference count the |delegate_| to avoid cyclic reference counting. |
| 104 WebRtcLocalAudioTrack* delegate_; | 104 WebRtcLocalAudioTrack* delegate_; |
| 105 mutable base::Lock lock_; | 105 mutable base::Lock lock_; |
| 106 | 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(TrackOwner); | 107 DISALLOW_COPY_AND_ASSIGN(TrackOwner); |
| 108 }; | 108 }; |
| 109 | 109 |
| 110 // static | 110 // static |
| 111 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { | 111 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer( |
| 112 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); | 112 int render_view_id, const StreamDeviceInfo& device_info) { |
| 113 return capturer; | 113 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer( |
| 114 render_view_id, device_info); |
| 115 if (capturer->Initialize()) |
| 116 return capturer; |
| 117 |
| 118 return NULL; |
| 114 } | 119 } |
| 115 | 120 |
| 116 void WebRtcAudioCapturer::Reconfigure(int sample_rate, | 121 void WebRtcAudioCapturer::Reconfigure(int sample_rate, |
| 117 media::ChannelLayout channel_layout, | 122 media::ChannelLayout channel_layout, |
| 118 int effects) { | 123 int effects) { |
| 119 DCHECK(thread_checker_.CalledOnValidThread()); | 124 DCHECK(thread_checker_.CalledOnValidThread()); |
| 120 int buffer_size = GetBufferSize(sample_rate); | 125 int buffer_size = GetBufferSize(sample_rate); |
| 121 DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size; | 126 DVLOG(1) << "Using WebRTC input buffer size: " << buffer_size; |
| 122 | 127 |
| 123 media::AudioParameters::Format format = | 128 media::AudioParameters::Format format = |
| 124 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; | 129 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; |
| 125 | 130 |
| 126 // bits_per_sample is always 16 for now. | 131 // bits_per_sample is always 16 for now. |
| 127 int bits_per_sample = 16; | 132 int bits_per_sample = 16; |
| 128 media::AudioParameters params(format, channel_layout, 0, sample_rate, | 133 media::AudioParameters params(format, channel_layout, 0, sample_rate, |
| 129 bits_per_sample, buffer_size, effects); | 134 bits_per_sample, buffer_size, effects); |
| 130 { | 135 { |
| 131 base::AutoLock auto_lock(lock_); | 136 base::AutoLock auto_lock(lock_); |
| 132 params_ = params; | 137 params_ = params; |
| 133 | 138 |
| 134 // Notify all tracks about the new format. | 139 // Notify all tracks about the new format. |
| 135 tracks_.TagAll(); | 140 tracks_.TagAll(); |
| 136 } | 141 } |
| 137 } | 142 } |
| 138 | 143 |
| 139 bool WebRtcAudioCapturer::Initialize(int render_view_id, | 144 bool WebRtcAudioCapturer::Initialize() { |
| 140 media::ChannelLayout channel_layout, | |
| 141 int sample_rate, | |
| 142 int buffer_size, | |
| 143 int session_id, | |
| 144 const std::string& device_id, | |
| 145 int paired_output_sample_rate, | |
| 146 int paired_output_frames_per_buffer, | |
| 147 int effects) { | |
| 148 DCHECK(thread_checker_.CalledOnValidThread()); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 149 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | 146 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; |
| 147 WebRtcLogMessage(base::StringPrintf( |
| 148 "WAC::Initialize. render_view_id=%d" |
| 149 ", channel_layout=%d, sample_rate=%d, buffer_size=%d" |
| 150 ", session_id=%d, paired_output_sample_rate=%d" |
| 151 ", paired_output_frames_per_buffer=%d, effects=%d. ", |
| 152 render_view_id_, |
| 153 device_info_.device.input.channel_layout, |
| 154 device_info_.device.input.sample_rate, |
| 155 device_info_.device.input.frames_per_buffer, |
| 156 device_info_.session_id, |
| 157 device_info_.device.matched_output.sample_rate, |
| 158 device_info_.device.matched_output.frames_per_buffer, |
| 159 device_info_.device.input.effects)); |
| 150 | 160 |
| 161 if (render_view_id_ == -1) { |
| 162 // Return true here to allow injecting a new source via |
| 163 // SetCapturerSourceForTesting() at a later state. |
| 164 return true; |
| 165 } |
| 166 |
| 167 media::ChannelLayout channel_layout = static_cast<media::ChannelLayout>( |
| 168 device_info_.device.input.channel_layout); |
| 151 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; | 169 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; |
| 152 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | 170 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
| 153 channel_layout, media::CHANNEL_LAYOUT_MAX); | 171 channel_layout, media::CHANNEL_LAYOUT_MAX); |
| 154 | 172 |
| 155 WebRtcLogMessage(base::StringPrintf( | |
| 156 "WAC::Initialize. render_view_id=%d" | |
| 157 ", channel_layout=%d, sample_rate=%d, buffer_size=%d" | |
| 158 ", session_id=%d, paired_output_sample_rate=%d" | |
| 159 ", paired_output_frames_per_buffer=%d", | |
| 160 render_view_id, | |
| 161 channel_layout, | |
| 162 sample_rate, | |
| 163 buffer_size, | |
| 164 session_id, | |
| 165 paired_output_sample_rate, | |
| 166 paired_output_frames_per_buffer)); | |
| 167 | |
| 168 render_view_id_ = render_view_id; | |
| 169 session_id_ = session_id; | |
| 170 device_id_ = device_id; | |
| 171 hardware_buffer_size_ = buffer_size; | |
| 172 output_sample_rate_ = paired_output_sample_rate; | |
| 173 output_frames_per_buffer_= paired_output_frames_per_buffer; | |
| 174 | |
| 175 if (render_view_id == -1) { | |
| 176 // Return true here to allow injecting a new source via SetCapturerSource() | |
| 177 // at a later state. | |
| 178 return true; | |
| 179 } | |
| 180 | |
| 181 // Verify that the reported input channel configuration is supported. | 173 // Verify that the reported input channel configuration is supported. |
| 182 if (channel_layout != media::CHANNEL_LAYOUT_MONO && | 174 if (channel_layout != media::CHANNEL_LAYOUT_MONO && |
| 183 channel_layout != media::CHANNEL_LAYOUT_STEREO) { | 175 channel_layout != media::CHANNEL_LAYOUT_STEREO) { |
| 184 DLOG(ERROR) << channel_layout | 176 DLOG(ERROR) << channel_layout |
| 185 << " is not a supported input channel configuration."; | 177 << " is not a supported input channel configuration."; |
| 186 return false; | 178 return false; |
| 187 } | 179 } |
| 188 | 180 |
| 189 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate; | 181 DVLOG(1) << "Audio input hardware sample rate: " |
| 190 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate); | 182 << device_info_.device.input.sample_rate; |
| 183 media::AudioSampleRate asr = media::AsAudioSampleRate( |
| 184 device_info_.device.input.sample_rate); |
| 191 if (asr != media::kUnexpectedAudioSampleRate) { | 185 if (asr != media::kUnexpectedAudioSampleRate) { |
| 192 UMA_HISTOGRAM_ENUMERATION( | 186 UMA_HISTOGRAM_ENUMERATION( |
| 193 "WebRTC.AudioInputSampleRate", asr, media::kUnexpectedAudioSampleRate); | 187 "WebRTC.AudioInputSampleRate", asr, media::kUnexpectedAudioSampleRate); |
| 194 } else { | 188 } else { |
| 195 UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", sample_rate); | 189 UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", |
| 190 device_info_.device.input.sample_rate); |
| 196 } | 191 } |
| 197 | 192 |
| 198 // Verify that the reported input hardware sample rate is supported | 193 // Verify that the reported input hardware sample rate is supported |
| 199 // on the current platform. | 194 // on the current platform. |
| 200 if (std::find(&kValidInputRates[0], | 195 if (std::find(&kValidInputRates[0], |
| 201 &kValidInputRates[0] + arraysize(kValidInputRates), | 196 &kValidInputRates[0] + arraysize(kValidInputRates), |
| 202 sample_rate) == | 197 device_info_.device.input.sample_rate) == |
| 203 &kValidInputRates[arraysize(kValidInputRates)]) { | 198 &kValidInputRates[arraysize(kValidInputRates)]) { |
| 204 DLOG(ERROR) << sample_rate << " is not a supported input rate."; | 199 DLOG(ERROR) << device_info_.device.input.sample_rate |
| 200 << " is not a supported input rate."; |
| 205 return false; | 201 return false; |
| 206 } | 202 } |
| 207 | 203 |
| 208 // Create and configure the default audio capturing source. The |source_| | 204 // Create and configure the default audio capturing source. |
| 209 // will be overwritten if an external client later calls SetCapturerSource() | 205 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id_), |
| 210 // providing an alternative media::AudioCapturerSource. | |
| 211 SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id), | |
| 212 channel_layout, | 206 channel_layout, |
| 213 static_cast<float>(sample_rate), | 207 static_cast<float>(device_info_.device.input.sample_rate), |
| 214 effects); | 208 device_info_.device.input.effects); |
| 215 | 209 |
| 216 return true; | 210 return true; |
| 217 } | 211 } |
| 218 | 212 |
| 219 WebRtcAudioCapturer::WebRtcAudioCapturer() | 213 WebRtcAudioCapturer::WebRtcAudioCapturer(int render_view_id, |
| 214 const StreamDeviceInfo& device_info) |
| 220 : running_(false), | 215 : running_(false), |
| 221 render_view_id_(-1), | 216 render_view_id_(render_view_id), |
| 222 hardware_buffer_size_(0), | 217 device_info_(device_info), |
| 223 session_id_(0), | |
| 224 volume_(0), | 218 volume_(0), |
| 225 peer_connection_mode_(false), | 219 peer_connection_mode_(false), |
| 226 output_sample_rate_(0), | |
| 227 output_frames_per_buffer_(0), | |
| 228 key_pressed_(false) { | 220 key_pressed_(false) { |
| 229 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | 221 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; |
| 230 } | 222 } |
| 231 | 223 |
| 232 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 224 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
| 233 DCHECK(thread_checker_.CalledOnValidThread()); | 225 DCHECK(thread_checker_.CalledOnValidThread()); |
| 234 DCHECK(tracks_.IsEmpty()); | 226 DCHECK(tracks_.IsEmpty()); |
| 235 DCHECK(!running_); | 227 DCHECK(!running_); |
| 236 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | 228 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; |
| 237 } | 229 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 old_source->Stop(); | 301 old_source->Stop(); |
| 310 | 302 |
| 311 // Dispatch the new parameters both to the sink(s) and to the new source. | 303 // Dispatch the new parameters both to the sink(s) and to the new source. |
| 312 // The idea is to get rid of any dependency of the microphone parameters | 304 // The idea is to get rid of any dependency of the microphone parameters |
| 313 // which would normally be used by default. | 305 // which would normally be used by default. |
| 314 Reconfigure(sample_rate, channel_layout, effects); | 306 Reconfigure(sample_rate, channel_layout, effects); |
| 315 | 307 |
| 316 // Make sure to grab the new parameters in case they were reconfigured. | 308 // Make sure to grab the new parameters in case they were reconfigured. |
| 317 media::AudioParameters params = audio_parameters(); | 309 media::AudioParameters params = audio_parameters(); |
| 318 if (source.get()) | 310 if (source.get()) |
| 319 source->Initialize(params, this, session_id_); | 311 source->Initialize(params, this, session_id()); |
| 320 | 312 |
| 321 if (restart_source) | 313 if (restart_source) |
| 322 Start(); | 314 Start(); |
| 323 } | 315 } |
| 324 | 316 |
| 325 void WebRtcAudioCapturer::EnablePeerConnectionMode() { | 317 void WebRtcAudioCapturer::EnablePeerConnectionMode() { |
| 326 DCHECK(thread_checker_.CalledOnValidThread()); | 318 DCHECK(thread_checker_.CalledOnValidThread()); |
| 327 DVLOG(1) << "EnablePeerConnectionMode"; | 319 DVLOG(1) << "EnablePeerConnectionMode"; |
| 328 // Do nothing if the peer connection mode has been enabled. | 320 // Do nothing if the peer connection mode has been enabled. |
| 329 if (peer_connection_mode_) | 321 if (peer_connection_mode_) |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const { | 468 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const { |
| 477 base::AutoLock auto_lock(lock_); | 469 base::AutoLock auto_lock(lock_); |
| 478 return params_; | 470 return params_; |
| 479 } | 471 } |
| 480 | 472 |
| 481 bool WebRtcAudioCapturer::GetPairedOutputParameters( | 473 bool WebRtcAudioCapturer::GetPairedOutputParameters( |
| 482 int* session_id, | 474 int* session_id, |
| 483 int* output_sample_rate, | 475 int* output_sample_rate, |
| 484 int* output_frames_per_buffer) const { | 476 int* output_frames_per_buffer) const { |
| 485 // Don't set output parameters unless all of them are valid. | 477 // Don't set output parameters unless all of them are valid. |
| 486 if (session_id_ <= 0 || !output_sample_rate_ || !output_frames_per_buffer_) | 478 if (device_info_.session_id <= 0 || |
| 479 !device_info_.device.matched_output.sample_rate || |
| 480 !device_info_.device.matched_output.frames_per_buffer) |
| 487 return false; | 481 return false; |
| 488 | 482 |
| 489 *session_id = session_id_; | 483 *session_id = device_info_.session_id; |
| 490 *output_sample_rate = output_sample_rate_; | 484 *output_sample_rate = device_info_.device.matched_output.sample_rate; |
| 491 *output_frames_per_buffer = output_frames_per_buffer_; | 485 *output_frames_per_buffer = |
| 486 device_info_.device.matched_output.frames_per_buffer; |
| 492 | 487 |
| 493 return true; | 488 return true; |
| 494 } | 489 } |
| 495 | 490 |
| 496 int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const { | 491 int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const { |
| 497 DCHECK(thread_checker_.CalledOnValidThread()); | 492 DCHECK(thread_checker_.CalledOnValidThread()); |
| 498 #if defined(OS_ANDROID) | 493 #if defined(OS_ANDROID) |
| 499 // TODO(henrika): Tune and adjust buffer size on Android. | 494 // TODO(henrika): Tune and adjust buffer size on Android. |
| 500 return (2 * sample_rate / 100); | 495 return (2 * sample_rate / 100); |
| 501 #endif | 496 #endif |
| 502 | 497 |
| 503 // PeerConnection is running at a buffer size of 10ms data. A multiple of | 498 // PeerConnection is running at a buffer size of 10ms data. A multiple of |
| 504 // 10ms as the buffer size can give the best performance to PeerConnection. | 499 // 10ms as the buffer size can give the best performance to PeerConnection. |
| 505 int peer_connection_buffer_size = sample_rate / 100; | 500 int peer_connection_buffer_size = sample_rate / 100; |
| 506 | 501 |
| 507 // Use the native hardware buffer size in non peer connection mode when the | 502 // Use the native hardware buffer size in non peer connection mode when the |
| 508 // platform is using a native buffer size smaller than the PeerConnection | 503 // platform is using a native buffer size smaller than the PeerConnection |
| 509 // buffer size. | 504 // buffer size. |
| 510 if (!peer_connection_mode_ && hardware_buffer_size_ && | 505 int hardware_buffer_size = device_info_.device.input.frames_per_buffer; |
| 511 hardware_buffer_size_ <= peer_connection_buffer_size) { | 506 if (!peer_connection_mode_ && hardware_buffer_size && |
| 512 return hardware_buffer_size_; | 507 hardware_buffer_size <= peer_connection_buffer_size) { |
| 508 return hardware_buffer_size; |
| 513 } | 509 } |
| 514 | 510 |
| 515 return (sample_rate / 100); | 511 return (sample_rate / 100); |
| 516 } | 512 } |
| 517 | 513 |
| 518 void WebRtcAudioCapturer::GetAudioProcessingParams( | 514 void WebRtcAudioCapturer::GetAudioProcessingParams( |
| 519 base::TimeDelta* delay, int* volume, bool* key_pressed) { | 515 base::TimeDelta* delay, int* volume, bool* key_pressed) { |
| 520 base::AutoLock auto_lock(lock_); | 516 base::AutoLock auto_lock(lock_); |
| 521 *delay = audio_delay_; | 517 *delay = audio_delay_; |
| 522 *volume = volume_; | 518 *volume = volume_; |
| 523 *key_pressed = key_pressed_; | 519 *key_pressed = key_pressed_; |
| 524 } | 520 } |
| 525 | 521 |
| 522 void WebRtcAudioCapturer::SetCapturerSourceForTesting( |
| 523 const scoped_refptr<media::AudioCapturerSource>& source, |
| 524 media::AudioParameters params) { |
| 525 // Create a new audio stream as source which uses the new source. |
| 526 SetCapturerSource(source, params.channel_layout(), |
| 527 static_cast<float>(params.sample_rate()), |
| 528 params.effects()); |
| 529 } |
| 530 |
| 526 } // namespace content | 531 } // namespace content |
| OLD | NEW |