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
VoipCore(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 VoipCore::VoipCore(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 audio_processing_ = std::move(audio_processing);
50 audio_mixer_ = AudioMixerImpl::Create();
51
52 // AudioTransportImpl depends on audio mixer and audio processing instances.
53 audio_transport_ = std::make_unique<AudioTransportImpl>(
54 audio_mixer_.get(), audio_processing_.get(), nullptr);
55 }
56
InitializeIfNeeded()57 bool VoipCore::InitializeIfNeeded() {
58 // `audio_device_module_` internally owns a lock and the whole logic here
59 // needs to be executed atomically once using another lock in VoipCore.
60 // Further changes in this method will need to make sure that no deadlock is
61 // introduced in the future.
62 MutexLock lock(&lock_);
63
64 if (initialized_) {
65 return true;
66 }
67
68 // Initialize ADM.
69 if (audio_device_module_->Init() != 0) {
70 RTC_LOG(LS_ERROR) << "Failed to initialize the ADM.";
71 return false;
72 }
73
74 // Note that failures on initializing default recording/speaker devices are
75 // not considered to be fatal here. In certain case, caller may not care about
76 // recording device functioning (e.g webinar where only speaker is available).
77 // It's also possible that there are other audio devices available that may
78 // work.
79
80 // Initialize default speaker device.
81 if (audio_device_module_->SetPlayoutDevice(kAudioDeviceId) != 0) {
82 RTC_LOG(LS_WARNING) << "Unable to set playout device.";
83 }
84 if (audio_device_module_->InitSpeaker() != 0) {
85 RTC_LOG(LS_WARNING) << "Unable to access speaker.";
86 }
87
88 // Initialize default recording device.
89 if (audio_device_module_->SetRecordingDevice(kAudioDeviceId) != 0) {
90 RTC_LOG(LS_WARNING) << "Unable to set recording device.";
91 }
92 if (audio_device_module_->InitMicrophone() != 0) {
93 RTC_LOG(LS_WARNING) << "Unable to access microphone.";
94 }
95
96 // Set number of channels on speaker device.
97 bool available = false;
98 if (audio_device_module_->StereoPlayoutIsAvailable(&available) != 0) {
99 RTC_LOG(LS_WARNING) << "Unable to query stereo playout.";
100 }
101 if (audio_device_module_->SetStereoPlayout(available) != 0) {
102 RTC_LOG(LS_WARNING) << "Unable to set mono/stereo playout mode.";
103 }
104
105 // Set number of channels on recording device.
106 available = false;
107 if (audio_device_module_->StereoRecordingIsAvailable(&available) != 0) {
108 RTC_LOG(LS_WARNING) << "Unable to query stereo recording.";
109 }
110 if (audio_device_module_->SetStereoRecording(available) != 0) {
111 RTC_LOG(LS_WARNING) << "Unable to set stereo recording mode.";
112 }
113
114 if (audio_device_module_->RegisterAudioCallback(audio_transport_.get()) !=
115 0) {
116 RTC_LOG(LS_WARNING) << "Unable to register audio callback.";
117 }
118
119 initialized_ = true;
120
121 return true;
122 }
123
CreateChannel(Transport * transport,absl::optional<uint32_t> local_ssrc)124 ChannelId VoipCore::CreateChannel(Transport* transport,
125 absl::optional<uint32_t> local_ssrc) {
126 ChannelId channel_id;
127
128 // Set local ssrc to random if not set by caller.
129 if (!local_ssrc) {
130 Random random(rtc::TimeMicros());
131 local_ssrc = random.Rand<uint32_t>();
132 }
133
134 rtc::scoped_refptr<AudioChannel> channel =
135 rtc::make_ref_counted<AudioChannel>(transport, local_ssrc.value(),
136 task_queue_factory_.get(),
137 audio_mixer_.get(), decoder_factory_);
138
139 {
140 MutexLock lock(&lock_);
141
142 channel_id = static_cast<ChannelId>(next_channel_id_);
143 channels_[channel_id] = channel;
144 next_channel_id_++;
145 if (next_channel_id_ >= kMaxChannelId) {
146 next_channel_id_ = 0;
147 }
148 }
149
150 // Set ChannelId in audio channel for logging/debugging purpose.
151 channel->SetId(channel_id);
152
153 return channel_id;
154 }
155
ReleaseChannel(ChannelId channel_id)156 VoipResult VoipCore::ReleaseChannel(ChannelId channel_id) {
157 // Destroy channel outside of the lock.
158 rtc::scoped_refptr<AudioChannel> channel;
159
160 bool no_channels_after_release = false;
161
162 {
163 MutexLock lock(&lock_);
164
165 auto iter = channels_.find(channel_id);
166 if (iter != channels_.end()) {
167 channel = std::move(iter->second);
168 channels_.erase(iter);
169 }
170
171 no_channels_after_release = channels_.empty();
172 }
173
174 VoipResult status_code = VoipResult::kOk;
175 if (!channel) {
176 RTC_LOG(LS_WARNING) << "Channel " << channel_id << " not found";
177 status_code = VoipResult::kInvalidArgument;
178 }
179
180 if (no_channels_after_release) {
181 // TODO(bugs.webrtc.org/11581): unclear if we still need to clear `channel`
182 // here.
183 channel = nullptr;
184
185 // Make sure to stop playout on ADM if it is playing.
186 if (audio_device_module_->Playing()) {
187 if (audio_device_module_->StopPlayout() != 0) {
188 RTC_LOG(LS_WARNING) << "StopPlayout failed";
189 status_code = VoipResult::kInternal;
190 }
191 }
192 }
193
194 return status_code;
195 }
196
GetChannel(ChannelId channel_id)197 rtc::scoped_refptr<AudioChannel> VoipCore::GetChannel(ChannelId channel_id) {
198 rtc::scoped_refptr<AudioChannel> channel;
199 {
200 MutexLock lock(&lock_);
201 auto iter = channels_.find(channel_id);
202 if (iter != channels_.end()) {
203 channel = iter->second;
204 }
205 }
206 if (!channel) {
207 RTC_LOG(LS_ERROR) << "Channel " << channel_id << " not found";
208 }
209 return channel;
210 }
211
UpdateAudioTransportWithSenders()212 bool VoipCore::UpdateAudioTransportWithSenders() {
213 std::vector<AudioSender*> audio_senders;
214
215 // Gather a list of audio channel that are currently sending along with
216 // highest sampling rate and channel numbers to configure into audio
217 // transport.
218 int max_sampling_rate = 8000;
219 size_t max_num_channels = 1;
220 {
221 MutexLock lock(&lock_);
222 // Reserve to prevent run time vector re-allocation.
223 audio_senders.reserve(channels_.size());
224 for (auto kv : channels_) {
225 rtc::scoped_refptr<AudioChannel>& channel = kv.second;
226 if (channel->IsSendingMedia()) {
227 auto encoder_format = channel->GetEncoderFormat();
228 if (!encoder_format) {
229 RTC_LOG(LS_ERROR)
230 << "channel " << channel->GetId() << " encoder is not set";
231 continue;
232 }
233 audio_senders.push_back(channel->GetAudioSender());
234 max_sampling_rate =
235 std::max(max_sampling_rate, encoder_format->clockrate_hz);
236 max_num_channels =
237 std::max(max_num_channels, encoder_format->num_channels);
238 }
239 }
240 }
241
242 audio_transport_->UpdateAudioSenders(audio_senders, max_sampling_rate,
243 max_num_channels);
244
245 // Depending on availability of senders, turn on or off ADM recording.
246 if (!audio_senders.empty()) {
247 // Initialize audio device module and default device if needed.
248 if (!InitializeIfNeeded()) {
249 return false;
250 }
251
252 if (!audio_device_module_->Recording()) {
253 if (audio_device_module_->InitRecording() != 0) {
254 RTC_LOG(LS_ERROR) << "InitRecording failed";
255 return false;
256 }
257 if (audio_device_module_->StartRecording() != 0) {
258 RTC_LOG(LS_ERROR) << "StartRecording failed";
259 return false;
260 }
261 }
262 } else {
263 if (audio_device_module_->Recording() &&
264 audio_device_module_->StopRecording() != 0) {
265 RTC_LOG(LS_ERROR) << "StopRecording failed";
266 return false;
267 }
268 }
269 return true;
270 }
271
StartSend(ChannelId channel_id)272 VoipResult VoipCore::StartSend(ChannelId channel_id) {
273 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
274
275 if (!channel) {
276 return VoipResult::kInvalidArgument;
277 }
278
279 if (!channel->StartSend()) {
280 return VoipResult::kFailedPrecondition;
281 }
282
283 return UpdateAudioTransportWithSenders() ? VoipResult::kOk
284 : VoipResult::kInternal;
285 }
286
StopSend(ChannelId channel_id)287 VoipResult VoipCore::StopSend(ChannelId channel_id) {
288 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
289
290 if (!channel) {
291 return VoipResult::kInvalidArgument;
292 }
293
294 channel->StopSend();
295
296 return UpdateAudioTransportWithSenders() ? VoipResult::kOk
297 : VoipResult::kInternal;
298 }
299
StartPlayout(ChannelId channel_id)300 VoipResult VoipCore::StartPlayout(ChannelId channel_id) {
301 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
302
303 if (!channel) {
304 return VoipResult::kInvalidArgument;
305 }
306
307 if (channel->IsPlaying()) {
308 return VoipResult::kOk;
309 }
310
311 if (!channel->StartPlay()) {
312 return VoipResult::kFailedPrecondition;
313 }
314
315 // Initialize audio device module and default device if needed.
316 if (!InitializeIfNeeded()) {
317 return VoipResult::kInternal;
318 }
319
320 if (!audio_device_module_->Playing()) {
321 if (audio_device_module_->InitPlayout() != 0) {
322 RTC_LOG(LS_ERROR) << "InitPlayout failed";
323 return VoipResult::kInternal;
324 }
325 if (audio_device_module_->StartPlayout() != 0) {
326 RTC_LOG(LS_ERROR) << "StartPlayout failed";
327 return VoipResult::kInternal;
328 }
329 }
330
331 return VoipResult::kOk;
332 }
333
StopPlayout(ChannelId channel_id)334 VoipResult VoipCore::StopPlayout(ChannelId channel_id) {
335 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
336
337 if (!channel) {
338 return VoipResult::kInvalidArgument;
339 }
340
341 channel->StopPlay();
342
343 return VoipResult::kOk;
344 }
345
ReceivedRTPPacket(ChannelId channel_id,rtc::ArrayView<const uint8_t> rtp_packet)346 VoipResult VoipCore::ReceivedRTPPacket(
347 ChannelId channel_id,
348 rtc::ArrayView<const uint8_t> rtp_packet) {
349 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
350
351 if (!channel) {
352 return VoipResult::kInvalidArgument;
353 }
354
355 channel->ReceivedRTPPacket(rtp_packet);
356
357 return VoipResult::kOk;
358 }
359
ReceivedRTCPPacket(ChannelId channel_id,rtc::ArrayView<const uint8_t> rtcp_packet)360 VoipResult VoipCore::ReceivedRTCPPacket(
361 ChannelId channel_id,
362 rtc::ArrayView<const uint8_t> rtcp_packet) {
363 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
364
365 if (!channel) {
366 return VoipResult::kInvalidArgument;
367 }
368
369 channel->ReceivedRTCPPacket(rtcp_packet);
370
371 return VoipResult::kOk;
372 }
373
SetSendCodec(ChannelId channel_id,int payload_type,const SdpAudioFormat & encoder_format)374 VoipResult VoipCore::SetSendCodec(ChannelId channel_id,
375 int payload_type,
376 const SdpAudioFormat& encoder_format) {
377 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
378
379 if (!channel) {
380 return VoipResult::kInvalidArgument;
381 }
382
383 auto encoder = encoder_factory_->MakeAudioEncoder(
384 payload_type, encoder_format, absl::nullopt);
385 channel->SetEncoder(payload_type, encoder_format, std::move(encoder));
386
387 return VoipResult::kOk;
388 }
389
SetReceiveCodecs(ChannelId channel_id,const std::map<int,SdpAudioFormat> & decoder_specs)390 VoipResult VoipCore::SetReceiveCodecs(
391 ChannelId channel_id,
392 const std::map<int, SdpAudioFormat>& decoder_specs) {
393 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
394
395 if (!channel) {
396 return VoipResult::kInvalidArgument;
397 }
398
399 channel->SetReceiveCodecs(decoder_specs);
400
401 return VoipResult::kOk;
402 }
403
RegisterTelephoneEventType(ChannelId channel_id,int rtp_payload_type,int sample_rate_hz)404 VoipResult VoipCore::RegisterTelephoneEventType(ChannelId channel_id,
405 int rtp_payload_type,
406 int sample_rate_hz) {
407 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
408
409 if (!channel) {
410 return VoipResult::kInvalidArgument;
411 }
412
413 channel->RegisterTelephoneEventType(rtp_payload_type, sample_rate_hz);
414
415 return VoipResult::kOk;
416 }
417
SendDtmfEvent(ChannelId channel_id,DtmfEvent dtmf_event,int duration_ms)418 VoipResult VoipCore::SendDtmfEvent(ChannelId channel_id,
419 DtmfEvent dtmf_event,
420 int duration_ms) {
421 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
422
423 if (!channel) {
424 return VoipResult::kInvalidArgument;
425 }
426
427 return (channel->SendTelephoneEvent(static_cast<int>(dtmf_event), duration_ms)
428 ? VoipResult::kOk
429 : VoipResult::kFailedPrecondition);
430 }
431
GetIngressStatistics(ChannelId channel_id,IngressStatistics & ingress_stats)432 VoipResult VoipCore::GetIngressStatistics(ChannelId channel_id,
433 IngressStatistics& ingress_stats) {
434 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
435
436 if (!channel) {
437 return VoipResult::kInvalidArgument;
438 }
439
440 ingress_stats = channel->GetIngressStatistics();
441
442 return VoipResult::kOk;
443 }
444
GetChannelStatistics(ChannelId channel_id,ChannelStatistics & channel_stats)445 VoipResult VoipCore::GetChannelStatistics(ChannelId channel_id,
446 ChannelStatistics& channel_stats) {
447 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
448
449 if (!channel) {
450 return VoipResult::kInvalidArgument;
451 }
452
453 channel_stats = channel->GetChannelStatistics();
454
455 return VoipResult::kOk;
456 }
457
SetInputMuted(ChannelId channel_id,bool enable)458 VoipResult VoipCore::SetInputMuted(ChannelId channel_id, bool enable) {
459 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
460
461 if (!channel) {
462 return VoipResult::kInvalidArgument;
463 }
464
465 channel->SetMute(enable);
466
467 return VoipResult::kOk;
468 }
469
GetInputVolumeInfo(ChannelId channel_id,VolumeInfo & input_volume)470 VoipResult VoipCore::GetInputVolumeInfo(ChannelId channel_id,
471 VolumeInfo& input_volume) {
472 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
473
474 if (!channel) {
475 return VoipResult::kInvalidArgument;
476 }
477
478 input_volume.audio_level = channel->GetInputAudioLevel();
479 input_volume.total_energy = channel->GetInputTotalEnergy();
480 input_volume.total_duration = channel->GetInputTotalDuration();
481
482 return VoipResult::kOk;
483 }
484
GetOutputVolumeInfo(ChannelId channel_id,VolumeInfo & output_volume)485 VoipResult VoipCore::GetOutputVolumeInfo(ChannelId channel_id,
486 VolumeInfo& output_volume) {
487 rtc::scoped_refptr<AudioChannel> channel = GetChannel(channel_id);
488
489 if (!channel) {
490 return VoipResult::kInvalidArgument;
491 }
492
493 output_volume.audio_level = channel->GetOutputAudioLevel();
494 output_volume.total_energy = channel->GetOutputTotalEnergy();
495 output_volume.total_duration = channel->GetOutputTotalDuration();
496
497 return VoipResult::kOk;
498 }
499
500 } // namespace webrtc
501