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