| 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/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "content/child/child_process.h" | 14 #include "content/child/child_process.h" |
| 15 #include "content/renderer/media/audio_device_factory.h" | 15 #include "content/renderer/media/audio_device_factory.h" |
| 16 #include "content/renderer/media/media_stream_audio_processor.h" | 16 #include "content/renderer/media/media_stream_audio_processor.h" |
| 17 #include "content/renderer/media/media_stream_audio_processor_options.h" | 17 #include "content/renderer/media/media_stream_audio_processor_options.h" |
| 18 #include "content/renderer/media/media_stream_audio_source.h" | 18 #include "content/renderer/media/media_stream_audio_source.h" |
| 19 #include "content/renderer/media/media_stream_constraints_util.h" | 19 #include "content/renderer/media/media_stream_constraints_util.h" |
| 20 #include "content/renderer/media/webrtc_audio_device_impl.h" | 20 #include "content/renderer/media/webrtc_audio_device_impl.h" |
| 21 #include "content/renderer/media/webrtc_local_audio_track.h" | 21 #include "content/renderer/media/webrtc_local_audio_track.h" |
| 22 #include "content/renderer/media/webrtc_logging.h" | 22 #include "content/renderer/media/webrtc_logging.h" |
| 23 #include "media/audio/sample_rates.h" | 23 #include "media/audio/sample_rates.h" |
| 24 | 24 |
| 25 namespace content { | 25 namespace content { |
| 26 | 26 |
| 27 namespace { |
| 28 |
| 29 // Audio buffer sizes are specified in milliseconds. |
| 30 const char kAudioLatency[] = "latencyMs"; |
| 31 const int kMinAudioLatencyMs = 0; |
| 32 const int kMaxAudioLatencyMs = 10000; |
| 33 |
| 34 // Method to check if any of the data in |audio_source| has energy. |
| 35 bool HasDataEnergy(const media::AudioBus& audio_source) { |
| 36 for (int ch = 0; ch < audio_source.channels(); ++ch) { |
| 37 const float* channel_ptr = audio_source.channel(ch); |
| 38 for (int frame = 0; frame < audio_source.frames(); ++frame) { |
| 39 if (channel_ptr[frame] != 0) |
| 40 return true; |
| 41 } |
| 42 } |
| 43 |
| 44 // All the data is zero. |
| 45 return false; |
| 46 } |
| 47 |
| 48 } // namespace |
| 49 |
| 27 // Reference counted container of WebRtcLocalAudioTrack delegate. | 50 // Reference counted container of WebRtcLocalAudioTrack delegate. |
| 28 // TODO(xians): Switch to MediaStreamAudioSinkOwner. | 51 // TODO(xians): Switch to MediaStreamAudioSinkOwner. |
| 29 class WebRtcAudioCapturer::TrackOwner | 52 class WebRtcAudioCapturer::TrackOwner |
| 30 : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> { | 53 : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> { |
| 31 public: | 54 public: |
| 32 explicit TrackOwner(WebRtcLocalAudioTrack* track) | 55 explicit TrackOwner(WebRtcLocalAudioTrack* track) |
| 33 : delegate_(track) {} | 56 : delegate_(track) {} |
| 34 | 57 |
| 35 void Capture(const media::AudioBus& audio_bus, | 58 void Capture(const media::AudioBus& audio_bus, |
| 36 base::TimeTicks estimated_capture_time) { | 59 base::TimeTicks estimated_capture_time, |
| 60 bool force_report_nonzero_energy) { |
| 37 base::AutoLock lock(lock_); | 61 base::AutoLock lock(lock_); |
| 38 if (delegate_) { | 62 if (delegate_) { |
| 39 delegate_->Capture(audio_bus, estimated_capture_time); | 63 delegate_->Capture(audio_bus, |
| 64 estimated_capture_time, |
| 65 force_report_nonzero_energy); |
| 40 } | 66 } |
| 41 } | 67 } |
| 42 | 68 |
| 43 void OnSetFormat(const media::AudioParameters& params) { | 69 void OnSetFormat(const media::AudioParameters& params) { |
| 44 base::AutoLock lock(lock_); | 70 base::AutoLock lock(lock_); |
| 45 if (delegate_) | 71 if (delegate_) |
| 46 delegate_->OnSetFormat(params); | 72 delegate_->OnSetFormat(params); |
| 47 } | 73 } |
| 48 | 74 |
| 75 void SetAudioProcessor( |
| 76 const scoped_refptr<MediaStreamAudioProcessor>& processor) { |
| 77 base::AutoLock lock(lock_); |
| 78 if (delegate_) |
| 79 delegate_->SetAudioProcessor(processor); |
| 80 } |
| 81 |
| 49 void Reset() { | 82 void Reset() { |
| 50 base::AutoLock lock(lock_); | 83 base::AutoLock lock(lock_); |
| 51 delegate_ = NULL; | 84 delegate_ = NULL; |
| 52 } | 85 } |
| 53 | 86 |
| 54 void Stop() { | 87 void Stop() { |
| 55 base::AutoLock lock(lock_); | 88 base::AutoLock lock(lock_); |
| 56 DCHECK(delegate_); | 89 DCHECK(delegate_); |
| 57 | 90 |
| 58 // This can be reentrant so reset |delegate_| before calling out. | 91 // This can be reentrant so reset |delegate_| before calling out. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 84 } | 117 } |
| 85 | 118 |
| 86 // Do NOT reference count the |delegate_| to avoid cyclic reference counting. | 119 // Do NOT reference count the |delegate_| to avoid cyclic reference counting. |
| 87 WebRtcLocalAudioTrack* delegate_; | 120 WebRtcLocalAudioTrack* delegate_; |
| 88 mutable base::Lock lock_; | 121 mutable base::Lock lock_; |
| 89 | 122 |
| 90 DISALLOW_COPY_AND_ASSIGN(TrackOwner); | 123 DISALLOW_COPY_AND_ASSIGN(TrackOwner); |
| 91 }; | 124 }; |
| 92 | 125 |
| 93 // static | 126 // static |
| 94 scoped_ptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer( | 127 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer( |
| 95 int render_frame_id, | 128 int render_frame_id, |
| 96 const StreamDeviceInfo& device_info, | 129 const StreamDeviceInfo& device_info, |
| 97 const blink::WebMediaConstraints& constraints, | 130 const blink::WebMediaConstraints& constraints, |
| 98 WebRtcAudioDeviceImpl* audio_device, | 131 WebRtcAudioDeviceImpl* audio_device, |
| 99 MediaStreamAudioSource* audio_source) { | 132 MediaStreamAudioSource* audio_source) { |
| 100 scoped_ptr<WebRtcAudioCapturer> capturer(new WebRtcAudioCapturer( | 133 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer( |
| 101 render_frame_id, device_info, constraints, audio_device, audio_source)); | 134 render_frame_id, device_info, constraints, audio_device, audio_source); |
| 102 if (capturer->Initialize()) | 135 if (capturer->Initialize()) |
| 103 return capturer; | 136 return capturer; |
| 104 | 137 |
| 105 return NULL; | 138 return NULL; |
| 106 } | 139 } |
| 107 | 140 |
| 108 bool WebRtcAudioCapturer::Initialize() { | 141 bool WebRtcAudioCapturer::Initialize() { |
| 109 DCHECK(thread_checker_.CalledOnValidThread()); | 142 DCHECK(thread_checker_.CalledOnValidThread()); |
| 110 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | 143 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; |
| 111 WebRtcLogMessage(base::StringPrintf( | 144 WebRtcLogMessage(base::StringPrintf( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 << device_info_.device.input.sample_rate; | 199 << device_info_.device.input.sample_rate; |
| 167 media::AudioSampleRate asr; | 200 media::AudioSampleRate asr; |
| 168 if (media::ToAudioSampleRate(device_info_.device.input.sample_rate, &asr)) { | 201 if (media::ToAudioSampleRate(device_info_.device.input.sample_rate, &asr)) { |
| 169 UMA_HISTOGRAM_ENUMERATION( | 202 UMA_HISTOGRAM_ENUMERATION( |
| 170 "WebRTC.AudioInputSampleRate", asr, media::kAudioSampleRateMax + 1); | 203 "WebRTC.AudioInputSampleRate", asr, media::kAudioSampleRateMax + 1); |
| 171 } else { | 204 } else { |
| 172 UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", | 205 UMA_HISTOGRAM_COUNTS("WebRTC.AudioInputSampleRateUnexpected", |
| 173 device_info_.device.input.sample_rate); | 206 device_info_.device.input.sample_rate); |
| 174 } | 207 } |
| 175 | 208 |
| 209 // Initialize the buffer size to zero, which means it wasn't specified. |
| 210 // If it is out of range, we return it to zero. |
| 211 int buffer_size_ms = 0; |
| 212 int buffer_size_samples = 0; |
| 213 GetConstraintValueAsInteger(constraints_, kAudioLatency, &buffer_size_ms); |
| 214 if (buffer_size_ms < kMinAudioLatencyMs || |
| 215 buffer_size_ms > kMaxAudioLatencyMs) { |
| 216 DVLOG(1) << "Ignoring out of range buffer size " << buffer_size_ms; |
| 217 } else { |
| 218 buffer_size_samples = |
| 219 device_info_.device.input.sample_rate * buffer_size_ms / 1000; |
| 220 } |
| 221 DVLOG_IF(1, buffer_size_samples > 0) |
| 222 << "Custom audio buffer size: " << buffer_size_samples << " samples"; |
| 223 |
| 176 // Create and configure the default audio capturing source. | 224 // Create and configure the default audio capturing source. |
| 177 SetCapturerSourceInternal( | 225 SetCapturerSourceInternal( |
| 178 AudioDeviceFactory::NewInputDevice(render_frame_id_), channel_layout, | 226 AudioDeviceFactory::NewInputDevice(render_frame_id_), |
| 179 device_info_.device.input.sample_rate); | 227 channel_layout, |
| 228 device_info_.device.input.sample_rate, |
| 229 buffer_size_samples); |
| 180 | 230 |
| 181 // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware | 231 // Add the capturer to the WebRtcAudioDeviceImpl since it needs some hardware |
| 182 // information from the capturer. | 232 // information from the capturer. |
| 183 if (audio_device_) | 233 if (audio_device_) |
| 184 audio_device_->AddAudioCapturer(this); | 234 audio_device_->AddAudioCapturer(this); |
| 185 | 235 |
| 186 return true; | 236 return true; |
| 187 } | 237 } |
| 188 | 238 |
| 189 WebRtcAudioCapturer::WebRtcAudioCapturer( | 239 WebRtcAudioCapturer::WebRtcAudioCapturer( |
| (...skipping 18 matching lines...) Expand all Loading... |
| 208 } | 258 } |
| 209 | 259 |
| 210 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 260 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
| 211 DCHECK(thread_checker_.CalledOnValidThread()); | 261 DCHECK(thread_checker_.CalledOnValidThread()); |
| 212 DCHECK(tracks_.IsEmpty()); | 262 DCHECK(tracks_.IsEmpty()); |
| 213 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | 263 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; |
| 214 Stop(); | 264 Stop(); |
| 215 } | 265 } |
| 216 | 266 |
| 217 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) { | 267 void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) { |
| 218 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 219 DCHECK(track); | 268 DCHECK(track); |
| 220 DVLOG(1) << "WebRtcAudioCapturer::AddTrack()"; | 269 DVLOG(1) << "WebRtcAudioCapturer::AddTrack()"; |
| 221 | 270 |
| 222 track->SetLevel(level_calculator_.level()); | |
| 223 | |
| 224 // The track only grabs stats from the audio processor. Stats are only | |
| 225 // available if audio processing is turned on. Therefore, only provide the | |
| 226 // track a reference if audio processing is turned on. | |
| 227 if (audio_processor_->has_audio_processing()) | |
| 228 track->SetAudioProcessor(audio_processor_); | |
| 229 | |
| 230 { | 271 { |
| 231 base::AutoLock auto_lock(lock_); | 272 base::AutoLock auto_lock(lock_); |
| 232 // Verify that |track| is not already added to the list. | 273 // Verify that |track| is not already added to the list. |
| 233 DCHECK(!tracks_.Contains(TrackOwner::TrackWrapper(track))); | 274 DCHECK(!tracks_.Contains(TrackOwner::TrackWrapper(track))); |
| 234 | 275 |
| 235 // Add with a tag, so we remember to call OnSetFormat() on the new | 276 // Add with a tag, so we remember to call OnSetFormat() on the new |
| 236 // track. | 277 // track. |
| 237 scoped_refptr<TrackOwner> track_owner(new TrackOwner(track)); | 278 scoped_refptr<TrackOwner> track_owner(new TrackOwner(track)); |
| 238 tracks_.AddAndTag(track_owner.get()); | 279 tracks_.AddAndTag(track_owner.get()); |
| 239 } | 280 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 263 // we have to call StopSource on the MediaStreamSource. This will call | 304 // we have to call StopSource on the MediaStreamSource. This will call |
| 264 // MediaStreamAudioSource::DoStopSource which in turn call | 305 // MediaStreamAudioSource::DoStopSource which in turn call |
| 265 // WebRtcAudioCapturerer::Stop(); | 306 // WebRtcAudioCapturerer::Stop(); |
| 266 audio_source_->StopSource(); | 307 audio_source_->StopSource(); |
| 267 } | 308 } |
| 268 } | 309 } |
| 269 | 310 |
| 270 void WebRtcAudioCapturer::SetCapturerSourceInternal( | 311 void WebRtcAudioCapturer::SetCapturerSourceInternal( |
| 271 const scoped_refptr<media::AudioCapturerSource>& source, | 312 const scoped_refptr<media::AudioCapturerSource>& source, |
| 272 media::ChannelLayout channel_layout, | 313 media::ChannelLayout channel_layout, |
| 273 int sample_rate) { | 314 int sample_rate, |
| 315 int buffer_size) { |
| 274 DCHECK(thread_checker_.CalledOnValidThread()); | 316 DCHECK(thread_checker_.CalledOnValidThread()); |
| 275 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," | 317 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," |
| 276 << "sample_rate=" << sample_rate << ")"; | 318 << "sample_rate=" << sample_rate << ")"; |
| 277 scoped_refptr<media::AudioCapturerSource> old_source; | 319 scoped_refptr<media::AudioCapturerSource> old_source; |
| 278 { | 320 { |
| 279 base::AutoLock auto_lock(lock_); | 321 base::AutoLock auto_lock(lock_); |
| 280 if (source_.get() == source.get()) | 322 if (source_.get() == source.get()) |
| 281 return; | 323 return; |
| 282 | 324 |
| 283 source_.swap(old_source); | 325 source_.swap(old_source); |
| 284 source_ = source; | 326 source_ = source; |
| 285 | 327 |
| 286 // Reset the flag to allow starting the new source. | 328 // Reset the flag to allow starting the new source. |
| 287 running_ = false; | 329 running_ = false; |
| 288 } | 330 } |
| 289 | 331 |
| 290 DVLOG(1) << "Switching to a new capture source."; | 332 DVLOG(1) << "Switching to a new capture source."; |
| 291 if (old_source.get()) | 333 if (old_source.get()) |
| 292 old_source->Stop(); | 334 old_source->Stop(); |
| 293 | 335 |
| 336 // If the buffer size is zero, it has not been specified. |
| 337 // We either default to 10ms, or use the hardware buffer size. |
| 338 if (buffer_size == 0) |
| 339 buffer_size = GetBufferSize(sample_rate); |
| 340 |
| 294 // Dispatch the new parameters both to the sink(s) and to the new source, | 341 // Dispatch the new parameters both to the sink(s) and to the new source, |
| 295 // also apply the new |constraints|. | 342 // also apply the new |constraints|. |
| 296 // The idea is to get rid of any dependency of the microphone parameters | 343 // The idea is to get rid of any dependency of the microphone parameters |
| 297 // which would normally be used by default. | 344 // which would normally be used by default. |
| 298 // bits_per_sample is always 16 for now. | 345 // bits_per_sample is always 16 for now. |
| 299 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 346 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 300 channel_layout, sample_rate, 16, | 347 channel_layout, sample_rate, 16, buffer_size); |
| 301 GetBufferSize(sample_rate)); | |
| 302 params.set_effects(device_info_.device.input.effects); | 348 params.set_effects(device_info_.device.input.effects); |
| 303 DCHECK(params.IsValid()); | |
| 304 | 349 |
| 305 { | 350 { |
| 306 base::AutoLock auto_lock(lock_); | 351 base::AutoLock auto_lock(lock_); |
| 307 | 352 // Notify the |audio_processor_| of the new format. |
| 308 // Notify the |audio_processor_| of the new format. We're doing this while | |
| 309 // the lock is held only because the signaling thread might be calling | |
| 310 // GetInputFormat(). Simultaneous reads from the audio thread are NOT the | |
| 311 // concern here since the source is currently stopped (i.e., no audio | |
| 312 // capture calls can be executing). | |
| 313 audio_processor_->OnCaptureFormatChanged(params); | 353 audio_processor_->OnCaptureFormatChanged(params); |
| 314 | 354 |
| 315 // Notify all tracks about the new format. | 355 // Notify all tracks about the new format. |
| 316 tracks_.TagAll(); | 356 tracks_.TagAll(); |
| 317 } | 357 } |
| 318 | 358 |
| 319 if (source.get()) | 359 if (source.get()) |
| 320 source->Initialize(params, this, device_info_.session_id); | 360 source->Initialize(params, this, session_id()); |
| 321 | 361 |
| 322 Start(); | 362 Start(); |
| 323 } | 363 } |
| 324 | 364 |
| 325 void WebRtcAudioCapturer::EnablePeerConnectionMode() { | 365 void WebRtcAudioCapturer::EnablePeerConnectionMode() { |
| 326 DCHECK(thread_checker_.CalledOnValidThread()); | 366 DCHECK(thread_checker_.CalledOnValidThread()); |
| 327 DVLOG(1) << "EnablePeerConnectionMode"; | 367 DVLOG(1) << "EnablePeerConnectionMode"; |
| 328 // Do nothing if the peer connection mode has been enabled. | 368 // Do nothing if the peer connection mode has been enabled. |
| 329 if (peer_connection_mode_) | 369 if (peer_connection_mode_) |
| 330 return; | 370 return; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 346 // Do nothing if the current buffer size is the WebRtc native buffer size. | 386 // Do nothing if the current buffer size is the WebRtc native buffer size. |
| 347 if (GetBufferSize(input_params.sample_rate()) == | 387 if (GetBufferSize(input_params.sample_rate()) == |
| 348 input_params.frames_per_buffer()) { | 388 input_params.frames_per_buffer()) { |
| 349 return; | 389 return; |
| 350 } | 390 } |
| 351 | 391 |
| 352 // Create a new audio stream as source which will open the hardware using | 392 // Create a new audio stream as source which will open the hardware using |
| 353 // WebRtc native buffer size. | 393 // WebRtc native buffer size. |
| 354 SetCapturerSourceInternal(AudioDeviceFactory::NewInputDevice(render_frame_id), | 394 SetCapturerSourceInternal(AudioDeviceFactory::NewInputDevice(render_frame_id), |
| 355 input_params.channel_layout(), | 395 input_params.channel_layout(), |
| 356 input_params.sample_rate()); | 396 input_params.sample_rate(), |
| 397 0); |
| 357 } | 398 } |
| 358 | 399 |
| 359 void WebRtcAudioCapturer::Start() { | 400 void WebRtcAudioCapturer::Start() { |
| 360 DCHECK(thread_checker_.CalledOnValidThread()); | 401 DCHECK(thread_checker_.CalledOnValidThread()); |
| 361 DVLOG(1) << "WebRtcAudioCapturer::Start()"; | 402 DVLOG(1) << "WebRtcAudioCapturer::Start()"; |
| 362 base::AutoLock auto_lock(lock_); | 403 base::AutoLock auto_lock(lock_); |
| 363 if (running_ || !source_.get()) | 404 if (running_ || !source_.get()) |
| 364 return; | 405 return; |
| 365 | 406 |
| 366 // Start the data source, i.e., start capturing data from the current source. | 407 // Start the data source, i.e., start capturing data from the current source. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 | 500 |
| 460 // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC. | 501 // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC. |
| 461 // The volume can be higher than 255 on Linux, and it will be cropped to | 502 // The volume can be higher than 255 on Linux, and it will be cropped to |
| 462 // 255 since AGC does not allow values out of range. | 503 // 255 since AGC does not allow values out of range. |
| 463 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); | 504 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); |
| 464 current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_; | 505 current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_; |
| 465 tracks = tracks_.Items(); | 506 tracks = tracks_.Items(); |
| 466 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); | 507 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); |
| 467 } | 508 } |
| 468 | 509 |
| 469 // Sanity-check the input audio format in debug builds. Then, notify the | |
| 470 // tracks if the format has changed. | |
| 471 // | |
| 472 // Locking is not needed here to read the audio input/output parameters | |
| 473 // because the audio processor format changes only occur while audio capture | |
| 474 // is stopped. | |
| 475 DCHECK(audio_processor_->InputFormat().IsValid()); | 510 DCHECK(audio_processor_->InputFormat().IsValid()); |
| 476 DCHECK_EQ(audio_source->channels(), | 511 DCHECK_EQ(audio_source->channels(), |
| 477 audio_processor_->InputFormat().channels()); | 512 audio_processor_->InputFormat().channels()); |
| 478 DCHECK_EQ(audio_source->frames(), | 513 DCHECK_EQ(audio_source->frames(), |
| 479 audio_processor_->InputFormat().frames_per_buffer()); | 514 audio_processor_->InputFormat().frames_per_buffer()); |
| 480 if (!tracks_to_notify_format.empty()) { | 515 |
| 481 const media::AudioParameters& output_params = | 516 // Notify the tracks on when the format changes. This will do nothing if |
| 482 audio_processor_->OutputFormat(); | 517 // |tracks_to_notify_format| is empty. |
| 483 for (const auto& track : tracks_to_notify_format) | 518 const media::AudioParameters& output_params = |
| 484 track->OnSetFormat(output_params); | 519 audio_processor_->OutputFormat(); |
| 520 for (const auto& track : tracks_to_notify_format) { |
| 521 track->OnSetFormat(output_params); |
| 522 track->SetAudioProcessor(audio_processor_); |
| 485 } | 523 } |
| 486 | 524 |
| 487 // Figure out if the pre-processed data has any energy or not. This | 525 // Figure out if the pre-processed data has any energy or not, the |
| 488 // information will be passed to the level calculator to force it to report | 526 // information will be passed to the track to force the calculator |
| 489 // energy in case the post-processed data is zeroed by the audio processing. | 527 // to report energy in case the post-processed data is zeroed by the audio |
| 490 const bool force_report_nonzero_energy = !audio_source->AreFramesZero(); | 528 // processing. |
| 529 const bool force_report_nonzero_energy = HasDataEnergy(*audio_source); |
| 491 | 530 |
| 492 // Push the data to the processor for processing. | 531 // Push the data to the processor for processing. |
| 493 audio_processor_->PushCaptureData( | 532 audio_processor_->PushCaptureData( |
| 494 *audio_source, | 533 *audio_source, |
| 495 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds)); | 534 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds)); |
| 496 | 535 |
| 497 // Process and consume the data in the processor until there is not enough | 536 // Process and consume the data in the processor until there is not enough |
| 498 // data in the processor. | 537 // data in the processor. |
| 499 media::AudioBus* processed_data = nullptr; | 538 media::AudioBus* processed_data = nullptr; |
| 500 base::TimeDelta processed_data_audio_delay; | 539 base::TimeDelta processed_data_audio_delay; |
| 501 int new_volume = 0; | 540 int new_volume = 0; |
| 502 while (audio_processor_->ProcessAndConsumeData( | 541 while (audio_processor_->ProcessAndConsumeData( |
| 503 current_volume, key_pressed, | 542 current_volume, key_pressed, |
| 504 &processed_data, &processed_data_audio_delay, &new_volume)) { | 543 &processed_data, &processed_data_audio_delay, &new_volume)) { |
| 505 DCHECK(processed_data); | 544 DCHECK(processed_data); |
| 506 | |
| 507 level_calculator_.Calculate(*processed_data, force_report_nonzero_energy); | |
| 508 | |
| 509 const base::TimeTicks processed_data_capture_time = | 545 const base::TimeTicks processed_data_capture_time = |
| 510 reference_clock_snapshot - processed_data_audio_delay; | 546 reference_clock_snapshot - processed_data_audio_delay; |
| 511 for (const auto& track : tracks) | 547 for (const auto& track : tracks) { |
| 512 track->Capture(*processed_data, processed_data_capture_time); | 548 track->Capture(*processed_data, |
| 549 processed_data_capture_time, |
| 550 force_report_nonzero_energy); |
| 551 } |
| 513 | 552 |
| 514 if (new_volume) { | 553 if (new_volume) { |
| 515 SetVolume(new_volume); | 554 SetVolume(new_volume); |
| 516 | 555 |
| 517 // Update the |current_volume| to avoid passing the old volume to AGC. | 556 // Update the |current_volume| to avoid passing the old volume to AGC. |
| 518 current_volume = new_volume; | 557 current_volume = new_volume; |
| 519 } | 558 } |
| 520 } | 559 } |
| 521 } | 560 } |
| 522 | 561 |
| 523 void WebRtcAudioCapturer::OnCaptureError(const std::string& message) { | 562 void WebRtcAudioCapturer::OnCaptureError(const std::string& message) { |
| 524 WebRtcLogMessage("WAC::OnCaptureError: " + message); | 563 WebRtcLogMessage("WAC::OnCaptureError: " + message); |
| 525 } | 564 } |
| 526 | 565 |
| 527 media::AudioParameters WebRtcAudioCapturer::GetInputFormat() const { | 566 media::AudioParameters WebRtcAudioCapturer::source_audio_parameters() const { |
| 528 base::AutoLock auto_lock(lock_); | 567 base::AutoLock auto_lock(lock_); |
| 529 return audio_processor_->InputFormat(); | 568 return audio_processor_.get() ? audio_processor_->InputFormat() |
| 569 : media::AudioParameters(); |
| 570 } |
| 571 |
| 572 bool WebRtcAudioCapturer::GetPairedOutputParameters( |
| 573 int* session_id, |
| 574 int* output_sample_rate, |
| 575 int* output_frames_per_buffer) const { |
| 576 // Don't set output parameters unless all of them are valid. |
| 577 if (device_info_.session_id <= 0 || |
| 578 !device_info_.device.matched_output.sample_rate || |
| 579 !device_info_.device.matched_output.frames_per_buffer) |
| 580 return false; |
| 581 |
| 582 *session_id = device_info_.session_id; |
| 583 *output_sample_rate = device_info_.device.matched_output.sample_rate; |
| 584 *output_frames_per_buffer = |
| 585 device_info_.device.matched_output.frames_per_buffer; |
| 586 |
| 587 return true; |
| 530 } | 588 } |
| 531 | 589 |
| 532 int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const { | 590 int WebRtcAudioCapturer::GetBufferSize(int sample_rate) const { |
| 533 DCHECK(thread_checker_.CalledOnValidThread()); | 591 DCHECK(thread_checker_.CalledOnValidThread()); |
| 534 #if defined(OS_ANDROID) | 592 #if defined(OS_ANDROID) |
| 535 // TODO(henrika): Tune and adjust buffer size on Android. | 593 // TODO(henrika): Tune and adjust buffer size on Android. |
| 536 return (2 * sample_rate / 100); | 594 return (2 * sample_rate / 100); |
| 537 #endif | 595 #endif |
| 538 | 596 |
| 539 // PeerConnection is running at a buffer size of 10ms data. A multiple of | 597 // PeerConnection is running at a buffer size of 10ms data. A multiple of |
| (...skipping 12 matching lines...) Expand all Loading... |
| 552 return hardware_buffer_size; | 610 return hardware_buffer_size; |
| 553 } | 611 } |
| 554 | 612 |
| 555 return (sample_rate / 100); | 613 return (sample_rate / 100); |
| 556 } | 614 } |
| 557 | 615 |
| 558 void WebRtcAudioCapturer::SetCapturerSource( | 616 void WebRtcAudioCapturer::SetCapturerSource( |
| 559 const scoped_refptr<media::AudioCapturerSource>& source, | 617 const scoped_refptr<media::AudioCapturerSource>& source, |
| 560 media::AudioParameters params) { | 618 media::AudioParameters params) { |
| 561 // Create a new audio stream as source which uses the new source. | 619 // Create a new audio stream as source which uses the new source. |
| 562 SetCapturerSourceInternal(source, params.channel_layout(), | 620 SetCapturerSourceInternal(source, |
| 563 params.sample_rate()); | 621 params.channel_layout(), |
| 622 params.sample_rate(), |
| 623 0); |
| 564 } | 624 } |
| 565 | 625 |
| 566 } // namespace content | 626 } // namespace content |
| OLD | NEW |