• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/audio_egress.h"
12 
13 #include <utility>
14 #include <vector>
15 
16 #include "rtc_base/logging.h"
17 
18 namespace webrtc {
19 
AudioEgress(RtpRtcpInterface * rtp_rtcp,Clock * clock,TaskQueueFactory * task_queue_factory)20 AudioEgress::AudioEgress(RtpRtcpInterface* rtp_rtcp,
21                          Clock* clock,
22                          TaskQueueFactory* task_queue_factory)
23     : rtp_rtcp_(rtp_rtcp),
24       rtp_sender_audio_(clock, rtp_rtcp_->RtpSender()),
25       audio_coding_(AudioCodingModule::Create(AudioCodingModule::Config())),
26       encoder_queue_(task_queue_factory->CreateTaskQueue(
27           "AudioEncoder",
28           TaskQueueFactory::Priority::NORMAL)) {
29   audio_coding_->RegisterTransportCallback(this);
30 }
31 
~AudioEgress()32 AudioEgress::~AudioEgress() {
33   audio_coding_->RegisterTransportCallback(nullptr);
34 }
35 
IsSending() const36 bool AudioEgress::IsSending() const {
37   return rtp_rtcp_->SendingMedia();
38 }
39 
SetEncoder(int payload_type,const SdpAudioFormat & encoder_format,std::unique_ptr<AudioEncoder> encoder)40 void AudioEgress::SetEncoder(int payload_type,
41                              const SdpAudioFormat& encoder_format,
42                              std::unique_ptr<AudioEncoder> encoder) {
43   RTC_DCHECK_GE(payload_type, 0);
44   RTC_DCHECK_LE(payload_type, 127);
45 
46   SetEncoderFormat(encoder_format);
47 
48   // The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate)
49   // as well as some other things, so we collect this info and send it along.
50   rtp_rtcp_->RegisterSendPayloadFrequency(payload_type,
51                                           encoder->RtpTimestampRateHz());
52   rtp_sender_audio_.RegisterAudioPayload("audio", payload_type,
53                                          encoder->RtpTimestampRateHz(),
54                                          encoder->NumChannels(), 0);
55 
56   audio_coding_->SetEncoder(std::move(encoder));
57 }
58 
StartSend()59 void AudioEgress::StartSend() {
60   rtp_rtcp_->SetSendingMediaStatus(true);
61 }
62 
StopSend()63 void AudioEgress::StopSend() {
64   rtp_rtcp_->SetSendingMediaStatus(false);
65 }
66 
SendAudioData(std::unique_ptr<AudioFrame> audio_frame)67 void AudioEgress::SendAudioData(std::unique_ptr<AudioFrame> audio_frame) {
68   RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0);
69   RTC_DCHECK_LE(audio_frame->num_channels_, 8);
70 
71   encoder_queue_.PostTask(
72       [this, audio_frame = std::move(audio_frame)]() mutable {
73         RTC_DCHECK_RUN_ON(&encoder_queue_);
74         if (!rtp_rtcp_->SendingMedia()) {
75           return;
76         }
77 
78         AudioFrameOperations::Mute(audio_frame.get(),
79                                    encoder_context_.previously_muted_,
80                                    encoder_context_.mute_);
81         encoder_context_.previously_muted_ = encoder_context_.mute_;
82 
83         audio_frame->timestamp_ = encoder_context_.frame_rtp_timestamp_;
84 
85         // This call will trigger AudioPacketizationCallback::SendData if
86         // encoding is done and payload is ready for packetization and
87         // transmission. Otherwise, it will return without invoking the
88         // callback.
89         if (audio_coding_->Add10MsData(*audio_frame) < 0) {
90           RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
91           return;
92         }
93 
94         encoder_context_.frame_rtp_timestamp_ +=
95             rtc::dchecked_cast<uint32_t>(audio_frame->samples_per_channel_);
96       });
97 }
98 
SendData(AudioFrameType frame_type,uint8_t payload_type,uint32_t timestamp,const uint8_t * payload_data,size_t payload_size)99 int32_t AudioEgress::SendData(AudioFrameType frame_type,
100                               uint8_t payload_type,
101                               uint32_t timestamp,
102                               const uint8_t* payload_data,
103                               size_t payload_size) {
104   RTC_DCHECK_RUN_ON(&encoder_queue_);
105 
106   rtc::ArrayView<const uint8_t> payload(payload_data, payload_size);
107 
108   // Currently we don't get a capture time from downstream modules (ADM,
109   // AudioTransportImpl).
110   // TODO(natim@webrtc.org): Integrate once it's ready.
111   constexpr uint32_t kUndefinedCaptureTime = -1;
112 
113   // Push data from ACM to RTP/RTCP-module to deliver audio frame for
114   // packetization.
115   if (!rtp_rtcp_->OnSendingRtpFrame(timestamp, kUndefinedCaptureTime,
116                                     payload_type,
117                                     /*force_sender_report=*/false)) {
118     return -1;
119   }
120 
121   const uint32_t rtp_timestamp = timestamp + rtp_rtcp_->StartTimestamp();
122 
123   // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
124   if (!rtp_sender_audio_.SendAudio(frame_type, payload_type, rtp_timestamp,
125                                    payload.data(), payload.size())) {
126     RTC_DLOG(LS_ERROR)
127         << "AudioEgress::SendData() failed to send data to RTP/RTCP module";
128     return -1;
129   }
130 
131   return 0;
132 }
133 
RegisterTelephoneEventType(int rtp_payload_type,int sample_rate_hz)134 void AudioEgress::RegisterTelephoneEventType(int rtp_payload_type,
135                                              int sample_rate_hz) {
136   RTC_DCHECK_GE(rtp_payload_type, 0);
137   RTC_DCHECK_LE(rtp_payload_type, 127);
138 
139   rtp_rtcp_->RegisterSendPayloadFrequency(rtp_payload_type, sample_rate_hz);
140   rtp_sender_audio_.RegisterAudioPayload("telephone-event", rtp_payload_type,
141                                          sample_rate_hz, 0, 0);
142 }
143 
SendTelephoneEvent(int dtmf_event,int duration_ms)144 bool AudioEgress::SendTelephoneEvent(int dtmf_event, int duration_ms) {
145   RTC_DCHECK_GE(dtmf_event, 0);
146   RTC_DCHECK_LE(dtmf_event, 255);
147   RTC_DCHECK_GE(duration_ms, 0);
148   RTC_DCHECK_LE(duration_ms, 65535);
149 
150   if (!IsSending()) {
151     return false;
152   }
153 
154   constexpr int kTelephoneEventAttenuationdB = 10;
155 
156   if (rtp_sender_audio_.SendTelephoneEvent(dtmf_event, duration_ms,
157                                            kTelephoneEventAttenuationdB) != 0) {
158     RTC_DLOG(LS_ERROR) << "SendTelephoneEvent() failed to send event";
159     return false;
160   }
161   return true;
162 }
163 
SetMute(bool mute)164 void AudioEgress::SetMute(bool mute) {
165   encoder_queue_.PostTask([this, mute] {
166     RTC_DCHECK_RUN_ON(&encoder_queue_);
167     encoder_context_.mute_ = mute;
168   });
169 }
170 
171 }  // namespace webrtc
172