blob: 9ccc3ec44bac0ad02f15f61000815c832e510f5d [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_() {
Karl Wiberg83d3ec12017-09-28 19:54:38 +020038 last_payload_.emplace(AudioPayload{0, 1, 0});
wu@webrtc.org822fbd82013-08-15 23:38:54 +000039 memset(current_remote_energy_, 0, sizeof(current_remote_energy_));
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
danilchap799a9d02016-09-22 03:36:27 -070042// Outband TelephoneEvent(DTMF) detection
43void RTPReceiverAudio::SetTelephoneEventForwardToDecoder(
44 bool forward_to_decoder) {
45 rtc::CritScope lock(&crit_sect_);
46 telephone_event_forward_to_decoder_ = forward_to_decoder;
47}
48
49// Is forwarding of outband telephone events turned on/off?
50bool RTPReceiverAudio::TelephoneEventForwardToDecoder() const {
51 rtc::CritScope lock(&crit_sect_);
52 return telephone_event_forward_to_decoder_;
53}
54
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000055bool RTPReceiverAudio::TelephoneEventPayloadType(
wu@webrtc.org822fbd82013-08-15 23:38:54 +000056 int8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -070057 rtc::CritScope lock(&crit_sect_);
pkasting@chromium.orgd3245462015-02-23 21:28:22 +000058 return telephone_event_payload_type_ == payload_type;
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
ossu425a6cc2016-10-05 08:44:22 -070061bool RTPReceiverAudio::CNGPayloadType(int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -070062 rtc::CritScope lock(&crit_sect_);
ossu425a6cc2016-10-05 08:44:22 -070063 return payload_type == cng_nb_payload_type_ ||
64 payload_type == cng_wb_payload_type_ ||
65 payload_type == cng_swb_payload_type_ ||
66 payload_type == cng_fb_payload_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +000067}
68
wu@webrtc.org822fbd82013-08-15 23:38:54 +000069bool RTPReceiverAudio::ShouldReportCsrcChanges(uint8_t payload_type) const {
phoglund@webrtc.org5accd372013-01-22 12:31:01 +000070 // Don't do this for DTMF packets, otherwise it's fine.
71 return !TelephoneEventPayloadType(payload_type);
72}
73
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +000074// - Sample based or frame based codecs based on RFC 3551
75// -
76// - NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples.
77// - The correct rate is 4 bits/sample.
78// -
79// - name of sampling default
80// - encoding sample/frame bits/sample rate ms/frame ms/packet
81// -
82// - Sample based audio codecs
83// - DVI4 sample 4 var. 20
84// - G722 sample 4 16,000 20
85// - G726-40 sample 5 8,000 20
86// - G726-32 sample 4 8,000 20
87// - G726-24 sample 3 8,000 20
88// - G726-16 sample 2 8,000 20
89// - L8 sample 8 var. 20
90// - L16 sample 16 var. 20
91// - PCMA sample 8 var. 20
92// - PCMU sample 8 var. 20
93// -
94// - Frame based audio codecs
95// - G723 frame N/A 8,000 30 30
96// - G728 frame N/A 8,000 2.5 20
97// - G729 frame N/A 8,000 10 20
98// - G729D frame N/A 8,000 10 20
99// - G729E frame N/A 8,000 10 20
100// - GSM frame N/A 8,000 20 20
101// - GSM-EFR frame N/A 8,000 20 20
102// - LPC frame N/A 8,000 20 20
103// - MPA frame N/A var. var.
104// -
105// - G7221 frame N/A
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000106int32_t RTPReceiverAudio::OnNewPayloadTypeCreated(
magjed56124bd2016-11-24 09:34:46 -0800107 const CodecInst& audio_codec) {
danilchap7c9426c2016-04-14 03:05:31 -0700108 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.org92bb4172012-12-13 10:48:24 +0000109
magjed56124bd2016-11-24 09:34:46 -0800110 if (RtpUtility::StringCompare(audio_codec.plname, "telephone-event", 15)) {
111 telephone_event_payload_type_ = audio_codec.pltype;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000112 }
magjed56124bd2016-11-24 09:34:46 -0800113 if (RtpUtility::StringCompare(audio_codec.plname, "cn", 2)) {
ossu425a6cc2016-10-05 08:44:22 -0700114 // We support comfort noise at four different frequencies.
magjed56124bd2016-11-24 09:34:46 -0800115 if (audio_codec.plfreq == 8000) {
116 cng_nb_payload_type_ = audio_codec.pltype;
117 } else if (audio_codec.plfreq == 16000) {
118 cng_wb_payload_type_ = audio_codec.pltype;
119 } else if (audio_codec.plfreq == 32000) {
120 cng_swb_payload_type_ = audio_codec.pltype;
121 } else if (audio_codec.plfreq == 48000) {
122 cng_fb_payload_type_ = audio_codec.pltype;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000123 } else {
124 assert(false);
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000125 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 }
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000127 }
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000128 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129}
130
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000131int32_t RTPReceiverAudio::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
132 const PayloadUnion& specific_payload,
133 bool is_red,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000134 const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000135 size_t payload_length,
Niels Möllerbbf389c2017-09-26 14:05:05 +0200136 int64_t timestamp_ms) {
sprang@webrtc.org0200f702015-02-16 12:06:00 +0000137 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::ParseRtp",
138 "seqnum", rtp_header->header.sequenceNumber, "timestamp",
139 rtp_header->header.timestamp);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000140 rtp_header->type.Audio.numEnergy = rtp_header->header.numCSRCs;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000141 num_energy_ = rtp_header->type.Audio.numEnergy;
142 if (rtp_header->type.Audio.numEnergy > 0 &&
143 rtp_header->type.Audio.numEnergy <= kRtpCsrcSize) {
144 memcpy(current_remote_energy_,
145 rtp_header->type.Audio.arrOfEnergy,
146 rtp_header->type.Audio.numEnergy);
147 }
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000148
skvlad98bb6642016-04-07 15:36:45 -0700149 if (first_packet_received_()) {
150 LOG(LS_INFO) << "Received first audio RTP packet";
151 }
152
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000153 return ParseAudioCodecSpecific(rtp_header,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000154 payload,
minyue@webrtc.org663da0a2013-09-26 15:21:26 +0000155 payload_length,
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000156 specific_payload.Audio,
157 is_red);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000158}
159
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000160RTPAliveType RTPReceiverAudio::ProcessDeadOrAlive(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000161 uint16_t last_payload_length) const {
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000162
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000163 // Our CNG is 9 bytes; if it's a likely CNG the receiver needs to check
164 // kRtpNoRtp against NetEq speech_type kOutputPLCtoCNG.
165 if (last_payload_length < 10) { // our CNG is 9 bytes
166 return kRtpNoRtp;
167 } else {
168 return kRtpDead;
169 }
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000170}
171
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000172void RTPReceiverAudio::CheckPayloadChanged(int8_t payload_type,
ossu425a6cc2016-10-05 08:44:22 -0700173 PayloadUnion* /* specific_payload */,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000174 bool* should_discard_changes) {
ossu425a6cc2016-10-05 08:44:22 -0700175 *should_discard_changes =
176 TelephoneEventPayloadType(payload_type) || CNGPayloadType(payload_type);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000177}
178
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000179int RTPReceiverAudio::Energy(uint8_t array_of_energy[kRtpCsrcSize]) const {
danilchap7c9426c2016-04-14 03:05:31 -0700180 rtc::CritScope cs(&crit_sect_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000181
182 assert(num_energy_ <= kRtpCsrcSize);
183
184 if (num_energy_ > 0) {
185 memcpy(array_of_energy, current_remote_energy_,
186 sizeof(uint8_t) * num_energy_);
187 }
188 return num_energy_;
189}
190
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000191int32_t RTPReceiverAudio::InvokeOnInitializeDecoder(
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000192 RtpFeedback* callback,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000193 int8_t payload_type,
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000194 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000195 const PayloadUnion& specific_payload) const {
Peter Boströmac547a62015-09-17 23:03:57 +0200196 if (-1 ==
197 callback->OnInitializeDecoder(
198 payload_type, payload_name, specific_payload.Audio.frequency,
199 specific_payload.Audio.channels, specific_payload.Audio.rate)) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000200 LOG(LS_ERROR) << "Failed to create decoder for payload type: "
pkasting@chromium.org026b8922015-01-30 19:53:42 +0000201 << payload_name << "/" << static_cast<int>(payload_type);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000202 return -1;
203 }
204 return 0;
205}
206
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000207// We are not allowed to have any critsects when calling data_callback.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000208int32_t RTPReceiverAudio::ParseAudioCodecSpecific(
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000209 WebRtcRTPHeader* rtp_header,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000210 const uint8_t* payload_data,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000211 size_t payload_length,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000212 const AudioPayload& audio_specific,
213 bool is_red) {
henrik.lundinb8c55b12017-05-10 07:38:01 -0700214 RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
215 const size_t payload_data_length =
216 payload_length - rtp_header->header.paddingLength;
217 if (payload_data_length == 0) {
218 rtp_header->type.Audio.isCNG = false;
219 rtp_header->frameType = kEmptyFrame;
220 return data_callback_->OnReceivedPayloadData(nullptr, 0, rtp_header);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000221 }
222
223 bool telephone_event_packet =
224 TelephoneEventPayloadType(rtp_header->header.payloadType);
225 if (telephone_event_packet) {
danilchap7c9426c2016-04-14 03:05:31 -0700226 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000227
228 // RFC 4733 2.3
229 // 0 1 2 3
230 // 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
231 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
232 // | event |E|R| volume | duration |
233 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234 //
henrik.lundinb8c55b12017-05-10 07:38:01 -0700235 if (payload_data_length % 4 != 0) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000236 return -1;
237 }
henrik.lundinb8c55b12017-05-10 07:38:01 -0700238 size_t number_of_events = payload_data_length / 4;
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000239
240 // sanity
241 if (number_of_events >= MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS) {
242 number_of_events = MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS;
243 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000244 for (size_t n = 0; n < number_of_events; ++n) {
henrik.lundinb8c55b12017-05-10 07:38:01 -0700245 RTC_DCHECK_GE(payload_data_length, (4 * n) + 2);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000246 bool end = (payload_data[(4 * n) + 1] & 0x80) ? true : false;
247
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000248 std::set<uint8_t>::iterator event =
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000249 telephone_event_reported_.find(payload_data[4 * n]);
250
251 if (event != telephone_event_reported_.end()) {
252 // we have already seen this event
253 if (end) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000254 telephone_event_reported_.erase(payload_data[4 * n]);
255 }
256 } else {
257 if (end) {
258 // don't add if it's a end of a tone
259 } else {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000260 telephone_event_reported_.insert(payload_data[4 * n]);
261 }
262 }
263 }
264
265 // RFC 4733 2.5.1.3 & 2.5.2.3 Long-Duration Events
266 // should not be a problem since we don't care about the duration
267
268 // RFC 4733 See 2.5.1.5. & 2.5.2.4. Multiple Events in a Packet
269 }
270
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000271 {
danilchap7c9426c2016-04-14 03:05:31 -0700272 rtc::CritScope lock(&crit_sect_);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000273
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000274 // Check if this is a CNG packet, receiver might want to know
ossu425a6cc2016-10-05 08:44:22 -0700275 if (CNGPayloadType(rtp_header->header.payloadType)) {
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000276 rtp_header->type.Audio.isCNG = true;
277 rtp_header->frameType = kAudioFrameCN;
278 } else {
279 rtp_header->frameType = kAudioFrameSpeech;
280 rtp_header->type.Audio.isCNG = false;
281 }
282
283 // check if it's a DTMF event, hence something we can playout
284 if (telephone_event_packet) {
danilchap799a9d02016-09-22 03:36:27 -0700285 if (!telephone_event_forward_to_decoder_) {
286 // don't forward event to decoder
287 return 0;
288 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000289 std::set<uint8_t>::iterator first =
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000290 telephone_event_reported_.begin();
291 if (first != telephone_event_reported_.end() && *first > 15) {
292 // don't forward non DTMF events
293 return 0;
294 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 }
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000296 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000297 // TODO(holmer): Break this out to have RED parsing handled generically.
henrik.lundinb8c55b12017-05-10 07:38:01 -0700298 RTC_DCHECK_GT(payload_data_length, 0);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000299 if (is_red && !(payload_data[0] & 0x80)) {
300 // we recive only one frame packed in a RED packet remove the RED wrapper
301 rtp_header->header.payloadType = payload_data[0];
niklase@google.com470e71d2011-07-07 08:21:25 +0000302
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000303 // only one frame in the RED strip the one byte to help NetEq
phoglund@webrtc.orga22a9bd2013-01-14 10:01:55 +0000304 return data_callback_->OnReceivedPayloadData(
henrik.lundinb8c55b12017-05-10 07:38:01 -0700305 payload_data + 1, payload_data_length - 1, rtp_header);
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000306 }
307
308 rtp_header->type.Audio.channel = audio_specific.channels;
henrik.lundinb8c55b12017-05-10 07:38:01 -0700309 return data_callback_->OnReceivedPayloadData(payload_data,
310 payload_data_length, rtp_header);
niklase@google.com470e71d2011-07-07 08:21:25 +0000311}
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000312} // namespace webrtc