Chromium Code Reviews| 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_renderer.h" | 5 #include "content/renderer/media/webrtc_audio_renderer.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include <utility> | 8 #include <utility> |
| 8 | 9 |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 11 #include "base/location.h" | 12 #include "base/location.h" |
| 12 #include "base/logging.h" | 13 #include "base/logging.h" |
| 13 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 16 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 // This is a simple wrapper class that's handed out to users of a shared | 49 // This is a simple wrapper class that's handed out to users of a shared |
| 49 // WebRtcAudioRenderer instance. This class maintains the per-user 'playing' | 50 // WebRtcAudioRenderer instance. This class maintains the per-user 'playing' |
| 50 // and 'started' states to avoid problems related to incorrect usage which | 51 // and 'started' states to avoid problems related to incorrect usage which |
| 51 // might violate the implementation assumptions inside WebRtcAudioRenderer | 52 // might violate the implementation assumptions inside WebRtcAudioRenderer |
| 52 // (see the play reference count). | 53 // (see the play reference count). |
| 53 class SharedAudioRenderer : public MediaStreamAudioRenderer { | 54 class SharedAudioRenderer : public MediaStreamAudioRenderer { |
| 54 public: | 55 public: |
| 55 // Callback definition for a callback that is called when when Play(), Pause() | 56 // Callback definition for a callback that is called when when Play(), Pause() |
| 56 // or SetVolume are called (whenever the internal |playing_state_| changes). | 57 // or SetVolume are called (whenever the internal |playing_state_| changes). |
| 57 typedef base::Callback<void(const blink::WebMediaStream&, | 58 typedef base::Callback<void(const blink::WebMediaStream&, |
| 58 WebRtcAudioRenderer::PlayingState*)> | 59 WebRtcAudioRenderer::PlayingState*, |
| 60 bool playing_state_deleted)> | |
| 59 OnPlayStateChanged; | 61 OnPlayStateChanged; |
| 60 | 62 |
| 61 SharedAudioRenderer(const scoped_refptr<MediaStreamAudioRenderer>& delegate, | 63 SharedAudioRenderer(const scoped_refptr<MediaStreamAudioRenderer>& delegate, |
| 62 const blink::WebMediaStream& media_stream, | 64 const blink::WebMediaStream& media_stream, |
| 63 const OnPlayStateChanged& on_play_state_changed) | 65 const OnPlayStateChanged& on_play_state_changed) |
| 64 : delegate_(delegate), | 66 : delegate_(delegate), |
| 65 media_stream_(media_stream), | 67 media_stream_(media_stream), |
| 66 started_(false), | 68 started_(false), |
| 67 on_play_state_changed_(on_play_state_changed) { | 69 on_play_state_changed_(on_play_state_changed) { |
| 68 DCHECK(!on_play_state_changed_.is_null()); | 70 DCHECK(!on_play_state_changed_.is_null()); |
| 69 DCHECK(!media_stream_.isNull()); | 71 DCHECK(!media_stream_.isNull()); |
| 70 } | 72 } |
| 71 | 73 |
| 72 protected: | 74 protected: |
| 73 ~SharedAudioRenderer() override { | 75 ~SharedAudioRenderer() override { |
| 74 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 75 DVLOG(1) << __func__; | 77 DVLOG(1) << __func__; |
| 76 Stop(); | 78 Stop(); |
| 79 // Make extra sure no reference to the playing state is left. | |
| 80 on_play_state_changed_.Run(media_stream_, &playing_state_, true); | |
|
tommi (sloooow) - chröme
2017/03/17 12:44:08
did you consider having a separate callback for wh
Max Morin
2017/03/17 14:08:04
I went ahead and kept delegate_ as a pointer to in
| |
| 77 } | 81 } |
| 78 | 82 |
| 79 void Start() override { | 83 void Start() override { |
| 80 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 81 if (started_) | 85 if (started_) |
| 82 return; | 86 return; |
| 83 started_ = true; | 87 started_ = true; |
| 84 delegate_->Start(); | 88 delegate_->Start(); |
| 85 } | 89 } |
| 86 | 90 |
| 87 void Play() override { | 91 void Play() override { |
| 88 DCHECK(thread_checker_.CalledOnValidThread()); | 92 DCHECK(thread_checker_.CalledOnValidThread()); |
| 89 DCHECK(started_); | 93 DCHECK(started_); |
| 90 if (playing_state_.playing()) | 94 if (playing_state_.playing()) |
| 91 return; | 95 return; |
| 92 playing_state_.set_playing(true); | 96 playing_state_.set_playing(true); |
| 93 on_play_state_changed_.Run(media_stream_, &playing_state_); | 97 on_play_state_changed_.Run(media_stream_, &playing_state_, false); |
| 94 } | 98 } |
| 95 | 99 |
| 96 void Pause() override { | 100 void Pause() override { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); | 101 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 DCHECK(started_); | 102 DCHECK(started_); |
| 99 if (!playing_state_.playing()) | 103 if (!playing_state_.playing()) |
| 100 return; | 104 return; |
| 101 playing_state_.set_playing(false); | 105 playing_state_.set_playing(false); |
| 102 on_play_state_changed_.Run(media_stream_, &playing_state_); | 106 on_play_state_changed_.Run(media_stream_, &playing_state_, false); |
| 103 } | 107 } |
| 104 | 108 |
| 105 void Stop() override { | 109 void Stop() override { |
| 106 DCHECK(thread_checker_.CalledOnValidThread()); | 110 DCHECK(thread_checker_.CalledOnValidThread()); |
| 107 if (!started_) | 111 if (!started_) |
| 108 return; | 112 return; |
| 109 Pause(); | 113 Pause(); |
| 110 started_ = false; | 114 started_ = false; |
| 111 delegate_->Stop(); | 115 delegate_->Stop(); |
| 112 } | 116 } |
| 113 | 117 |
| 114 void SetVolume(float volume) override { | 118 void SetVolume(float volume) override { |
| 115 DCHECK(thread_checker_.CalledOnValidThread()); | 119 DCHECK(thread_checker_.CalledOnValidThread()); |
| 116 DCHECK(volume >= 0.0f && volume <= 1.0f); | 120 DCHECK(volume >= 0.0f && volume <= 1.0f); |
| 117 playing_state_.set_volume(volume); | 121 playing_state_.set_volume(volume); |
| 118 on_play_state_changed_.Run(media_stream_, &playing_state_); | 122 on_play_state_changed_.Run(media_stream_, &playing_state_, false); |
| 119 } | 123 } |
| 120 | 124 |
| 121 media::OutputDeviceInfo GetOutputDeviceInfo() override { | 125 media::OutputDeviceInfo GetOutputDeviceInfo() override { |
| 122 DCHECK(thread_checker_.CalledOnValidThread()); | 126 DCHECK(thread_checker_.CalledOnValidThread()); |
| 123 return delegate_->GetOutputDeviceInfo(); | 127 return delegate_->GetOutputDeviceInfo(); |
| 124 } | 128 } |
| 125 | 129 |
| 126 void SwitchOutputDevice( | 130 void SwitchOutputDevice( |
| 127 const std::string& device_id, | 131 const std::string& device_id, |
| 128 const url::Origin& security_origin, | 132 const url::Origin& security_origin, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 | 246 |
| 243 void WebRtcAudioRenderer::Play() { | 247 void WebRtcAudioRenderer::Play() { |
| 244 DVLOG(1) << "WebRtcAudioRenderer::Play()"; | 248 DVLOG(1) << "WebRtcAudioRenderer::Play()"; |
| 245 DCHECK(thread_checker_.CalledOnValidThread()); | 249 DCHECK(thread_checker_.CalledOnValidThread()); |
| 246 | 250 |
| 247 if (playing_state_.playing()) | 251 if (playing_state_.playing()) |
| 248 return; | 252 return; |
| 249 | 253 |
| 250 playing_state_.set_playing(true); | 254 playing_state_.set_playing(true); |
| 251 | 255 |
| 252 OnPlayStateChanged(media_stream_, &playing_state_); | 256 OnPlayStateChanged(media_stream_, &playing_state_, false); |
| 253 } | 257 } |
| 254 | 258 |
| 255 void WebRtcAudioRenderer::EnterPlayState() { | 259 void WebRtcAudioRenderer::EnterPlayState() { |
| 256 DVLOG(1) << "WebRtcAudioRenderer::EnterPlayState()"; | 260 DVLOG(1) << "WebRtcAudioRenderer::EnterPlayState()"; |
| 257 DCHECK(thread_checker_.CalledOnValidThread()); | 261 DCHECK(thread_checker_.CalledOnValidThread()); |
| 258 DCHECK_GT(start_ref_count_, 0) << "Did you forget to call Start()?"; | 262 DCHECK_GT(start_ref_count_, 0) << "Did you forget to call Start()?"; |
| 259 base::AutoLock auto_lock(lock_); | 263 base::AutoLock auto_lock(lock_); |
| 260 if (state_ == UNINITIALIZED) | 264 if (state_ == UNINITIALIZED) |
| 261 return; | 265 return; |
| 262 | 266 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 274 } | 278 } |
| 275 | 279 |
| 276 void WebRtcAudioRenderer::Pause() { | 280 void WebRtcAudioRenderer::Pause() { |
| 277 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; | 281 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; |
| 278 DCHECK(thread_checker_.CalledOnValidThread()); | 282 DCHECK(thread_checker_.CalledOnValidThread()); |
| 279 if (!playing_state_.playing()) | 283 if (!playing_state_.playing()) |
| 280 return; | 284 return; |
| 281 | 285 |
| 282 playing_state_.set_playing(false); | 286 playing_state_.set_playing(false); |
| 283 | 287 |
| 284 OnPlayStateChanged(media_stream_, &playing_state_); | 288 OnPlayStateChanged(media_stream_, &playing_state_, false); |
| 285 } | 289 } |
| 286 | 290 |
| 287 void WebRtcAudioRenderer::EnterPauseState() { | 291 void WebRtcAudioRenderer::EnterPauseState() { |
| 288 DVLOG(1) << "WebRtcAudioRenderer::EnterPauseState()"; | 292 DVLOG(1) << "WebRtcAudioRenderer::EnterPauseState()"; |
| 289 DCHECK(thread_checker_.CalledOnValidThread()); | 293 DCHECK(thread_checker_.CalledOnValidThread()); |
| 290 DCHECK_GT(start_ref_count_, 0) << "Did you forget to call Start()?"; | 294 DCHECK_GT(start_ref_count_, 0) << "Did you forget to call Start()?"; |
| 291 base::AutoLock auto_lock(lock_); | 295 base::AutoLock auto_lock(lock_); |
| 292 if (state_ == UNINITIALIZED) | 296 if (state_ == UNINITIALIZED) |
| 293 return; | 297 return; |
| 294 | 298 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 // callback may currently be executing and trying to grab the lock while we're | 337 // callback may currently be executing and trying to grab the lock while we're |
| 334 // stopping the thread on which it runs. | 338 // stopping the thread on which it runs. |
| 335 sink_->Stop(); | 339 sink_->Stop(); |
| 336 } | 340 } |
| 337 | 341 |
| 338 void WebRtcAudioRenderer::SetVolume(float volume) { | 342 void WebRtcAudioRenderer::SetVolume(float volume) { |
| 339 DCHECK(thread_checker_.CalledOnValidThread()); | 343 DCHECK(thread_checker_.CalledOnValidThread()); |
| 340 DCHECK(volume >= 0.0f && volume <= 1.0f); | 344 DCHECK(volume >= 0.0f && volume <= 1.0f); |
| 341 | 345 |
| 342 playing_state_.set_volume(volume); | 346 playing_state_.set_volume(volume); |
| 343 OnPlayStateChanged(media_stream_, &playing_state_); | 347 OnPlayStateChanged(media_stream_, &playing_state_, false); |
| 344 } | 348 } |
| 345 | 349 |
| 346 media::OutputDeviceInfo WebRtcAudioRenderer::GetOutputDeviceInfo() { | 350 media::OutputDeviceInfo WebRtcAudioRenderer::GetOutputDeviceInfo() { |
| 347 DCHECK(thread_checker_.CalledOnValidThread()); | 351 DCHECK(thread_checker_.CalledOnValidThread()); |
| 348 return sink_ ? sink_->GetOutputDeviceInfo() : media::OutputDeviceInfo(); | 352 return sink_ ? sink_->GetOutputDeviceInfo() : media::OutputDeviceInfo(); |
| 349 } | 353 } |
| 350 | 354 |
| 351 base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const { | 355 base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const { |
| 352 DCHECK(thread_checker_.CalledOnValidThread()); | 356 DCHECK(thread_checker_.CalledOnValidThread()); |
| 353 base::AutoLock auto_lock(lock_); | 357 base::AutoLock auto_lock(lock_); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 array.erase(state_it); | 563 array.erase(state_it); |
| 560 | 564 |
| 561 if (array.empty()) | 565 if (array.empty()) |
| 562 source_playing_states_.erase(found); | 566 source_playing_states_.erase(found); |
| 563 | 567 |
| 564 return true; | 568 return true; |
| 565 } | 569 } |
| 566 | 570 |
| 567 void WebRtcAudioRenderer::OnPlayStateChanged( | 571 void WebRtcAudioRenderer::OnPlayStateChanged( |
| 568 const blink::WebMediaStream& media_stream, | 572 const blink::WebMediaStream& media_stream, |
| 569 PlayingState* state) { | 573 PlayingState* state, |
| 574 bool playing_state_deleted) { | |
| 570 DCHECK(thread_checker_.CalledOnValidThread()); | 575 DCHECK(thread_checker_.CalledOnValidThread()); |
| 576 if (playing_state_deleted) { | |
| 577 // It is possible we associated |state| to a source for a track that is no | |
| 578 // longer in |media_stream|. We iterate over |source_playing_states_| to | |
| 579 // ensure there are no dangling pointers to |state| there. See | |
| 580 // crbug.com/697256. | |
| 581 for (auto it = source_playing_states_.begin(); | |
| 582 it != source_playing_states_.end();) { | |
| 583 PlayingStates& states = it->second; | |
| 584 // We cannot use RemovePlayingState as it might invalidate |it|. | |
| 585 states.erase(std::remove(states.begin(), states.end(), state), | |
| 586 states.end()); | |
| 587 if (states.empty()) | |
| 588 it = source_playing_states_.erase(it); | |
| 589 else | |
| 590 ++it; | |
| 591 } | |
| 592 return; | |
| 593 } | |
| 571 blink::WebVector<blink::WebMediaStreamTrack> web_tracks; | 594 blink::WebVector<blink::WebMediaStreamTrack> web_tracks; |
| 572 media_stream.audioTracks(web_tracks); | 595 media_stream.audioTracks(web_tracks); |
| 573 | 596 |
| 574 for (const blink::WebMediaStreamTrack& web_track : web_tracks) { | 597 for (const blink::WebMediaStreamTrack& web_track : web_tracks) { |
| 575 // WebRtcAudioRenderer can only render audio tracks received from a remote | 598 // WebRtcAudioRenderer can only render audio tracks received from a remote |
| 576 // peer. Since the actual MediaStream is mutable from JavaScript, we need | 599 // peer. Since the actual MediaStream is mutable from JavaScript, we need |
| 577 // to make sure |web_track| is actually a remote track. | 600 // to make sure |web_track| is actually a remote track. |
| 578 PeerConnectionRemoteAudioTrack* const remote_track = | 601 PeerConnectionRemoteAudioTrack* const remote_track = |
| 579 PeerConnectionRemoteAudioTrack::From( | 602 PeerConnectionRemoteAudioTrack::From( |
| 580 MediaStreamAudioTrack::From(web_track)); | 603 MediaStreamAudioTrack::From(web_track)); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 sink_params_ = new_sink_params; | 681 sink_params_ = new_sink_params; |
| 659 } | 682 } |
| 660 | 683 |
| 661 // Specify the latency info to be passed to the browser side. | 684 // Specify the latency info to be passed to the browser side. |
| 662 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( | 685 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( |
| 663 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); | 686 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); |
| 664 sink_->Initialize(new_sink_params, this); | 687 sink_->Initialize(new_sink_params, this); |
| 665 } | 688 } |
| 666 | 689 |
| 667 } // namespace content | 690 } // namespace content |
| OLD | NEW |