• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 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 "audio/voip/voip_core.h"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <utility>
16 
17 #include "api/audio_codecs/audio_format.h"
18 #include "rtc_base/logging.h"
19 
20 namespace webrtc {
21 
22 namespace {
23 
24 // For Windows, use specific enum type to initialize default audio device as
25 // defined in AudioDeviceModule::WindowsDeviceType.
26 #if defined(WEBRTC_WIN)
27 constexpr AudioDeviceModule::WindowsDeviceType kAudioDeviceId =
28     AudioDeviceModule::WindowsDeviceType::kDefaultCommunicationDevice;
29 #else
30 constexpr uint16_t kAudioDeviceId = 0;
31 #endif  // defined(WEBRTC_WIN)
32 
33 // Maximum value range limit on ChannelId. This can be increased without any
34 // side effect and only set at this moderate value for better readability for
35 // logging.
36 static constexpr int kMaxChannelId = 100000;
37 
38 }  // namespace
39 
Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,std::unique_ptr<TaskQueueFactory> task_queue_factory,rtc::scoped_refptr<AudioDeviceModule> audio_device_module,rtc::scoped_refptr<AudioProcessing> audio_processing)40 bool VoipCore::Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
41                     rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
42                     std::unique_ptr<TaskQueueFactory> task_queue_factory,
43                     rtc::scoped_refptr<AudioDeviceModule> audio_device_module,
44                     rtc::scoped_refptr<AudioProcessing> audio_processing) {
45   encoder_factory_ = std::move(encoder_factory);
46   decoder_factory_ = std::move(decoder_factory);
47   task_queue_factory_ = std::move(task_queue_factory);
48   audio_device_module_ = std::move(audio_device_module);
49 
50   process_thread_ = ProcessThread::Create("ModuleProcessThread");
51   audio_mixer_ = AudioMixerImpl::Create();
52 
53   if (audio_processing) {
54     audio_processing_ = std::move(audio_processing);
55     AudioProcessing::Config apm_config = audio_processing_->GetConfig();
56     apm_config.echo_canceller.enabled = true;
57     audio_processing_->ApplyConfig(apm_config);
58   }
59 
60   // AudioTransportImpl depends on audio mixer and audio processing instances.
61   audio_transport_ = std::make_unique<AudioTransportImpl>(
62       audio_mixer_.get(), audio_processing_.get());
63 
64   // Initialize ADM.
65   if (audio_device_module_->Init() != 0) {
66     RTC_LOG(LS_ERROR) << "Failed to initialize the ADM.";
67     return false;
68   }
69 
70   // Note that failures on initializing default recording/speaker devices are
71   // not considered to be fatal here. In certain case, caller may not care about
72   // recording device functioning (e.g webinar where only speaker is available).
73   // It's also possible that there are other audio devices available that may
74   // work.
75   // TODO(natim@webrtc.org): consider moving this part out of initialization.
76 
77   // Initialize default speaker device.
78   if (audio_device_module_->SetPlayoutDevice(kAudioDeviceId) != 0) {
79     RTC_LOG(LS_WARNING) << "Unable to set playout device.";
80   }
81   if (audio_device_module_->InitSpeaker() != 0) {
82     RTC_LOG(LS_WARNING) << "Unable to access speaker.";
83   }
84 
85   // Initialize default recording device.
86   if (audio_device_module_->SetRecordingDevice(kAudioDeviceId) != 0) {
87     RTC_LOG(LS_WARNING) << "Unable to set recording device.";
88   }
89   if (audio_device_module_->InitMicrophone() != 0) {
90     RTC_LOG(LS_WARNING) << "Unable to access microphone.";
91   }
92 
93   // Set number of channels on speaker device.
94   bool available = false;
95   if (audio_device_module_->StereoPlayoutIsAvailable(&available) != 0) {
96     RTC_LOG(LS_WARNING) << "Unable to query stereo playout.";
97   }
98   if (audio_device_module_->SetStereoPlayout(available) != 0) {
99     RTC_LOG(LS_WARNING) << "Unable to set mono/stereo playout mode.";
100   }
101 
102   // Set number of channels on recording device.
103   available = false;
104   if (audio_device_module_->StereoRecordingIsAvailable(&available) != 0) {
105     RTC_LOG(LS_WARNING) << "Unable to query stereo recording.";
106   }
107   if (audio_device_module_->SetStereoRecording(available) != 0) {
108     RTC_LOG(LS_WARNING) << "Unable to set stereo recording mode.";
109   }
110 
111   if (audio_device_module_->RegisterAudioCallback(audio_transport_.get()) !=
112       0) {
113     RTC_LOG(LS_WARNING) << "Unable to register audio callback.";
114   }
115 
116   return true;
117 }
118 
CreateChannel(Transport * transport,absl::optional<uint32_t> local_ssrc)119 absl::optional<ChannelId> VoipCore::CreateChannel(
120     Transport* transport,
121     absl::optional<uint32_t> local_ssrc) {
122   absl::optional<ChannelId> channel;
123 
124   // Set local ssrc to random if not set by caller.
125   if (!local_ssrc) {
126     Random random(rtc::TimeMicros());
127     local_ssrc = random.Rand<uint32_t>();
128   }
129 
130   rtc::scoped_refptr<AudioChannel> audio_channel =
131       new rtc::RefCountedObject<AudioChannel>(
132           transport, local_ssrc.value(), task_queue_factory_.get(),
133           process_thread_.get(), audio_mixer_.get(), decoder_factory_);
134 
135   {
136     MutexLock lock(&lock_);
137 
138     channel = static_cast<ChannelId>(next_channel_id_);
139     channels_[*channel] = audio_channel;
140     next_channel_id_++;
141     if (next_channel_id_ >= kMaxChannelId) {
142       next_channel_id_ = 0;
143     }
144   }
145 
146   // Set ChannelId in audio channel for logging/debugging purpose.
147   audio_channel->SetId(*channel);
148 
149   return channel;
150 }
151 
ReleaseChannel(ChannelId channel)152 void VoipCore::ReleaseChannel(ChannelId channel) {
153   // Destroy channel outside of the lock.
154   rtc::scoped_refptr<AudioChannel> audio_channel;
155   {
156     MutexLock lock(&lock_);
157 
158     auto iter = channels_.find(channel);
159     if (iter != channels_.end()) {
160       audio_channel = std::move(iter->second);
161       channels_.erase(iter);
162     }
163   }
164   if (!audio_channel) {
165     RTC_LOG(LS_WARNING) << "Channel " << channel << " not found";
166   }
167 }
168 
GetChannel(ChannelId channel)169 rtc::scoped_refptr<AudioChannel> VoipCore::GetChannel(ChannelId channel) {
170   rtc::scoped_refptr<AudioChannel> audio_channel;
171   {
172     MutexLock lock(&lock_);
173     auto iter = channels_.find(channel);
174     if (iter != channels_.end()) {
175       audio_channel = iter->second;
176     }
177   }
178   if (!audio_channel) {
179     RTC_LOG(LS_ERROR) << "Channel " << channel << " not found";
180   }
181   return audio_channel;
182 }
183 
UpdateAudioTransportWithSenders()184 bool VoipCore::UpdateAudioTransportWithSenders() {
185   std::vector<AudioSender*> audio_senders;
186 
187   // Gather a list of audio channel that are currently sending along with
188   // highest sampling rate and channel numbers to configure into audio
189   // transport.
190   int max_sampling_rate = 8000;
191   size_t max_num_channels = 1;
192   {
193     MutexLock lock(&lock_);
194     // Reserve to prevent run time vector re-allocation.
195     audio_senders.reserve(channels_.size());
196     for (auto kv : channels_) {
197       rtc::scoped_refptr<AudioChannel>& channel = kv.second;
198       if (channel->IsSendingMedia()) {
199         auto encoder_format = channel->GetEncoderFormat();
200         if (!encoder_format) {
201           RTC_LOG(LS_ERROR)
202               << "channel " << channel->GetId() << " encoder is not set";
203           continue;
204         }
205         audio_senders.push_back(channel->GetAudioSender());
206         max_sampling_rate =
207             std::max(max_sampling_rate, encoder_format->clockrate_hz);
208         max_num_channels =
209             std::max(max_num_channels, encoder_format->num_channels);
210       }
211     }
212   }
213 
214   audio_transport_->UpdateAudioSenders(audio_senders, max_sampling_rate,
215                                        max_num_channels);
216 
217   // Depending on availability of senders, turn on or off ADM recording.
218   if (!audio_senders.empty()) {
219     if (!audio_device_module_->Recording()) {
220       if (audio_device_module_->InitRecording() != 0) {
221         RTC_LOG(LS_ERROR) << "InitRecording failed";
222         return false;
223       }
224       if (audio_device_module_->StartRecording() != 0) {
225         RTC_LOG(LS_ERROR) << "StartRecording failed";
226         return false;
227       }
228     }
229   } else {
230     if (audio_device_module_->Recording() &&
231         audio_device_module_->StopRecording() != 0) {
232       RTC_LOG(LS_ERROR) << "StopRecording failed";
233       return false;
234     }
235   }
236   return true;
237 }
238 
StartSend(ChannelId channel)239 bool VoipCore::StartSend(ChannelId channel) {
240   auto audio_channel = GetChannel(channel);
241   if (!audio_channel) {
242     return false;
243   }
244 
245   audio_channel->StartSend();
246 
247   return UpdateAudioTransportWithSenders();
248 }
249 
StopSend(ChannelId channel)250 bool VoipCore::StopSend(ChannelId channel) {
251   auto audio_channel = GetChannel(channel);
252   if (!audio_channel) {
253     return false;
254   }
255 
256   audio_channel->StopSend();
257 
258   return UpdateAudioTransportWithSenders();
259 }
260 
StartPlayout(ChannelId channel)261 bool VoipCore::StartPlayout(ChannelId channel) {
262   auto audio_channel = GetChannel(channel);
263   if (!audio_channel) {
264     return false;
265   }
266 
267   audio_channel->StartPlay();
268 
269   if (!audio_device_module_->Playing()) {
270     if (audio_device_module_->InitPlayout() != 0) {
271       RTC_LOG(LS_ERROR) << "InitPlayout failed";
272       return false;
273     }
274     if (audio_device_module_->StartPlayout() != 0) {
275       RTC_LOG(LS_ERROR) << "StartPlayout failed";
276       return false;
277     }
278   }
279   return true;
280 }
281 
StopPlayout(ChannelId channel)282 bool VoipCore::StopPlayout(ChannelId channel) {
283   auto audio_channel = GetChannel(channel);
284   if (!audio_channel) {
285     return false;
286   }
287 
288   audio_channel->StopPlay();
289 
290   bool stop_device = true;
291   {
292     MutexLock lock(&lock_);
293     for (auto kv : channels_) {
294       rtc::scoped_refptr<AudioChannel>& channel = kv.second;
295       if (channel->IsPlaying()) {
296         stop_device = false;
297         break;
298       }
299     }
300   }
301 
302   if (stop_device && audio_device_module_->Playing()) {
303     if (audio_device_module_->StopPlayout() != 0) {
304       RTC_LOG(LS_ERROR) << "StopPlayout failed";
305       return false;
306     }
307   }
308   return true;
309 }
310 
ReceivedRTPPacket(ChannelId channel,rtc::ArrayView<const uint8_t> rtp_packet)311 void VoipCore::ReceivedRTPPacket(ChannelId channel,
312                                  rtc::ArrayView<const uint8_t> rtp_packet) {
313   // Failure to locate channel is logged internally in GetChannel.
314   if (auto audio_channel = GetChannel(channel)) {
315     audio_channel->ReceivedRTPPacket(rtp_packet);
316   }
317 }
318 
ReceivedRTCPPacket(ChannelId channel,rtc::ArrayView<const uint8_t> rtcp_packet)319 void VoipCore::ReceivedRTCPPacket(ChannelId channel,
320                                   rtc::ArrayView<const uint8_t> rtcp_packet) {
321   // Failure to locate channel is logged internally in GetChannel.
322   if (auto audio_channel = GetChannel(channel)) {
323     audio_channel->ReceivedRTCPPacket(rtcp_packet);
324   }
325 }
326 
SetSendCodec(ChannelId channel,int payload_type,const SdpAudioFormat & encoder_format)327 void VoipCore::SetSendCodec(ChannelId channel,
328                             int payload_type,
329                             const SdpAudioFormat& encoder_format) {
330   // Failure to locate channel is logged internally in GetChannel.
331   if (auto audio_channel = GetChannel(channel)) {
332     auto encoder = encoder_factory_->MakeAudioEncoder(
333         payload_type, encoder_format, absl::nullopt);
334     audio_channel->SetEncoder(payload_type, encoder_format, std::move(encoder));
335   }
336 }
337 
SetReceiveCodecs(ChannelId channel,const std::map<int,SdpAudioFormat> & decoder_specs)338 void VoipCore::SetReceiveCodecs(
339     ChannelId channel,
340     const std::map<int, SdpAudioFormat>& decoder_specs) {
341   // Failure to locate channel is logged internally in GetChannel.
342   if (auto audio_channel = GetChannel(channel)) {
343     audio_channel->SetReceiveCodecs(decoder_specs);
344   }
345 }
346 
347 }  // namespace webrtc
348