| 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_; | 
| } | 
|  | 
|  |