Index: content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
diff --git a/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc b/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
index f169880cd17f393551d016c861bcda96b2aca0af..e11760715c4c17616665b7603c5815da83ddea3b 100644 |
--- a/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
+++ b/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
@@ -4,12 +4,17 @@ |
#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h" |
+#include <limits> |
+ |
+#include "base/bind.h" |
#include "base/location.h" |
#include "base/logging.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/synchronization/waitable_event.h" |
#include "content/renderer/media/media_stream_audio_processor.h" |
+#include "content/renderer/media/media_stream_audio_track.h" |
#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" |
#include "content/renderer/media/webrtc/webrtc_audio_sink_adapter.h" |
-#include "content/renderer/media/webrtc_local_audio_track.h" |
#include "content/renderer/render_thread_impl.h" |
#include "third_party/webrtc/api/mediastreaminterface.h" |
@@ -45,17 +50,19 @@ WebRtcLocalAudioTrackAdapter::WebRtcLocalAudioTrackAdapter( |
webrtc::AudioSourceInterface* track_source, |
scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner) |
: webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), |
- owner_(NULL), |
track_source_(track_source), |
signaling_task_runner_(std::move(signaling_task_runner)) {} |
WebRtcLocalAudioTrackAdapter::~WebRtcLocalAudioTrackAdapter() { |
} |
-void WebRtcLocalAudioTrackAdapter::Initialize(WebRtcLocalAudioTrack* owner) { |
- DCHECK(!owner_); |
- DCHECK(owner); |
- owner_ = owner; |
+void WebRtcLocalAudioTrackAdapter::SetMediaStreamAudioTrack( |
+ base::WeakPtr<MediaStreamAudioTrack> track) { |
+ // Note: Single-threaded unit tests might not provide a task runner (or even a |
+ // main-thread MessageLoop). |
+ if (base::MessageLoop* main_loop = base::MessageLoop::current()) |
+ main_task_runner_ = main_loop->task_runner(); |
+ track_ = track; |
} |
void WebRtcLocalAudioTrackAdapter::SetAudioProcessor( |
@@ -94,38 +101,65 @@ bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) { |
void WebRtcLocalAudioTrackAdapter::AddSink( |
webrtc::AudioTrackSinkInterface* sink) { |
- DCHECK(!signaling_task_runner_ || |
- signaling_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK(sink); |
+ |
+ // The MediaStream object graph may only be modified on the main thread, so |
+ // trampoline if necessary. |
+ if (main_task_runner_ && !main_task_runner_->RunsTasksOnCurrentThread()) { |
+ main_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&WebRtcLocalAudioTrackAdapter::AddSink, this, sink)); |
+ return; |
+ } |
+ |
#ifndef NDEBUG |
// Verify that |sink| has not been added. |
- for (ScopedVector<WebRtcAudioSinkAdapter>::const_iterator it = |
- sink_adapters_.begin(); |
- it != sink_adapters_.end(); ++it) { |
- DCHECK(!(*it)->IsEqual(sink)); |
- } |
+ for (const auto& adapter : sink_adapters_) |
+ DCHECK(!adapter->IsEqual(sink)); |
#endif |
- scoped_ptr<WebRtcAudioSinkAdapter> adapter( |
- new WebRtcAudioSinkAdapter(sink)); |
- owner_->AddSink(adapter.get()); |
- sink_adapters_.push_back(adapter.release()); |
+ if (track_) { |
+ scoped_ptr<WebRtcAudioSinkAdapter> adapter( |
+ new WebRtcAudioSinkAdapter(sink)); |
+ track_->AddSink(adapter.get()); |
+ sink_adapters_.push_back(std::move(adapter)); |
+ } |
} |
void WebRtcLocalAudioTrackAdapter::RemoveSink( |
webrtc::AudioTrackSinkInterface* sink) { |
- DCHECK(!signaling_task_runner_ || |
- signaling_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK(sink); |
- for (ScopedVector<WebRtcAudioSinkAdapter>::iterator it = |
- sink_adapters_.begin(); |
- it != sink_adapters_.end(); ++it) { |
+ |
+ // The MediaStream object graph may only be modified on the main thread, so |
+ // trampoline if necessary. Furthermore, block the current thread until the |
+ // task has completed because the interface contract requires the audio flow |
+ // to |sink| be stopped when this method returns. |
+ if (main_task_runner_ && !main_task_runner_->RunsTasksOnCurrentThread()) { |
+ base::WaitableEvent done_event(false, false); |
+ main_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&WebRtcLocalAudioTrackAdapter::RemoveSinkOnMainThread, this, |
+ sink, &done_event)); |
+ done_event.Wait(); |
+ } else { |
+ RemoveSinkOnMainThread(sink, nullptr); |
+ } |
+} |
+ |
+void WebRtcLocalAudioTrackAdapter::RemoveSinkOnMainThread( |
+ webrtc::AudioTrackSinkInterface* sink, |
+ base::WaitableEvent* done_event) { |
+ DCHECK(!main_task_runner_ || main_task_runner_->RunsTasksOnCurrentThread()); |
+ for (auto it = sink_adapters_.begin(); it != sink_adapters_.end(); ++it) { |
if ((*it)->IsEqual(sink)) { |
- owner_->RemoveSink(*it); |
+ if (track_) |
+ track_->RemoveSink(it->get()); |
sink_adapters_.erase(it); |
- return; |
+ break; |
} |
} |
+ if (done_event) |
+ done_event->Signal(); |
} |
bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) { |