Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webrtc_local_audio_track.cc
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.
4
5 #include "content/renderer/media/webrtc_local_audio_track.h"
6
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"
16
17 namespace content {
18
19 WebRtcLocalAudioTrack::WebRtcLocalAudioTrack(
20     WebRtcLocalAudioTrackAdapter* adapter,
21     const scoped_refptr<WebRtcAudioCapturer>& capturer,
22     WebAudioCapturerSource* webaudio_source)
23     : MediaStreamTrack(adapter, true),
24       adapter_(adapter),
25       capturer_(capturer),
26       webaudio_source_(webaudio_source) {
27   DCHECK(capturer.get() || webaudio_source);
28
29   adapter_->Initialize(this);
30
31   DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()";
32 }
33
34 WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
35   DCHECK(main_render_thread_checker_.CalledOnValidThread());
36   DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()";
37   // Users might not call Stop() on the track.
38   Stop();
39 }
40
41 void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
42                                     base::TimeDelta delay,
43                                     int volume,
44                                     bool key_pressed,
45                                     bool need_audio_processing) {
46   DCHECK(capture_thread_checker_.CalledOnValidThread());
47
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);
53
54   scoped_refptr<WebRtcAudioCapturer> capturer;
55   SinkList::ItemList sinks;
56   SinkList::ItemList sinks_to_notify_format;
57   {
58     base::AutoLock auto_lock(lock_);
59     capturer = capturer_;
60     sinks = sinks_.Items();
61     sinks_.RetrieveAndClearTags(&sinks_to_notify_format);
62   }
63
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_);
69   }
70
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();
78        it != sinks.end();
79        ++it) {
80     int new_volume = (*it)->OnData(audio_data,
81                                    audio_parameters_.sample_rate(),
82                                    audio_parameters_.channels(),
83                                    audio_parameters_.frames_per_buffer(),
84                                    voe_channels,
85                                    delay.InMilliseconds(),
86                                    volume,
87                                    need_audio_processing,
88                                    key_pressed);
89     if (new_volume != 0 && capturer.get() && !webaudio_source_.get()) {
90       // Feed the new volume to WebRtc while changing the volume on the
91       // browser.
92       capturer->SetVolume(new_volume);
93     }
94   }
95 }
96
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
101   // thread.
102   capture_thread_checker_.DetachFromThread();
103   DCHECK(capture_thread_checker_.CalledOnValidThread());
104
105   audio_parameters_ = params;
106   level_calculator_.reset(new MediaStreamAudioLevelCalculator());
107
108   base::AutoLock auto_lock(lock_);
109   // Remember to notify all sinks of the new format.
110   sinks_.TagAll();
111 }
112
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() ?
120       processor : NULL);
121 }
122
123 void WebRtcLocalAudioTrack::AddSink(MediaStreamAudioSink* sink) {
124   DCHECK(main_render_thread_checker_.CalledOnValidThread());
125   DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
126   base::AutoLock auto_lock(lock_);
127
128   // Verify that |sink| is not already added to the list.
129   DCHECK(!sinks_.Contains(
130       MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink)));
131
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());
139 }
140
141 void WebRtcLocalAudioTrack::RemoveSink(MediaStreamAudioSink* sink) {
142   DCHECK(main_render_thread_checker_.CalledOnValidThread());
143   DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
144
145   base::AutoLock auto_lock(lock_);
146
147   scoped_refptr<MediaStreamAudioTrackSink> removed_item = sinks_.Remove(
148       MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink));
149
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();
155 }
156
157 void WebRtcLocalAudioTrack::AddSink(PeerConnectionAudioSink* sink) {
158   DCHECK(main_render_thread_checker_.CalledOnValidThread());
159   DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
160   base::AutoLock auto_lock(lock_);
161
162   // Verify that |sink| is not already added to the list.
163   DCHECK(!sinks_.Contains(
164       MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink)));
165
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());
173 }
174
175 void WebRtcLocalAudioTrack::RemoveSink(PeerConnectionAudioSink* sink) {
176   DCHECK(main_render_thread_checker_.CalledOnValidThread());
177   DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
178
179   base::AutoLock auto_lock(lock_);
180
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();
188 }
189
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);
200   }
201
202   SinkList::ItemList sinks;
203   {
204     base::AutoLock auto_lock(lock_);
205     sinks = sinks_.Items();
206   }
207   for (SinkList::ItemList::const_iterator it = sinks.begin();
208        it != sinks.end();
209        ++it) {
210     (*it)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateLive);
211   }
212 }
213
214 void WebRtcLocalAudioTrack::Stop() {
215   DCHECK(main_render_thread_checker_.CalledOnValidThread());
216   DVLOG(1) << "WebRtcLocalAudioTrack::Stop()";
217   if (!capturer_.get() && !webaudio_source_.get())
218     return;
219
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();
226   } else {
227     // It is necessary to call RemoveTrack on the |capturer_| to avoid getting
228     // audio callback after Stop().
229     capturer_->RemoveTrack(this);
230   }
231
232   // Protect the pointers using the lock when accessing |sinks_| and
233   // setting the |capturer_| to NULL.
234   SinkList::ItemList sinks;
235   {
236     base::AutoLock auto_lock(lock_);
237     sinks = sinks_.Items();
238     sinks_.Clear();
239     webaudio_source_ = NULL;
240     capturer_ = NULL;
241   }
242
243   for (SinkList::ItemList::const_iterator it = sinks.begin();
244        it != sinks.end();
245        ++it){
246     (*it)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded);
247     (*it)->Reset();
248   }
249 }
250
251 }  // namespace content