blob: 270c00d48ae82cdc45fb50f98c24b0d8b1575ce6 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_receiver_audio.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h> // assert
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000014#include <math.h> // pow()
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000015#include <string.h> // memcpy()
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000016
Mirko Bonadei71207422017-09-15 13:58:09 +020017#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/logging.h"
19#include "rtc_base/trace_event.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
21namespace webrtc {
wu@webrtc.org822fbd82013-08-15 23:38:54 +000022RTPReceiverStrategy* RTPReceiverStrategy::CreateAudioStrategy(
solenberg1d031392016-03-30 02:42:32 -070023 RtpData* data_callback) {
24 return new RTPReceiverAudio(data_callback);
wu@webrtc.org822fbd82013-08-15 23:38:54 +000025}
26
solenberg1d031392016-03-30 02:42:32 -070027RTPReceiverAudio::RTPReceiverAudio(RtpData* data_callback)
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000028 : RTPReceiverStrategy(data_callback),
danilchap799a9d02016-09-22 03:36:27 -070029 TelephoneEventHandler(),
danilchap799a9d02016-09-22 03:36:27 -070030 telephone_event_forward_to_decoder_(false),
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000031 telephone_event_payload_type_(-1),
32 cng_nb_payload_type_(-1),
33 cng_wb_payload_type_(-1),
34 cng_swb_payload_type_(-1),
35 cng_fb_payload_type_(-1),
wu@webrtc.org822fbd82013-08-15 23:38:54 +000036 num_energy_(0),
solenberg1d031392016-03-30 02:42:32 -070037 current_remote_energy_() {
wu@webrtc.org822fbd82013-08-15 23:38:54 +000038 memset(current_remote_energy_, 0, sizeof(current_remote_energy_));
niklase@google.com470e71d2011-07-07 08:21:25 +000039}
40
danilchap799a9d02016-09-22 03:36:27 -070041// Outband TelephoneEvent(DTMF) detection
42void RTPReceiverAudio::SetTelephoneEventForwardToDecoder(
43 bool forward_to_decoder) {
44 rtc::CritScope lock(&crit_sect_);
45 telephone_event_forward_to_decoder_ = forward_to_decoder;
46}
47
48// Is forwarding of outband telephone events turned on/off?
49bool RTPReceiverAudio::TelephoneEventForwardToDecoder() const {
50 rtc::CritScope lock(&crit_sect_);
51 return telephone_event_forward_to_decoder_;
52}
53
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000054bool RTPReceiverAudio::TelephoneEventPayloadType(
wu@webrtc.org822fbd82013-08-15 23:38:54 +000055 int8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -070056 rtc::CritScope lock(&crit_sect_);
pkasting@chromium.orgd3245462015-02-23 21:28:22 +000057 return telephone_event_payload_type_ == payload_type;
niklase@google.com470e71d2011-07-07 08:21:25 +000058}
59
ossu425a6cc2016-10-05 08:44:22 -070060bool RTPReceiverAudio::CNGPayloadType(int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -070061 rtc::CritScope lock(&crit_sect_);
ossu425a6cc2016-10-05 08:44:22 -070062 return payload_type == cng_nb_payload_type_ ||
63 payload_type == cng_wb_payload_type_ ||
64 payload_type == cng_swb_payload_type_ ||
65 payload_type == cng_fb_payload_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +000066}
67
wu@webrtc.org822fbd82013-08-15 23:38:54 +000068bool RTPReceiverAudio::ShouldReportCsrcChanges(uint8_t payload_type) const {
phoglund@webrtc.org5accd372013-01-22 12:31:01 +000069 // Don't do this for DTMF packets, otherwise it's fine.
70 return !TelephoneEventPayloadType(payload_type);
71}
72
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000073// - Sample based or frame based codecs based on RFC 3551
74// -
75// - NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples.
76// - The correct rate is 4 bits/sample.
77// -
78// - name of sampling default
79// - encoding sample/frame bits/sample rate ms/frame ms/packet
80// -
81// - Sample based audio codecs
82// - DVI4 sample 4 var. 20
83// - G722 sample 4 16,000 20
84// - G726-40 sample 5 8,000 20
85// - G726-32 sample 4 8,000 20
86// - G726-24 sample 3 8,000 20
87// - G726-16 sample 2 8,000 20
88// - L8 sample 8 var. 20
89// - L16 sample 16 var. 20
90// - PCMA sample 8 var. 20
91// - PCMU sample 8 var. 20
92// -
93// - Frame based audio codecs
94// - G723 frame N/A 8,000 30 30
95// - G728 frame N/A 8,000 2.5 20
96// - G729 frame N/A 8,000 10 20
97// - G729D frame N/A 8,000 10 20
98// - G729E frame N/A 8,000 10 20
99// - GSM frame N/A 8,000 20 20
100// - GSM-EFR frame N/A 8,000 20 20
101// - LPC frame N/A 8,000 20 20
102// - MPA frame N/A var. var.
103// -
104// - G7221 frame N/A
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000105int32_t RTPReceiverAudio::OnNewPayloadTypeCreated(
Karl Wibergc62f6c72017-10-04 12:38:53 +0200106 int payload_type,
107 const SdpAudioFormat& audio_format) {
danilchap7c9426c2016-04-14 03:05:31 -0700108 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.org92bb4172012-12-13 10:48:24 +0000109
Karl Wibergc62f6c72017-10-04 12:38:53 +0200110 if (RtpUtility::StringCompare(audio_format.name.c_str(), "telephone-event",
111 15)) {
112 telephone_event_payload_type_ = payload_type;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000113 }
Karl Wibergc62f6c72017-10-04 12:38:53 +0200114 if (RtpUtility::StringCompare(audio_format.name.c_str(), "cn", 2)) {
ossu425a6cc2016-10-05 08:44:22 -0700115 // We support comfort noise at four different frequencies.
Karl Wibergc62f6c72017-10-04 12:38:53 +0200116 if (audio_format.clockrate_hz == 8000) {
117 cng_nb_payload_type_ = payload_type;
118 } else if (audio_format.clockrate_hz == 16000) {
119 cng_wb_payload_type_ = payload_type;
120 } else if (audio_format.clockrate_hz == 32000) {
121 cng_swb_payload_type_ = payload_type;
122 } else if (audio_format.clockrate_hz == 48000) {
123 cng_fb_payload_type_ = payload_type;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000124 } else {
125 assert(false);
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000126 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 }
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000128 }
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000129 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130}
131
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000132int32_t RTPReceiverAudio::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
133 const PayloadUnion& specific_payload,
134 bool is_red,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000135 const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000136 size_t payload_length,
Niels Möllerbbf389c2017-09-26 14:05:05 +0200137 int64_t timestamp_ms) {
sprang@webrtc.org0200f702015-02-16 12:06:00 +0000138 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::ParseRtp",
139 "seqnum", rtp_header->header.sequenceNumber, "timestamp",
140 rtp_header->header.timestamp);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000141 rtp_header->type.Audio.numEnergy = rtp_header->header.numCSRCs;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000142 num_energy_ = rtp_header->type.Audio.numEnergy;
143 if (rtp_header->type.Audio.numEnergy > 0 &&
144 rtp_header->type.Audio.numEnergy <= kRtpCsrcSize) {
145 memcpy(current_remote_energy_,
146 rtp_header->type.Audio.arrOfEnergy,
147 rtp_header->type.Audio.numEnergy);
148 }
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000149
skvlad98bb6642016-04-07 15:36:45 -0700150 if (first_packet_received_()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100151 RTC_LOG(LS_INFO) << "Received first audio RTP packet";
skvlad98bb6642016-04-07 15:36:45 -0700152 }
153
Karl Wibergc856dc22017-09-28 20:13:59 +0200154 return ParseAudioCodecSpecific(rtp_header, payload, payload_length,
155 specific_payload.audio_payload(), is_red);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000156}
157
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000158RTPAliveType RTPReceiverAudio::ProcessDeadOrAlive(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000159 uint16_t last_payload_length) const {
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000160
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000161 // Our CNG is 9 bytes; if it's a likely CNG the receiver needs to check
162 // kRtpNoRtp against NetEq speech_type kOutputPLCtoCNG.
163 if (last_payload_length < 10) { // our CNG is 9 bytes
164 return kRtpNoRtp;
165 } else {
166 return kRtpDead;
167 }
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000168}
169
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000170void RTPReceiverAudio::CheckPayloadChanged(int8_t payload_type,
ossu425a6cc2016-10-05 08:44:22 -0700171 PayloadUnion* /* specific_payload */,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000172 bool* should_discard_changes) {
ossu425a6cc2016-10-05 08:44:22 -0700173 *should_discard_changes =
174 TelephoneEventPayloadType(payload_type) || CNGPayloadType(payload_type);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000175}
176
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000177int RTPReceiverAudio::Energy(uint8_t array_of_energy[kRtpCsrcSize]) const {
danilchap7c9426c2016-04-14 03:05:31 -0700178 rtc::CritScope cs(&crit_sect_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000179
180 assert(num_energy_ <= kRtpCsrcSize);
181
182 if (num_energy_ > 0) {
183 memcpy(array_of_energy, current_remote_energy_,
184 sizeof(uint8_t) * num_energy_);
185 }
186 return num_energy_;
187}
188
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000189int32_t RTPReceiverAudio::InvokeOnInitializeDecoder(
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000190 RtpFeedback* callback,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000191 int8_t payload_type,
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000192 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000193 const PayloadUnion& specific_payload) const {
Karl Wibergc856dc22017-09-28 20:13:59 +0200194 const auto& ap = specific_payload.audio_payload();
Karl Wibergc62f6c72017-10-04 12:38:53 +0200195 if (callback->OnInitializeDecoder(payload_type, ap.format, ap.rate) == -1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100196 RTC_LOG(LS_ERROR) << "Failed to create decoder for payload type: "
197 << payload_name << "/" << static_cast<int>(payload_type);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000198 return -1;
199 }
200 return 0;
201}
202
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000203// We are not allowed to have any critsects when calling data_callback.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000204int32_t RTPReceiverAudio::ParseAudioCodecSpecific(
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000205 WebRtcRTPHeader* rtp_header,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000206 const uint8_t* payload_data,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000207 size_t payload_length,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000208 const AudioPayload& audio_specific,
209 bool is_red) {
henrik.lundinb8c55b12017-05-10 07:38:01 -0700210 RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
211 const size_t payload_data_length =
212 payload_length - rtp_header->header.paddingLength;
213 if (payload_data_length == 0) {
214 rtp_header->type.Audio.isCNG = false;
215 rtp_header->frameType = kEmptyFrame;
216 return data_callback_->OnReceivedPayloadData(nullptr, 0, rtp_header);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000217 }
218
219 bool telephone_event_packet =
220 TelephoneEventPayloadType(rtp_header->header.payloadType);
221 if (telephone_event_packet) {
danilchap7c9426c2016-04-14 03:05:31 -0700222 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000223
224 // RFC 4733 2.3
225 // 0 1 2 3
226 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
227 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 // | event |E|R| volume | duration |
229 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230 //
henrik.lundinb8c55b12017-05-10 07:38:01 -0700231 if (payload_data_length % 4 != 0) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000232 return -1;
233 }
henrik.lundinb8c55b12017-05-10 07:38:01 -0700234 size_t number_of_events = payload_data_length / 4;
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000235
236 // sanity
237 if (number_of_events >= MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS) {
238 number_of_events = MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS;
239 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000240 for (size_t n = 0; n < number_of_events; ++n) {
henrik.lundinb8c55b12017-05-10 07:38:01 -0700241 RTC_DCHECK_GE(payload_data_length, (4 * n) + 2);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000242 bool end = (payload_data[(4 * n) + 1] & 0x80) ? true : false;
243
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000244 std::set<uint8_t>::iterator event =
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000245 telephone_event_reported_.find(payload_data[4 * n]);
246
247 if (event != telephone_event_reported_.end()) {
248 // we have already seen this event
249 if (end) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000250 telephone_event_reported_.erase(payload_data[4 * n]);
251 }
252 } else {
253 if (end) {
254 // don't add if it's a end of a tone
255 } else {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000256 telephone_event_reported_.insert(payload_data[4 * n]);
257 }
258 }
259 }
260
261 // RFC 4733 2.5.1.3 & 2.5.2.3 Long-Duration Events
262 // should not be a problem since we don't care about the duration
263
264 // RFC 4733 See 2.5.1.5. & 2.5.2.4. Multiple Events in a Packet
265 }
266
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000267 {
danilchap7c9426c2016-04-14 03:05:31 -0700268 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000269
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000270 // Check if this is a CNG packet, receiver might want to know
ossu425a6cc2016-10-05 08:44:22 -0700271 if (CNGPayloadType(rtp_header->header.payloadType)) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000272 rtp_header->type.Audio.isCNG = true;
273 rtp_header->frameType = kAudioFrameCN;
274 } else {
275 rtp_header->frameType = kAudioFrameSpeech;
276 rtp_header->type.Audio.isCNG = false;
277 }
278
279 // check if it's a DTMF event, hence something we can playout
280 if (telephone_event_packet) {
danilchap799a9d02016-09-22 03:36:27 -0700281 if (!telephone_event_forward_to_decoder_) {
282 // don't forward event to decoder
283 return 0;
284 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000285 std::set<uint8_t>::iterator first =
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000286 telephone_event_reported_.begin();
287 if (first != telephone_event_reported_.end() && *first > 15) {
288 // don't forward non DTMF events
289 return 0;
290 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 }
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000292 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000293 // TODO(holmer): Break this out to have RED parsing handled generically.
henrik.lundinb8c55b12017-05-10 07:38:01 -0700294 RTC_DCHECK_GT(payload_data_length, 0);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000295 if (is_red && !(payload_data[0] & 0x80)) {
296 // we recive only one frame packed in a RED packet remove the RED wrapper
297 rtp_header->header.payloadType = payload_data[0];
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000299 // only one frame in the RED strip the one byte to help NetEq
phoglund@webrtc.orga22a9bd2013-01-14 10:01:55 +0000300 return data_callback_->OnReceivedPayloadData(
henrik.lundinb8c55b12017-05-10 07:38:01 -0700301 payload_data + 1, payload_data_length - 1, rtp_header);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000302 }
303
Karl Wibergc62f6c72017-10-04 12:38:53 +0200304 rtp_header->type.Audio.channel = audio_specific.format.num_channels;
henrik.lundinb8c55b12017-05-10 07:38:01 -0700305 return data_callback_->OnReceivedPayloadData(payload_data,
306 payload_data_length, rtp_header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307}
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000308} // namespace webrtc