blob: 24e1eeed204371694f7c8d9bed73f239c463c7be [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +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
11/*
12 * Implementation of the RecIn function, which is the main function for inserting RTP
13 * packets into NetEQ.
14 */
15
16#include "mcu.h"
17
18#include <string.h>
19
20#include "signal_processing_library.h"
21
22#include "automode.h"
23#include "dtmf_buffer.h"
24#include "neteq_defines.h"
25#include "neteq_error_codes.h"
26
27
28int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput,
29 WebRtc_UWord32 uw32_timeRec)
30{
31 RTPPacket_t RTPpacket[2];
32 int i_k;
33 int i_ok = 0, i_No_Of_Payloads = 1;
34 WebRtc_Word16 flushed = 0;
35 WebRtc_Word16 codecPos;
niklase@google.com470e71d2011-07-07 08:21:25 +000036 int curr_Codec;
37 WebRtc_Word16 isREDPayload = 0;
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +000038 WebRtc_Word32 temp_bufsize;
niklase@google.com470e71d2011-07-07 08:21:25 +000039#ifdef NETEQ_RED_CODEC
40 RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */
41 RTPpacketPtr[0] = &RTPpacket[0];
42 RTPpacketPtr[1] = &RTPpacket[1];
43#endif
44
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +000045 temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(&MCU_inst->PacketBuffer_inst,
46 &MCU_inst->codec_DB_inst);
niklase@google.com470e71d2011-07-07 08:21:25 +000047 /*
48 * Copy from input RTP packet to local copy
49 * (mainly to enable multiple payloads using RED)
50 */
51
52 WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t));
53
54 /* Reinitialize NetEq if it's needed (changed SSRC or first call) */
55
56 if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1))
57 {
58 WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber);
59 MCU_inst->first_packet = 0;
60
61 /* Flush the buffer */
62 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
63
64 /* Store new SSRC */
65 MCU_inst->ssrc = RTPpacket[0].ssrc;
66
67 /* Update codecs */
68 MCU_inst->timeStamp = RTPpacket[0].timeStamp;
69 MCU_inst->current_Payload = RTPpacket[0].payloadType;
70
71 /*Set MCU to update codec on next SignalMCU call */
72 MCU_inst->new_codec = 1;
73
74 /* Reset timestamp scaling */
75 MCU_inst->TSscalingInitialized = 0;
76
77 }
78
79 /* Call RTCP statistics */
80 i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst), RTPpacket[0].seqNumber,
81 RTPpacket[0].timeStamp, uw32_timeRec);
82
83 /* If Redundancy is supported and this is the redundancy payload, separate the payloads */
84#ifdef NETEQ_RED_CODEC
85 if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
86 kDecoderRED))
87 {
88
89 /* Split the payload into a main and a redundancy payloads */
90 i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads);
91 if (i_ok < 0)
92 {
93 /* error returned */
94 return i_ok;
95 }
96
97 /*
98 * Only accept a few redundancies of the same type as the main data,
99 * AVT events and CNG.
100 */
101 if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType)
102 && (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
103 kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload(
104 &MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload(
105 &MCU_inst->codec_DB_inst, RTPpacket[0].payloadType))
106 && (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType)))
107 {
108 i_No_Of_Payloads = 1;
109 }
110 isREDPayload = 1;
111 }
112#endif
113
114 /* loop over the number of payloads */
115 for (i_k = 0; i_k < i_No_Of_Payloads; i_k++)
116 {
117
118 if (isREDPayload == 1)
119 {
120 RTPpacket[i_k].rcuPlCntr = i_k;
121 }
122 else
123 {
124 RTPpacket[i_k].rcuPlCntr = 0;
125 }
126
127 /* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */
128 if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
129 kDecoderILBC))
130 {
131 i_ok = WebRtcNetEQ_DbGetSplitInfo(
132 &MCU_inst->PayloadSplit_inst,
133 (enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
134 RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen);
135 if (i_ok < 0)
136 {
137 /* error returned */
138 return i_ok;
139 }
140 }
141
142 /* Get information about timestamp scaling for this payload type */
143 i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType);
144 if (i_ok < 0)
145 {
146 /* error returned */
147 return i_ok;
148 }
149
150 if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling)
151 {
152 /* Must initialize scaling with current timestamps */
153 MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
154 MCU_inst->internalTS = RTPpacket[i_k].timeStamp;
155 MCU_inst->TSscalingInitialized = 1;
156 }
157
158 /* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */
159 if (MCU_inst->TSscalingInitialized == 1)
160 {
161 WebRtc_UWord32 newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst,
162 RTPpacket[i_k].timeStamp);
163
164 /* save the incoming timestamp for next time */
165 MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
166
167 /* add the scaled difference to last scaled timestamp and save ... */
168 MCU_inst->internalTS = newTS;
169
170 RTPpacket[i_k].timeStamp = newTS;
171 }
172
173 /* Is this a DTMF packet?*/
174 if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
175 kDecoderAVT))
176 {
177#ifdef NETEQ_ATEVENT_DECODE
178 if (MCU_inst->AVT_PlayoutOn)
179 {
180 i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst,
181 RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen,
182 RTPpacket[i_k].timeStamp);
183 if (i_ok != 0)
184 {
185 return i_ok;
186 }
187 }
188#endif
189#ifdef NETEQ_STEREO
190 if (MCU_inst->usingStereo == 0)
191 {
192 /* do not set this for DTMF packets when using stereo mode */
193 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
194 }
195#else
196 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
197#endif
198 }
199 else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst,
200 RTPpacket[i_k].payloadType))
201 {
202 /* Is this a CNG packet? how should we handle this?*/
203#ifdef NETEQ_CNG_CODEC
204 /* Get CNG sample rate */
205 WebRtc_UWord16 fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
206 RTPpacket[i_k].payloadType);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000207
208 /* Force sampling frequency to 32000 Hz CNG 48000 Hz. */
209 /* TODO(tlegrand): remove limitation once ACM has full 48 kHz
210 * support. */
211 if (fsCng > 32000) {
212 fsCng = 32000;
213 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 if ((fsCng != MCU_inst->fs) && (fsCng > 8000))
215 {
216 /*
217 * We have received CNG with a different sample rate from what we are using
218 * now (must be > 8000, since we may use only one CNG type (default) for all
219 * frequencies). Flush buffer and signal new codec.
220 */
221 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
222 MCU_inst->new_codec = 1;
223 MCU_inst->current_Codec = -1;
224 }
225 i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst,
226 &RTPpacket[i_k], &flushed);
227 if (i_ok < 0)
228 {
229 return RECIN_CNG_ERROR;
230 }
231 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
232#else /* NETEQ_CNG_CODEC not defined */
233 return RECIN_UNKNOWNPAYLOAD;
234#endif /* NETEQ_CNG_CODEC */
235 }
236 else
237 {
238 /* Reinitialize the splitting if the payload and/or the payload length has changed */
239 curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
240 RTPpacket[i_k].payloadType);
241 if (curr_Codec != MCU_inst->current_Codec)
242 {
243 if (curr_Codec < 0)
244 {
245 return RECIN_UNKNOWNPAYLOAD;
246 }
247 MCU_inst->current_Codec = curr_Codec;
248 MCU_inst->current_Payload = RTPpacket[i_k].payloadType;
249 i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst,
250 (enum WebRtcNetEQDecoder) MCU_inst->current_Codec,
251 RTPpacket[i_k].payloadLen);
252 if (i_ok < 0)
253 { /* error returned */
254 return i_ok;
255 }
256 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
257 MCU_inst->new_codec = 1;
258 }
259
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 /* Parse the payload and insert it into the buffer */
261 i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k],
262 &MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst, &flushed);
263 if (i_ok < 0)
264 {
265 return i_ok;
266 }
267 if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0)
268 {
269 /* first normal packet after CNG or DTMF */
270 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1;
271 }
272 }
273 /* Reset DSP timestamp etc. if packet buffer flushed */
274 if (flushed)
275 {
276 MCU_inst->new_codec = 1;
277 }
278 }
279
280 /*
281 * Update Bandwidth Estimate
282 * Only send the main payload to BWE
283 */
284 if ((curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
285 RTPpacket[0].payloadType)) >= 0)
286 {
287 codecPos = MCU_inst->codec_DB_inst.position[curr_Codec];
288 if (MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos] != NULL) /* codec has BWE function */
289 {
290 if (RTPpacket[0].starts_byte1) /* check for shifted byte alignment */
291 {
292 /* re-align to 16-bit alignment */
293 for (i_k = 0; i_k < RTPpacket[0].payloadLen; i_k++)
294 {
295 WEBRTC_SPL_SET_BYTE(RTPpacket[0].payload,
296 WEBRTC_SPL_GET_BYTE(RTPpacket[0].payload, i_k+1),
297 i_k);
298 }
299 RTPpacket[0].starts_byte1 = 0;
300 }
301
302 MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos](
303 MCU_inst->codec_DB_inst.codec_state[codecPos],
304 (G_CONST WebRtc_UWord16 *) RTPpacket[0].payload,
305 (WebRtc_Word32) RTPpacket[0].payloadLen, RTPpacket[0].seqNumber,
306 (WebRtc_UWord32) RTPpacket[0].timeStamp, (WebRtc_UWord32) uw32_timeRec);
307 }
308 }
309
310 if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == 0)
311 {
312 /* Calculate the total speech length carried in each packet */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000313 temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(
314 &MCU_inst->PacketBuffer_inst, &MCU_inst->codec_DB_inst)
315 - temp_bufsize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000316
317 if ((temp_bufsize > 0) && (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF
318 == 0) && (temp_bufsize
319 != MCU_inst->BufferStat_inst.Automode_inst.packetSpeechLenSamp))
320 {
321 /* Change the auto-mode parameters if packet length has changed */
322 WebRtcNetEQ_SetPacketSpeechLen(&(MCU_inst->BufferStat_inst.Automode_inst),
323 (WebRtc_Word16) temp_bufsize, MCU_inst->fs);
324 }
325
326 /* update statistics */
327 if ((WebRtc_Word32) (RTPpacket[0].timeStamp - MCU_inst->timeStamp) >= 0
328 && !MCU_inst->new_codec)
329 {
330 /*
331 * Only update statistics if incoming packet is not older than last played out
332 * packet, and if new codec flag is not set.
333 */
334 WebRtcNetEQ_UpdateIatStatistics(&MCU_inst->BufferStat_inst.Automode_inst,
335 MCU_inst->PacketBuffer_inst.maxInsertPositions, RTPpacket[0].seqNumber,
336 RTPpacket[0].timeStamp, MCU_inst->fs,
337 WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) MCU_inst->current_Codec),
338 (MCU_inst->NetEqPlayoutMode == kPlayoutStreaming));
339 }
340 }
341 else if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == -1)
342 {
343 /*
344 * This is first "normal" packet after CNG or DTMF.
345 * Reset packet time counter and measure time until next packet,
346 * but don't update statistics.
347 */
348 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 0;
349 MCU_inst->BufferStat_inst.Automode_inst.packetIatCountSamp = 0;
350 }
351 return 0;
352
353}
354
355int WebRtcNetEQ_GetTimestampScaling(MCUInst_t *MCU_inst, int rtpPayloadType)
356{
357 enum WebRtcNetEQDecoder codec;
358 int codecNumber;
359
360 codecNumber = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, rtpPayloadType);
361 if (codecNumber < 0)
362 {
363 /* error */
364 return codecNumber;
365 }
366
367 /* cast to enumerator */
368 codec = (enum WebRtcNetEQDecoder) codecNumber;
369
370 /*
371 * The factor obtained below is the number with which the RTP timestamp must be
372 * multiplied to get the true sample count.
373 */
374 switch (codec)
375 {
376 case kDecoderG722:
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000377 case kDecoderG722_2ch:
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 {
379 /* Use timestamp scaling with factor 2 (two output samples per RTP timestamp) */
380 MCU_inst->scalingFactor = kTSscalingTwo;
381 break;
382 }
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000383 case kDecoderOpus:
tina.legrand@webrtc.org0ad3c1a2012-11-07 08:07:29 +0000384 case kDecoderOpus_2ch:
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000385 {
386 /* We resample Opus internally to 32 kHz, but timestamps
387 * are counted at 48 kHz. So there are two output samples
388 * per three RTP timestamp ticks. */
389 MCU_inst->scalingFactor = kTSscalingTwoThirds;
390 break;
391 }
392
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 case kDecoderAVT:
394 case kDecoderCNG:
395 {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000396 /* TODO(tlegrand): remove scaling once ACM has full 48 kHz
397 * support. */
398 WebRtc_UWord16 sample_freq =
399 WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
400 rtpPayloadType);
401 if (sample_freq == 48000) {
402 MCU_inst->scalingFactor = kTSscalingTwoThirds;
403 }
404
405 /* For sample_freq <= 32 kHz, do not change the timestamp scaling
406 * settings. */
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 break;
408 }
409 default:
410 {
411 /* do not use timestamp scaling */
412 MCU_inst->scalingFactor = kTSnoScaling;
413 break;
414 }
415 }
416 return 0;
417}
418
419WebRtc_UWord32 WebRtcNetEQ_ScaleTimestampExternalToInternal(const MCUInst_t *MCU_inst,
420 WebRtc_UWord32 externalTS)
421{
422 WebRtc_Word32 timestampDiff;
423 WebRtc_UWord32 internalTS;
424
425 /* difference between this and last incoming timestamp */
426 timestampDiff = externalTS - MCU_inst->externalTS;
427
428 switch (MCU_inst->scalingFactor)
429 {
430 case kTSscalingTwo:
431 {
432 /* multiply with 2 */
433 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
434 break;
435 }
436 case kTSscalingTwoThirds:
437 {
438 /* multiply with 2/3 */
439 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
440 timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
441 break;
442 }
443 case kTSscalingFourThirds:
444 {
445 /* multiply with 4/3 */
446 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 2);
447 timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
448 break;
449 }
450 default:
451 {
452 /* no scaling */
453 }
454 }
455
456 /* add the scaled difference to last scaled timestamp and save ... */
457 internalTS = MCU_inst->internalTS + timestampDiff;
458
459 return internalTS;
460}
461
462WebRtc_UWord32 WebRtcNetEQ_ScaleTimestampInternalToExternal(const MCUInst_t *MCU_inst,
463 WebRtc_UWord32 internalTS)
464{
465 WebRtc_Word32 timestampDiff;
466 WebRtc_UWord32 externalTS;
467
468 /* difference between this and last incoming timestamp */
469 timestampDiff = (WebRtc_Word32) internalTS - MCU_inst->internalTS;
470
471 switch (MCU_inst->scalingFactor)
472 {
473 case kTSscalingTwo:
474 {
475 /* divide by 2 */
476 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
477 break;
478 }
479 case kTSscalingTwoThirds:
480 {
481 /* multiply with 3/2 */
482 timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
483 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
484 break;
485 }
486 case kTSscalingFourThirds:
487 {
488 /* multiply with 3/4 */
489 timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
490 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 2);
491 break;
492 }
493 default:
494 {
495 /* no scaling */
496 }
497 }
498
499 /* add the scaled difference to last scaled timestamp and save ... */
500 externalTS = MCU_inst->externalTS + timestampDiff;
501
502 return externalTS;
503}