xref: /aosp_15_r20/external/webrtc/audio/voip/voip_core.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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