1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/renderer/media/webrtc_local_audio_track.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/renderer/media_stream_audio_sink.h"
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/renderer/media/media_stream_audio_level_calculator.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/renderer/media/media_stream_audio_processor.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/renderer/media/media_stream_audio_sink_owner.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/renderer/media/media_stream_audio_track_sink.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/renderer/media/peer_connection_audio_sink_owner.h"
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/renderer/media/webaudio_capturer_source.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/renderer/media/webrtc_audio_capturer.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace content {
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebRtcLocalAudioTrack::WebRtcLocalAudioTrack(
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebRtcLocalAudioTrackAdapter* adapter,
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const scoped_refptr<WebRtcAudioCapturer>& capturer,
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebAudioCapturerSource* webaudio_source)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : MediaStreamTrack(adapter, true),
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      adapter_(adapter),
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      capturer_(capturer),
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      webaudio_source_(webaudio_source) {
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(capturer.get() || webaudio_source);
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  adapter_->Initialize(this);
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()";
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()";
377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Users might not call Stop() on the track.
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  Stop();
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebRtcLocalAudioTrack::Capture(const int16* audio_data,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::TimeDelta delay,
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    int volume,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    bool key_pressed,
45ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                                    bool need_audio_processing,
46ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                                    bool force_report_nonzero_energy) {
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(capture_thread_checker_.CalledOnValidThread());
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Calculate the signal level regardless if the track is disabled or enabled.
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int signal_level = level_calculator_->Calculate(
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      audio_data, audio_parameters_.channels(),
52ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      audio_parameters_.frames_per_buffer(), force_report_nonzero_energy);
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  adapter_->SetSignalLevel(signal_level);
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_refptr<WebRtcAudioCapturer> capturer;
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SinkList::ItemList sinks;
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SinkList::ItemList sinks_to_notify_format;
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::AutoLock auto_lock(lock_);
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    capturer = capturer_;
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sinks = sinks_.Items();
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sinks_.RetrieveAndClearTags(&sinks_to_notify_format);
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Notify the tracks on when the format changes. This will do nothing if
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // |sinks_to_notify_format| is empty.
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (SinkList::ItemList::const_iterator it = sinks_to_notify_format.begin();
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != sinks_to_notify_format.end(); ++it) {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->OnSetFormat(audio_parameters_);
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Feed the data to the sinks.
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(jiayl): we should not pass the real audio data down if the track is
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // disabled. This is currently done so to feed input to WebRTC typing
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // detection and should be changed when audio processing is moved from
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // WebRTC to the track.
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<int> voe_channels = adapter_->VoeChannels();
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (SinkList::ItemList::const_iterator it = sinks.begin();
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != sinks.end();
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int new_volume = (*it)->OnData(audio_data,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   audio_parameters_.sample_rate(),
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   audio_parameters_.channels(),
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   audio_parameters_.frames_per_buffer(),
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   voe_channels,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   delay.InMilliseconds(),
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   volume,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   need_audio_processing,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   key_pressed);
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (new_volume != 0 && capturer.get() && !webaudio_source_.get()) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Feed the new volume to WebRtc while changing the volume on the
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // browser.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      capturer->SetVolume(new_volume);
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioTrack::OnSetFormat(
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const media::AudioParameters& params) {
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::OnSetFormat()";
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If the source is restarted, we might have changed to another capture
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // thread.
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  capture_thread_checker_.DetachFromThread();
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(capture_thread_checker_.CalledOnValidThread());
105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_parameters_ = params;
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  level_calculator_.reset(new MediaStreamAudioLevelCalculator());
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Remember to notify all sinks of the new format.
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sinks_.TagAll();
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void WebRtcLocalAudioTrack::SetAudioProcessor(
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const scoped_refptr<MediaStreamAudioProcessor>& processor) {
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // if the |processor| does not have audio processing, which can happen if
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // kDisableAudioTrackProcessing is set set or all the constraints in
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the |processor| are turned off. In such case, we pass NULL to the
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // adapter to indicate that no stats can be gotten from the processor.
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  adapter_->SetAudioProcessor(processor->has_audio_processing() ?
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      processor : NULL);
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioTrack::AddSink(MediaStreamAudioSink* sink) {
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Verify that |sink| is not already added to the list.
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(!sinks_.Contains(
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink)));
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Create (and add to the list) a new MediaStreamAudioTrackSink
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // which owns the |sink| and delagates all calls to the
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // MediaStreamAudioSink interface. It will be tagged in the list, so
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // we remember to call OnSetFormat() on the new sink.
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<MediaStreamAudioTrackSink> sink_owner(
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new MediaStreamAudioSinkOwner(sink));
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  sinks_.AddAndTag(sink_owner.get());
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioTrack::RemoveSink(MediaStreamAudioSink* sink) {
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<MediaStreamAudioTrackSink> removed_item = sinks_.Remove(
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MediaStreamAudioTrackSink::WrapsMediaStreamSink(sink));
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Clear the delegate to ensure that no more capture callbacks will
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // be sent to this sink. Also avoids a possible crash which can happen
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // if this method is called while capturing is active.
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (removed_item.get())
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    removed_item->Reset();
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioTrack::AddSink(PeerConnectionAudioSink* sink) {
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::AddSink()";
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Verify that |sink| is not already added to the list.
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(!sinks_.Contains(
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink)));
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Create (and add to the list) a new MediaStreamAudioTrackSink
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // which owns the |sink| and delagates all calls to the
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // MediaStreamAudioSink interface. It will be tagged in the list, so
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // we remember to call OnSetFormat() on the new sink.
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<MediaStreamAudioTrackSink> sink_owner(
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new PeerConnectionAudioSinkOwner(sink));
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  sinks_.AddAndTag(sink_owner.get());
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioTrack::RemoveSink(PeerConnectionAudioSink* sink) {
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<MediaStreamAudioTrackSink> removed_item = sinks_.Remove(
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MediaStreamAudioTrackSink::WrapsPeerConnectionSink(sink));
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Clear the delegate to ensure that no more capture callbacks will
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // be sent to this sink. Also avoids a possible crash which can happen
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // if this method is called while capturing is active.
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (removed_item.get())
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    removed_item->Reset();
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void WebRtcLocalAudioTrack::Start() {
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::Start()";
194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (webaudio_source_.get()) {
195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // If the track is hooking up with WebAudio, do NOT add the track to the
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // capturer as its sink otherwise two streams in different clock will be
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // pushed through the same track.
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    webaudio_source_->Start(this, capturer_.get());
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (capturer_.get()) {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    capturer_->AddTrack(this);
201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SinkList::ItemList sinks;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::AutoLock auto_lock(lock_);
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sinks = sinks_.Items();
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (SinkList::ItemList::const_iterator it = sinks.begin();
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != sinks.end();
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateLive);
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void WebRtcLocalAudioTrack::Stop() {
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(main_render_thread_checker_.CalledOnValidThread());
2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioTrack::Stop()";
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!capturer_.get() && !webaudio_source_.get())
219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return;
220bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (webaudio_source_.get()) {
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Called Stop() on the |webaudio_source_| explicitly so that
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // |webaudio_source_| won't push more data to the track anymore.
224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Also note that the track is not registered as a sink to the |capturer_|
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // in such case and no need to call RemoveTrack().
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    webaudio_source_->Stop();
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  } else {
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // It is necessary to call RemoveTrack on the |capturer_| to avoid getting
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // audio callback after Stop().
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    capturer_->RemoveTrack(this);
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
232bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
233bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Protect the pointers using the lock when accessing |sinks_| and
234bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // setting the |capturer_| to NULL.
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SinkList::ItemList sinks;
236bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  {
237bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    base::AutoLock auto_lock(lock_);
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sinks = sinks_.Items();
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sinks_.Clear();
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    webaudio_source_ = NULL;
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    capturer_ = NULL;
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
243bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (SinkList::ItemList::const_iterator it = sinks.begin();
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       it != sinks.end();
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it){
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded);
248bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    (*it)->Reset();
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace content
253