• 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 bool AudioEgress::StartSend() {
60   if (!GetEncoderFormat()) {
61     RTC_DLOG(LS_WARNING) << "Send codec has not been set yet";
62     return false;
63   }
64   rtp_rtcp_->SetSendingMediaStatus(true);
65   return true;
66 }
67 
StopSend()68 void AudioEgress::StopSend() {
69   rtp_rtcp_->SetSendingMediaStatus(false);
70 }
71 
SendAudioData(std::unique_ptr<AudioFrame> audio_frame)72 void AudioEgress::SendAudioData(std::unique_ptr<AudioFrame> audio_frame) {
73   RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0);
74   RTC_DCHECK_LE(audio_frame->num_channels_, 8);
75 
76   encoder_queue_.PostTask(
77       [this, audio_frame = std::move(audio_frame)]() mutable {
78         RTC_DCHECK_RUN_ON(&encoder_queue_);
79         if (!rtp_rtcp_->SendingMedia()) {
80           return;
81         }
82 
83         double duration_seconds =
84             static_cast<double>(audio_frame->samples_per_channel_) /
85             audio_frame->sample_rate_hz_;
86 
87         input_audio_level_.ComputeLevel(*audio_frame, duration_seconds);
88 
89         AudioFrameOperations::Mute(audio_frame.get(),
90                                    encoder_context_.previously_muted_,
91                                    encoder_context_.mute_);
92         encoder_context_.previously_muted_ = encoder_context_.mute_;
93 
94         audio_frame->timestamp_ = encoder_context_.frame_rtp_timestamp_;
95 
96         // This call will trigger AudioPacketizationCallback::SendData if
97         // encoding is done and payload is ready for packetization and
98         // transmission. Otherwise, it will return without invoking the
99         // callback.
100         if (audio_coding_->Add10MsData(*audio_frame) < 0) {
101           RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
102           return;
103         }
104 
105         encoder_context_.frame_rtp_timestamp_ +=
106             rtc::dchecked_cast<uint32_t>(audio_frame->samples_per_channel_);
107       });
108 }
109 
SendData(AudioFrameType frame_type,uint8_t payload_type,uint32_t timestamp,const uint8_t * payload_data,size_t payload_size)110 int32_t AudioEgress::SendData(AudioFrameType frame_type,
111                               uint8_t payload_type,
112                               uint32_t timestamp,
113                               const uint8_t* payload_data,
114                               size_t payload_size) {
115   RTC_DCHECK_RUN_ON(&encoder_queue_);
116 
117   rtc::ArrayView<const uint8_t> payload(payload_data, payload_size);
118 
119   // Currently we don't get a capture time from downstream modules (ADM,
120   // AudioTransportImpl).
121   // TODO(natim@webrtc.org): Integrate once it's ready.
122   constexpr uint32_t kUndefinedCaptureTime = -1;
123 
124   // Push data from ACM to RTP/RTCP-module to deliver audio frame for
125   // packetization.
126   if (!rtp_rtcp_->OnSendingRtpFrame(timestamp, kUndefinedCaptureTime,
127                                     payload_type,
128                                     /*force_sender_report=*/false)) {
129     return -1;
130   }
131 
132   const uint32_t rtp_timestamp = timestamp + rtp_rtcp_->StartTimestamp();
133 
134   // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
135   if (!rtp_sender_audio_.SendAudio(frame_type, payload_type, rtp_timestamp,
136                                    payload.data(), payload.size())) {
137     RTC_DLOG(LS_ERROR)
138         << "AudioEgress::SendData() failed to send data to RTP/RTCP module";
139     return -1;
140   }
141 
142   return 0;
143 }
144 
RegisterTelephoneEventType(int rtp_payload_type,int sample_rate_hz)145 void AudioEgress::RegisterTelephoneEventType(int rtp_payload_type,
146                                              int sample_rate_hz) {
147   RTC_DCHECK_GE(rtp_payload_type, 0);
148   RTC_DCHECK_LE(rtp_payload_type, 127);
149 
150   rtp_rtcp_->RegisterSendPayloadFrequency(rtp_payload_type, sample_rate_hz);
151   rtp_sender_audio_.RegisterAudioPayload("telephone-event", rtp_payload_type,
152                                          sample_rate_hz, 0, 0);
153 }
154 
SendTelephoneEvent(int dtmf_event,int duration_ms)155 bool AudioEgress::SendTelephoneEvent(int dtmf_event, int duration_ms) {
156   RTC_DCHECK_GE(dtmf_event, 0);
157   RTC_DCHECK_LE(dtmf_event, 255);
158   RTC_DCHECK_GE(duration_ms, 0);
159   RTC_DCHECK_LE(duration_ms, 65535);
160 
161   if (!IsSending()) {
162     return false;
163   }
164 
165   constexpr int kTelephoneEventAttenuationdB = 10;
166 
167   if (rtp_sender_audio_.SendTelephoneEvent(dtmf_event, duration_ms,
168                                            kTelephoneEventAttenuationdB) != 0) {
169     RTC_DLOG(LS_ERROR) << "SendTelephoneEvent() failed to send event";
170     return false;
171   }
172   return true;
173 }
174 
SetMute(bool mute)175 void AudioEgress::SetMute(bool mute) {
176   encoder_queue_.PostTask([this, mute] {
177     RTC_DCHECK_RUN_ON(&encoder_queue_);
178     encoder_context_.mute_ = mute;
179   });
180 }
181 
182 }  // namespace webrtc
183