diff options
Diffstat (limited to 'third_party/libwebrtc/audio/voip/audio_egress.cc')
-rw-r--r-- | third_party/libwebrtc/audio/voip/audio_egress.cc | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/third_party/libwebrtc/audio/voip/audio_egress.cc b/third_party/libwebrtc/audio/voip/audio_egress.cc new file mode 100644 index 0000000000..95a1a3351e --- /dev/null +++ b/third_party/libwebrtc/audio/voip/audio_egress.cc @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "audio/voip/audio_egress.h" + +#include <utility> +#include <vector> + +#include "rtc_base/logging.h" + +namespace webrtc { + +AudioEgress::AudioEgress(RtpRtcpInterface* rtp_rtcp, + Clock* clock, + TaskQueueFactory* task_queue_factory) + : rtp_rtcp_(rtp_rtcp), + rtp_sender_audio_(clock, rtp_rtcp_->RtpSender()), + audio_coding_(AudioCodingModule::Create()), + encoder_queue_(task_queue_factory->CreateTaskQueue( + "AudioEncoder", + TaskQueueFactory::Priority::NORMAL)) { + audio_coding_->RegisterTransportCallback(this); +} + +AudioEgress::~AudioEgress() { + audio_coding_->RegisterTransportCallback(nullptr); +} + +bool AudioEgress::IsSending() const { + return rtp_rtcp_->SendingMedia(); +} + +void AudioEgress::SetEncoder(int payload_type, + const SdpAudioFormat& encoder_format, + std::unique_ptr<AudioEncoder> encoder) { + RTC_DCHECK_GE(payload_type, 0); + RTC_DCHECK_LE(payload_type, 127); + + SetEncoderFormat(encoder_format); + + // The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate) + // as well as some other things, so we collect this info and send it along. + rtp_rtcp_->RegisterSendPayloadFrequency(payload_type, + encoder->RtpTimestampRateHz()); + rtp_sender_audio_.RegisterAudioPayload("audio", payload_type, + encoder->RtpTimestampRateHz(), + encoder->NumChannels(), 0); + + audio_coding_->SetEncoder(std::move(encoder)); +} + +bool AudioEgress::StartSend() { + if (!GetEncoderFormat()) { + RTC_DLOG(LS_WARNING) << "Send codec has not been set yet"; + return false; + } + rtp_rtcp_->SetSendingMediaStatus(true); + return true; +} + +void AudioEgress::StopSend() { + rtp_rtcp_->SetSendingMediaStatus(false); +} + +void AudioEgress::SendAudioData(std::unique_ptr<AudioFrame> audio_frame) { + RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0); + RTC_DCHECK_LE(audio_frame->num_channels_, 8); + + encoder_queue_.PostTask( + [this, audio_frame = std::move(audio_frame)]() mutable { + RTC_DCHECK_RUN_ON(&encoder_queue_); + if (!rtp_rtcp_->SendingMedia()) { + return; + } + + double duration_seconds = + static_cast<double>(audio_frame->samples_per_channel_) / + audio_frame->sample_rate_hz_; + + input_audio_level_.ComputeLevel(*audio_frame, duration_seconds); + + AudioFrameOperations::Mute(audio_frame.get(), + encoder_context_.previously_muted_, + encoder_context_.mute_); + encoder_context_.previously_muted_ = encoder_context_.mute_; + + audio_frame->timestamp_ = encoder_context_.frame_rtp_timestamp_; + + // This call will trigger AudioPacketizationCallback::SendData if + // encoding is done and payload is ready for packetization and + // transmission. Otherwise, it will return without invoking the + // callback. + if (audio_coding_->Add10MsData(*audio_frame) < 0) { + RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed."; + return; + } + + encoder_context_.frame_rtp_timestamp_ += + rtc::dchecked_cast<uint32_t>(audio_frame->samples_per_channel_); + }); +} + +int32_t AudioEgress::SendData(AudioFrameType frame_type, + uint8_t payload_type, + uint32_t timestamp, + const uint8_t* payload_data, + size_t payload_size) { + RTC_DCHECK_RUN_ON(&encoder_queue_); + + rtc::ArrayView<const uint8_t> payload(payload_data, payload_size); + + // Currently we don't get a capture time from downstream modules (ADM, + // AudioTransportImpl). + // TODO(natim@webrtc.org): Integrate once it's ready. + constexpr uint32_t kUndefinedCaptureTime = -1; + + // Push data from ACM to RTP/RTCP-module to deliver audio frame for + // packetization. + if (!rtp_rtcp_->OnSendingRtpFrame(timestamp, kUndefinedCaptureTime, + payload_type, + /*force_sender_report=*/false)) { + return -1; + } + + const uint32_t rtp_timestamp = timestamp + rtp_rtcp_->StartTimestamp(); + + // This call will trigger Transport::SendPacket() from the RTP/RTCP module. + if (!rtp_sender_audio_.SendAudio({.type = frame_type, + .payload = payload, + .payload_id = payload_type, + .rtp_timestamp = rtp_timestamp})) { + RTC_DLOG(LS_ERROR) + << "AudioEgress::SendData() failed to send data to RTP/RTCP module"; + return -1; + } + + return 0; +} + +void AudioEgress::RegisterTelephoneEventType(int rtp_payload_type, + int sample_rate_hz) { + RTC_DCHECK_GE(rtp_payload_type, 0); + RTC_DCHECK_LE(rtp_payload_type, 127); + + rtp_rtcp_->RegisterSendPayloadFrequency(rtp_payload_type, sample_rate_hz); + rtp_sender_audio_.RegisterAudioPayload("telephone-event", rtp_payload_type, + sample_rate_hz, 0, 0); +} + +bool AudioEgress::SendTelephoneEvent(int dtmf_event, int duration_ms) { + RTC_DCHECK_GE(dtmf_event, 0); + RTC_DCHECK_LE(dtmf_event, 255); + RTC_DCHECK_GE(duration_ms, 0); + RTC_DCHECK_LE(duration_ms, 65535); + + if (!IsSending()) { + return false; + } + + constexpr int kTelephoneEventAttenuationdB = 10; + + if (rtp_sender_audio_.SendTelephoneEvent(dtmf_event, duration_ms, + kTelephoneEventAttenuationdB) != 0) { + RTC_DLOG(LS_ERROR) << "SendTelephoneEvent() failed to send event"; + return false; + } + return true; +} + +void AudioEgress::SetMute(bool mute) { + encoder_queue_.PostTask([this, mute] { + RTC_DCHECK_RUN_ON(&encoder_queue_); + encoder_context_.mute_ = mute; + }); +} + +} // namespace webrtc |