OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/webrtc_local_audio_track_adapter.h" | 5 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h" |
6 | 6 |
| 7 #include <limits> |
| 8 |
| 9 #include "base/bind.h" |
7 #include "base/location.h" | 10 #include "base/location.h" |
8 #include "base/logging.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/synchronization/waitable_event.h" |
9 #include "content/renderer/media/media_stream_audio_processor.h" | 13 #include "content/renderer/media/media_stream_audio_processor.h" |
10 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" | 14 #include "content/renderer/media/media_stream_audio_track.h" |
11 #include "content/renderer/media/webrtc/webrtc_audio_sink_adapter.h" | 15 #include "content/renderer/media/webrtc/webrtc_audio_sink_adapter.h" |
12 #include "content/renderer/media/webrtc_local_audio_track.h" | |
13 #include "content/renderer/render_thread_impl.h" | |
14 #include "third_party/webrtc/api/mediastreaminterface.h" | 16 #include "third_party/webrtc/api/mediastreaminterface.h" |
15 | 17 |
16 namespace content { | 18 namespace content { |
17 | 19 |
18 static const char kAudioTrackKind[] = "audio"; | 20 static const char kAudioTrackKind[] = "audio"; |
19 | 21 |
20 scoped_refptr<WebRtcLocalAudioTrackAdapter> | 22 scoped_refptr<WebRtcLocalAudioTrackAdapter> |
21 WebRtcLocalAudioTrackAdapter::Create( | 23 WebRtcLocalAudioTrackAdapter::Create( |
22 const std::string& label, | 24 const std::string& label, |
23 webrtc::AudioSourceInterface* track_source) { | 25 webrtc::AudioSourceInterface* track_source, |
24 // TODO(tommi): Change this so that the signaling thread is one of the | 26 const scoped_refptr<base::SingleThreadTaskRunner>& signaling_task_runner) { |
25 // parameters to this method. | 27 return new rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>( |
26 scoped_refptr<base::SingleThreadTaskRunner> signaling_thread; | 28 label, track_source, signaling_task_runner); |
27 RenderThreadImpl* current = RenderThreadImpl::current(); | |
28 if (current) { | |
29 PeerConnectionDependencyFactory* pc_factory = | |
30 current->GetPeerConnectionDependencyFactory(); | |
31 signaling_thread = pc_factory->GetWebRtcSignalingThread(); | |
32 } | |
33 | |
34 LOG_IF(ERROR, !signaling_thread.get()) << "No signaling thread!"; | |
35 | |
36 rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>* adapter = | |
37 new rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>( | |
38 label, track_source, signaling_thread); | |
39 return adapter; | |
40 } | 29 } |
41 | 30 |
42 WebRtcLocalAudioTrackAdapter::WebRtcLocalAudioTrackAdapter( | 31 WebRtcLocalAudioTrackAdapter::WebRtcLocalAudioTrackAdapter( |
43 const std::string& label, | 32 const std::string& label, |
44 webrtc::AudioSourceInterface* track_source, | 33 webrtc::AudioSourceInterface* track_source, |
45 const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread) | 34 const scoped_refptr<base::SingleThreadTaskRunner>& signaling_task_runner) |
46 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), | 35 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), |
47 owner_(NULL), | |
48 track_source_(track_source), | 36 track_source_(track_source), |
49 signaling_thread_(signaling_thread), | 37 signaling_task_runner_(signaling_task_runner), |
50 signal_level_(0) { | 38 track_(nullptr) { |
51 signaling_thread_checker_.DetachFromThread(); | 39 // Note: Single-threaded unit tests might not provide a task runner (or a |
52 capture_thread_.DetachFromThread(); | 40 // main-thread MessageLoop). |
| 41 if (signaling_task_runner) { |
| 42 if (base::MessageLoop* main_loop = base::MessageLoop::current()) |
| 43 main_task_runner_ = main_loop->task_runner(); |
| 44 } |
53 } | 45 } |
54 | 46 |
55 WebRtcLocalAudioTrackAdapter::~WebRtcLocalAudioTrackAdapter() { | 47 WebRtcLocalAudioTrackAdapter::~WebRtcLocalAudioTrackAdapter() { |
56 } | 48 } |
57 | 49 |
58 void WebRtcLocalAudioTrackAdapter::Initialize(WebRtcLocalAudioTrack* owner) { | 50 void WebRtcLocalAudioTrackAdapter::SetMediaStreamAudioTrack( |
59 DCHECK(!owner_); | 51 MediaStreamAudioTrack* track) { |
60 DCHECK(owner); | 52 DCHECK(!main_task_runner_ || main_task_runner_->RunsTasksOnCurrentThread()); |
61 owner_ = owner; | 53 track_ = track; |
62 } | 54 } |
63 | 55 |
64 void WebRtcLocalAudioTrackAdapter::SetAudioProcessor( | 56 void WebRtcLocalAudioTrackAdapter::SetAudioProcessor( |
65 const scoped_refptr<MediaStreamAudioProcessor>& processor) { | 57 const scoped_refptr<MediaStreamAudioProcessor>& processor) { |
66 // SetAudioProcessor will be called when a new capture thread has been | |
67 // initialized, so we need to detach from any current capture thread we're | |
68 // checking and attach to the current one. | |
69 capture_thread_.DetachFromThread(); | |
70 DCHECK(capture_thread_.CalledOnValidThread()); | |
71 base::AutoLock auto_lock(lock_); | 58 base::AutoLock auto_lock(lock_); |
72 audio_processor_ = processor; | 59 audio_processor_ = processor; |
73 } | 60 } |
74 | 61 |
| 62 void WebRtcLocalAudioTrackAdapter::SetReportedLevel( |
| 63 const scoped_refptr<MediaStreamAudioLevelCalculator::ReportedLevel>& |
| 64 reported_level) { |
| 65 base::AutoLock auto_lock(lock_); |
| 66 reported_level_ = reported_level; |
| 67 } |
| 68 |
| 69 |
75 std::string WebRtcLocalAudioTrackAdapter::kind() const { | 70 std::string WebRtcLocalAudioTrackAdapter::kind() const { |
76 return kAudioTrackKind; | 71 return kAudioTrackKind; |
77 } | 72 } |
78 | 73 |
79 bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) { | 74 bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) { |
80 // If we're not called on the signaling thread, we need to post a task to | 75 // If we're not called on the signaling thread, we need to post a task to |
81 // change the state on the correct thread. | 76 // change the state on the correct thread. |
82 if (signaling_thread_.get() && !signaling_thread_->BelongsToCurrentThread()) { | 77 if (signaling_task_runner_.get() && |
83 signaling_thread_->PostTask(FROM_HERE, | 78 !signaling_task_runner_->RunsTasksOnCurrentThread()) { |
| 79 signaling_task_runner_->PostTask(FROM_HERE, |
84 base::Bind( | 80 base::Bind( |
85 base::IgnoreResult(&WebRtcLocalAudioTrackAdapter::set_enabled), | 81 base::IgnoreResult(&WebRtcLocalAudioTrackAdapter::set_enabled), |
86 this, enable)); | 82 this, enable)); |
87 return true; | 83 return true; |
88 } | 84 } |
89 | 85 |
90 return webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>:: | 86 return webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>:: |
91 set_enabled(enable); | 87 set_enabled(enable); |
92 } | 88 } |
93 | 89 |
94 void WebRtcLocalAudioTrackAdapter::AddSink( | 90 void WebRtcLocalAudioTrackAdapter::AddSink( |
95 webrtc::AudioTrackSinkInterface* sink) { | 91 webrtc::AudioTrackSinkInterface* sink) { |
96 DCHECK(signaling_thread_checker_.CalledOnValidThread()); | |
97 DCHECK(sink); | 92 DCHECK(sink); |
| 93 |
| 94 // Normal case: WebRtc will call into this method on the signaling thread. In |
| 95 // this case, post a task to the main thread to add the sink, since the |
| 96 // MediaStream object graph may only be modified from there. |
| 97 if (main_task_runner_.get() && |
| 98 !main_task_runner_->RunsTasksOnCurrentThread()) { |
| 99 DCHECK(signaling_task_runner_ && |
| 100 signaling_task_runner_->RunsTasksOnCurrentThread()); |
| 101 main_task_runner_->PostTask( |
| 102 FROM_HERE, |
| 103 base::Bind(&WebRtcLocalAudioTrackAdapter::AddSink, this, sink)); |
| 104 return; |
| 105 } |
| 106 |
98 #ifndef NDEBUG | 107 #ifndef NDEBUG |
99 // Verify that |sink| has not been added. | 108 // Verify that |sink| has not been added. |
100 for (ScopedVector<WebRtcAudioSinkAdapter>::const_iterator it = | 109 for (ScopedVector<WebRtcAudioSinkAdapter>::const_iterator it = |
101 sink_adapters_.begin(); | 110 sink_adapters_.begin(); |
102 it != sink_adapters_.end(); ++it) { | 111 it != sink_adapters_.end(); ++it) { |
103 DCHECK(!(*it)->IsEqual(sink)); | 112 DCHECK(!(*it)->IsEqual(sink)); |
104 } | 113 } |
105 #endif | 114 #endif |
106 | 115 |
107 scoped_ptr<WebRtcAudioSinkAdapter> adapter( | 116 scoped_ptr<WebRtcAudioSinkAdapter> adapter(new WebRtcAudioSinkAdapter(sink)); |
108 new WebRtcAudioSinkAdapter(sink)); | 117 if (track_) |
109 owner_->AddSink(adapter.get()); | 118 track_->AddSink(adapter.get()); |
110 sink_adapters_.push_back(adapter.release()); | 119 sink_adapters_.push_back(std::move(adapter)); |
111 } | 120 } |
112 | 121 |
113 void WebRtcLocalAudioTrackAdapter::RemoveSink( | 122 void WebRtcLocalAudioTrackAdapter::RemoveSink( |
114 webrtc::AudioTrackSinkInterface* sink) { | 123 webrtc::AudioTrackSinkInterface* sink) { |
115 DCHECK(signaling_thread_checker_.CalledOnValidThread()); | 124 // Normal case: WebRtc will call into this method on the signaling thread. In |
| 125 // this case, post a task to the main thread to remove the sink, since the |
| 126 // MediaStream object graph may only be modified from there. Furthermore, |
| 127 // block the current thread until the task has completed to ensure the audio |
| 128 // flow to |sink| has been stopped by the time this method returns. |
| 129 if (main_task_runner_.get() && |
| 130 !main_task_runner_->RunsTasksOnCurrentThread()) { |
| 131 DCHECK(signaling_task_runner_ && |
| 132 signaling_task_runner_->RunsTasksOnCurrentThread()); |
| 133 base::WaitableEvent done_event(false, false); |
| 134 main_task_runner_->PostTask( |
| 135 FROM_HERE, |
| 136 base::Bind(&WebRtcLocalAudioTrackAdapter::RemoveSinkOnMainThread, |
| 137 this, sink, &done_event)); |
| 138 done_event.Wait(); |
| 139 return; |
| 140 } |
| 141 |
| 142 // For single-threaded unit tests: |
| 143 RemoveSinkOnMainThread(sink, nullptr); |
| 144 } |
| 145 |
| 146 void WebRtcLocalAudioTrackAdapter::RemoveSinkOnMainThread( |
| 147 webrtc::AudioTrackSinkInterface* sink, |
| 148 base::WaitableEvent* done_event) { |
| 149 DCHECK(!main_task_runner_ || main_task_runner_->RunsTasksOnCurrentThread()); |
116 DCHECK(sink); | 150 DCHECK(sink); |
117 for (ScopedVector<WebRtcAudioSinkAdapter>::iterator it = | 151 for (ScopedVector<WebRtcAudioSinkAdapter>::iterator it = |
118 sink_adapters_.begin(); | 152 sink_adapters_.begin(); |
119 it != sink_adapters_.end(); ++it) { | 153 it != sink_adapters_.end(); ++it) { |
120 if ((*it)->IsEqual(sink)) { | 154 if ((*it)->IsEqual(sink)) { |
121 owner_->RemoveSink(*it); | 155 if (track_) |
| 156 track_->RemoveSink(*it); |
122 sink_adapters_.erase(it); | 157 sink_adapters_.erase(it); |
123 return; | 158 break; |
124 } | 159 } |
125 } | 160 } |
| 161 if (done_event) |
| 162 done_event->Signal(); |
126 } | 163 } |
127 | 164 |
128 bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) { | 165 bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) { |
129 DCHECK(signaling_thread_checker_.CalledOnValidThread()); | 166 // Note: Called on the signaling thread by WebRtc. |
130 | 167 float signal_level = 0.0f; |
131 base::AutoLock auto_lock(lock_); | 168 { |
132 *level = signal_level_; | 169 base::AutoLock auto_lock(lock_); |
| 170 if (!reported_level_) |
| 171 return false; |
| 172 signal_level = reported_level_->Get(); |
| 173 } |
| 174 DCHECK_GE(signal_level, 0.0f); |
| 175 DCHECK_LE(signal_level, 1.0f); |
| 176 *level = static_cast<int>(signal_level * std::numeric_limits<int16_t>::max() + |
| 177 0.5f /* rounding to nearest int */); |
133 return true; | 178 return true; |
134 } | 179 } |
135 | 180 |
136 rtc::scoped_refptr<webrtc::AudioProcessorInterface> | 181 rtc::scoped_refptr<webrtc::AudioProcessorInterface> |
137 WebRtcLocalAudioTrackAdapter::GetAudioProcessor() { | 182 WebRtcLocalAudioTrackAdapter::GetAudioProcessor() { |
138 DCHECK(signaling_thread_checker_.CalledOnValidThread()); | 183 // Note: Called on the signaling thread by WebRtc. |
139 base::AutoLock auto_lock(lock_); | 184 base::AutoLock auto_lock(lock_); |
140 return audio_processor_.get(); | 185 return audio_processor_.get(); |
141 } | 186 } |
142 | 187 |
143 void WebRtcLocalAudioTrackAdapter::SetSignalLevel(int signal_level) { | |
144 DCHECK(capture_thread_.CalledOnValidThread()); | |
145 base::AutoLock auto_lock(lock_); | |
146 signal_level_ = signal_level; | |
147 } | |
148 | |
149 webrtc::AudioSourceInterface* WebRtcLocalAudioTrackAdapter::GetSource() const { | 188 webrtc::AudioSourceInterface* WebRtcLocalAudioTrackAdapter::GetSource() const { |
150 DCHECK(signaling_thread_checker_.CalledOnValidThread()); | 189 // Note: Called on the signaling thread by WebRtc. |
151 return track_source_; | 190 return track_source_; |
152 } | 191 } |
153 | 192 |
154 } // namespace content | 193 } // namespace content |
OLD | NEW |