blob: 3c50578d2350882d57ff8c708a2b7f868fa1a0b4 [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
Karl Wibergc856dc22017-09-28 20:13:59 +0200153 return ParseAudioCodecSpecific(rtp_header, payload, payload_length,
154 specific_payload.audio_payload(), is_red);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000155}
156
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000157RTPAliveType RTPReceiverAudio::ProcessDeadOrAlive(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000158 uint16_t last_payload_length) const {
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000159
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000160 // Our CNG is 9 bytes; if it's a likely CNG the receiver needs to check
161 // kRtpNoRtp against NetEq speech_type kOutputPLCtoCNG.
162 if (last_payload_length < 10) { // our CNG is 9 bytes
163 return kRtpNoRtp;
164 } else {
165 return kRtpDead;
166 }
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000167}
168
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000169void RTPReceiverAudio::CheckPayloadChanged(int8_t payload_type,
ossu425a6cc2016-10-05 08:44:22 -0700170 PayloadUnion* /* specific_payload */,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000171 bool* should_discard_changes) {
ossu425a6cc2016-10-05 08:44:22 -0700172 *should_discard_changes =
173 TelephoneEventPayloadType(payload_type) || CNGPayloadType(payload_type);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000174}
175
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000176int RTPReceiverAudio::Energy(uint8_t array_of_energy[kRtpCsrcSize]) const {
danilchap7c9426c2016-04-14 03:05:31 -0700177 rtc::CritScope cs(&crit_sect_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000178
179 assert(num_energy_ <= kRtpCsrcSize);
180
181 if (num_energy_ > 0) {
182 memcpy(array_of_energy, current_remote_energy_,
183 sizeof(uint8_t) * num_energy_);
184 }
185 return num_energy_;
186}
187
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000188int32_t RTPReceiverAudio::InvokeOnInitializeDecoder(
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000189 RtpFeedback* callback,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000190 int8_t payload_type,
phoglund@webrtc.orga7303bd2013-02-05 15:12:39 +0000191 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000192 const PayloadUnion& specific_payload) const {
Karl Wibergc856dc22017-09-28 20:13:59 +0200193 const auto& ap = specific_payload.audio_payload();
194 if (callback->OnInitializeDecoder(payload_type, payload_name, ap.frequency,
195 ap.channels, ap.rate) == -1) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000196 LOG(LS_ERROR) << "Failed to create decoder for payload type: "
pkasting@chromium.org026b8922015-01-30 19:53:42 +0000197 << 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
304 rtp_header->type.Audio.channel = audio_specific.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