sl@0
|
1 |
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
//
|
sl@0
|
15 |
|
sl@0
|
16 |
#include "MmfBtAudioCodec.h"
|
sl@0
|
17 |
#include <mmfpaniccodes.h>
|
sl@0
|
18 |
#include "MmfBtImaAdpcmToPcm16HwDevice.h"
|
sl@0
|
19 |
#include "../../MmfBtFileDependencyUtil.h"
|
sl@0
|
20 |
|
sl@0
|
21 |
/**
|
sl@0
|
22 |
*
|
sl@0
|
23 |
* NewL
|
sl@0
|
24 |
*
|
sl@0
|
25 |
*/
|
sl@0
|
26 |
CMMFImaAdpcmToPcm16CodecHwDevice* CMMFImaAdpcmToPcm16CodecHwDevice::NewL()
|
sl@0
|
27 |
{
|
sl@0
|
28 |
CMMFImaAdpcmToPcm16CodecHwDevice* self=new(ELeave)CMMFImaAdpcmToPcm16CodecHwDevice();
|
sl@0
|
29 |
CleanupStack::PushL(self);
|
sl@0
|
30 |
self->ConstructL();
|
sl@0
|
31 |
CleanupStack::Pop(self);
|
sl@0
|
32 |
return self;
|
sl@0
|
33 |
}
|
sl@0
|
34 |
|
sl@0
|
35 |
/**
|
sl@0
|
36 |
*
|
sl@0
|
37 |
* ConstructL
|
sl@0
|
38 |
*
|
sl@0
|
39 |
*/
|
sl@0
|
40 |
void CMMFImaAdpcmToPcm16CodecHwDevice::ConstructL()
|
sl@0
|
41 |
{
|
sl@0
|
42 |
iCodec = new (ELeave) CMMFImaAdpcmToPcm16Codec();
|
sl@0
|
43 |
}
|
sl@0
|
44 |
|
sl@0
|
45 |
/**
|
sl@0
|
46 |
*
|
sl@0
|
47 |
* ~CMMFMulawPcm16HwDevice
|
sl@0
|
48 |
*
|
sl@0
|
49 |
*/
|
sl@0
|
50 |
CMMFImaAdpcmToPcm16CodecHwDevice::~CMMFImaAdpcmToPcm16CodecHwDevice()
|
sl@0
|
51 |
{
|
sl@0
|
52 |
}
|
sl@0
|
53 |
|
sl@0
|
54 |
/**
|
sl@0
|
55 |
*
|
sl@0
|
56 |
* Codec
|
sl@0
|
57 |
*
|
sl@0
|
58 |
*/
|
sl@0
|
59 |
CMMFSwCodec &CMMFImaAdpcmToPcm16CodecHwDevice::Codec()
|
sl@0
|
60 |
{
|
sl@0
|
61 |
return *iCodec;
|
sl@0
|
62 |
}
|
sl@0
|
63 |
|
sl@0
|
64 |
/**
|
sl@0
|
65 |
@see CMMFSwCodecWrapper::Start
|
sl@0
|
66 |
|
sl@0
|
67 |
this function sets SampleRate and Channels for CMMFImaAdpcmToPcm16Codec
|
sl@0
|
68 |
*/
|
sl@0
|
69 |
TInt CMMFImaAdpcmToPcm16CodecHwDevice::Start(TDeviceFunc aFuncCmd, TDeviceFlow aFlowCmd)
|
sl@0
|
70 |
{
|
sl@0
|
71 |
TInt err = CMMFSwCodecWrapper::Start(aFuncCmd, aFlowCmd);
|
sl@0
|
72 |
if (err != 0)
|
sl@0
|
73 |
return err;
|
sl@0
|
74 |
return ((CMMFImaAdpcmToPcm16Codec*)iCodec)->Configure(iChannels, iSampleRate);
|
sl@0
|
75 |
}
|
sl@0
|
76 |
|
sl@0
|
77 |
CMMFImaAdpcmToPcm16Codec::CMMFImaAdpcmToPcm16Codec()
|
sl@0
|
78 |
{
|
sl@0
|
79 |
iChannels = 1;
|
sl@0
|
80 |
iSampleRate = 0;
|
sl@0
|
81 |
iBlockAlign = KImaAdpcmBlockAlign;
|
sl@0
|
82 |
iSamplesPerBlock = KImaAdpcmSamplesPerBlock;
|
sl@0
|
83 |
}
|
sl@0
|
84 |
/**
|
sl@0
|
85 |
*
|
sl@0
|
86 |
* ProcessL
|
sl@0
|
87 |
* @param aSrc
|
sl@0
|
88 |
* @param aDst
|
sl@0
|
89 |
* @pre position of buffer aSrc is 0
|
sl@0
|
90 |
* @pre position of buffer aDst is 0
|
sl@0
|
91 |
* @pre sufficient bytes in output to consume input
|
sl@0
|
92 |
* @return TCodecProcessResult
|
sl@0
|
93 |
* This function converts IMA ADPCM samples to PCM samples.
|
sl@0
|
94 |
*
|
sl@0
|
95 |
*/
|
sl@0
|
96 |
CMMFSwCodec::TCodecProcessResult CMMFImaAdpcmToPcm16Codec::ProcessL(const CMMFBuffer& aSrc, CMMFBuffer& aDst)
|
sl@0
|
97 |
{
|
sl@0
|
98 |
CMMFSwCodec::TCodecProcessResult result;
|
sl@0
|
99 |
result.iCodecProcessStatus = result.iCodecProcessStatus = TCodecProcessResult::EProcessComplete;
|
sl@0
|
100 |
|
sl@0
|
101 |
//convert from generic CMMFBuffer to CMMFDataBuffer
|
sl@0
|
102 |
const CMMFDataBuffer* src = STATIC_CAST(const CMMFDataBuffer*, &aSrc);
|
sl@0
|
103 |
CMMFDataBuffer* dst = STATIC_CAST(CMMFDataBuffer*, &aDst);
|
sl@0
|
104 |
|
sl@0
|
105 |
if( !CheckPreconditions( src, dst ) )
|
sl@0
|
106 |
{
|
sl@0
|
107 |
//[ precondition(s) violation ]
|
sl@0
|
108 |
User::Leave(KErrArgument);
|
sl@0
|
109 |
}
|
sl@0
|
110 |
|
sl@0
|
111 |
//calculate how much source is required to fill the destination buffer
|
sl@0
|
112 |
TUint blocksRemaining = src->Data().Length() / iBlockAlign;
|
sl@0
|
113 |
|
sl@0
|
114 |
//we need to cast away CONST even on the source, as the TClass needs a TUint8*
|
sl@0
|
115 |
TUint8* pSrc = CONST_CAST(TUint8*,src->Data().Ptr());
|
sl@0
|
116 |
TUint8* pDst = CONST_CAST(TUint8*,dst->Data().Ptr());
|
sl@0
|
117 |
|
sl@0
|
118 |
//[ [process full blocks ]
|
sl@0
|
119 |
TUint dstBytesAdded = 0;
|
sl@0
|
120 |
for( TUint count = 0; count < blocksRemaining; count++ )
|
sl@0
|
121 |
{
|
sl@0
|
122 |
iImaAdpcmTo16Pcm.Convert(pSrc, pDst, iSamplesPerBlock);
|
sl@0
|
123 |
pSrc += iBlockAlign;
|
sl@0
|
124 |
pDst += (iSamplesPerBlock * sizeof(TInt16));
|
sl@0
|
125 |
dstBytesAdded += (iSamplesPerBlock * sizeof(TInt16));
|
sl@0
|
126 |
}
|
sl@0
|
127 |
|
sl@0
|
128 |
result.iCodecProcessStatus = TCodecProcessResult::EProcessComplete;
|
sl@0
|
129 |
result.iSrcBytesProcessed = blocksRemaining * iBlockAlign;
|
sl@0
|
130 |
result.iDstBytesAdded = dstBytesAdded;
|
sl@0
|
131 |
dst->Data().SetLength(result.iDstBytesAdded);
|
sl@0
|
132 |
|
sl@0
|
133 |
//[ check post conditions
|
sl@0
|
134 |
__ASSERT_DEBUG( (src->Position() == 0), TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation ));
|
sl@0
|
135 |
__ASSERT_DEBUG( (dst->Position() == 0), TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation ));
|
sl@0
|
136 |
TInt r1 = src->Data().Length();
|
sl@0
|
137 |
r1 /= iBlockAlign;
|
sl@0
|
138 |
TInt r2 = dst->Data().Length();
|
sl@0
|
139 |
r2 /=(iSamplesPerBlock * sizeof(TInt16));
|
sl@0
|
140 |
__ASSERT_DEBUG( r1== r2, TMmfAudioCodecPanicsNameSpace::Panic(TMmfAudioCodecPanicsNameSpace::EPostConditionViolation ));
|
sl@0
|
141 |
__ASSERT_DEBUG( dst->Data().Length() % 2 == 0, TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation )); // pcm output
|
sl@0
|
142 |
|
sl@0
|
143 |
return result;
|
sl@0
|
144 |
}
|
sl@0
|
145 |
|
sl@0
|
146 |
/**
|
sl@0
|
147 |
*
|
sl@0
|
148 |
* Preconditions
|
sl@0
|
149 |
* This methos tests the preconditions of the ProcessL method
|
sl@0
|
150 |
* @return TBool ETrue for sucess and EFalse for failure of the preconditions
|
sl@0
|
151 |
*
|
sl@0
|
152 |
**/
|
sl@0
|
153 |
TBool CMMFImaAdpcmToPcm16Codec::CheckPreconditions( const CMMFDataBuffer* aSrcBuffer, CMMFDataBuffer* aDestBuffer )
|
sl@0
|
154 |
{
|
sl@0
|
155 |
TBool result = EFalse;
|
sl@0
|
156 |
|
sl@0
|
157 |
if(! aSrcBuffer )
|
sl@0
|
158 |
{
|
sl@0
|
159 |
return result;
|
sl@0
|
160 |
}
|
sl@0
|
161 |
|
sl@0
|
162 |
if( ! aDestBuffer )
|
sl@0
|
163 |
{
|
sl@0
|
164 |
return result;
|
sl@0
|
165 |
}
|
sl@0
|
166 |
|
sl@0
|
167 |
// Check position of src and dest are 0
|
sl@0
|
168 |
if( aSrcBuffer->Position() )
|
sl@0
|
169 |
{
|
sl@0
|
170 |
return result;
|
sl@0
|
171 |
}
|
sl@0
|
172 |
|
sl@0
|
173 |
// Check position of src and dest are 0
|
sl@0
|
174 |
if( aDestBuffer->Position() )
|
sl@0
|
175 |
{
|
sl@0
|
176 |
return result;
|
sl@0
|
177 |
}
|
sl@0
|
178 |
|
sl@0
|
179 |
// check there are sufficient bytes in the output to consume the input
|
sl@0
|
180 |
const TUint KTempBufferSize = iSamplesPerBlock * 2;
|
sl@0
|
181 |
TInt numInputSubFrames = aSrcBuffer->Data().Length() / iBlockAlign;
|
sl@0
|
182 |
TInt numOutputSubFrames = aDestBuffer->Data().MaxLength() / KTempBufferSize;
|
sl@0
|
183 |
|
sl@0
|
184 |
//[ we need modulo 1010 bytes on all src frames that are not the last
|
sl@0
|
185 |
// frame
|
sl@0
|
186 |
// For the last frame we will code only whole frames and effectively
|
sl@0
|
187 |
// drop any remaining samples]
|
sl@0
|
188 |
TBool validInputDataLength = (aSrcBuffer->Data().Length() % iBlockAlign == 0) ;
|
sl@0
|
189 |
|
sl@0
|
190 |
if( (numInputSubFrames > numOutputSubFrames) || // sufficient space in the output for the input
|
sl@0
|
191 |
(aSrcBuffer->Position() > 0 ) || // position must be zero since we can eat all the data
|
sl@0
|
192 |
(aDestBuffer->Position() > 0 ) ||
|
sl@0
|
193 |
(!validInputDataLength)) //position must be zero
|
sl@0
|
194 |
{
|
sl@0
|
195 |
return result;
|
sl@0
|
196 |
}
|
sl@0
|
197 |
|
sl@0
|
198 |
result = ETrue; // preconditions have been satisfied
|
sl@0
|
199 |
|
sl@0
|
200 |
return result;
|
sl@0
|
201 |
}
|
sl@0
|
202 |
|
sl@0
|
203 |
TInt CMMFImaAdpcmToPcm16Codec::Configure(TUint aChannels, TUint aSampleRate)
|
sl@0
|
204 |
{
|
sl@0
|
205 |
iChannels = aChannels;
|
sl@0
|
206 |
iSampleRate = aSampleRate;
|
sl@0
|
207 |
|
sl@0
|
208 |
switch (iSampleRate * iChannels)
|
sl@0
|
209 |
{
|
sl@0
|
210 |
case 8000: // fall through, same as 11025
|
sl@0
|
211 |
case 11025:
|
sl@0
|
212 |
case 16000:
|
sl@0
|
213 |
iBlockAlign = 256;
|
sl@0
|
214 |
break;
|
sl@0
|
215 |
case 22050:
|
sl@0
|
216 |
iBlockAlign = 512;
|
sl@0
|
217 |
break;
|
sl@0
|
218 |
|
sl@0
|
219 |
case 44100:
|
sl@0
|
220 |
iBlockAlign = 1024;
|
sl@0
|
221 |
break;
|
sl@0
|
222 |
|
sl@0
|
223 |
case 88200:
|
sl@0
|
224 |
iBlockAlign = 2048;
|
sl@0
|
225 |
break;
|
sl@0
|
226 |
|
sl@0
|
227 |
default:
|
sl@0
|
228 |
return KErrArgument;
|
sl@0
|
229 |
}
|
sl@0
|
230 |
|
sl@0
|
231 |
const TUint KImaAdpcmBitsPerSample = 4;
|
sl@0
|
232 |
// SamplesPerBlock = [(BlockAlign - 4 * Channels) * 8] / (BitsPerSample * Channels) + 1
|
sl@0
|
233 |
iSamplesPerBlock = (iBlockAlign - 4 * iChannels) * 8 / (KImaAdpcmBitsPerSample * iChannels) + 1;
|
sl@0
|
234 |
|
sl@0
|
235 |
return KErrNone;
|
sl@0
|
236 |
}
|
sl@0
|
237 |
|
sl@0
|
238 |
|
sl@0
|
239 |
|