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
3 // found in the LICENSE file.
5 #include "content/renderer/media/webrtc_local_audio_track.h"
7 #include "content/public/renderer/media_stream_audio_sink.h"
8 #include "content/renderer/media/media_stream_audio_level_calculator.h"
9 #include "content/renderer/media/media_stream_audio_processor.h"
10 #include "content/renderer/media/media_stream_audio_sink_owner.h"
11 #include "content/renderer/media/media_stream_audio_track_sink.h"
12 #include "content/renderer/media/peer_connection_audio_sink_owner.h"
13 #include "content/renderer/media/webaudio_capturer_source.h"
14 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
15 #include "content/renderer/media/webrtc_audio_capturer.h"
19 WebRtcLocalAudioTrack::WebRtcLocalAudioTrack(
20 WebRtcLocalAudioTrackAdapter
* adapter
,
21 const scoped_refptr
<WebRtcAudioCapturer
>& capturer
,
22 WebAudioCapturerSource
* webaudio_source
)
23 : MediaStreamTrack(adapter
, true),
26 webaudio_source_(webaudio_source
) {
27 DCHECK(capturer
.get() || webaudio_source
);
29 adapter_
->Initialize(this);
31 DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()";
34 WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
35 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
36 DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()";
37 // Users might not call Stop() on the track.
41 void WebRtcLocalAudioTrack::Capture(const int16
* audio_data
,
42 base::TimeDelta delay
,
45 bool need_audio_processing
) {
46 DCHECK(capture_thread_checker_
.CalledOnValidThread());
48 // Calculate the signal level regardless if the track is disabled or enabled.
49 int signal_level
= level_calculator_
->Calculate(
50 audio_data
, audio_parameters_
.channels(),
51 audio_parameters_
.frames_per_buffer());
52 adapter_
->SetSignalLevel(signal_level
);
54 scoped_refptr
<WebRtcAudioCapturer
> capturer
;
55 SinkList::ItemList sinks
;
56 SinkList::ItemList sinks_to_notify_format
;
58 base::AutoLock
auto_lock(lock_
);
60 sinks
= sinks_
.Items();
61 sinks_
.RetrieveAndClearTags(&sinks_to_notify_format
);
64 // Notify the tracks on when the format changes. This will do nothing if
65 // |sinks_to_notify_format| is empty.
66 for (SinkList::ItemList::const_iterator it
= sinks_to_notify_format
.begin();
67 it
!= sinks_to_notify_format
.end(); ++it
) {
68 (*it
)->OnSetFormat(audio_parameters_
);
71 // Feed the data to the sinks.
72 // TODO(jiayl): we should not pass the real audio data down if the track is
73 // disabled. This is currently done so to feed input to WebRTC typing
74 // detection and should be changed when audio processing is moved from
75 // WebRTC to the track.
76 std::vector
<int> voe_channels
= adapter_
->VoeChannels();
77 for (SinkList::ItemList::const_iterator it
= sinks
.begin();
80 int new_volume
= (*it
)->OnData(audio_data
,
81 audio_parameters_
.sample_rate(),
82 audio_parameters_
.channels(),
83 audio_parameters_
.frames_per_buffer(),
85 delay
.InMilliseconds(),
87 need_audio_processing
,
89 if (new_volume
!= 0 && capturer
.get() && !webaudio_source_
.get()) {
90 // Feed the new volume to WebRtc while changing the volume on the
92 capturer
->SetVolume(new_volume
);
97 void WebRtcLocalAudioTrack::OnSetFormat(
98 const media::AudioParameters
& params
) {
99 DVLOG(1) << "WebRtcLocalAudioTrack::OnSetFormat()";
100 // If the source is restarted, we might have changed to another capture
102 capture_thread_checker_
.DetachFromThread();
103 DCHECK(capture_thread_checker_
.CalledOnValidThread());
105 audio_parameters_
= params
;
106 level_calculator_
.reset(new MediaStreamAudioLevelCalculator());
108 base::AutoLock
auto_lock(lock_
);
109 // Remember to notify all sinks of the new format.
113 void WebRtcLocalAudioTrack::SetAudioProcessor(
114 const scoped_refptr
<MediaStreamAudioProcessor
>& processor
) {
115 // if the |processor| does not have audio processing, which can happen if
116 // kDisableAudioTrackProcessing is set set or all the constraints in
117 // the |processor| are turned off. In such case, we pass NULL to the
118 // adapter to indicate that no stats can be gotten from the processor.
119 adapter_
->SetAudioProcessor(processor
->has_audio_processing() ?
123 void WebRtcLocalAudioTrack::AddSink(MediaStreamAudioSink
* sink
) {
124 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
125 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
126 base::AutoLock
auto_lock(lock_
);
128 // Verify that |sink| is not already added to the list.
129 DCHECK(!sinks_
.Contains(
130 MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink
)));
132 // Create (and add to the list) a new MediaStreamAudioTrackSink
133 // which owns the |sink| and delagates all calls to the
134 // MediaStreamAudioSink interface. It will be tagged in the list, so
135 // we remember to call OnSetFormat() on the new sink.
136 scoped_refptr
<MediaStreamAudioTrackSink
> sink_owner(
137 new MediaStreamAudioSinkOwner(sink
));
138 sinks_
.AddAndTag(sink_owner
.get());
141 void WebRtcLocalAudioTrack::RemoveSink(MediaStreamAudioSink
* sink
) {
142 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
143 DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
145 base::AutoLock
auto_lock(lock_
);
147 scoped_refptr
<MediaStreamAudioTrackSink
> removed_item
= sinks_
.Remove(
148 MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink
));
150 // Clear the delegate to ensure that no more capture callbacks will
151 // be sent to this sink. Also avoids a possible crash which can happen
152 // if this method is called while capturing is active.
153 if (removed_item
.get())
154 removed_item
->Reset();
157 void WebRtcLocalAudioTrack::AddSink(PeerConnectionAudioSink
* sink
) {
158 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
159 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
160 base::AutoLock
auto_lock(lock_
);
162 // Verify that |sink| is not already added to the list.
163 DCHECK(!sinks_
.Contains(
164 MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink
)));
166 // Create (and add to the list) a new MediaStreamAudioTrackSink
167 // which owns the |sink| and delagates all calls to the
168 // MediaStreamAudioSink interface. It will be tagged in the list, so
169 // we remember to call OnSetFormat() on the new sink.
170 scoped_refptr
<MediaStreamAudioTrackSink
> sink_owner(
171 new PeerConnectionAudioSinkOwner(sink
));
172 sinks_
.AddAndTag(sink_owner
.get());
175 void WebRtcLocalAudioTrack::RemoveSink(PeerConnectionAudioSink
* sink
) {
176 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
177 DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
179 base::AutoLock
auto_lock(lock_
);
181 scoped_refptr
<MediaStreamAudioTrackSink
> removed_item
= sinks_
.Remove(
182 MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink
));
183 // Clear the delegate to ensure that no more capture callbacks will
184 // be sent to this sink. Also avoids a possible crash which can happen
185 // if this method is called while capturing is active.
186 if (removed_item
.get())
187 removed_item
->Reset();
190 void WebRtcLocalAudioTrack::Start() {
191 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
192 DVLOG(1) << "WebRtcLocalAudioTrack::Start()";
193 if (webaudio_source_
.get()) {
194 // If the track is hooking up with WebAudio, do NOT add the track to the
195 // capturer as its sink otherwise two streams in different clock will be
196 // pushed through the same track.
197 webaudio_source_
->Start(this, capturer_
.get());
198 } else if (capturer_
.get()) {
199 capturer_
->AddTrack(this);
202 SinkList::ItemList sinks
;
204 base::AutoLock
auto_lock(lock_
);
205 sinks
= sinks_
.Items();
207 for (SinkList::ItemList::const_iterator it
= sinks
.begin();
210 (*it
)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateLive
);
214 void WebRtcLocalAudioTrack::Stop() {
215 DCHECK(main_render_thread_checker_
.CalledOnValidThread());
216 DVLOG(1) << "WebRtcLocalAudioTrack::Stop()";
217 if (!capturer_
.get() && !webaudio_source_
.get())
220 if (webaudio_source_
.get()) {
221 // Called Stop() on the |webaudio_source_| explicitly so that
222 // |webaudio_source_| won't push more data to the track anymore.
223 // Also note that the track is not registered as a sink to the |capturer_|
224 // in such case and no need to call RemoveTrack().
225 webaudio_source_
->Stop();
227 // It is necessary to call RemoveTrack on the |capturer_| to avoid getting
228 // audio callback after Stop().
229 capturer_
->RemoveTrack(this);
232 // Protect the pointers using the lock when accessing |sinks_| and
233 // setting the |capturer_| to NULL.
234 SinkList::ItemList sinks
;
236 base::AutoLock
auto_lock(lock_
);
237 sinks
= sinks_
.Items();
239 webaudio_source_
= NULL
;
243 for (SinkList::ItemList::const_iterator it
= sinks
.begin();
246 (*it
)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded
);
251 } // namespace content