OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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_local_audio_track.h" | 5 #include "content/renderer/media/webrtc_local_audio_track.h" |
6 | 6 |
| 7 #include "content/public/renderer/media_stream_audio_sink.h" |
| 8 #include "content/renderer/media/media_stream_audio_sink_owner.h" |
7 #include "content/renderer/media/webaudio_capturer_source.h" | 9 #include "content/renderer/media/webaudio_capturer_source.h" |
8 #include "content/renderer/media/webrtc_audio_capturer.h" | 10 #include "content/renderer/media/webrtc_audio_capturer.h" |
9 #include "content/renderer/media/webrtc_audio_capturer_sink_owner.h" | 11 #include "content/renderer/media/webrtc_audio_device_impl.h" |
10 #include "content/renderer/media/webrtc_local_audio_source_provider.h" | 12 #include "content/renderer/media/webrtc_local_audio_source_provider.h" |
11 #include "media/base/audio_fifo.h" | 13 #include "media/base/audio_fifo.h" |
12 #include "third_party/libjingle/source/talk/media/base/audiorenderer.h" | 14 #include "third_party/libjingle/source/talk/media/base/audiorenderer.h" |
13 | 15 |
14 namespace content { | 16 namespace content { |
15 | 17 |
16 static const size_t kMaxNumberOfBuffersInFifo = 2; | 18 static const size_t kMaxNumberOfBuffersInFifo = 2; |
17 static const char kAudioTrackKind[] = "audio"; | 19 static const char kAudioTrackKind[] = "audio"; |
18 | 20 |
19 namespace { | 21 namespace { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 voe_channels = voe_channels_; | 174 voe_channels = voe_channels_; |
173 sinks = sinks_; | 175 sinks = sinks_; |
174 std::swap(sinks_to_notify_format_, sinks_to_notify_format); | 176 std::swap(sinks_to_notify_format_, sinks_to_notify_format); |
175 is_webaudio_source = (webaudio_source_.get() != NULL); | 177 is_webaudio_source = (webaudio_source_.get() != NULL); |
176 } | 178 } |
177 | 179 |
178 // Notify the tracks on when the format changes. This will do nothing if | 180 // Notify the tracks on when the format changes. This will do nothing if |
179 // |sinks_to_notify_format| is empty. | 181 // |sinks_to_notify_format| is empty. |
180 for (SinkList::const_iterator it = sinks_to_notify_format.begin(); | 182 for (SinkList::const_iterator it = sinks_to_notify_format.begin(); |
181 it != sinks_to_notify_format.end(); ++it) { | 183 it != sinks_to_notify_format.end(); ++it) { |
182 (*it)->SetCaptureFormat(buffer_->params()); | 184 (*it)->OnSetFormat(buffer_->params()); |
183 } | 185 } |
184 | 186 |
185 // Push the data to the fifo. | 187 // Push the data to the fifo. |
186 buffer_->Push(audio_source); | 188 buffer_->Push(audio_source); |
187 | 189 |
188 // When the source is WebAudio, turn off the audio processing if the delay | 190 // When the source is WebAudio, turn off the audio processing if the delay |
189 // value is 0 even though the constraint is set to true. In such case, it | 191 // value is 0 even though the constraint is set to true. In such case, it |
190 // indicates the data is not from microphone. | 192 // indicates the data is not from microphone. |
191 // TODO(xians): remove the flag when supporting one APM per audio track. | 193 // TODO(xians): remove the flag when supporting one APM per audio track. |
192 // See crbug/264611 for details. | 194 // See crbug/264611 for details. |
193 bool need_audio_processing = need_audio_processing_; | 195 bool need_audio_processing = need_audio_processing_; |
194 if (is_webaudio_source && need_audio_processing) | 196 if (is_webaudio_source && need_audio_processing) |
195 need_audio_processing = (audio_delay_milliseconds != 0); | 197 need_audio_processing = (audio_delay_milliseconds != 0); |
196 | 198 |
197 int current_volume = volume; | 199 int current_volume = volume; |
198 while (buffer_->Consume()) { | 200 while (buffer_->Consume()) { |
199 // Feed the data to the sinks. | 201 // Feed the data to the sinks. |
200 // TODO (jiayl): we should not pass the real audio data down if the track is | 202 // TODO (jiayl): we should not pass the real audio data down if the track is |
201 // disabled. This is currently done so to feed input to WebRTC typing | 203 // disabled. This is currently done so to feed input to WebRTC typing |
202 // detection and should be changed when audio processing is moved from | 204 // detection and should be changed when audio processing is moved from |
203 // WebRTC to the track. | 205 // WebRTC to the track. |
204 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) { | 206 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) { |
205 int new_volume = (*it)->CaptureData(voe_channels, | 207 int new_volume = (*it)->OnData(buffer_->buffer(), |
206 buffer_->buffer(), | 208 buffer_->params().sample_rate(), |
207 buffer_->params().sample_rate(), | 209 buffer_->params().channels(), |
208 buffer_->params().channels(), | 210 buffer_->params().frames_per_buffer(), |
209 buffer_->params().frames_per_buffer(), | 211 voe_channels, |
210 audio_delay_milliseconds, | 212 audio_delay_milliseconds, |
211 current_volume, | 213 current_volume, |
212 need_audio_processing, | 214 need_audio_processing, |
213 key_pressed); | 215 key_pressed); |
214 if (new_volume != 0 && capturer.get()) { | 216 if (new_volume != 0 && capturer.get()) { |
215 // Feed the new volume to WebRtc while changing the volume on the | 217 // Feed the new volume to WebRtc while changing the volume on the |
216 // browser. | 218 // browser. |
217 capturer->SetVolume(new_volume); | 219 capturer->SetVolume(new_volume); |
218 current_volume = new_volume; | 220 current_volume = new_volume; |
219 } | 221 } |
220 } | 222 } |
221 } | 223 } |
222 } | 224 } |
223 | 225 |
224 void WebRtcLocalAudioTrack::SetCaptureFormat( | 226 void WebRtcLocalAudioTrack::OnSetFormat( |
225 const media::AudioParameters& params) { | 227 const media::AudioParameters& params) { |
226 DVLOG(1) << "WebRtcLocalAudioTrack::SetCaptureFormat()"; | 228 DVLOG(1) << "WebRtcLocalAudioTrack::OnSetFormat()"; |
227 // If the source is restarted, we might have changed to another capture | 229 // If the source is restarted, we might have changed to another capture |
228 // thread. | 230 // thread. |
229 capture_thread_checker_.DetachFromThread(); | 231 capture_thread_checker_.DetachFromThread(); |
230 DCHECK(capture_thread_checker_.CalledOnValidThread()); | 232 DCHECK(capture_thread_checker_.CalledOnValidThread()); |
231 | 233 |
232 DCHECK(params.IsValid()); | 234 DCHECK(params.IsValid()); |
233 buffer_->Configure(params); | 235 buffer_->Configure(params); |
234 | 236 |
235 base::AutoLock auto_lock(lock_); | 237 base::AutoLock auto_lock(lock_); |
236 // Copy |sinks_| to |sinks_to_notify_format_| to notify all the sinks | 238 // Copy |sinks_| to |sinks_to_notify_format_| to notify all the sinks |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 } | 270 } |
269 | 271 |
270 cricket::AudioRenderer* WebRtcLocalAudioTrack::GetRenderer() { | 272 cricket::AudioRenderer* WebRtcLocalAudioTrack::GetRenderer() { |
271 return this; | 273 return this; |
272 } | 274 } |
273 | 275 |
274 std::string WebRtcLocalAudioTrack::kind() const { | 276 std::string WebRtcLocalAudioTrack::kind() const { |
275 return kAudioTrackKind; | 277 return kAudioTrackKind; |
276 } | 278 } |
277 | 279 |
278 void WebRtcLocalAudioTrack::AddSink(WebRtcAudioCapturerSink* sink) { | 280 void WebRtcLocalAudioTrack::AddSink(MediaStreamAudioSink* sink) { |
279 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 281 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
280 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()"; | 282 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()"; |
281 base::AutoLock auto_lock(lock_); | 283 base::AutoLock auto_lock(lock_); |
282 | 284 |
283 // Verify that |sink| is not already added to the list. | 285 // Verify that |sink| is not already added to the list. |
284 DCHECK(std::find_if( | 286 DCHECK(std::find_if( |
285 sinks_.begin(), sinks_.end(), | 287 sinks_.begin(), sinks_.end(), |
286 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)) == sinks_.end()); | 288 MediaStreamAudioSinkOwner::WrapsSink(sink)) == sinks_.end()); |
287 | 289 |
288 // Create (and add to the list) a new WebRtcAudioCapturerSinkOwner which owns | 290 // Create (and add to the list) a new MediaStreamAudioSinkOwner which owns |
289 // the |sink| and delagates all calls to the WebRtcAudioCapturerSink | 291 // the |sink| and delagates all calls to the MediaStreamAudioSink |
290 // interface. | 292 // interface. |
291 scoped_refptr<WebRtcAudioCapturerSinkOwner> sink_owner( | 293 scoped_refptr<MediaStreamAudioSinkOwner> sink_owner( |
292 new WebRtcAudioCapturerSinkOwner(sink)); | 294 new MediaStreamAudioSinkOwner(sink)); |
293 sinks_.push_back(sink_owner); | 295 sinks_.push_back(sink_owner); |
294 | 296 |
295 // Also push the |sink_owner| to |sinks_to_notify_format_| so that we will | 297 // Also push the |sink_owner| to |sinks_to_notify_format_| so that we will |
296 // call SetCaptureFormat() on the new sink. | 298 // call OnSetFormat() on the new sink. |
297 sinks_to_notify_format_.push_back(sink_owner); | 299 sinks_to_notify_format_.push_back(sink_owner); |
298 } | 300 } |
299 | 301 |
300 void WebRtcLocalAudioTrack::RemoveSink( | 302 void WebRtcLocalAudioTrack::RemoveSink(MediaStreamAudioSink* sink) { |
301 WebRtcAudioCapturerSink* sink) { | |
302 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 303 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
303 DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()"; | 304 DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()"; |
304 | 305 |
305 base::AutoLock auto_lock(lock_); | 306 base::AutoLock auto_lock(lock_); |
306 // Remove the item on |tracks_to_notify_format_|. | 307 // Remove the item on |tracks_to_notify_format_|. |
307 // This has to be done before remove the element in |sinks_| since there it | 308 // This has to be done before remove the element in |sinks_| since there it |
308 // will clear the delegate. | 309 // will clear the delegate. |
309 SinkList::iterator it = std::find_if( | 310 SinkList::iterator it = std::find_if( |
310 sinks_to_notify_format_.begin(), sinks_to_notify_format_.end(), | 311 sinks_to_notify_format_.begin(), sinks_to_notify_format_.end(), |
311 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)); | 312 MediaStreamAudioSinkOwner::WrapsSink(sink)); |
312 if (it != sinks_to_notify_format_.end()) | 313 if (it != sinks_to_notify_format_.end()) |
313 sinks_to_notify_format_.erase(it); | 314 sinks_to_notify_format_.erase(it); |
314 | 315 |
315 // Get iterator to the first element for which WrapsSink(sink) returns true. | 316 // Get iterator to the first element for which WrapsSink(sink) returns true. |
316 it = std::find_if(sinks_.begin(), sinks_.end(), | 317 it = std::find_if(sinks_.begin(), sinks_.end(), |
317 WebRtcAudioCapturerSinkOwner::WrapsSink(sink)); | 318 MediaStreamAudioSinkOwner::WrapsSink(sink)); |
318 if (it != sinks_.end()) { | 319 if (it != sinks_.end()) { |
319 // Clear the delegate to ensure that no more capture callbacks will | 320 // Clear the delegate to ensure that no more capture callbacks will |
320 // be sent to this sink. Also avoids a possible crash which can happen | 321 // be sent to this sink. Also avoids a possible crash which can happen |
| 322 // if this method is called while capturing is active. |
| 323 (*it)->Reset(); |
| 324 sinks_.erase(it); |
| 325 } |
| 326 } |
| 327 |
| 328 void WebRtcLocalAudioTrack::AddSink(PeerConnectionAudioSink* sink) { |
| 329 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 330 DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()"; |
| 331 base::AutoLock auto_lock(lock_); |
| 332 |
| 333 // Verify that |sink| is not already added to the list. |
| 334 DCHECK(std::find_if( |
| 335 sinks_.begin(), sinks_.end(), |
| 336 MediaStreamAudioSinkOwner::WrapsPeerConnectionSink(sink)) == |
| 337 sinks_.end()); |
| 338 |
| 339 // Create (and add to the list) a new MediaStreamAudioSinkOwner which owns |
| 340 // the |sink| and delagates all calls to the MediaStreamAudioSink |
| 341 // interface. |
| 342 scoped_refptr<MediaStreamAudioSinkOwner> sink_owner( |
| 343 new MediaStreamAudioSinkOwner(sink)); |
| 344 sinks_.push_back(sink_owner); |
| 345 |
| 346 // Also push the |sink_owner| to |sinks_to_notify_format_| so that we will |
| 347 // call OnSetFormat() on the new sink. |
| 348 sinks_to_notify_format_.push_back(sink_owner); |
| 349 } |
| 350 |
| 351 void WebRtcLocalAudioTrack::RemoveSink(PeerConnectionAudioSink* sink) { |
| 352 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 353 DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()"; |
| 354 |
| 355 base::AutoLock auto_lock(lock_); |
| 356 // Remove the item on |tracks_to_notify_format_|. |
| 357 // This has to be done before remove the element in |sinks_| since there it |
| 358 // will clear the delegate. |
| 359 SinkList::iterator it = std::find_if( |
| 360 sinks_to_notify_format_.begin(), sinks_to_notify_format_.end(), |
| 361 MediaStreamAudioSinkOwner::WrapsPeerConnectionSink(sink)); |
| 362 if (it != sinks_to_notify_format_.end()) |
| 363 sinks_to_notify_format_.erase(it); |
| 364 |
| 365 // Get iterator to the first element for which WrapsPeerConnectionSink(sink) |
| 366 // returns true. |
| 367 it = std::find_if(sinks_.begin(), sinks_.end(), |
| 368 MediaStreamAudioSinkOwner::WrapsPeerConnectionSink(sink)); |
| 369 if (it != sinks_.end()) { |
| 370 // Clear the delegate to ensure that no more capture callbacks will |
| 371 // be sent to this sink. Also avoids a possible crash which can happen |
321 // if this method is called while capturing is active. | 372 // if this method is called while capturing is active. |
322 (*it)->Reset(); | 373 (*it)->Reset(); |
323 sinks_.erase(it); | 374 sinks_.erase(it); |
324 } | 375 } |
325 } | 376 } |
326 | 377 |
327 void WebRtcLocalAudioTrack::Start() { | 378 void WebRtcLocalAudioTrack::Start() { |
328 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 379 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
329 DVLOG(1) << "WebRtcLocalAudioTrack::Start()"; | 380 DVLOG(1) << "WebRtcLocalAudioTrack::Start()"; |
330 if (webaudio_source_.get()) { | 381 if (webaudio_source_.get()) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 sinks_to_notify_format_.clear(); | 417 sinks_to_notify_format_.clear(); |
367 webaudio_source_ = NULL; | 418 webaudio_source_ = NULL; |
368 capturer_ = NULL; | 419 capturer_ = NULL; |
369 } | 420 } |
370 | 421 |
371 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) | 422 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) |
372 (*it)->Reset(); | 423 (*it)->Reset(); |
373 } | 424 } |
374 | 425 |
375 } // namespace content | 426 } // namespace content |
OLD | NEW |