• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2014 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "pc/remote_audio_source.h"
12 
13 #include <stddef.h>
14 
15 #include <memory>
16 #include <string>
17 
18 #include "absl/algorithm/container.h"
19 #include "api/scoped_refptr.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/constructor_magic.h"
22 #include "rtc_base/location.h"
23 #include "rtc_base/logging.h"
24 #include "rtc_base/numerics/safe_conversions.h"
25 #include "rtc_base/thread.h"
26 #include "rtc_base/thread_checker.h"
27 
28 namespace webrtc {
29 
30 // This proxy is passed to the underlying media engine to receive audio data as
31 // they come in. The data will then be passed back up to the RemoteAudioSource
32 // which will fan it out to all the sinks that have been added to it.
33 class RemoteAudioSource::AudioDataProxy : public AudioSinkInterface {
34  public:
AudioDataProxy(RemoteAudioSource * source)35   explicit AudioDataProxy(RemoteAudioSource* source) : source_(source) {
36     RTC_DCHECK(source);
37   }
~AudioDataProxy()38   ~AudioDataProxy() override { source_->OnAudioChannelGone(); }
39 
40   // AudioSinkInterface implementation.
OnData(const AudioSinkInterface::Data & audio)41   void OnData(const AudioSinkInterface::Data& audio) override {
42     source_->OnData(audio);
43   }
44 
45  private:
46   const rtc::scoped_refptr<RemoteAudioSource> source_;
47 
48   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioDataProxy);
49 };
50 
RemoteAudioSource(rtc::Thread * worker_thread)51 RemoteAudioSource::RemoteAudioSource(rtc::Thread* worker_thread)
52     : main_thread_(rtc::Thread::Current()),
53       worker_thread_(worker_thread),
54       state_(MediaSourceInterface::kLive) {
55   RTC_DCHECK(main_thread_);
56   RTC_DCHECK(worker_thread_);
57 }
58 
~RemoteAudioSource()59 RemoteAudioSource::~RemoteAudioSource() {
60   RTC_DCHECK(main_thread_->IsCurrent());
61   RTC_DCHECK(audio_observers_.empty());
62   RTC_DCHECK(sinks_.empty());
63 }
64 
Start(cricket::VoiceMediaChannel * media_channel,absl::optional<uint32_t> ssrc)65 void RemoteAudioSource::Start(cricket::VoiceMediaChannel* media_channel,
66                               absl::optional<uint32_t> ssrc) {
67   RTC_DCHECK_RUN_ON(main_thread_);
68   RTC_DCHECK(media_channel);
69 
70   // Register for callbacks immediately before AddSink so that we always get
71   // notified when a channel goes out of scope (signaled when "AudioDataProxy"
72   // is destroyed).
73   worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
74     ssrc ? media_channel->SetRawAudioSink(
75                *ssrc, std::make_unique<AudioDataProxy>(this))
76          : media_channel->SetDefaultRawAudioSink(
77                std::make_unique<AudioDataProxy>(this));
78   });
79 }
80 
Stop(cricket::VoiceMediaChannel * media_channel,absl::optional<uint32_t> ssrc)81 void RemoteAudioSource::Stop(cricket::VoiceMediaChannel* media_channel,
82                              absl::optional<uint32_t> ssrc) {
83   RTC_DCHECK_RUN_ON(main_thread_);
84   RTC_DCHECK(media_channel);
85 
86   worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
87     ssrc ? media_channel->SetRawAudioSink(*ssrc, nullptr)
88          : media_channel->SetDefaultRawAudioSink(nullptr);
89   });
90 }
91 
state() const92 MediaSourceInterface::SourceState RemoteAudioSource::state() const {
93   RTC_DCHECK(main_thread_->IsCurrent());
94   return state_;
95 }
96 
remote() const97 bool RemoteAudioSource::remote() const {
98   RTC_DCHECK(main_thread_->IsCurrent());
99   return true;
100 }
101 
SetVolume(double volume)102 void RemoteAudioSource::SetVolume(double volume) {
103   RTC_DCHECK_GE(volume, 0);
104   RTC_DCHECK_LE(volume, 10);
105   for (auto* observer : audio_observers_) {
106     observer->OnSetVolume(volume);
107   }
108 }
109 
RegisterAudioObserver(AudioObserver * observer)110 void RemoteAudioSource::RegisterAudioObserver(AudioObserver* observer) {
111   RTC_DCHECK(observer != NULL);
112   RTC_DCHECK(!absl::c_linear_search(audio_observers_, observer));
113   audio_observers_.push_back(observer);
114 }
115 
UnregisterAudioObserver(AudioObserver * observer)116 void RemoteAudioSource::UnregisterAudioObserver(AudioObserver* observer) {
117   RTC_DCHECK(observer != NULL);
118   audio_observers_.remove(observer);
119 }
120 
AddSink(AudioTrackSinkInterface * sink)121 void RemoteAudioSource::AddSink(AudioTrackSinkInterface* sink) {
122   RTC_DCHECK(main_thread_->IsCurrent());
123   RTC_DCHECK(sink);
124 
125   if (state_ != MediaSourceInterface::kLive) {
126     RTC_LOG(LS_ERROR) << "Can't register sink as the source isn't live.";
127     return;
128   }
129 
130   MutexLock lock(&sink_lock_);
131   RTC_DCHECK(!absl::c_linear_search(sinks_, sink));
132   sinks_.push_back(sink);
133 }
134 
RemoveSink(AudioTrackSinkInterface * sink)135 void RemoteAudioSource::RemoveSink(AudioTrackSinkInterface* sink) {
136   RTC_DCHECK(main_thread_->IsCurrent());
137   RTC_DCHECK(sink);
138 
139   MutexLock lock(&sink_lock_);
140   sinks_.remove(sink);
141 }
142 
OnData(const AudioSinkInterface::Data & audio)143 void RemoteAudioSource::OnData(const AudioSinkInterface::Data& audio) {
144   // Called on the externally-owned audio callback thread, via/from webrtc.
145   MutexLock lock(&sink_lock_);
146   for (auto* sink : sinks_) {
147     // When peerconnection acts as an audio source, it should not provide
148     // absolute capture timestamp.
149     sink->OnData(audio.data, 16, audio.sample_rate, audio.channels,
150                  audio.samples_per_channel,
151                  /*absolute_capture_timestamp_ms=*/absl::nullopt);
152   }
153 }
154 
OnAudioChannelGone()155 void RemoteAudioSource::OnAudioChannelGone() {
156   // Called when the audio channel is deleted.  It may be the worker thread
157   // in libjingle or may be a different worker thread.
158   // This object needs to live long enough for the cleanup logic in OnMessage to
159   // run, so take a reference to it as the data. Sometimes the message may not
160   // be processed (because the thread was destroyed shortly after this call),
161   // but that is fine because the thread destructor will take care of destroying
162   // the message data which will release the reference on RemoteAudioSource.
163   main_thread_->Post(RTC_FROM_HERE, this, 0,
164                      new rtc::ScopedRefMessageData<RemoteAudioSource>(this));
165 }
166 
OnMessage(rtc::Message * msg)167 void RemoteAudioSource::OnMessage(rtc::Message* msg) {
168   RTC_DCHECK(main_thread_->IsCurrent());
169   sinks_.clear();
170   state_ = MediaSourceInterface::kEnded;
171   FireOnChanged();
172   // Will possibly delete this RemoteAudioSource since it is reference counted
173   // in the message.
174   delete msg->pdata;
175 }
176 
177 }  // namespace webrtc
178