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 20a3969d11312d81c0b99354bc08c3f476666884..f713e7d073b53b04cec4b085c41dce8689a81f42 100644 |
--- a/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
+++ b/content/renderer/media/webrtc/webrtc_local_audio_track_adapter.cc |
@@ -4,13 +4,15 @@ |
#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/webrtc/peer_connection_dependency_factory.h" |
+#include "content/renderer/media/media_stream_audio_track.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" |
namespace content { |
@@ -20,58 +22,51 @@ static const char kAudioTrackKind[] = "audio"; |
scoped_refptr<WebRtcLocalAudioTrackAdapter> |
WebRtcLocalAudioTrackAdapter::Create( |
const std::string& label, |
- webrtc::AudioSourceInterface* track_source) { |
- // TODO(tommi): Change this so that the signaling thread is one of the |
- // parameters to this method. |
- scoped_refptr<base::SingleThreadTaskRunner> signaling_thread; |
- RenderThreadImpl* current = RenderThreadImpl::current(); |
- if (current) { |
- PeerConnectionDependencyFactory* pc_factory = |
- current->GetPeerConnectionDependencyFactory(); |
- signaling_thread = pc_factory->GetWebRtcSignalingThread(); |
- } |
- |
- LOG_IF(ERROR, !signaling_thread.get()) << "No signaling thread!"; |
- |
- rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>* adapter = |
- new rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>( |
- label, track_source, signaling_thread); |
- return adapter; |
+ webrtc::AudioSourceInterface* track_source, |
+ const scoped_refptr<base::SingleThreadTaskRunner>& signaling_task_runner) { |
+ return new rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>( |
+ label, track_source, signaling_task_runner); |
} |
WebRtcLocalAudioTrackAdapter::WebRtcLocalAudioTrackAdapter( |
const std::string& label, |
webrtc::AudioSourceInterface* track_source, |
- const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread) |
+ const scoped_refptr<base::SingleThreadTaskRunner>& signaling_task_runner) |
: webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), |
- owner_(NULL), |
track_source_(track_source), |
- signaling_thread_(signaling_thread), |
- signal_level_(0) { |
- signaling_thread_checker_.DetachFromThread(); |
- capture_thread_.DetachFromThread(); |
+ signaling_task_runner_(signaling_task_runner), |
+ track_(nullptr) { |
+ // Note: Single-threaded unit tests might not provide a task runner (or a |
+ // main-thread MessageLoop). |
+ if (signaling_task_runner) { |
+ if (base::MessageLoop* main_loop = base::MessageLoop::current()) |
+ main_task_runner_ = main_loop->task_runner(); |
+ } |
} |
WebRtcLocalAudioTrackAdapter::~WebRtcLocalAudioTrackAdapter() { |
} |
-void WebRtcLocalAudioTrackAdapter::Initialize(WebRtcLocalAudioTrack* owner) { |
- DCHECK(!owner_); |
- DCHECK(owner); |
- owner_ = owner; |
+void WebRtcLocalAudioTrackAdapter::SetMediaStreamAudioTrack( |
+ MediaStreamAudioTrack* track) { |
+ DCHECK(!main_task_runner_ || main_task_runner_->RunsTasksOnCurrentThread()); |
+ track_ = track; |
} |
void WebRtcLocalAudioTrackAdapter::SetAudioProcessor( |
const scoped_refptr<MediaStreamAudioProcessor>& processor) { |
- // SetAudioProcessor will be called when a new capture thread has been |
- // initialized, so we need to detach from any current capture thread we're |
- // checking and attach to the current one. |
- capture_thread_.DetachFromThread(); |
- DCHECK(capture_thread_.CalledOnValidThread()); |
base::AutoLock auto_lock(lock_); |
audio_processor_ = processor; |
} |
+void WebRtcLocalAudioTrackAdapter::SetReportedLevel( |
+ const scoped_refptr<MediaStreamAudioLevelCalculator::ReportedLevel>& |
+ reported_level) { |
+ base::AutoLock auto_lock(lock_); |
+ reported_level_ = reported_level; |
+} |
+ |
+ |
std::string WebRtcLocalAudioTrackAdapter::kind() const { |
return kAudioTrackKind; |
} |
@@ -79,8 +74,9 @@ std::string WebRtcLocalAudioTrackAdapter::kind() const { |
bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) { |
// If we're not called on the signaling thread, we need to post a task to |
// change the state on the correct thread. |
- if (signaling_thread_.get() && !signaling_thread_->BelongsToCurrentThread()) { |
- signaling_thread_->PostTask(FROM_HERE, |
+ if (signaling_task_runner_.get() && |
+ !signaling_task_runner_->RunsTasksOnCurrentThread()) { |
+ signaling_task_runner_->PostTask(FROM_HERE, |
base::Bind( |
base::IgnoreResult(&WebRtcLocalAudioTrackAdapter::set_enabled), |
this, enable)); |
@@ -93,8 +89,21 @@ bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) { |
void WebRtcLocalAudioTrackAdapter::AddSink( |
webrtc::AudioTrackSinkInterface* sink) { |
- DCHECK(signaling_thread_checker_.CalledOnValidThread()); |
DCHECK(sink); |
+ |
+ // Normal case: WebRtc will call into this method on the signaling thread. In |
+ // this case, post a task to the main thread to add the sink, since the |
+ // MediaStream object graph may only be modified from there. |
+ if (main_task_runner_.get() && |
+ !main_task_runner_->RunsTasksOnCurrentThread()) { |
+ DCHECK(signaling_task_runner_ && |
+ signaling_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 = |
@@ -104,50 +113,80 @@ void WebRtcLocalAudioTrackAdapter::AddSink( |
} |
#endif |
- scoped_ptr<WebRtcAudioSinkAdapter> adapter( |
- new WebRtcAudioSinkAdapter(sink)); |
- owner_->AddSink(adapter.get()); |
- sink_adapters_.push_back(adapter.release()); |
+ scoped_ptr<WebRtcAudioSinkAdapter> adapter(new WebRtcAudioSinkAdapter(sink)); |
+ if (track_) |
+ track_->AddSink(adapter.get()); |
+ sink_adapters_.push_back(std::move(adapter)); |
} |
void WebRtcLocalAudioTrackAdapter::RemoveSink( |
webrtc::AudioTrackSinkInterface* sink) { |
- DCHECK(signaling_thread_checker_.CalledOnValidThread()); |
+ // Normal case: WebRtc will call into this method on the signaling thread. In |
+ // this case, post a task to the main thread to remove the sink, since the |
+ // MediaStream object graph may only be modified from there. Furthermore, |
+ // block the current thread until the task has completed to ensure the audio |
+ // flow to |sink| has been stopped by the time this method returns. |
+ if (main_task_runner_.get() && |
+ !main_task_runner_->RunsTasksOnCurrentThread()) { |
+ DCHECK(signaling_task_runner_ && |
+ signaling_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(); |
+ return; |
+ } |
+ |
+ // For single-threaded unit tests: |
+ RemoveSinkOnMainThread(sink, nullptr); |
+} |
+ |
+void WebRtcLocalAudioTrackAdapter::RemoveSinkOnMainThread( |
+ webrtc::AudioTrackSinkInterface* sink, |
+ base::WaitableEvent* done_event) { |
+ DCHECK(!main_task_runner_ || main_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK(sink); |
for (ScopedVector<WebRtcAudioSinkAdapter>::iterator it = |
sink_adapters_.begin(); |
it != sink_adapters_.end(); ++it) { |
if ((*it)->IsEqual(sink)) { |
- owner_->RemoveSink(*it); |
+ if (track_) |
+ track_->RemoveSink(*it); |
sink_adapters_.erase(it); |
- return; |
+ break; |
} |
} |
+ if (done_event) |
+ done_event->Signal(); |
} |
bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) { |
- DCHECK(signaling_thread_checker_.CalledOnValidThread()); |
- |
- base::AutoLock auto_lock(lock_); |
- *level = signal_level_; |
+ // Note: Called on the signaling thread by WebRtc. |
+ float signal_level = 0.0f; |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ if (!reported_level_) |
+ return false; |
+ signal_level = reported_level_->Get(); |
+ } |
+ DCHECK_GE(signal_level, 0.0f); |
+ DCHECK_LE(signal_level, 1.0f); |
+ *level = static_cast<int>(signal_level * std::numeric_limits<int16_t>::max() + |
+ 0.5f /* rounding to nearest int */); |
return true; |
} |
rtc::scoped_refptr<webrtc::AudioProcessorInterface> |
WebRtcLocalAudioTrackAdapter::GetAudioProcessor() { |
- DCHECK(signaling_thread_checker_.CalledOnValidThread()); |
+ // Note: Called on the signaling thread by WebRtc. |
base::AutoLock auto_lock(lock_); |
return audio_processor_.get(); |
} |
-void WebRtcLocalAudioTrackAdapter::SetSignalLevel(int signal_level) { |
- DCHECK(capture_thread_.CalledOnValidThread()); |
- base::AutoLock auto_lock(lock_); |
- signal_level_ = signal_level; |
-} |
- |
webrtc::AudioSourceInterface* WebRtcLocalAudioTrackAdapter::GetSource() const { |
- DCHECK(signaling_thread_checker_.CalledOnValidThread()); |
+ // Note: Called on the signaling thread by WebRtc. |
return track_source_; |
} |