|
1 /* |
|
2 * Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: PayloadFormat plugin capable to read RTP payload containing |
|
15 * AMR audio. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 // INCLUDE FILES |
|
23 #include "amrpayloaddecoder.h" |
|
24 #include "amrcommonutil.h" |
|
25 #include "amrpayloadheader.h" |
|
26 #include "amrtocentry.h" |
|
27 |
|
28 // ============================= LOCAL FUNCTIONS =============================== |
|
29 |
|
30 // ============================ MEMBER FUNCTIONS =============================== |
|
31 |
|
32 // ----------------------------------------------------------------------------- |
|
33 // CAmrPayloadDecoder::CAmrPayloadDecoder |
|
34 // C++ default constructor can NOT contain any code, that |
|
35 // might leave. |
|
36 // ----------------------------------------------------------------------------- |
|
37 // |
|
38 CAmrPayloadDecoder::CAmrPayloadDecoder( TBool aIsNb ) : CAmrPayloadFormatter( aIsNb ) |
|
39 { |
|
40 DP_AMR_DECODE ("CAmrPayloadDecoder::CAmrPayloadDecoder"); |
|
41 } |
|
42 |
|
43 |
|
44 // ----------------------------------------------------------------------------- |
|
45 // CAmrPayloadEncoder::ConstructL |
|
46 // Symbian 2nd phase constructor can leave. |
|
47 // ----------------------------------------------------------------------------- |
|
48 // |
|
49 void CAmrPayloadDecoder::ConstructL( ) |
|
50 { |
|
51 DP_AMR_DECODE( "CAmrPayloadDecoder::ConstructL" ); |
|
52 |
|
53 // Allocate memory for iHeaderDecoder and iTocEntryDecoder |
|
54 iHeaderDecoder = CAmrPayloadHeader::NewL(); |
|
55 iTocEntryDecoder = CAmrTocEntry::NewL(); |
|
56 |
|
57 #ifdef FTD_ENABLED |
|
58 |
|
59 User::LeaveIfError( iCodecStatsQueue.OpenGlobal( KMccCodecStats, |
|
60 EOwnerProcess ) ); |
|
61 User::LeaveIfError( iJBufStatsQueue.OpenGlobal( KMccJBufferStats, |
|
62 EOwnerProcess ) ); |
|
63 |
|
64 #endif |
|
65 } |
|
66 |
|
67 |
|
68 // ----------------------------------------------------------------------------- |
|
69 // CAmrPayloadDecoder::NewL |
|
70 // Two-phased constructor. |
|
71 // ----------------------------------------------------------------------------- |
|
72 // |
|
73 CAmrPayloadDecoder* CAmrPayloadDecoder::NewL( TBool aIsNb ) |
|
74 { |
|
75 DP_AMR_DECODE( "CAmrPayloadDecoder::NewL" ); |
|
76 |
|
77 CAmrPayloadDecoder* self = new( ELeave ) CAmrPayloadDecoder( aIsNb ); |
|
78 |
|
79 CleanupStack::PushL( self ); |
|
80 self->ConstructL( ); |
|
81 CleanupStack::Pop( self ); |
|
82 |
|
83 return self; |
|
84 } |
|
85 |
|
86 // ----------------------------------------------------------------------------- |
|
87 // CAmrPayloadDecoder::~CAmrPayloadDecoder |
|
88 // Destructor |
|
89 // ----------------------------------------------------------------------------- |
|
90 // |
|
91 CAmrPayloadDecoder::~CAmrPayloadDecoder( ) |
|
92 { |
|
93 DP_AMR_DECODE( "CAmrPayloadDecoder::~CAmrPayloadDecoder" ); |
|
94 |
|
95 delete iHeaderDecoder; |
|
96 delete iTocEntryDecoder; |
|
97 |
|
98 #ifdef FTD_ENABLED |
|
99 |
|
100 iCodecStatsQueue.Close(); |
|
101 iJBufStatsQueue.Close(); |
|
102 |
|
103 #endif |
|
104 } |
|
105 |
|
106 // ----------------------------------------------------------------------------- |
|
107 // CAmrPayloadDecoder::DoInitialize |
|
108 // Initialize decoder. Decoder should be initialized when starting playing. |
|
109 // ----------------------------------------------------------------------------- |
|
110 // |
|
111 void CAmrPayloadDecoder::DoInitialize() |
|
112 { |
|
113 DP_AMR_DECODE( "CAmrPayloadDecoder::DoInitialize" ); |
|
114 |
|
115 } |
|
116 |
|
117 // ----------------------------------------------------------------------------- |
|
118 // CAmrPayloadDecoder::DecodePayload |
|
119 // Decode payload data received in the payload buffer. |
|
120 // If AMR FEC is used and redundant frames are discarded, time stamp is |
|
121 // increased to correspond start of remaining frames. |
|
122 // ----------------------------------------------------------------------------- |
|
123 // |
|
124 TInt CAmrPayloadDecoder::DecodePayload( TUint32& aTimeStamp, TUint32 aTimeStampInc ) |
|
125 { |
|
126 DP_AMR_DECODE( "CAmrPayloadDecoder::DecodePayload" ); |
|
127 |
|
128 iTimeStamp = aTimeStamp; |
|
129 iTimeStampInc = aTimeStampInc; |
|
130 Decode( iPayload, iPayloadSize ); |
|
131 aTimeStamp = iTimeStamp; |
|
132 iFrameIndex = 0; |
|
133 return iDecodedFrames; |
|
134 } |
|
135 |
|
136 |
|
137 // ----------------------------------------------------------------------------- |
|
138 // CAmrPayloadDecoder::ModeRequest |
|
139 // Get AMR codec mode request ( CMR ) received in the payload. |
|
140 // ----------------------------------------------------------------------------- |
|
141 // |
|
142 TAmrModeRequest CAmrPayloadDecoder::ModeRequest() const |
|
143 { |
|
144 DP_AMR_DECODE( "CAmrPayloadDecoder::ModeRequest" ); |
|
145 |
|
146 return iModeRequest; |
|
147 } |
|
148 |
|
149 |
|
150 // ----------------------------------------------------------------------------- |
|
151 // CAmrPayloadDecoder::Frames |
|
152 // Get AMR frames decoded from the payload. |
|
153 // ----------------------------------------------------------------------------- |
|
154 // |
|
155 TAmrFrame* CAmrPayloadDecoder::Frames( ) |
|
156 { |
|
157 DP_AMR_DECODE( "CAmrPayloadDecoder::Frames" ); |
|
158 |
|
159 return iFrames; |
|
160 } |
|
161 |
|
162 // ----------------------------------------------------------------------------- |
|
163 // CAmrPayloadDecoder::CompareBuffers |
|
164 // Compares contents of two buffers. |
|
165 // ----------------------------------------------------------------------------- |
|
166 // |
|
167 TBool CAmrPayloadDecoder::CompareBuffers( const TDesC8& aBuffer, |
|
168 const TAmrFrame& aFrameToCmp, |
|
169 TInt aOctetsToCmp ) const |
|
170 { |
|
171 DP_AMR_DECODE( "CAmrPayloadDecoder::CompareBuffers" ); |
|
172 |
|
173 TBool isSame( ETrue ); |
|
174 if ( EAmrFrameNoData == aFrameToCmp.iFrameType ) |
|
175 { |
|
176 if ( aBuffer.Size() ) |
|
177 { |
|
178 return EFalse; |
|
179 } |
|
180 else |
|
181 { |
|
182 return ETrue; |
|
183 } |
|
184 } |
|
185 else |
|
186 { |
|
187 if ( 0 == aBuffer.Size() ) |
|
188 { |
|
189 return EFalse; |
|
190 } |
|
191 } |
|
192 |
|
193 TStreamDecoder decoder; |
|
194 decoder.Initialize( aFrameToCmp.iFrameData, 0, aFrameToCmp.iBitIndex ); |
|
195 |
|
196 TInt octetsToCmp = aOctetsToCmp < aBuffer.Size() ? aOctetsToCmp : aBuffer.Size(); |
|
197 for ( TInt i = 0; i < octetsToCmp && isSame; i++ ) |
|
198 { |
|
199 TUint8 val = TUint8( decoder.Decode( KBitsIn1Byte ) ); |
|
200 if ( aBuffer[i] != val ) |
|
201 { |
|
202 isSame = EFalse; |
|
203 } |
|
204 } |
|
205 |
|
206 return isSame; |
|
207 } |
|
208 |
|
209 // ----------------------------------------------------------------------------- |
|
210 // CAmrPayloadDecoder::Decode |
|
211 // Decode the AMR payload ( for one RTP packet ) from a given buffer. |
|
212 // If more frames is received than expected based on SDPs PTIme negotiation, |
|
213 // we may have AMR FEC frames in a payload. Frames from previous payload are |
|
214 // compared to first frame in a new payload. If match is found we have received |
|
215 // that frame before and have redundant frames, which MUST be discarded. |
|
216 // After processing frames them are saved for redundancy check at next round. |
|
217 // ----------------------------------------------------------------------------- |
|
218 // |
|
219 void CAmrPayloadDecoder::Decode( const TUint8* aBuffer, |
|
220 TInt aBufferSize ) |
|
221 { |
|
222 DP_AMR_DECODE( "CAmrPayloadDecoder::Decode" ); |
|
223 |
|
224 TInt byteIndex( 0 ); |
|
225 TInt bitIndex( 0 ); |
|
226 |
|
227 // Decode Payload Header first |
|
228 iHeaderDecoder->Decode( aBuffer, byteIndex, bitIndex ); |
|
229 iModeRequest = iHeaderDecoder->iCmr; |
|
230 |
|
231 // Decode TOC entries |
|
232 iDecodedFrames = DecodeTableOfContents( aBuffer, aBufferSize, byteIndex, bitIndex ); |
|
233 |
|
234 // Update frame positions in the `iFrames' array. |
|
235 CalculateFramePosition( aBuffer, iDecodedFrames ); |
|
236 |
|
237 // Discard redundand frames already received |
|
238 TUint framesToDel( 0 ); |
|
239 TInt numOfFramesSaved( iFrameDatas.Count() ); |
|
240 DP_AMR_DECODE2( "CAmrPayloadDecoder::Decode - NUM OF SAVED FRAMES %d", numOfFramesSaved ); |
|
241 |
|
242 DP_AMR_DECODE2( "CAmrPayloadDecoder::Decode - DECODED FRAMES %d", iDecodedFrames ); |
|
243 |
|
244 TInt i = 0; |
|
245 TInt ind = 0; |
|
246 |
|
247 #ifdef _DEBUG |
|
248 if ( iDecodedFrames > KMaxFrameCountPerPacket ) |
|
249 { |
|
250 DP_AMR_DECODE3("CAmrPayloadDecoder::Decode, iDecodedFrames: %d > KMaxFrameCountPerPacket: %d", \ |
|
251 iDecodedFrames , KMaxFrameCountPerPacket); |
|
252 } |
|
253 for ( i = 0; i < iDecodedFrames; i++ ) |
|
254 { |
|
255 DP_AMR_DECODE2( "DECODED FRAME #%d: ", i ); |
|
256 if ( EAmrFrameNoData != iFrames[i].iFrameType ) |
|
257 { |
|
258 TStreamDecoder decoder; |
|
259 TUint8* refBufPtr = iFrames[i].iFrameData; |
|
260 decoder.Initialize( refBufPtr, 0, iFrames[i].iBitIndex ); |
|
261 TUint32 vals[KNumValue5]; |
|
262 for ( ind = 0; ind < (TInt) KNumValue5; ind ++ ) |
|
263 { |
|
264 vals[ind] = decoder.Decode( KBitsIn1Byte ); |
|
265 } |
|
266 DP_AMR_DECODE6( "| %d | %d | %d | %d | %d |", vals[KNumValue0], vals[KNumValue1], |
|
267 vals[KNumValue2], vals[KNumValue3], vals[KNumValue4] ); |
|
268 } |
|
269 else |
|
270 { |
|
271 DP_AMR_DECODE( "DECODED FRAME - NO DATA FRAME" ); |
|
272 } |
|
273 } |
|
274 |
|
275 for ( i = 0; i < numOfFramesSaved; i++ ) |
|
276 { |
|
277 if ( (*iFrameDatas[i] ).Size() ) |
|
278 { |
|
279 DP_AMR_DECODE3( "SAVED FRAME #%d, l: %d", i, (*iFrameDatas[i] ).Size() ); |
|
280 } |
|
281 else |
|
282 { |
|
283 DP_AMR_DECODE2( "SAVED FRAME #%d - NO DATA FRAME: ", i ); |
|
284 } |
|
285 } |
|
286 #endif |
|
287 |
|
288 // Last frame in previous payload is always other than NO_DATA frame, |
|
289 // so newly received frames can be compared to it. |
|
290 TInt lastFrameInd = numOfFramesSaved - 1 >= 0 ? numOfFramesSaved - 1 : 0; |
|
291 for ( i = 0; i < iDecodedFrames && numOfFramesSaved; i++ ) |
|
292 { |
|
293 DP_AMR_DECODE2( "CMP LAST FRAME FROM PREV PAYLOAD TO NEW FRAME #%d", i ); |
|
294 if ( CompareBuffers( *iFrameDatas[lastFrameInd], |
|
295 iFrames[i], |
|
296 KMaxCompareOctets ) ) |
|
297 { |
|
298 // Last frame from previous payload matched with some frame in a |
|
299 // new payload. Frames from this point onwards can be accepted. |
|
300 framesToDel = i + 1; |
|
301 for ( ind = 0; ind < iDecodedFrames; ind++ ) |
|
302 { |
|
303 iFrames[ ind ] = iFrames[ ind + framesToDel ]; |
|
304 } |
|
305 |
|
306 i = iDecodedFrames; // Stop loop |
|
307 iDecodedFrames -= framesToDel; |
|
308 if ( iDecodedFrames <= 0 ) |
|
309 { |
|
310 DP_AMR_DECODE( "Amr::Decode - NO FRAMES REMAINING AFTER RED CHECK" ); |
|
311 iDecodedFrames = 0; |
|
312 } |
|
313 iTimeStamp += iTimeStampInc * framesToDel; |
|
314 } |
|
315 } |
|
316 |
|
317 DP_AMR_DECODE2( "NUMBER OF RED FRAMES SKIPPED %d: ", framesToDel ); |
|
318 |
|
319 // Save received frames for redundancy check purposes |
|
320 if ( iDecodedFrames ) |
|
321 { |
|
322 iFrameDatas.ResetAndDestroy(); |
|
323 } |
|
324 |
|
325 if ( iDecodedFrames > KMaxFrameCountPerPacket ) |
|
326 { |
|
327 DP_AMR_DECODE3("CAmrPayloadDecoder::Decode, iDecodedFrames: %d > KMaxFrameCountPerPacket: %d", \ |
|
328 iDecodedFrames , KMaxFrameCountPerPacket); |
|
329 } |
|
330 for ( i = 0; i < iDecodedFrames; i++ ) |
|
331 { |
|
332 if ( EAmrFrameNoData != iFrames[i].iFrameType ) |
|
333 { |
|
334 TInt dataLen = SpeechBitCount( iFrames[i].iFrameType ); |
|
335 HBufC8* frame = HBufC8::New( dataLen / KBitsIn1Byte + 1 ); |
|
336 if (frame) |
|
337 { |
|
338 TUint8* toBuf = const_cast<TUint8*>( ( *frame ).Ptr() ); |
|
339 TStreamEncoder encoder; |
|
340 encoder.Initialize( toBuf, 0, 0 ); |
|
341 encoder.Encode( iFrames[i].iFrameData, 0, iFrames[i].iBitIndex, dataLen ); |
|
342 TPtr8 dataPtr = frame->Des(); |
|
343 dataPtr.SetLength( dataLen / KBitsIn1Byte + 1 ); |
|
344 if (iFrameDatas.Append( frame ) != KErrNone) |
|
345 { |
|
346 delete frame; |
|
347 } |
|
348 } |
|
349 } |
|
350 else |
|
351 { |
|
352 HBufC8* frame = HBufC8::New( 0 ); |
|
353 if (frame && iFrameDatas.Append( frame ) != KErrNone) |
|
354 { |
|
355 delete frame; |
|
356 } |
|
357 } |
|
358 } |
|
359 |
|
360 #ifdef FTD_ENABLED |
|
361 |
|
362 TMccCodecStats stats; |
|
363 stats.iCMRDownlink = iModeRequest; |
|
364 stats.SetFieldUpdatedFlag( ECMRDownlink ); |
|
365 iCodecStatsQueue.Send( stats ); |
|
366 |
|
367 TMccJBufferStats jStats; |
|
368 jStats.iRedLevel = framesToDel; |
|
369 jStats.iSampleSizeMultiplier = iDecodedFrames; |
|
370 jStats.SetFieldUpdatedFlag( ERedLevel ); |
|
371 jStats.SetFieldUpdatedFlag( ESampleSizeMultiplier ); |
|
372 |
|
373 iJBufStatsQueue.Send( jStats ); |
|
374 |
|
375 #endif |
|
376 } |
|
377 |
|
378 // ----------------------------------------------------------------------------- |
|
379 // CAmrPayloadDecoder::DecodeTableOfContents |
|
380 // Decode TOC ( Table of contents ) entries from the payload buffer. |
|
381 // Decoded values are put in `iFrames[]' array. |
|
382 // Return number of TOC entries decoded. |
|
383 // ----------------------------------------------------------------------------- |
|
384 // |
|
385 TInt CAmrPayloadDecoder::DecodeTableOfContents( const TUint8* aBuffer, |
|
386 TInt aBufferSize, |
|
387 TInt& aByteIndex, |
|
388 TInt& aBitIndex ) |
|
389 { |
|
390 DP_AMR_DECODE( "CAmrPayloadDecoder::DecodeTableOfContents" ); |
|
391 |
|
392 TInt curChannel( 0 ); |
|
393 TInt i( 0 ); |
|
394 |
|
395 for ( i = 0; ( i < KMaxFrameCountPerPacket ) && ( aByteIndex < aBufferSize ); i++ ) |
|
396 { |
|
397 iTocEntryDecoder->Decode( aBuffer, aByteIndex, aBitIndex ); |
|
398 iFrames[i].iFrameType = iTocEntryDecoder->iFrameType; |
|
399 iFrames[i].iFrameQualityInd = iTocEntryDecoder->iFrameQualityInd; |
|
400 iFrames[i].iChannel = curChannel; |
|
401 |
|
402 if ( !( iTocEntryDecoder->iFrameFollowed ) ) |
|
403 { |
|
404 break; |
|
405 } |
|
406 |
|
407 // Update currentChannel |
|
408 curChannel++; |
|
409 if ( curChannel == iChannelCount ) |
|
410 { |
|
411 curChannel = 0; |
|
412 } |
|
413 } |
|
414 |
|
415 return i + 1; |
|
416 } |
|
417 |
|
418 // ----------------------------------------------------------------------------- |
|
419 // CAmrPayloadDecoder::CalculateFramePosition |
|
420 // Calculate frames' starting Byte and Bit positions. |
|
421 // ----------------------------------------------------------------------------- |
|
422 // |
|
423 void CAmrPayloadDecoder::CalculateFramePosition( const TUint8* aBuffer, |
|
424 TInt aFrameCount ) |
|
425 { |
|
426 DP_AMR_DECODE( "CAmrPayloadDecoder::CalculateFramePosition" ); |
|
427 |
|
428 TUint frameByteIndex; |
|
429 TUint frameBitIndex; |
|
430 |
|
431 // Number of bits for CMR and TOC entries |
|
432 TUint bitCount = KHeaderBitsBE + KTOCFieldBitsBE * TUint( aFrameCount ); |
|
433 |
|
434 if ( aFrameCount > KMaxFrameCountPerPacket ) |
|
435 { |
|
436 DP_AMR_DECODE3("CAmrPayloadDecoder::CalculateFramePosition, aFrameCount: %d > KMaxFrameCountPerPacket: %d", \ |
|
437 aFrameCount, KMaxFrameCountPerPacket); |
|
438 } |
|
439 for ( TInt i = 0; i < aFrameCount; i++ ) |
|
440 { |
|
441 frameByteIndex = bitCount >> KNumValue3; |
|
442 frameBitIndex = bitCount & KBitIndex7; |
|
443 if ( EAmrFrameNoData == iFrames[i].iFrameType ) |
|
444 { |
|
445 iFrames[i].iBitIndex = 0; |
|
446 iFrames[i].iFrameData = NULL; |
|
447 } |
|
448 else |
|
449 { |
|
450 // Set frame byte and bit positions |
|
451 iFrames[i].iBitIndex = frameBitIndex; |
|
452 iFrames[i].iFrameData = const_cast<TUint8*>( aBuffer ) + frameByteIndex; |
|
453 } |
|
454 |
|
455 // Update bit-count for next frame entry. |
|
456 bitCount = bitCount + TUint( SpeechBitCount( iFrames[i].iFrameType ) ); |
|
457 } |
|
458 } |
|
459 |
|
460 |
|
461 // ========================== OTHER EXPORTED FUNCTIONS ========================= |
|
462 |
|
463 // End of File |
|
464 |