Update contrib.
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // source\server\MmfBtSwCodecPlayDatapath.cpp
18 #include "mmfBtSwCodecPlayDataPath.h"
19 #include "mmfbtswcodecwrapper.h"
20 #include "mmfbtswcodecwrappercustominterfacesuids.hrh"
21 #include <mmfpaniccodes.h>
22 #include "mmfBtSwCodecUtility.h"
24 #include "MMFBtRoutingSoundDevice.h"
25 #include "A2dpBTHeadsetAudioIfClientServer.h" // for TRange (will be deprecated)
27 CMMFSwCodecPlayDataPath* CMMFSwCodecPlayDataPath::NewL( CRoutingSoundPlayDevice* aSoundDevice,
30 CMMFSwCodecPlayDataPath* self = new(ELeave) CMMFSwCodecPlayDataPath(aSoundDevice,
32 CleanupStack::PushL(self);
39 void CMMFSwCodecPlayDataPath::ConstructL()
41 iAudioPlayer = new (ELeave) CDataPathPlayer(*this,CActive::EPriorityUserInput);
42 iSoundDeviceErrorReceiver = new (ELeave) CSoundDevPlayErrorReceiver(*this, CActive::EPriorityUserInput);
43 iUtility = CMMFSwCodecUtility::NewL();
47 CMMFSwCodecPlayDataPath::~CMMFSwCodecPlayDataPath()
50 delete iSoundDeviceErrorReceiver;
53 TRequestStatus status;
54 iSoundDevice->CloseDevice(iDeviceUid, status);
55 //TODO there should be a timeout for the line below
56 User::WaitForRequest(status);
61 if (!iCodec->IsNullCodec())
63 delete iSoundDeviceBuffer;
67 #ifdef __USE_MMF_TRANSFERBUFFERS__
68 delete iTransferWindow;
72 iTransferBuffer->Close();
73 delete iTransferBuffer;
77 #ifdef __USE_MMF_PTRBUFFERS__
78 delete iPtrBufferMemoryBlock;
83 TInt CMMFSwCodecPlayDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
86 if (iHwDeviceObserver)
88 error = KErrAlreadyExists;
92 iHwDeviceObserver = &aObserver;
99 TInt CMMFSwCodecPlayDataPath::AddCodec(CMMFSwCodec& aCodec)
103 return KErrNotSupported; //doesn't support multiple codecs
110 // Allocate data buffer
111 iSourceBufferSize = iCodec->SourceBufferSize();
112 iSoundDevBufferSize = iCodec->SinkBufferSize();
114 if ((!iSourceBufferSize) || (!iSoundDevBufferSize))
116 err = KErrArgument; //codec plugin has not specified buffer size
121 #ifdef __USE_MMF_TRANSFERBUFFERS__
122 TRAP(err,iSourceBuffer = CreateTransferBufferL(iSourceBufferSize, static_cast<CMMFTransferBuffer*>(iSourceBuffer)));
124 #ifdef __USE_MMF_PTRBUFFERS__
125 TRAP(err,iSourceBuffer = CreatePtrBufferL(iSourceBufferSize));
127 TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize));
133 if (iCodec->IsNullCodec())
134 {//use source buffer for sound device buffer
135 iSoundDeviceBuffer = NULL;
138 {//codec needs separate source and sound device buffers
139 TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
146 TInt CMMFSwCodecPlayDataPath::Start()
148 TInt startError = KErrNone;
150 if (!iCodec || (!iSoundDevice->Handle()))
152 //check that a codec has been added and the sound device is open
153 startError = KErrNotReady;
156 if (iState == EPaused)
157 {//we are paused so need to resume play
161 RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Resume"));
163 iAudioPlayer->ResumePlaying();
167 else if (!startError)
170 RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Normal"));
174 iNoMoreSourceData = EFalse;
175 iSourceBuffer->SetLastBuffer(EFalse);
177 iSoundDeviceErrorReceiver->Start();
178 TRAP(startError, FillSourceBufferL()); //get initial buffer of audio data
179 if (startError == KErrNone)
181 // Start the player objects
182 iAudioPlayer->Start();
185 {//failed to start up correctly go back to stopped state
187 iSoundDeviceErrorReceiver->Stop();
195 // *** Main Play Loop ***
197 void CMMFSwCodecPlayDataPath::FillSourceBufferL()
198 {//asks observer to fill the source buffer
199 // Ask immediately for data from the observer
200 #ifdef __CYCLE_MMF_DATABUFFERS__
201 // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
202 // If the creation fails, we carry on regardless as the original buffer will not have been
203 // destroyed. Must do this as alloc fail tests will not run.
206 iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
208 #endif // __CYCLE_MMF_DATABUFFERS__
209 User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer));
214 void CMMFSwCodecPlayDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
215 {//call back from observer to indicate buffer has been filled
216 if (iState == EStopped)
217 User::Leave(KErrNotReady);//ok if paused?
219 iSourceBuffer = &aBuffer;
220 iSourceBuffer->SetStatus(EFull);
222 RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL"));
225 //need to check that the buffer size is not 0 - if so assume we've reached the end of the data
226 if (!iSourceBuffer->BufferSize())
227 {//no buffer - could be end of source or could be that the source has no data??
228 iNoMoreSourceData = ETrue;
230 RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-NoMoreSourceData"));
233 //even if the buffer size is 0 we still
234 //need to perform the following to get the sound device callback
235 FillSoundDeviceBufferL(); //get buffer in pcm16 format for sound device
237 // attenuate the amplitude of the samples if volume ramping has been changed
239 if (iCustomInterface)
241 TTimeIntervalMicroSeconds volumeRamp = iCustomInterface->VolumeRamp();
242 if (volumeRamp != iVolumeRamp)
244 iVolumeRamp = volumeRamp;
245 if (iVolumeRamp.Int64() != 0)
247 iUtility->ConfigAudioRamper(
251 iRampAudioSample = ETrue;
255 iRampAudioSample = EFalse;
258 if (iRampAudioSample)
260 iRampAudioSample = iUtility->RampAudio(iSoundDeviceBuffer);
264 iAudioPlayer->PlayData(*iSoundDeviceBuffer); //play data to sound drivers
266 if (iSourceBuffer->LastBuffer())//check last buffer flag
268 iNoMoreSourceData = ETrue;
270 RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-LBNoMoreSourceData"));
276 void CMMFSwCodecPlayDataPath::FillSoundDeviceBufferL()
277 {//use CMMFSwCodec to fill the sound device buffer
279 CMMFSwCodec::TCodecProcessResult codecProcessResult;
281 if (iCodec->IsNullCodec())
282 {//no codec so data can be sent direct to sink
283 iSoundDeviceBuffer = iSourceBuffer;
284 iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
288 //pass buffer to codec for processing
289 codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSoundDeviceBuffer);
290 if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sound dev
291 iSoundDeviceBuffer->SetLastBuffer(ETrue);
292 if ((!iSoundDeviceBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
293 {//the codec has added data but not set the buffer length
294 iSoundDeviceBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
296 //only supports EProcessComplete
297 switch (codecProcessResult.iCodecProcessStatus)
299 case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
300 //finished procesing source data - all data in sink buffer
302 iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
305 case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
306 //could be the last buffer in which case dst might not get filled
308 iSoundDeviceBuffer->SetStatus(EFull); //sink buffer is full
311 case CMMFSwCodec::TCodecProcessResult::EEndOfData:
312 //no more data - send what we've got to the sink
313 //note we can't always rely on this - in many cases the codec will not know when
314 //it has reached the end of data.
316 iSoundDeviceBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
317 iNoMoreSourceData = ETrue;
318 //doesn't matter if sink buffer is not full
322 Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
328 void CMMFSwCodecPlayDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
329 {//call back from CDataPathPlayer when the sound device buffer has been emptied
330 if (&aBuffer != iSoundDeviceBuffer)
331 Panic(EMMFSwCodecWrapperBadBuffer);
332 if (!iNoMoreSourceData)
336 //*** End of Main Play Loop ***
339 void CMMFSwCodecPlayDataPath::Stop()
341 iAudioPlayer->Cancel();
342 iSoundDeviceErrorReceiver->Cancel();
343 TRequestStatus status;
344 iSoundDevice->CloseDevice(iDeviceUid, status);
345 User::WaitForRequest(status);
347 #ifdef __CYCLE_MMF_DATABUFFERS__
348 // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
349 // If the creation fails, we carry on regardless as the original buffer will not have been
350 // destroyed. Must do this as alloc fail tests will not run.
353 iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
355 #endif // __CYCLE_MMF_DATABUFFERS__
361 void CMMFSwCodecPlayDataPath::Pause()
363 //since a pause can happen anyway in the datatransfer -need to set to a known
364 //state so that when play is resumed the behaviour is predictable
365 if (iSoundDevice->Handle())
367 iSoundDevice->PauseBuffer(); // ignores return value?
370 RDebug::Print(_L("Pause"));
374 {//an error must have occured
380 CRoutingSoundPlayDevice* CMMFSwCodecPlayDataPath::Device()
385 void CMMFSwCodecPlayDataPath::SoundDeviceException(TInt aError)
387 //this sends a request to the hw device observer usually Devsound
388 //to update the bytes played
389 //it is done here so that the sound driver can be closed prior to
390 //updating the plicy and sending the error back
391 TUid uidUpdateBytesPlayed;
392 uidUpdateBytesPlayed.iUid = KMmfHwDeviceObserverUpdateBytesPlayed;
394 iHwDeviceObserver->MsgFromHwDevice(uidUpdateBytesPlayed,dummy);
396 //this closes RMdaDevSound.
399 //inform devsound so it can update policy
400 iHwDeviceObserver->Stopped();
402 // Inform the observer of the exception condition
403 // We inform the hw device observer after the policy has been
404 // updated incase the observer relied on the error to assume
405 // the policy has been updated
406 iHwDeviceObserver->Error(aError);
410 void CMMFSwCodecPlayDataPath::SetPlayCustomInterface(MPlayCustomInterface& aCustomInterface)
412 iCustomInterface = &aCustomInterface;
415 void CMMFSwCodecPlayDataPath::SetConfigForAudioRamp(TUint aSampleRate, TUint aChannels)
417 iSampleRate = aSampleRate;
418 iChannels = aChannels;
421 /************************************************************************
423 ************************************************************************/
425 CDataPathPlayer::CDataPathPlayer(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
426 : CActive(aPriority), iParent(aParent)
428 CActiveScheduler::Add(this);
432 CDataPathPlayer::~CDataPathPlayer()
438 void CDataPathPlayer::Start()
444 void CDataPathPlayer::ResumePlaying()
446 if (iParent.Device()->Handle())
448 //should be ok to call this even if we are active
449 iParent.Device()->ResumePlaying();
450 iResumePlaying = ETrue;
453 RDebug::Print(_L("Playing Resumed"));
458 void CDataPathPlayer::PlayData(const CMMFDataBuffer& aData)
460 iDataFromSource = &aData;
464 RDebug::Print(_L("CDataPathPlayer::PlayData"));
466 iParent.Device()->PlayData(aData.Data(), iStatus);
472 void CDataPathPlayer::Stop()
476 iParent.Device()->FlushBuffer();
479 iParent.SoundDeviceException(KErrCancel);
483 void CDataPathPlayer::RunL()
486 RDebug::Print(_L("CDataPathPlayer::RunL error[%d]"), iStatus.Int());
490 iParent.BufferEmptiedL(static_cast<const CMMFDataBuffer&>(*iDataFromSource));
491 iResumePlaying = EFalse;
493 //if we don't have a sound driver handle then we have stopped
494 //but the client still thinks we are recording so swallow error
495 else if (iStatus.Int()!= KErrBadHandle)
497 iParent.SoundDeviceException(iStatus.Int());
502 TInt CDataPathPlayer::RunError(TInt aError)
509 void CDataPathPlayer::DoCancel()
511 if (iParent.Device()->Handle())
513 iParent.Device()->CancelPlayData();
514 iParent.Device()->FlushBuffer();
519 void CDataPathPlayer::Error(TInt aError)
521 iParent.SoundDeviceException(aError);
525 /************************************************************************
526 * CSoundDevPlayErrorReceiver *
527 ************************************************************************/
529 CSoundDevPlayErrorReceiver::CSoundDevPlayErrorReceiver(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
530 : CActive(aPriority), iParent(aParent)
532 CActiveScheduler::Add(this);
535 CSoundDevPlayErrorReceiver::~CSoundDevPlayErrorReceiver()
540 void CSoundDevPlayErrorReceiver::Start()
542 iParent.Device()->NotifyError(iStatus);
546 void CSoundDevPlayErrorReceiver::Stop()
551 void CSoundDevPlayErrorReceiver::RunL()
553 // An error has been returned
555 RDebug::Print(_L("CSoundDevPlayErrorReceiver::RunL[%d]"), iStatus.Int());
557 iParent.SoundDeviceException(iStatus.Int());
560 void CSoundDevPlayErrorReceiver::DoCancel()
562 iParent.Device()->CancelNotifyError();