sl@0
|
1 |
// Copyright (c) 2003-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 "tonedatapath.h"
|
sl@0
|
17 |
|
sl@0
|
18 |
|
sl@0
|
19 |
CToneDataPath* CToneDataPath::NewL()
|
sl@0
|
20 |
{
|
sl@0
|
21 |
CToneDataPath* self = new(ELeave) CToneDataPath;
|
sl@0
|
22 |
CleanupStack::PushL(self);
|
sl@0
|
23 |
self->ConstructL();
|
sl@0
|
24 |
CleanupStack::Pop();
|
sl@0
|
25 |
return self;
|
sl@0
|
26 |
}
|
sl@0
|
27 |
|
sl@0
|
28 |
|
sl@0
|
29 |
void CToneDataPath::ConstructL()
|
sl@0
|
30 |
{
|
sl@0
|
31 |
iAudioPlayer = new (ELeave) CToneDataPathPlayer(*this,CActive::EPriorityUserInput);
|
sl@0
|
32 |
iSoundDeviceErrorReceiver = new (ELeave) CToneSoundDevPlayErrorReceiver(*this, CActive::EPriorityUserInput);
|
sl@0
|
33 |
}
|
sl@0
|
34 |
|
sl@0
|
35 |
|
sl@0
|
36 |
CToneDataPath::~CToneDataPath()
|
sl@0
|
37 |
{
|
sl@0
|
38 |
delete iAudioPlayer;
|
sl@0
|
39 |
delete iSoundDeviceErrorReceiver;
|
sl@0
|
40 |
|
sl@0
|
41 |
iSoundDevice.Close();
|
sl@0
|
42 |
|
sl@0
|
43 |
if (iCodec)
|
sl@0
|
44 |
{
|
sl@0
|
45 |
delete iSourceBuffer;
|
sl@0
|
46 |
if (!iCodec->IsNullCodec())
|
sl@0
|
47 |
{
|
sl@0
|
48 |
delete iSoundDeviceBuffer;
|
sl@0
|
49 |
}
|
sl@0
|
50 |
}
|
sl@0
|
51 |
|
sl@0
|
52 |
#ifdef __USE_MMF_TRANSFERBUFFERS__
|
sl@0
|
53 |
delete iTransferWindow;
|
sl@0
|
54 |
|
sl@0
|
55 |
if(iTransferBuffer)
|
sl@0
|
56 |
{
|
sl@0
|
57 |
iTransferBuffer->Close();
|
sl@0
|
58 |
delete iTransferBuffer;
|
sl@0
|
59 |
}
|
sl@0
|
60 |
#endif
|
sl@0
|
61 |
|
sl@0
|
62 |
#ifdef __USE_MMF_PTRBUFFERS__
|
sl@0
|
63 |
delete iPtrBufferMemoryBlock;
|
sl@0
|
64 |
#endif
|
sl@0
|
65 |
}
|
sl@0
|
66 |
|
sl@0
|
67 |
|
sl@0
|
68 |
TInt CToneDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
|
sl@0
|
69 |
{
|
sl@0
|
70 |
TInt error;
|
sl@0
|
71 |
if (iHwDeviceObserver)
|
sl@0
|
72 |
{
|
sl@0
|
73 |
error = KErrAlreadyExists;
|
sl@0
|
74 |
}
|
sl@0
|
75 |
else
|
sl@0
|
76 |
{
|
sl@0
|
77 |
iHwDeviceObserver = &aObserver;
|
sl@0
|
78 |
error = KErrNone;
|
sl@0
|
79 |
}
|
sl@0
|
80 |
return error;
|
sl@0
|
81 |
}
|
sl@0
|
82 |
|
sl@0
|
83 |
|
sl@0
|
84 |
TInt CToneDataPath::AddCodec(CToneCodec& aCodec)
|
sl@0
|
85 |
{
|
sl@0
|
86 |
if (iCodec)
|
sl@0
|
87 |
{
|
sl@0
|
88 |
return KErrNotSupported; //doesn't support multiple codecs
|
sl@0
|
89 |
}
|
sl@0
|
90 |
|
sl@0
|
91 |
TInt err = KErrNone;
|
sl@0
|
92 |
|
sl@0
|
93 |
iCodec = &aCodec;
|
sl@0
|
94 |
|
sl@0
|
95 |
// Allocate data buffer
|
sl@0
|
96 |
iSourceBufferSize = iCodec->SourceBufferSize();
|
sl@0
|
97 |
iSoundDevBufferSize = iCodec->SinkBufferSize();
|
sl@0
|
98 |
|
sl@0
|
99 |
if ((!iSourceBufferSize)||(!iSoundDevBufferSize))
|
sl@0
|
100 |
{
|
sl@0
|
101 |
err = KErrArgument; //codec plugin has not specified buffer size
|
sl@0
|
102 |
}
|
sl@0
|
103 |
|
sl@0
|
104 |
if (err == KErrNone)
|
sl@0
|
105 |
{
|
sl@0
|
106 |
#ifdef __USE_MMF_TRANSFERBUFFERS__
|
sl@0
|
107 |
TRAP(err,iSourceBuffer = CreateTransferBufferL(iSourceBufferSize, static_cast<CMMFTransferBuffer*>(iSourceBuffer)));
|
sl@0
|
108 |
#endif
|
sl@0
|
109 |
#ifdef __USE_MMF_PTRBUFFERS__
|
sl@0
|
110 |
TRAP(err,iSourceBuffer = CreatePtrBufferL(iSourceBufferSize));
|
sl@0
|
111 |
#else
|
sl@0
|
112 |
TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize));
|
sl@0
|
113 |
#endif
|
sl@0
|
114 |
}
|
sl@0
|
115 |
|
sl@0
|
116 |
if (err == KErrNone)
|
sl@0
|
117 |
{
|
sl@0
|
118 |
if (iCodec->IsNullCodec())
|
sl@0
|
119 |
{//use source buffer for sound device buffer
|
sl@0
|
120 |
iSoundDeviceBuffer = NULL;
|
sl@0
|
121 |
}
|
sl@0
|
122 |
else
|
sl@0
|
123 |
{//codec needs separate source and sound device buffers
|
sl@0
|
124 |
TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
|
sl@0
|
125 |
}
|
sl@0
|
126 |
}
|
sl@0
|
127 |
return err;
|
sl@0
|
128 |
}
|
sl@0
|
129 |
|
sl@0
|
130 |
TInt CToneDataPath::Start()
|
sl@0
|
131 |
{
|
sl@0
|
132 |
TInt startError = KErrNone;
|
sl@0
|
133 |
|
sl@0
|
134 |
if (!iCodec)
|
sl@0
|
135 |
{//check that a codec has been added
|
sl@0
|
136 |
startError = KErrNotReady;
|
sl@0
|
137 |
}
|
sl@0
|
138 |
if ((!iSoundDevice.Handle())&&(!startError))
|
sl@0
|
139 |
{//check that the sound drivers can be opened
|
sl@0
|
140 |
startError = iSoundDevice.Open();
|
sl@0
|
141 |
}
|
sl@0
|
142 |
|
sl@0
|
143 |
if (iState == EPaused)
|
sl@0
|
144 |
{//we are paused so need to resume play
|
sl@0
|
145 |
if (!startError)
|
sl@0
|
146 |
{
|
sl@0
|
147 |
#ifdef _SCW_DEBUG
|
sl@0
|
148 |
RDebug::Print(_L("CToneDataPath::Start-Resume"));
|
sl@0
|
149 |
#endif
|
sl@0
|
150 |
iAudioPlayer->ResumePlaying();
|
sl@0
|
151 |
iState = EPlaying;
|
sl@0
|
152 |
}
|
sl@0
|
153 |
}
|
sl@0
|
154 |
else if (!startError)
|
sl@0
|
155 |
{
|
sl@0
|
156 |
#ifdef _SCW_DEBUG
|
sl@0
|
157 |
RDebug::Print(_L("CToneDataPath::Start-Normal"));
|
sl@0
|
158 |
#endif
|
sl@0
|
159 |
// get sample rate and channels from RMdaDevSound
|
sl@0
|
160 |
RMdaDevSound::TCurrentSoundFormatBuf format;
|
sl@0
|
161 |
iSoundDevice.GetPlayFormat(format);
|
sl@0
|
162 |
iSampleRate = format().iRate;
|
sl@0
|
163 |
iChannels = format().iChannels;
|
sl@0
|
164 |
|
sl@0
|
165 |
iNoMoreSourceData = EFalse;
|
sl@0
|
166 |
iSourceBuffer->SetLastBuffer(EFalse);
|
sl@0
|
167 |
iState = EPlaying;
|
sl@0
|
168 |
iSoundDeviceErrorReceiver->Start();
|
sl@0
|
169 |
TRAP(startError,FillSourceBufferL()); //get initial buffer of audio data
|
sl@0
|
170 |
if (startError == KErrNone)
|
sl@0
|
171 |
{
|
sl@0
|
172 |
// Start the player objects
|
sl@0
|
173 |
iAudioPlayer->Start();
|
sl@0
|
174 |
}
|
sl@0
|
175 |
else
|
sl@0
|
176 |
{//failed to start up correctly go back to stopped state
|
sl@0
|
177 |
iState = EStopped;
|
sl@0
|
178 |
iSoundDeviceErrorReceiver->Stop();
|
sl@0
|
179 |
}
|
sl@0
|
180 |
}
|
sl@0
|
181 |
return startError;
|
sl@0
|
182 |
}
|
sl@0
|
183 |
|
sl@0
|
184 |
|
sl@0
|
185 |
// *** Main Play Loop ***
|
sl@0
|
186 |
|
sl@0
|
187 |
void CToneDataPath::FillSourceBufferL()
|
sl@0
|
188 |
{//asks observer to fill the source buffer
|
sl@0
|
189 |
// Ask immediately for data from the observer
|
sl@0
|
190 |
#ifdef __CYCLE_MMF_DATABUFFERS__
|
sl@0
|
191 |
// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
|
sl@0
|
192 |
// If the creation fails, we carry on regardless as the original buffer will not have been
|
sl@0
|
193 |
// destroyed. Must do this as alloc fail tests will not run.
|
sl@0
|
194 |
if(iSourceBuffer)
|
sl@0
|
195 |
{
|
sl@0
|
196 |
iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
|
sl@0
|
197 |
}
|
sl@0
|
198 |
#endif // __CYCLE_MMF_DATABUFFERS__
|
sl@0
|
199 |
User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer));
|
sl@0
|
200 |
|
sl@0
|
201 |
}
|
sl@0
|
202 |
|
sl@0
|
203 |
|
sl@0
|
204 |
void CToneDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
|
sl@0
|
205 |
{//call back from observer to indicate buffer has been filled
|
sl@0
|
206 |
|
sl@0
|
207 |
if (iState == EStopped)
|
sl@0
|
208 |
{
|
sl@0
|
209 |
User::Leave(KErrNotReady);//ok if paused?
|
sl@0
|
210 |
}
|
sl@0
|
211 |
|
sl@0
|
212 |
iSourceBuffer = &aBuffer;
|
sl@0
|
213 |
iSourceBuffer->SetStatus(EFull);
|
sl@0
|
214 |
#ifdef _SCW_DEBUG
|
sl@0
|
215 |
RDebug::Print(_L("CToneDataPath::BufferFilledL"));
|
sl@0
|
216 |
#endif
|
sl@0
|
217 |
|
sl@0
|
218 |
//need to check that the buffer size is not 0 - if so assume we've reached the end of the data
|
sl@0
|
219 |
iBuffSize = iSourceBuffer->BufferSize();
|
sl@0
|
220 |
if (!iBuffSize)
|
sl@0
|
221 |
{//no buffer - could be end of source or could be that the source has no data??
|
sl@0
|
222 |
iNoMoreSourceData = ETrue;
|
sl@0
|
223 |
#ifdef _SCW_DEBUG
|
sl@0
|
224 |
RDebug::Print(_L("CToneDataPath::BufferFilledL-NoMoreSourceData"));
|
sl@0
|
225 |
#endif
|
sl@0
|
226 |
}
|
sl@0
|
227 |
//even if the buffer size is 0 we still
|
sl@0
|
228 |
//need to perform the following to get the sound device callback
|
sl@0
|
229 |
FillSoundDeviceBufferL(); //get buffer in pcm16 format for sound device
|
sl@0
|
230 |
|
sl@0
|
231 |
iAudioPlayer->PlayData(*iSoundDeviceBuffer); //play data to sound drivers
|
sl@0
|
232 |
}
|
sl@0
|
233 |
|
sl@0
|
234 |
|
sl@0
|
235 |
void CToneDataPath::FillSoundDeviceBufferL()
|
sl@0
|
236 |
{//use CToneCodec to fill the sound device buffer
|
sl@0
|
237 |
|
sl@0
|
238 |
CToneCodec::TCodecProcessResult codecProcessResult;
|
sl@0
|
239 |
|
sl@0
|
240 |
if (iCodec->IsNullCodec())
|
sl@0
|
241 |
{//no codec so data can be sent direct to sink
|
sl@0
|
242 |
iSoundDeviceBuffer = iSourceBuffer;
|
sl@0
|
243 |
iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
|
sl@0
|
244 |
}
|
sl@0
|
245 |
else
|
sl@0
|
246 |
{
|
sl@0
|
247 |
//pass buffer to codec for processing
|
sl@0
|
248 |
codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSoundDeviceBuffer);
|
sl@0
|
249 |
|
sl@0
|
250 |
if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sound dev
|
sl@0
|
251 |
{
|
sl@0
|
252 |
iSoundDeviceBuffer->SetLastBuffer(ETrue);
|
sl@0
|
253 |
}
|
sl@0
|
254 |
if ((!iSoundDeviceBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
|
sl@0
|
255 |
{//the codec has added data but not set the buffer length
|
sl@0
|
256 |
iSoundDeviceBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
|
sl@0
|
257 |
}
|
sl@0
|
258 |
//only supports EProcessComplete
|
sl@0
|
259 |
switch (codecProcessResult.iCodecProcessStatus)
|
sl@0
|
260 |
{
|
sl@0
|
261 |
case CToneCodec::TCodecProcessResult::EProcessComplete:
|
sl@0
|
262 |
//finished procesing source data - all data in sink buffer
|
sl@0
|
263 |
{
|
sl@0
|
264 |
iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
|
sl@0
|
265 |
}
|
sl@0
|
266 |
break;
|
sl@0
|
267 |
#ifdef SYMBIAN_VARIABLE_BITRATE_CODEC
|
sl@0
|
268 |
case CToneCodec::TCodecProcessResult::EProcessIncomplete:
|
sl@0
|
269 |
//finished procesing source data - all data in sink buffer
|
sl@0
|
270 |
{
|
sl@0
|
271 |
iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
|
sl@0
|
272 |
}
|
sl@0
|
273 |
break;
|
sl@0
|
274 |
#endif
|
sl@0
|
275 |
case CToneCodec::TCodecProcessResult::EDstNotFilled:
|
sl@0
|
276 |
//could be the last buffer in which case dst might not get filled
|
sl@0
|
277 |
{
|
sl@0
|
278 |
iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
|
sl@0
|
279 |
}
|
sl@0
|
280 |
break;
|
sl@0
|
281 |
case CToneCodec::TCodecProcessResult::EEndOfData:
|
sl@0
|
282 |
//no more data - send what we've got to the sink
|
sl@0
|
283 |
//note we can't always rely on this - in many cases the codec will not know when
|
sl@0
|
284 |
//it has reached the end of data.
|
sl@0
|
285 |
{
|
sl@0
|
286 |
iSoundDeviceBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
|
sl@0
|
287 |
iNoMoreSourceData = ETrue;
|
sl@0
|
288 |
//doesn't matter if sink buffer is not full
|
sl@0
|
289 |
}
|
sl@0
|
290 |
break;
|
sl@0
|
291 |
default:
|
sl@0
|
292 |
//Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
|
sl@0
|
293 |
break;
|
sl@0
|
294 |
}
|
sl@0
|
295 |
}
|
sl@0
|
296 |
}
|
sl@0
|
297 |
|
sl@0
|
298 |
|
sl@0
|
299 |
void CToneDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
|
sl@0
|
300 |
{//call back from CToneDataPathPlayer when the sound device buffer has been emptied
|
sl@0
|
301 |
if (&aBuffer != iSoundDeviceBuffer)
|
sl@0
|
302 |
{
|
sl@0
|
303 |
Panic(EToneBadBuffer);
|
sl@0
|
304 |
}
|
sl@0
|
305 |
|
sl@0
|
306 |
if (!iNoMoreSourceData)
|
sl@0
|
307 |
{
|
sl@0
|
308 |
FillSourceBufferL();
|
sl@0
|
309 |
}
|
sl@0
|
310 |
}
|
sl@0
|
311 |
|
sl@0
|
312 |
//*** End of Main Play Loop ***
|
sl@0
|
313 |
|
sl@0
|
314 |
|
sl@0
|
315 |
void CToneDataPath::Stop()
|
sl@0
|
316 |
{
|
sl@0
|
317 |
iAudioPlayer->Cancel();
|
sl@0
|
318 |
iSoundDeviceErrorReceiver->Cancel();
|
sl@0
|
319 |
iSoundDevice.Close();
|
sl@0
|
320 |
|
sl@0
|
321 |
#ifdef __CYCLE_MMF_DATABUFFERS__
|
sl@0
|
322 |
// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
|
sl@0
|
323 |
// If the creation fails, we carry on regardless as the original buffer will not have been
|
sl@0
|
324 |
// destroyed. Must do this as alloc fail tests will not run.
|
sl@0
|
325 |
if(iSourceBuffer)
|
sl@0
|
326 |
{
|
sl@0
|
327 |
iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
|
sl@0
|
328 |
}
|
sl@0
|
329 |
#endif // __CYCLE_MMF_DATABUFFERS__
|
sl@0
|
330 |
|
sl@0
|
331 |
iState = EStopped;
|
sl@0
|
332 |
}
|
sl@0
|
333 |
|
sl@0
|
334 |
|
sl@0
|
335 |
void CToneDataPath::Pause()
|
sl@0
|
336 |
{
|
sl@0
|
337 |
//since a pause can happen anyway in the datatransfer -need to set to a known
|
sl@0
|
338 |
//state so that when play is resumed the behaviour is predictable
|
sl@0
|
339 |
if (iSoundDevice.Handle())
|
sl@0
|
340 |
{
|
sl@0
|
341 |
iSoundDevice.PausePlayBuffer(); //needs new LDD
|
sl@0
|
342 |
iState = EPaused;
|
sl@0
|
343 |
#ifdef _SCW_DEBUG
|
sl@0
|
344 |
RDebug::Print(_L("Pause"));
|
sl@0
|
345 |
#endif
|
sl@0
|
346 |
}
|
sl@0
|
347 |
else
|
sl@0
|
348 |
{//an error must have occured
|
sl@0
|
349 |
iState = EStopped;
|
sl@0
|
350 |
}
|
sl@0
|
351 |
}
|
sl@0
|
352 |
|
sl@0
|
353 |
|
sl@0
|
354 |
TInt CToneDataPath::EmptyBuffers()
|
sl@0
|
355 |
{
|
sl@0
|
356 |
TInt error = KErrNone;
|
sl@0
|
357 |
if (iSoundDevice.Handle() == 0)
|
sl@0
|
358 |
{
|
sl@0
|
359 |
error = KErrNotReady;
|
sl@0
|
360 |
}
|
sl@0
|
361 |
else
|
sl@0
|
362 |
{
|
sl@0
|
363 |
iSoundDevice.FlushPlayBuffer();
|
sl@0
|
364 |
}
|
sl@0
|
365 |
return error;
|
sl@0
|
366 |
}
|
sl@0
|
367 |
|
sl@0
|
368 |
|
sl@0
|
369 |
RMdaDevSound& CToneDataPath::Device()
|
sl@0
|
370 |
{
|
sl@0
|
371 |
return iSoundDevice;
|
sl@0
|
372 |
}
|
sl@0
|
373 |
|
sl@0
|
374 |
|
sl@0
|
375 |
void CToneDataPath::SoundDeviceException(TInt aError)
|
sl@0
|
376 |
{
|
sl@0
|
377 |
if(iIgnoreUnderflow)
|
sl@0
|
378 |
{
|
sl@0
|
379 |
if((aError == KErrUnderflow) && (!iNoMoreSourceData))
|
sl@0
|
380 |
{
|
sl@0
|
381 |
//ignore underflow
|
sl@0
|
382 |
return;
|
sl@0
|
383 |
}
|
sl@0
|
384 |
}
|
sl@0
|
385 |
|
sl@0
|
386 |
//this sends a request to the hw device observer
|
sl@0
|
387 |
//to update the bytes played
|
sl@0
|
388 |
//it is done here so that the sound driver can be closed prior to
|
sl@0
|
389 |
//updating the policy and sending the error back
|
sl@0
|
390 |
TUid uidUpdateBytesPlayed;
|
sl@0
|
391 |
uidUpdateBytesPlayed.iUid = KToneHwDeviceObserverUpdateBytesPlayed;
|
sl@0
|
392 |
TPtrC8 dummy(0,0);
|
sl@0
|
393 |
|
sl@0
|
394 |
ASSERT(iHwDeviceObserver);
|
sl@0
|
395 |
iHwDeviceObserver->MsgFromHwDevice(uidUpdateBytesPlayed,dummy);
|
sl@0
|
396 |
|
sl@0
|
397 |
//this closes RMdaDevSound.
|
sl@0
|
398 |
Stop();
|
sl@0
|
399 |
|
sl@0
|
400 |
//inform devsound so it can update policy
|
sl@0
|
401 |
iHwDeviceObserver->Stopped();
|
sl@0
|
402 |
|
sl@0
|
403 |
// Inform the observer of the exception condition
|
sl@0
|
404 |
// We inform the hw device observer after the policy has been
|
sl@0
|
405 |
// updated incase the observer relied on the error to assume
|
sl@0
|
406 |
// the policy has been updated
|
sl@0
|
407 |
iHwDeviceObserver->Error(aError);
|
sl@0
|
408 |
|
sl@0
|
409 |
RDebug::Print(_L("CToneDataPath::iHwDeviceObserver->Error(%d)"),aError);
|
sl@0
|
410 |
}
|
sl@0
|
411 |
|
sl@0
|
412 |
/**
|
sl@0
|
413 |
Retrieves a custom interface to the device.
|
sl@0
|
414 |
The reference CToneDataPath supports three custom interfaces,
|
sl@0
|
415 |
MEmptyBuffersCustomInterface, MSetVbrFlagCustomInterface and MIgnoreUnderflowEventsCustomInterface
|
sl@0
|
416 |
|
sl@0
|
417 |
@param aInterface
|
sl@0
|
418 |
Interface UID, defined with the custom interface.
|
sl@0
|
419 |
aInterface = KMmfUidEmptyBuffersCustomInterface for MEmptyBuffersCustomInterface,
|
sl@0
|
420 |
KSetVbrFlagCustomInterfaceTypeUid for MSetVbrFlagCustomInterface
|
sl@0
|
421 |
|
sl@0
|
422 |
@return A pointer to the interface implementation, or NULL if the device can not
|
sl@0
|
423 |
implement the interface requested. The return value must be cast to the
|
sl@0
|
424 |
correct type by the user.
|
sl@0
|
425 |
*/
|
sl@0
|
426 |
TAny* CToneDataPath::CustomInterface(TUid aInterface)
|
sl@0
|
427 |
{
|
sl@0
|
428 |
TAny* ret = NULL;
|
sl@0
|
429 |
|
sl@0
|
430 |
if (aInterface == KIgnoreUnderflowCustomInterfaceTypeUid)
|
sl@0
|
431 |
{
|
sl@0
|
432 |
MIgnoreUnderflowEventsCustomInterface* result = static_cast<MIgnoreUnderflowEventsCustomInterface*> (this);
|
sl@0
|
433 |
ret = static_cast<TAny*>(result);
|
sl@0
|
434 |
}
|
sl@0
|
435 |
return ret;
|
sl@0
|
436 |
}
|
sl@0
|
437 |
|
sl@0
|
438 |
|
sl@0
|
439 |
void CToneDataPath::IgnoreUnderflowEvents()
|
sl@0
|
440 |
{
|
sl@0
|
441 |
iIgnoreUnderflow = ETrue;
|
sl@0
|
442 |
}
|
sl@0
|
443 |
|
sl@0
|
444 |
|
sl@0
|
445 |
|
sl@0
|
446 |
/************************************************************************
|
sl@0
|
447 |
* CDataPathPlayer *
|
sl@0
|
448 |
************************************************************************/
|
sl@0
|
449 |
|
sl@0
|
450 |
CToneDataPathPlayer::CToneDataPathPlayer(CToneDataPath& aParent, TInt aPriority)
|
sl@0
|
451 |
: CActive(aPriority), iParent(aParent)
|
sl@0
|
452 |
{
|
sl@0
|
453 |
CActiveScheduler::Add(this);
|
sl@0
|
454 |
}
|
sl@0
|
455 |
|
sl@0
|
456 |
|
sl@0
|
457 |
CToneDataPathPlayer::~CToneDataPathPlayer()
|
sl@0
|
458 |
{
|
sl@0
|
459 |
Cancel();
|
sl@0
|
460 |
}
|
sl@0
|
461 |
|
sl@0
|
462 |
|
sl@0
|
463 |
void CToneDataPathPlayer::Start()
|
sl@0
|
464 |
{
|
sl@0
|
465 |
// No implementation
|
sl@0
|
466 |
}
|
sl@0
|
467 |
|
sl@0
|
468 |
|
sl@0
|
469 |
void CToneDataPathPlayer::ResumePlaying()
|
sl@0
|
470 |
{
|
sl@0
|
471 |
if (iParent.Device().Handle())
|
sl@0
|
472 |
{
|
sl@0
|
473 |
//should be ok to call this even if we are active
|
sl@0
|
474 |
iParent.Device().ResumePlaying();
|
sl@0
|
475 |
iResumePlaying = ETrue;
|
sl@0
|
476 |
}
|
sl@0
|
477 |
#ifdef _SCW_DEBUG
|
sl@0
|
478 |
RDebug::Print(_L("Playing Resumed"));
|
sl@0
|
479 |
#endif
|
sl@0
|
480 |
}
|
sl@0
|
481 |
|
sl@0
|
482 |
|
sl@0
|
483 |
void CToneDataPathPlayer::PlayData(const CMMFDataBuffer& aData)
|
sl@0
|
484 |
{
|
sl@0
|
485 |
iDataFromSource = &aData;
|
sl@0
|
486 |
if (!IsActive())
|
sl@0
|
487 |
{
|
sl@0
|
488 |
#ifdef _SCW_DEBUG
|
sl@0
|
489 |
RDebug::Print(_L("CToneDataPathPlayer::PlayData"));
|
sl@0
|
490 |
#endif
|
sl@0
|
491 |
iParent.Device().PlayData(iStatus,(static_cast<const CMMFDataBuffer*> (iDataFromSource))->Data());
|
sl@0
|
492 |
SetActive();
|
sl@0
|
493 |
}
|
sl@0
|
494 |
}
|
sl@0
|
495 |
|
sl@0
|
496 |
|
sl@0
|
497 |
void CToneDataPathPlayer::Stop()
|
sl@0
|
498 |
{
|
sl@0
|
499 |
if (!IsActive())
|
sl@0
|
500 |
{
|
sl@0
|
501 |
iParent.Device().FlushPlayBuffer(); // Otherwise won't be flushed
|
sl@0
|
502 |
}
|
sl@0
|
503 |
Cancel();
|
sl@0
|
504 |
iParent.SoundDeviceException(KErrCancel);
|
sl@0
|
505 |
}
|
sl@0
|
506 |
|
sl@0
|
507 |
|
sl@0
|
508 |
void CToneDataPathPlayer::RunL()
|
sl@0
|
509 |
{
|
sl@0
|
510 |
#ifdef _SCW_DEBUG
|
sl@0
|
511 |
RDebug::Print(_L("CToneDataPathPlayer::RunL error[%d]"), iStatus.Int());
|
sl@0
|
512 |
#endif
|
sl@0
|
513 |
if (iStatus.Int()!=KErrNone)
|
sl@0
|
514 |
{
|
sl@0
|
515 |
iParent.SoundDeviceException(iStatus.Int());
|
sl@0
|
516 |
}
|
sl@0
|
517 |
else
|
sl@0
|
518 |
{
|
sl@0
|
519 |
iParent.BufferEmptiedL(static_cast<const CMMFDataBuffer&>(*iDataFromSource));
|
sl@0
|
520 |
iResumePlaying = EFalse;
|
sl@0
|
521 |
}
|
sl@0
|
522 |
}
|
sl@0
|
523 |
|
sl@0
|
524 |
|
sl@0
|
525 |
TInt CToneDataPathPlayer::RunError(TInt aError)
|
sl@0
|
526 |
{
|
sl@0
|
527 |
Error(aError);
|
sl@0
|
528 |
return KErrNone;
|
sl@0
|
529 |
}
|
sl@0
|
530 |
|
sl@0
|
531 |
|
sl@0
|
532 |
void CToneDataPathPlayer::DoCancel()
|
sl@0
|
533 |
{
|
sl@0
|
534 |
if (iParent.Device().Handle())
|
sl@0
|
535 |
{
|
sl@0
|
536 |
iParent.Device().CancelPlayData();
|
sl@0
|
537 |
iParent.Device().FlushPlayBuffer();
|
sl@0
|
538 |
}
|
sl@0
|
539 |
}
|
sl@0
|
540 |
|
sl@0
|
541 |
|
sl@0
|
542 |
void CToneDataPathPlayer::Error(TInt aError)
|
sl@0
|
543 |
{
|
sl@0
|
544 |
iParent.SoundDeviceException(aError);
|
sl@0
|
545 |
}
|
sl@0
|
546 |
|
sl@0
|
547 |
|
sl@0
|
548 |
|
sl@0
|
549 |
/************************************************************************
|
sl@0
|
550 |
* CToneSoundDevPlayErrorReceiver *
|
sl@0
|
551 |
************************************************************************/
|
sl@0
|
552 |
|
sl@0
|
553 |
CToneSoundDevPlayErrorReceiver::CToneSoundDevPlayErrorReceiver(CToneDataPath& aParent, TInt aPriority)
|
sl@0
|
554 |
: CActive(aPriority), iParent(aParent)
|
sl@0
|
555 |
{
|
sl@0
|
556 |
CActiveScheduler::Add(this);
|
sl@0
|
557 |
}
|
sl@0
|
558 |
|
sl@0
|
559 |
CToneSoundDevPlayErrorReceiver::~CToneSoundDevPlayErrorReceiver()
|
sl@0
|
560 |
{
|
sl@0
|
561 |
Cancel();
|
sl@0
|
562 |
}
|
sl@0
|
563 |
|
sl@0
|
564 |
void CToneSoundDevPlayErrorReceiver::Start()
|
sl@0
|
565 |
{
|
sl@0
|
566 |
iParent.Device().NotifyPlayError(iStatus);
|
sl@0
|
567 |
SetActive();
|
sl@0
|
568 |
}
|
sl@0
|
569 |
|
sl@0
|
570 |
void CToneSoundDevPlayErrorReceiver::Stop()
|
sl@0
|
571 |
{
|
sl@0
|
572 |
Cancel();
|
sl@0
|
573 |
}
|
sl@0
|
574 |
|
sl@0
|
575 |
void CToneSoundDevPlayErrorReceiver::RunL()
|
sl@0
|
576 |
{
|
sl@0
|
577 |
TInt reason = iStatus.Int();
|
sl@0
|
578 |
Start();
|
sl@0
|
579 |
|
sl@0
|
580 |
// An error has been returned
|
sl@0
|
581 |
#ifdef _SCW_DEBUG
|
sl@0
|
582 |
RDebug::Print(_L("CToneSoundDevPlayErrorReceiver::RunL[%d]"), reason);
|
sl@0
|
583 |
#endif
|
sl@0
|
584 |
iParent.SoundDeviceException(reason);
|
sl@0
|
585 |
}
|
sl@0
|
586 |
|
sl@0
|
587 |
void CToneSoundDevPlayErrorReceiver::DoCancel()
|
sl@0
|
588 |
{
|
sl@0
|
589 |
iParent.Device().CancelNotifyPlayError();
|
sl@0
|
590 |
}
|
sl@0
|
591 |
|
sl@0
|
592 |
|
sl@0
|
593 |
|
sl@0
|
594 |
/*
|
sl@0
|
595 |
* CycleAudioBufferL
|
sl@0
|
596 |
*
|
sl@0
|
597 |
* Sets up a usable buffer for passing to MMF
|
sl@0
|
598 |
*
|
sl@0
|
599 |
* This method has been written such that it must allocate a new buffer before
|
sl@0
|
600 |
* replacing the existing one. The purpose of this is to force creation of a
|
sl@0
|
601 |
* new buffer. Simply deleting and then re-allocing may result in the same
|
sl@0
|
602 |
* address being used.
|
sl@0
|
603 |
*
|
sl@0
|
604 |
* Only cycles if there is enough memory
|
sl@0
|
605 |
*
|
sl@0
|
606 |
*/
|
sl@0
|
607 |
#ifdef __CYCLE_MMF_DATABUFFERS__
|
sl@0
|
608 |
CMMFDataBuffer* CToneDataPath::CycleAudioBuffer(CMMFDataBuffer* aBuffer)
|
sl@0
|
609 |
{
|
sl@0
|
610 |
CMMFDataBuffer* buffer = NULL;
|
sl@0
|
611 |
TUint bufferSize = aBuffer->Data().MaxLength();
|
sl@0
|
612 |
|
sl@0
|
613 |
#ifdef __USE_MMF_TRANSFERBUFFERS__
|
sl@0
|
614 |
TRAPD(err, buffer = CreateTransferBufferL(bufferSize, static_cast<CMMFTransferBuffer*>(aBuffer)));
|
sl@0
|
615 |
#else
|
sl@0
|
616 |
TRAPD(err,buffer = CMMFDataBuffer::NewL(bufferSize));
|
sl@0
|
617 |
|
sl@0
|
618 |
if (err == KErrNone)
|
sl@0
|
619 |
{
|
sl@0
|
620 |
delete aBuffer;
|
sl@0
|
621 |
}
|
sl@0
|
622 |
#endif
|
sl@0
|
623 |
if (err != KErrNone)
|
sl@0
|
624 |
{//there was a problem creating buffer eg OOM so use same buffer
|
sl@0
|
625 |
buffer = aBuffer;
|
sl@0
|
626 |
}
|
sl@0
|
627 |
|
sl@0
|
628 |
return buffer;
|
sl@0
|
629 |
|
sl@0
|
630 |
}
|
sl@0
|
631 |
#endif
|
sl@0
|
632 |
|
sl@0
|
633 |
/*
|
sl@0
|
634 |
* DoCleanupRHandleBase
|
sl@0
|
635 |
*
|
sl@0
|
636 |
* This method will initially Close the handle and then delete it.
|
sl@0
|
637 |
*
|
sl@0
|
638 |
*/
|
sl@0
|
639 |
#ifdef __USE_MMF_TRANSFERBUFFERS__
|
sl@0
|
640 |
inline static void DoCleanupRHandleBase(TAny* aRHandleBase)
|
sl@0
|
641 |
{
|
sl@0
|
642 |
ASSERT(aRHandleBase);
|
sl@0
|
643 |
RHandleBase* rHandleBase = static_cast<RHandleBase*> (aRHandleBase);
|
sl@0
|
644 |
TRAPD(error, rHandleBase->Close());
|
sl@0
|
645 |
delete aRHandleBase;
|
sl@0
|
646 |
}
|
sl@0
|
647 |
|
sl@0
|
648 |
CMMFTransferBuffer* CToneDataPath::CreateTransferBufferL(TUint aBufferSize, CMMFTransferBuffer* aOldBuffer)
|
sl@0
|
649 |
{
|
sl@0
|
650 |
CMMFTransferBuffer* buffer = NULL;
|
sl@0
|
651 |
|
sl@0
|
652 |
RTransferBuffer* transBuffer = new (ELeave) RTransferBuffer;
|
sl@0
|
653 |
|
sl@0
|
654 |
TCleanupItem bufferCleanupItem(DoCleanupRHandleBase, transBuffer); //closes and deletes.
|
sl@0
|
655 |
CleanupStack::PushL(bufferCleanupItem);
|
sl@0
|
656 |
|
sl@0
|
657 |
RTransferWindow* transWindow = new (ELeave) RTransferWindow;
|
sl@0
|
658 |
|
sl@0
|
659 |
TCleanupItem windowCleanupItem(DoCleanupRHandleBase, transWindow); //closes and deletes.
|
sl@0
|
660 |
CleanupStack::PushL(windowCleanupItem);
|
sl@0
|
661 |
|
sl@0
|
662 |
User::LeaveIfError(transBuffer->Create(aBufferSize));
|
sl@0
|
663 |
User::LeaveIfError(transWindow->Create(aBufferSize));
|
sl@0
|
664 |
User::LeaveIfError(transWindow->MapInBuffer(*transBuffer));
|
sl@0
|
665 |
|
sl@0
|
666 |
buffer = CMMFTransferBuffer::NewL(*transWindow);
|
sl@0
|
667 |
|
sl@0
|
668 |
delete aOldBuffer; //closes RTransferWindow
|
sl@0
|
669 |
delete iTransferWindow;
|
sl@0
|
670 |
|
sl@0
|
671 |
if(iTransferBuffer)
|
sl@0
|
672 |
{
|
sl@0
|
673 |
iTransferBuffer->Close();
|
sl@0
|
674 |
}
|
sl@0
|
675 |
delete iTransferBuffer;
|
sl@0
|
676 |
|
sl@0
|
677 |
iTransferBuffer = transBuffer;
|
sl@0
|
678 |
iTransferWindow = transWindow;
|
sl@0
|
679 |
|
sl@0
|
680 |
CleanupStack::Pop(transWindow);
|
sl@0
|
681 |
CleanupStack::Pop(transBuffer);
|
sl@0
|
682 |
|
sl@0
|
683 |
return buffer;
|
sl@0
|
684 |
}
|
sl@0
|
685 |
#endif
|
sl@0
|
686 |
|
sl@0
|
687 |
|
sl@0
|
688 |
#ifdef __USE_MMF_PTRBUFFERS__
|
sl@0
|
689 |
CMMFPtrBuffer* CToneDataPath::CreatePtrBufferL(TUint aBufferSize)
|
sl@0
|
690 |
{
|
sl@0
|
691 |
CMMFPtrBuffer* buffer = NULL;
|
sl@0
|
692 |
if (iPtrBufferMemoryBlock)
|
sl@0
|
693 |
{
|
sl@0
|
694 |
delete iPtrBufferMemoryBlock;//incase already exisits
|
sl@0
|
695 |
}
|
sl@0
|
696 |
iPtrBufferMemoryBlock = HBufC8::NewL(aBufferSize);
|
sl@0
|
697 |
TPtr8 ptrMemoryBlock(iPtrBufferMemoryBlock->Des());
|
sl@0
|
698 |
buffer = CMMFPtrBuffer::NewL(ptrMemoryBlock);
|
sl@0
|
699 |
return buffer;
|
sl@0
|
700 |
}
|
sl@0
|
701 |
#endif // __USE_MMF_PTRBUFFERS__
|
sl@0
|
702 |
|
sl@0
|
703 |
|
sl@0
|
704 |
|