|
1 /* |
|
2 * Copyright (c) 2004-2007 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: Comfort noise generator of MCC jitterbuffer |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 // INCLUDE FILES |
|
22 #include <ErrorConcealmentIntfc.h> |
|
23 #include "mmcccodecinformation.h" |
|
24 #include "mcccngenerator.h" |
|
25 #include "mccjitterbufferlogs.h" |
|
26 #include "mccinternaldef.h" |
|
27 |
|
28 // CONSTANTS |
|
29 |
|
30 // When the remote end sends us SID/CN frames, then we can update the SID/CN |
|
31 // parameters programmatically. Otherwise when we have not received any SID/CN |
|
32 // frames we should not try to "emulate" SID/CN frames. This can mess up the |
|
33 // decoder which could lead into a undesired artefacts in audio quality. |
|
34 // |
|
35 // Basically this means that if we have not aquired SID/CN frames |
|
36 // programmatically we will send NULL/NO_DATA data into the decoder. |
|
37 |
|
38 // AMR-NB SID FT value is 8 and is located in the upper 4 bits |
|
39 // See 3GPP TS 26.101 |
|
40 const TUint8 KAmrSidMode = 8; |
|
41 |
|
42 // AMR-WB SID FT value is 9 and is located in the upper 4 bits |
|
43 // See 3GPP TS 26.101 |
|
44 const TUint8 KAmrWbSidMode = 9; |
|
45 |
|
46 // AMR-NB mode mask |
|
47 const TUint8 KAmrModeMask = 0x78; |
|
48 |
|
49 // AMR-NB SID Update frame interval |
|
50 const TInt KAmrNbSidUpdateInterval = 8; |
|
51 |
|
52 // Minimum required data length for DTX decision |
|
53 const TInt KMinDataLenForDtx = 1; |
|
54 |
|
55 // AMR NO_DATA frame needs one byte |
|
56 // See 3GPP TS 26.101 and RFC 2367 |
|
57 // ________________ |
|
58 // |0|1|1|1|1|1|0|0| |
|
59 // |P| FT |Q|P|P| |
|
60 // |
|
61 // P = PADDING |
|
62 // FT = 15 = NO_DATA |
|
63 // Q = QUALITY |
|
64 const TUint8 KAmrNoDataFrame = 0x7C; |
|
65 |
|
66 // Length of the header and AMR NO_DATA frames |
|
67 const TInt KNoDataLength = 1; |
|
68 |
|
69 // AMR mode solving needs 3 bit shift |
|
70 const TInt KModeShiftBits = 3; |
|
71 |
|
72 #if ( defined __WINSCW__ ) || ( defined __WINS__ ) || ( defined TEST_EUNIT ) |
|
73 #define MCC_CN_GEN_DISABLE_CONCEALMENT |
|
74 #endif |
|
75 |
|
76 |
|
77 |
|
78 // ============================ MEMBER FUNCTIONS =============================== |
|
79 |
|
80 // ----------------------------------------------------------------------------- |
|
81 // CMccCnGenerator::NewL |
|
82 // Static constructor. |
|
83 // ----------------------------------------------------------------------------- |
|
84 // |
|
85 CMccCnGenerator* CMccCnGenerator::NewL( const TFourCC& aAudioType, |
|
86 CMMFDevSound& aDevSound ) |
|
87 { |
|
88 __CN_GEN( "CMccCnGenerator::NewL IN" ) |
|
89 |
|
90 CMccCnGenerator* self = new ( ELeave ) CMccCnGenerator( aAudioType, |
|
91 aDevSound ); |
|
92 |
|
93 CleanupStack::PushL( self ); |
|
94 self->ConstructL(); |
|
95 CleanupStack::Pop( self ); |
|
96 |
|
97 __CN_GEN( "CMccCnGenerator::NewL OUT" ) |
|
98 |
|
99 return self; |
|
100 } |
|
101 |
|
102 // ----------------------------------------------------------------------------- |
|
103 // CMccCnGenerator::CMccCnGenerator |
|
104 // C++ default constructor can NOT contain any code, that |
|
105 // might leave. |
|
106 // ----------------------------------------------------------------------------- |
|
107 // |
|
108 CMccCnGenerator::CMccCnGenerator( const TFourCC& aAudioType, |
|
109 CMMFDevSound& aDevSound ) : iAudioType( aAudioType ), iDevSound( aDevSound ) |
|
110 { |
|
111 |
|
112 } |
|
113 |
|
114 // ----------------------------------------------------------------------------- |
|
115 // CMccCnGenerator::ConstructL |
|
116 // Symbian 2nd phase constructor can leave. |
|
117 // ----------------------------------------------------------------------------- |
|
118 // |
|
119 void CMccCnGenerator::ConstructL() |
|
120 { |
|
121 __CN_GEN( "CMccCnGenerator::ConstructL" ) |
|
122 |
|
123 #ifdef MCC_CN_GEN_DISABLE_CONCEALMENT |
|
124 __CN_GEN( "CMccCnGenerator::ConstructL Please integrate MMF Cust IF's to emulator" ) |
|
125 #else |
|
126 iErrorConcealer = CErrorConcealmentIntfc::NewL( iDevSound ); |
|
127 #endif |
|
128 |
|
129 // Check the codec |
|
130 switch ( iAudioType.FourCC() ) |
|
131 { |
|
132 case KMccFourCCIdAMRNB: |
|
133 case KMccFourCCIdAMRWB: |
|
134 case KMccFourCCIdG711: |
|
135 case KMccFourCCIdILBC: |
|
136 case KMccFourCCIdG729: |
|
137 break; |
|
138 default: |
|
139 __CN_GEN( "CMccCnGenerator::ConstructL UNKNOWN CODEC" ) |
|
140 |
|
141 User::Leave( KErrNotSupported ); |
|
142 break; |
|
143 } |
|
144 } |
|
145 |
|
146 // ----------------------------------------------------------------------------- |
|
147 // CMccCnGenerator::~CMccCnGenerator |
|
148 // Destructor |
|
149 // ----------------------------------------------------------------------------- |
|
150 // |
|
151 CMccCnGenerator::~CMccCnGenerator() |
|
152 { |
|
153 delete iErrorConcealer; |
|
154 } |
|
155 |
|
156 // ----------------------------------------------------------------------------- |
|
157 // CMccCnGenerator::GenerateSidPacketL |
|
158 // Generate Sid Packet |
|
159 // ----------------------------------------------------------------------------- |
|
160 // |
|
161 void CMccCnGenerator::GenerateSidPacket( TDes8& aPayload, TInt aRequestSize ) |
|
162 { |
|
163 if ( aRequestSize > aPayload.MaxLength() ) |
|
164 { |
|
165 __CN_GEN( "CMccCnGenerator::GenerateSidPacket, adjust request size" ) |
|
166 aRequestSize = aPayload.MaxLength(); |
|
167 } |
|
168 |
|
169 iGeneratedCnFrames++; |
|
170 |
|
171 __CN_GEN_INT1( "CMccCnGenerator::GenerateSidPacket iGeneratedCnFrames: ", |
|
172 iGeneratedCnFrames ) |
|
173 |
|
174 #ifdef MCC_CN_GEN_DISABLE_CONCEALMENT |
|
175 |
|
176 // Fill with zeroes in emulator |
|
177 aPayload.SetMax(); |
|
178 aPayload.FillZ(); |
|
179 // WINSCW compile... |
|
180 aRequestSize = aRequestSize; |
|
181 |
|
182 #else // Real HW |
|
183 |
|
184 if ( KMccFourCCIdAMRNB == iAudioType.FourCC() ) |
|
185 { |
|
186 this->GenerateAmrNoDataPacket( aPayload ); |
|
187 if( KAmrNbSidUpdateInterval == iGeneratedCnFrames ) |
|
188 { |
|
189 // We've not received an SID_UPDATE for 8th frame |
|
190 // this means that it has been lost, so this means packet loss |
|
191 iDtxPeriodStarted = EFalse; |
|
192 } |
|
193 } |
|
194 else if ( KMccFourCCIdAMRWB == iAudioType.FourCC() ) |
|
195 { |
|
196 // Using temporarily pre-generated silent data |
|
197 // 04,10,21,00,39,1d,37,d4,91,74,7c,c2,78,e8,e0,88,e2,e0 |
|
198 // as no data frame causes decoder crash |
|
199 // |
|
200 const TInt KSilenceDataLength = 18; |
|
201 if ( aRequestSize >= KSilenceDataLength ) |
|
202 { |
|
203 __CN_GEN( "CMccCnGenerator::GenerateSidPacket, amr wb, do silence frame" ) |
|
204 const TUint8 KAmrSilenceFrameByte1 = 0x04; |
|
205 const TUint8 KAmrSilenceFrameByte2 = 0x10; |
|
206 const TUint8 KAmrSilenceFrameByte3 = 0x21; |
|
207 const TUint8 KAmrSilenceFrameByte4 = 0x00; |
|
208 const TUint8 KAmrSilenceFrameByte5 = 0x39; |
|
209 const TUint8 KAmrSilenceFrameByte6 = 0x1d; |
|
210 const TUint8 KAmrSilenceFrameByte7 = 0x37; |
|
211 const TUint8 KAmrSilenceFrameByte8 = 0xd4; |
|
212 const TUint8 KAmrSilenceFrameByte9 = 0x91; |
|
213 const TUint8 KAmrSilenceFrameByte10 = 0x74; |
|
214 const TUint8 KAmrSilenceFrameByte11 = 0x7c; |
|
215 const TUint8 KAmrSilenceFrameByte12 = 0xc2; |
|
216 const TUint8 KAmrSilenceFrameByte13 = 0x78; |
|
217 const TUint8 KAmrSilenceFrameByte14 = 0xe8; |
|
218 const TUint8 KAmrSilenceFrameByte15 = 0xe0; |
|
219 const TUint8 KAmrSilenceFrameByte16 = 0x88; |
|
220 const TUint8 KAmrSilenceFrameByte17 = 0xe2; |
|
221 const TUint8 KAmrSilenceFrameByte18 = 0xe0; |
|
222 aPayload.Copy( &KAmrSilenceFrameByte1, KNoDataLength ); |
|
223 aPayload.Append( &KAmrSilenceFrameByte2, KNoDataLength ); |
|
224 aPayload.Append( &KAmrSilenceFrameByte3, KNoDataLength ); |
|
225 aPayload.Append( &KAmrSilenceFrameByte4, KNoDataLength ); |
|
226 aPayload.Append( &KAmrSilenceFrameByte5, KNoDataLength ); |
|
227 aPayload.Append( &KAmrSilenceFrameByte6, KNoDataLength ); |
|
228 aPayload.Append( &KAmrSilenceFrameByte7, KNoDataLength ); |
|
229 aPayload.Append( &KAmrSilenceFrameByte8, KNoDataLength ); |
|
230 aPayload.Append( &KAmrSilenceFrameByte9, KNoDataLength ); |
|
231 aPayload.Append( &KAmrSilenceFrameByte10, KNoDataLength ); |
|
232 aPayload.Append( &KAmrSilenceFrameByte11, KNoDataLength ); |
|
233 aPayload.Append( &KAmrSilenceFrameByte12, KNoDataLength ); |
|
234 aPayload.Append( &KAmrSilenceFrameByte13, KNoDataLength ); |
|
235 aPayload.Append( &KAmrSilenceFrameByte14, KNoDataLength ); |
|
236 aPayload.Append( &KAmrSilenceFrameByte15, KNoDataLength ); |
|
237 aPayload.Append( &KAmrSilenceFrameByte16, KNoDataLength ); |
|
238 aPayload.Append( &KAmrSilenceFrameByte17, KNoDataLength ); |
|
239 aPayload.Append( &KAmrSilenceFrameByte18, KNoDataLength ); |
|
240 } |
|
241 else |
|
242 { |
|
243 __CN_GEN( "CMccCnGenerator::GenerateSidPacket, amr wb, do dummy frame" ) |
|
244 aPayload.SetLength( aRequestSize ); |
|
245 aPayload.FillZ(); |
|
246 } |
|
247 |
|
248 if ( KAmrNbSidUpdateInterval == iGeneratedCnFrames ) |
|
249 { |
|
250 // We've not received an SID_UPDATE for 8th frame |
|
251 // this means that it has been lost, so this means packet loss |
|
252 iDtxPeriodStarted = EFalse; |
|
253 } |
|
254 } |
|
255 else |
|
256 { |
|
257 this->GenerateVoIPNoDataPacket( aPayload, aRequestSize ); |
|
258 } |
|
259 |
|
260 #endif |
|
261 |
|
262 __CN_GEN( "CMccCnGenerator::GenerateSidPacket, exit" ) |
|
263 } |
|
264 |
|
265 // ----------------------------------------------------------------------------- |
|
266 // CMccCnGenerator::GenerateAmrNoDataPacket |
|
267 // Generates a AMR SID packet |
|
268 // ----------------------------------------------------------------------------- |
|
269 // |
|
270 void CMccCnGenerator::GenerateAmrNoDataPacket( TDes8& aPayload ) const |
|
271 { |
|
272 __CN_GEN( "CMccCnGenerator::GenerateAmrNoDataPacket" ) |
|
273 |
|
274 if ( aPayload.MaxLength() >= KNoDataLength ) |
|
275 { |
|
276 aPayload.Copy( &KAmrNoDataFrame, KNoDataLength ); |
|
277 } |
|
278 }; |
|
279 |
|
280 // ----------------------------------------------------------------------------- |
|
281 // CMccCnGenerator::GenerateVoIPNoDataPacketL |
|
282 // Generates a VoIP NO_DATA packet |
|
283 // ----------------------------------------------------------------------------- |
|
284 // |
|
285 void CMccCnGenerator::GenerateVoIPNoDataPacket( TDes8& aPayload, |
|
286 TInt aRequestSize ) const |
|
287 { |
|
288 __CN_GEN( "CMccCnGenerator::GenerateVoIPNoDataPacket" ) |
|
289 |
|
290 aPayload.FillZ( aRequestSize ); |
|
291 |
|
292 if ( !iDtxPeriodStarted ) |
|
293 { |
|
294 ConcealErrorForNextFrame(); |
|
295 } |
|
296 }; |
|
297 |
|
298 // ----------------------------------------------------------------------------- |
|
299 // CMccCnGenerator::ConcealErrorForNextFrame |
|
300 // Conceals an error for next frame |
|
301 // ----------------------------------------------------------------------------- |
|
302 // |
|
303 void CMccCnGenerator::ConcealErrorForNextFrame() const |
|
304 { |
|
305 #ifdef MCC_CN_GEN_DISABLE_CONCEALMENT |
|
306 |
|
307 __CN_GEN( "CMccCnGenerator::ConcealErrorForNextFrame EMULATOR BUILD" ) |
|
308 |
|
309 #else |
|
310 |
|
311 // If EC instance is available, otherwise ignore silently |
|
312 if( iErrorConcealer ) |
|
313 { |
|
314 __CN_GEN( "CMccCnGenerator::ConcealErrorForNextFrame" ) |
|
315 |
|
316 // Ignore return code, just keep going |
|
317 iErrorConcealer->ConcealErrorForNextBuffer(); |
|
318 } |
|
319 |
|
320 #endif |
|
321 } |
|
322 |
|
323 // ----------------------------------------------------------------------------- |
|
324 // CMccCnGenerator::DoDtxDecision() |
|
325 // Do the DTX decision based on used codec and buffer data |
|
326 // ----------------------------------------------------------------------------- |
|
327 // |
|
328 void CMccCnGenerator::DoDtxDecision( const TDesC8& aData ) |
|
329 { |
|
330 if ( KMinDataLenForDtx < aData.Length() ) |
|
331 { |
|
332 if ( this->IsSidBuffer( aData ) ) |
|
333 { |
|
334 // DTX period started or updated |
|
335 __CN_GEN( "CMccCnGenerator::DoDtxDecision DTX_START" ) |
|
336 |
|
337 iDtxPeriodStarted = ETrue; |
|
338 iGeneratedCnFrames = 0; |
|
339 } |
|
340 else |
|
341 { |
|
342 // DTX period has ended |
|
343 iDtxPeriodStarted = EFalse; |
|
344 } |
|
345 } |
|
346 } |
|
347 |
|
348 // ----------------------------------------------------------------------------- |
|
349 // CMccCnGenerator::IsSidBufferL() |
|
350 // Is the given buffer a SID UPDATE buffer |
|
351 // ----------------------------------------------------------------------------- |
|
352 // |
|
353 TBool CMccCnGenerator::IsSidBuffer( const TDesC8& aData ) const |
|
354 { |
|
355 if ( iAudioType == KMccFourCCIdAMRNB ) |
|
356 { |
|
357 // Get AMR mode masking the bits in the first byte and shifting |
|
358 const TUint8 mode( ( aData[0] & KAmrModeMask ) >> KModeShiftBits ); |
|
359 if( KAmrSidMode == mode ) |
|
360 { |
|
361 __CN_GEN( "CMccCnGenerator::IsSidBufferL AMR-NB ETrue" ) |
|
362 return ETrue; |
|
363 } |
|
364 else |
|
365 { |
|
366 __CN_GEN( "CMccCnGenerator::IsSidBufferL AMR-NB EFalse" ) |
|
367 return EFalse; |
|
368 } |
|
369 } |
|
370 else if ( iAudioType == KMccFourCCIdAMRWB ) |
|
371 { |
|
372 // Get AMR mode masking the bits in the first byte and shifting |
|
373 const TUint8 mode( ( aData[0] & KAmrModeMask ) >> KModeShiftBits ); |
|
374 if( KAmrWbSidMode == mode ) |
|
375 { |
|
376 __CN_GEN( "CMccCnGenerator::IsSidBufferL AMR-WB ETrue" ) |
|
377 return ETrue; |
|
378 } |
|
379 else |
|
380 { |
|
381 __CN_GEN( "CMccCnGenerator::IsSidBufferL AMR-WB EFalse" ) |
|
382 return EFalse; |
|
383 } |
|
384 } |
|
385 else if( iAudioType == KMccFourCCIdG711 || iAudioType == KMccFourCCIdILBC |
|
386 || iAudioType == KMccFourCCIdG729 ) |
|
387 { |
|
388 // Check the frame type |
|
389 if ( KVoIPCNFrame == aData[0] ) |
|
390 { |
|
391 __CN_GEN( "CMccCnGenerator::IsSidBufferL VOIP ETrue" ) |
|
392 |
|
393 return ETrue; |
|
394 } |
|
395 else |
|
396 { |
|
397 __CN_GEN( "CMccCnGenerator::IsSidBufferL VOIP EFalse" ) |
|
398 |
|
399 return EFalse; |
|
400 } |
|
401 } |
|
402 else |
|
403 { |
|
404 __CN_GEN( "CMccCnGenerator::IsSidBufferL UNKNOWN" ) |
|
405 |
|
406 return EFalse; |
|
407 } |
|
408 } |
|
409 |
|
410 // End of File |