blob: 17bea5f5bbffdf0cb6c5ff053e2749315301e910 [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
niklase@google.com470e71d2011-07-07 08:21:25 +000020#include "automode.h"
21#include "dtmf_buffer.h"
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +000022#include "mcu_dsp_common.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023#include "neteq_defines.h"
24#include "neteq_error_codes.h"
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +000025#include "signal_processing_library.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput,
pbos@webrtc.org0946a562013-04-09 00:28:06 +000028 uint32_t uw32_timeRec)
niklase@google.com470e71d2011-07-07 08:21:25 +000029{
30 RTPPacket_t RTPpacket[2];
31 int i_k;
32 int i_ok = 0, i_No_Of_Payloads = 1;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000033 int16_t flushed = 0;
34 int16_t codecPos;
niklase@google.com470e71d2011-07-07 08:21:25 +000035 int curr_Codec;
pbos@webrtc.org0946a562013-04-09 00:28:06 +000036 int16_t isREDPayload = 0;
37 int32_t temp_bufsize;
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +000038 int is_sync_rtp = MCU_inst->av_sync && WebRtcNetEQ_IsSyncPayload(
39 RTPpacketInput->payload, RTPpacketInput->payloadLen);
niklase@google.com470e71d2011-07-07 08:21:25 +000040#ifdef NETEQ_RED_CODEC
41 RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */
42 RTPpacketPtr[0] = &RTPpacket[0];
43 RTPpacketPtr[1] = &RTPpacket[1];
44#endif
45
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +000046 temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(&MCU_inst->PacketBuffer_inst,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +000047 &MCU_inst->codec_DB_inst,
48 MCU_inst->av_sync);
niklase@google.com470e71d2011-07-07 08:21:25 +000049 /*
50 * Copy from input RTP packet to local copy
51 * (mainly to enable multiple payloads using RED)
52 */
53
54 WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t));
55
56 /* Reinitialize NetEq if it's needed (changed SSRC or first call) */
57
58 if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1))
59 {
60 WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber);
61 MCU_inst->first_packet = 0;
62
63 /* Flush the buffer */
64 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
65
66 /* Store new SSRC */
67 MCU_inst->ssrc = RTPpacket[0].ssrc;
68
69 /* Update codecs */
70 MCU_inst->timeStamp = RTPpacket[0].timeStamp;
71 MCU_inst->current_Payload = RTPpacket[0].payloadType;
72
73 /*Set MCU to update codec on next SignalMCU call */
74 MCU_inst->new_codec = 1;
75
76 /* Reset timestamp scaling */
77 MCU_inst->TSscalingInitialized = 0;
78
79 }
80
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +000081 if (!is_sync_rtp) { /* Update only if it not sync packet. */
82 /* Call RTCP statistics if it is not sync packet. */
83 i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst),
84 RTPpacket[0].seqNumber,
85 RTPpacket[0].timeStamp, uw32_timeRec);
86 }
niklase@google.com470e71d2011-07-07 08:21:25 +000087
88 /* If Redundancy is supported and this is the redundancy payload, separate the payloads */
89#ifdef NETEQ_RED_CODEC
90 if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
91 kDecoderRED))
92 {
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +000093 if (is_sync_rtp)
94 {
95 /* Sync packet should not have RED payload type. */
96 return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
97 }
niklase@google.com470e71d2011-07-07 08:21:25 +000098
99 /* Split the payload into a main and a redundancy payloads */
100 i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads);
101 if (i_ok < 0)
102 {
103 /* error returned */
104 return i_ok;
105 }
106
107 /*
108 * Only accept a few redundancies of the same type as the main data,
109 * AVT events and CNG.
110 */
111 if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType)
112 && (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
113 kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload(
114 &MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload(
115 &MCU_inst->codec_DB_inst, RTPpacket[0].payloadType))
116 && (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType)))
117 {
118 i_No_Of_Payloads = 1;
119 }
120 isREDPayload = 1;
121 }
122#endif
123
124 /* loop over the number of payloads */
125 for (i_k = 0; i_k < i_No_Of_Payloads; i_k++)
126 {
127
128 if (isREDPayload == 1)
129 {
130 RTPpacket[i_k].rcuPlCntr = i_k;
131 }
132 else
133 {
134 RTPpacket[i_k].rcuPlCntr = 0;
135 }
136
137 /* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */
138 if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000139 kDecoderILBC) && !is_sync_rtp) /* Don't update if sync RTP. */
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 {
141 i_ok = WebRtcNetEQ_DbGetSplitInfo(
142 &MCU_inst->PayloadSplit_inst,
143 (enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
144 RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen);
145 if (i_ok < 0)
146 {
147 /* error returned */
148 return i_ok;
149 }
150 }
151
152 /* Get information about timestamp scaling for this payload type */
153 i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType);
154 if (i_ok < 0)
155 {
156 /* error returned */
157 return i_ok;
158 }
159
160 if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling)
161 {
162 /* Must initialize scaling with current timestamps */
163 MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
164 MCU_inst->internalTS = RTPpacket[i_k].timeStamp;
165 MCU_inst->TSscalingInitialized = 1;
166 }
167
168 /* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */
169 if (MCU_inst->TSscalingInitialized == 1)
170 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000171 uint32_t newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst,
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 RTPpacket[i_k].timeStamp);
173
174 /* save the incoming timestamp for next time */
175 MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
176
177 /* add the scaled difference to last scaled timestamp and save ... */
178 MCU_inst->internalTS = newTS;
179
180 RTPpacket[i_k].timeStamp = newTS;
181 }
182
183 /* Is this a DTMF packet?*/
184 if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
185 kDecoderAVT))
186 {
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000187 if (is_sync_rtp)
188 {
189 /* Sync RTP should not have AVT payload type. */
190 return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
191 }
192
niklase@google.com470e71d2011-07-07 08:21:25 +0000193#ifdef NETEQ_ATEVENT_DECODE
194 if (MCU_inst->AVT_PlayoutOn)
195 {
196 i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst,
197 RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen,
198 RTPpacket[i_k].timeStamp);
199 if (i_ok != 0)
200 {
201 return i_ok;
202 }
203 }
204#endif
205#ifdef NETEQ_STEREO
206 if (MCU_inst->usingStereo == 0)
207 {
208 /* do not set this for DTMF packets when using stereo mode */
209 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
210 }
211#else
212 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
213#endif
214 }
215 else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst,
216 RTPpacket[i_k].payloadType))
217 {
218 /* Is this a CNG packet? how should we handle this?*/
219#ifdef NETEQ_CNG_CODEC
220 /* Get CNG sample rate */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000221 uint16_t fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 RTPpacket[i_k].payloadType);
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000223 if (is_sync_rtp)
224 {
225 /* Sync RTP should not have CNG payload type. */
226 return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
227 }
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000228
229 /* Force sampling frequency to 32000 Hz CNG 48000 Hz. */
230 /* TODO(tlegrand): remove limitation once ACM has full 48 kHz
231 * support. */
232 if (fsCng > 32000) {
233 fsCng = 32000;
234 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 if ((fsCng != MCU_inst->fs) && (fsCng > 8000))
236 {
237 /*
238 * We have received CNG with a different sample rate from what we are using
239 * now (must be > 8000, since we may use only one CNG type (default) for all
240 * frequencies). Flush buffer and signal new codec.
241 */
242 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
243 MCU_inst->new_codec = 1;
244 MCU_inst->current_Codec = -1;
245 }
246 i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst,
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000247 &RTPpacket[i_k], &flushed, MCU_inst->av_sync);
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 if (i_ok < 0)
249 {
250 return RECIN_CNG_ERROR;
251 }
252 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
253#else /* NETEQ_CNG_CODEC not defined */
254 return RECIN_UNKNOWNPAYLOAD;
255#endif /* NETEQ_CNG_CODEC */
256 }
257 else
258 {
259 /* Reinitialize the splitting if the payload and/or the payload length has changed */
260 curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
261 RTPpacket[i_k].payloadType);
262 if (curr_Codec != MCU_inst->current_Codec)
263 {
264 if (curr_Codec < 0)
265 {
266 return RECIN_UNKNOWNPAYLOAD;
267 }
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000268 if (is_sync_rtp)
269 {
270 /* Sync RTP should not cause codec change. */
271 return RECIN_SYNC_RTP_CHANGED_CODEC;
272 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 MCU_inst->current_Codec = curr_Codec;
274 MCU_inst->current_Payload = RTPpacket[i_k].payloadType;
275 i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst,
276 (enum WebRtcNetEQDecoder) MCU_inst->current_Codec,
277 RTPpacket[i_k].payloadLen);
278 if (i_ok < 0)
279 { /* error returned */
280 return i_ok;
281 }
282 WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
283 MCU_inst->new_codec = 1;
284 }
285
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 /* Parse the payload and insert it into the buffer */
287 i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k],
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000288 &MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst,
289 &flushed, MCU_inst->av_sync);
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 if (i_ok < 0)
291 {
292 return i_ok;
293 }
294 if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0)
295 {
296 /* first normal packet after CNG or DTMF */
297 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1;
298 }
299 }
300 /* Reset DSP timestamp etc. if packet buffer flushed */
301 if (flushed)
302 {
303 MCU_inst->new_codec = 1;
304 }
305 }
306
307 /*
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000308 * If not sync RTP, update Bandwidth Estimate.
309 * Only send the main payload to BWE.
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 */
turaj@webrtc.org8630cfe2013-05-16 23:54:54 +0000311 if (!is_sync_rtp &&
312 (curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
niklase@google.com470e71d2011-07-07 08:21:25 +0000313 RTPpacket[0].payloadType)) >= 0)
314 {
315 codecPos = MCU_inst->codec_DB_inst.position[curr_Codec];
316 if (MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos] != NULL) /* codec has BWE function */
317 {
318 if (RTPpacket[0].starts_byte1) /* check for shifted byte alignment */
319 {
320 /* re-align to 16-bit alignment */
321 for (i_k = 0; i_k < RTPpacket[0].payloadLen; i_k++)
322 {
323 WEBRTC_SPL_SET_BYTE(RTPpacket[0].payload,
324 WEBRTC_SPL_GET_BYTE(RTPpacket[0].payload, i_k+1),
325 i_k);
326 }
327 RTPpacket[0].starts_byte1 = 0;
328 }
329
330 MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos](
331 MCU_inst->codec_DB_inst.codec_state[codecPos],
pbos@webrtc.orge4b60642013-04-10 18:06:57 +0000332 (const uint16_t *) RTPpacket[0].payload,
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000333 (int32_t) RTPpacket[0].payloadLen, RTPpacket[0].seqNumber,
334 (uint32_t) RTPpacket[0].timeStamp, (uint32_t) uw32_timeRec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000335 }
336 }
337
338 if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == 0)
339 {
340 /* Calculate the total speech length carried in each packet */
tina.legrand@webrtc.org5ac387c2012-11-19 08:02:55 +0000341 temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(
turaj@webrtc.org28d54ab2013-04-22 18:53:35 +0000342 &MCU_inst->PacketBuffer_inst, &MCU_inst->codec_DB_inst,
343 MCU_inst->av_sync) - temp_bufsize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 if ((temp_bufsize > 0) && (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF
346 == 0) && (temp_bufsize
347 != MCU_inst->BufferStat_inst.Automode_inst.packetSpeechLenSamp))
348 {
349 /* Change the auto-mode parameters if packet length has changed */
350 WebRtcNetEQ_SetPacketSpeechLen(&(MCU_inst->BufferStat_inst.Automode_inst),
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000351 (int16_t) temp_bufsize, MCU_inst->fs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 }
353
354 /* update statistics */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000355 if ((int32_t) (RTPpacket[0].timeStamp - MCU_inst->timeStamp) >= 0
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 && !MCU_inst->new_codec)
357 {
358 /*
359 * Only update statistics if incoming packet is not older than last played out
360 * packet, and if new codec flag is not set.
361 */
362 WebRtcNetEQ_UpdateIatStatistics(&MCU_inst->BufferStat_inst.Automode_inst,
363 MCU_inst->PacketBuffer_inst.maxInsertPositions, RTPpacket[0].seqNumber,
364 RTPpacket[0].timeStamp, MCU_inst->fs,
365 WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) MCU_inst->current_Codec),
366 (MCU_inst->NetEqPlayoutMode == kPlayoutStreaming));
367 }
368 }
369 else if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == -1)
370 {
371 /*
372 * This is first "normal" packet after CNG or DTMF.
373 * Reset packet time counter and measure time until next packet,
374 * but don't update statistics.
375 */
376 MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 0;
377 MCU_inst->BufferStat_inst.Automode_inst.packetIatCountSamp = 0;
378 }
379 return 0;
380
381}
382
383int WebRtcNetEQ_GetTimestampScaling(MCUInst_t *MCU_inst, int rtpPayloadType)
384{
385 enum WebRtcNetEQDecoder codec;
386 int codecNumber;
387
388 codecNumber = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, rtpPayloadType);
389 if (codecNumber < 0)
390 {
391 /* error */
392 return codecNumber;
393 }
394
395 /* cast to enumerator */
396 codec = (enum WebRtcNetEQDecoder) codecNumber;
397
398 /*
399 * The factor obtained below is the number with which the RTP timestamp must be
400 * multiplied to get the true sample count.
401 */
402 switch (codec)
403 {
404 case kDecoderG722:
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000405 case kDecoderG722_2ch:
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 {
407 /* Use timestamp scaling with factor 2 (two output samples per RTP timestamp) */
408 MCU_inst->scalingFactor = kTSscalingTwo;
409 break;
410 }
turaj@webrtc.orgb0dff122012-12-03 17:43:52 +0000411 case kDecoderISACfb:
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000412 case kDecoderOpus:
413 {
turaj@webrtc.orgb0dff122012-12-03 17:43:52 +0000414 /* We resample Opus internally to 32 kHz, and isac-fb decodes at
415 * 32 kHz, but timestamps are counted at 48 kHz. So there are two
416 * output samples per three RTP timestamp ticks. */
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000417 MCU_inst->scalingFactor = kTSscalingTwoThirds;
418 break;
419 }
420
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 case kDecoderAVT:
422 case kDecoderCNG:
423 {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000424 /* TODO(tlegrand): remove scaling once ACM has full 48 kHz
425 * support. */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000426 uint16_t sample_freq =
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000427 WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
428 rtpPayloadType);
429 if (sample_freq == 48000) {
430 MCU_inst->scalingFactor = kTSscalingTwoThirds;
431 }
432
433 /* For sample_freq <= 32 kHz, do not change the timestamp scaling
434 * settings. */
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 break;
436 }
437 default:
438 {
439 /* do not use timestamp scaling */
440 MCU_inst->scalingFactor = kTSnoScaling;
441 break;
442 }
443 }
444 return 0;
445}
446
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000447uint32_t WebRtcNetEQ_ScaleTimestampExternalToInternal(const MCUInst_t *MCU_inst,
448 uint32_t externalTS)
niklase@google.com470e71d2011-07-07 08:21:25 +0000449{
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000450 int32_t timestampDiff;
451 uint32_t internalTS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000452
453 /* difference between this and last incoming timestamp */
454 timestampDiff = externalTS - MCU_inst->externalTS;
455
456 switch (MCU_inst->scalingFactor)
457 {
458 case kTSscalingTwo:
459 {
460 /* multiply with 2 */
461 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
462 break;
463 }
464 case kTSscalingTwoThirds:
465 {
466 /* multiply with 2/3 */
467 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
468 timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
469 break;
470 }
471 case kTSscalingFourThirds:
472 {
473 /* multiply with 4/3 */
474 timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 2);
475 timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
476 break;
477 }
478 default:
479 {
480 /* no scaling */
481 }
482 }
483
484 /* add the scaled difference to last scaled timestamp and save ... */
485 internalTS = MCU_inst->internalTS + timestampDiff;
486
487 return internalTS;
488}
489
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000490uint32_t WebRtcNetEQ_ScaleTimestampInternalToExternal(const MCUInst_t *MCU_inst,
491 uint32_t internalTS)
niklase@google.com470e71d2011-07-07 08:21:25 +0000492{
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000493 int32_t timestampDiff;
494 uint32_t externalTS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
496 /* difference between this and last incoming timestamp */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000497 timestampDiff = (int32_t) internalTS - MCU_inst->internalTS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000498
499 switch (MCU_inst->scalingFactor)
500 {
501 case kTSscalingTwo:
502 {
503 /* divide by 2 */
504 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
505 break;
506 }
507 case kTSscalingTwoThirds:
508 {
509 /* multiply with 3/2 */
510 timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
511 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
512 break;
513 }
514 case kTSscalingFourThirds:
515 {
516 /* multiply with 3/4 */
517 timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
518 timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 2);
519 break;
520 }
521 default:
522 {
523 /* no scaling */
524 }
525 }
526
527 /* add the scaled difference to last scaled timestamp and save ... */
528 externalTS = MCU_inst->externalTS + timestampDiff;
529
530 return externalTS;
531}