tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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