blob: e0fef278b83372281af469f8266534da2c07ddc1 [file] [log] [blame]
Tim Na11f92bc2020-04-21 16:39:251/*
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 */
Tim Na8ab3c772020-03-27 00:16:5110
11#include "audio/voip/audio_egress.h"
12
13#include <utility>
14#include <vector>
15
Danil Chapovalovb1799b02024-01-18 10:57:4816#include "api/sequence_checker.h"
Tim Na8ab3c772020-03-27 00:16:5117#include "rtc_base/logging.h"
18
19namespace webrtc {
20
Danil Chapovalov943828b2024-08-02 09:31:5921AudioEgress::AudioEgress(const Environment& env, RtpRtcpInterface* rtp_rtcp)
Tim Na8ab3c772020-03-27 00:16:5122 : rtp_rtcp_(rtp_rtcp),
Danil Chapovalov943828b2024-08-02 09:31:5923 rtp_sender_audio_(&env.clock(), rtp_rtcp_->RtpSender()),
Henrik Lundin84f75692023-02-01 12:07:1024 audio_coding_(AudioCodingModule::Create()),
Danil Chapovalov943828b2024-08-02 09:31:5925 encoder_queue_(env.task_queue_factory().CreateTaskQueue(
Tim Na8ab3c772020-03-27 00:16:5126 "AudioEncoder",
Danil Chapovalovb1799b02024-01-18 10:57:4827 TaskQueueFactory::Priority::NORMAL)),
28 encoder_queue_checker_(encoder_queue_.get()) {
Tim Na8ab3c772020-03-27 00:16:5129 audio_coding_->RegisterTransportCallback(this);
30}
31
32AudioEgress::~AudioEgress() {
33 audio_coding_->RegisterTransportCallback(nullptr);
Danil Chapovalovb1799b02024-01-18 10:57:4834
35 // Delete first to ensure that there are no running tasks when the other
36 // members are destroyed.
37 encoder_queue_ = nullptr;
Tim Na8ab3c772020-03-27 00:16:5138}
39
40bool AudioEgress::IsSending() const {
Tim Na8ab3c772020-03-27 00:16:5141 return rtp_rtcp_->SendingMedia();
42}
43
44void AudioEgress::SetEncoder(int payload_type,
45 const SdpAudioFormat& encoder_format,
46 std::unique_ptr<AudioEncoder> encoder) {
Tim Na8ab3c772020-03-27 00:16:5147 RTC_DCHECK_GE(payload_type, 0);
48 RTC_DCHECK_LE(payload_type, 127);
49
Tim Nac0df5fc2020-05-05 18:03:5450 SetEncoderFormat(encoder_format);
Tim Na8ab3c772020-03-27 00:16:5151
52 // The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate)
53 // as well as some other things, so we collect this info and send it along.
54 rtp_rtcp_->RegisterSendPayloadFrequency(payload_type,
55 encoder->RtpTimestampRateHz());
56 rtp_sender_audio_.RegisterAudioPayload("audio", payload_type,
57 encoder->RtpTimestampRateHz(),
58 encoder->NumChannels(), 0);
59
60 audio_coding_->SetEncoder(std::move(encoder));
61}
62
Jason Longdba1f942020-08-06 19:16:0463bool AudioEgress::StartSend() {
64 if (!GetEncoderFormat()) {
65 RTC_DLOG(LS_WARNING) << "Send codec has not been set yet";
66 return false;
67 }
Tim Na8ab3c772020-03-27 00:16:5168 rtp_rtcp_->SetSendingMediaStatus(true);
Jason Longdba1f942020-08-06 19:16:0469 return true;
Tim Na8ab3c772020-03-27 00:16:5170}
71
72void AudioEgress::StopSend() {
Tim Na8ab3c772020-03-27 00:16:5173 rtp_rtcp_->SetSendingMediaStatus(false);
74}
75
76void AudioEgress::SendAudioData(std::unique_ptr<AudioFrame> audio_frame) {
77 RTC_DCHECK_GT(audio_frame->samples_per_channel_, 0);
78 RTC_DCHECK_LE(audio_frame->num_channels_, 8);
79
Danil Chapovalovb1799b02024-01-18 10:57:4880 encoder_queue_->PostTask(
Tim Na8ab3c772020-03-27 00:16:5181 [this, audio_frame = std::move(audio_frame)]() mutable {
Danil Chapovalovb1799b02024-01-18 10:57:4882 RTC_DCHECK_RUN_ON(&encoder_queue_checker_);
Tim Na8ab3c772020-03-27 00:16:5183 if (!rtp_rtcp_->SendingMedia()) {
84 return;
85 }
86
Tim Naa58cae32020-11-13 19:07:4387 double duration_seconds =
88 static_cast<double>(audio_frame->samples_per_channel_) /
89 audio_frame->sample_rate_hz_;
90
91 input_audio_level_.ComputeLevel(*audio_frame, duration_seconds);
92
Tim Na8ab3c772020-03-27 00:16:5193 AudioFrameOperations::Mute(audio_frame.get(),
94 encoder_context_.previously_muted_,
95 encoder_context_.mute_);
96 encoder_context_.previously_muted_ = encoder_context_.mute_;
97
98 audio_frame->timestamp_ = encoder_context_.frame_rtp_timestamp_;
99
100 // This call will trigger AudioPacketizationCallback::SendData if
101 // encoding is done and payload is ready for packetization and
102 // transmission. Otherwise, it will return without invoking the
103 // callback.
104 if (audio_coding_->Add10MsData(*audio_frame) < 0) {
105 RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
106 return;
107 }
108
109 encoder_context_.frame_rtp_timestamp_ +=
Evan Shrubsoleef95b202025-02-24 14:55:04110 dchecked_cast<uint32_t>(audio_frame->samples_per_channel_);
Tim Na8ab3c772020-03-27 00:16:51111 });
112}
113
114int32_t AudioEgress::SendData(AudioFrameType frame_type,
115 uint8_t payload_type,
116 uint32_t timestamp,
117 const uint8_t* payload_data,
118 size_t payload_size) {
Danil Chapovalovb1799b02024-01-18 10:57:48119 RTC_DCHECK_RUN_ON(&encoder_queue_checker_);
Tim Na8ab3c772020-03-27 00:16:51120
Evan Shrubsole18287f62025-04-15 14:50:04121 ArrayView<const uint8_t> payload(payload_data, payload_size);
Tim Na8ab3c772020-03-27 00:16:51122
123 // Currently we don't get a capture time from downstream modules (ADM,
124 // AudioTransportImpl).
125 // TODO(natim@webrtc.org): Integrate once it's ready.
126 constexpr uint32_t kUndefinedCaptureTime = -1;
127
128 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
129 // packetization.
130 if (!rtp_rtcp_->OnSendingRtpFrame(timestamp, kUndefinedCaptureTime,
131 payload_type,
132 /*force_sender_report=*/false)) {
133 return -1;
134 }
135
136 const uint32_t rtp_timestamp = timestamp + rtp_rtcp_->StartTimestamp();
137
138 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
Danil Chapovalov4c556212023-09-04 10:27:59139 if (!rtp_sender_audio_.SendAudio({.type = frame_type,
140 .payload = payload,
141 .payload_id = payload_type,
142 .rtp_timestamp = rtp_timestamp})) {
Tim Na8ab3c772020-03-27 00:16:51143 RTC_DLOG(LS_ERROR)
144 << "AudioEgress::SendData() failed to send data to RTP/RTCP module";
145 return -1;
146 }
147
148 return 0;
149}
150
151void AudioEgress::RegisterTelephoneEventType(int rtp_payload_type,
152 int sample_rate_hz) {
Tim Na8ab3c772020-03-27 00:16:51153 RTC_DCHECK_GE(rtp_payload_type, 0);
154 RTC_DCHECK_LE(rtp_payload_type, 127);
155
156 rtp_rtcp_->RegisterSendPayloadFrequency(rtp_payload_type, sample_rate_hz);
157 rtp_sender_audio_.RegisterAudioPayload("telephone-event", rtp_payload_type,
158 sample_rate_hz, 0, 0);
159}
160
161bool AudioEgress::SendTelephoneEvent(int dtmf_event, int duration_ms) {
Tim Na8ab3c772020-03-27 00:16:51162 RTC_DCHECK_GE(dtmf_event, 0);
163 RTC_DCHECK_LE(dtmf_event, 255);
164 RTC_DCHECK_GE(duration_ms, 0);
165 RTC_DCHECK_LE(duration_ms, 65535);
166
167 if (!IsSending()) {
168 return false;
169 }
170
171 constexpr int kTelephoneEventAttenuationdB = 10;
172
173 if (rtp_sender_audio_.SendTelephoneEvent(dtmf_event, duration_ms,
174 kTelephoneEventAttenuationdB) != 0) {
175 RTC_DLOG(LS_ERROR) << "SendTelephoneEvent() failed to send event";
176 return false;
177 }
178 return true;
179}
180
181void AudioEgress::SetMute(bool mute) {
Danil Chapovalovb1799b02024-01-18 10:57:48182 encoder_queue_->PostTask([this, mute] {
183 RTC_DCHECK_RUN_ON(&encoder_queue_checker_);
Tim Na8ab3c772020-03-27 00:16:51184 encoder_context_.mute_ = mute;
185 });
186}
187
188} // namespace webrtc