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\MmfBtSwCodecRecordDatapath.cpp
18 #include "mmfBtSwCodecRecordDataPath.h"
19 #include "mmfbtswcodecwrapper.h"
20 #include <mmfpaniccodes.h>
21 #include "MMFBtRoutingSoundDevice.h"
24 CMMFSwCodecRecordDataPath* CMMFSwCodecRecordDataPath::NewL(CRoutingSoundRecordDevice* aSoundDevice)
26 CMMFSwCodecRecordDataPath* self = new(ELeave) CMMFSwCodecRecordDataPath(aSoundDevice);
27 CleanupStack::PushL(self);
34 void CMMFSwCodecRecordDataPath::ConstructL()
36 iAudioRecorder = new (ELeave) CDataPathRecorder(*this,CActive::EPriorityUserInput);
37 iSoundDeviceErrorReceiver = new (ELeave) CSoundDevRecordErrorReceiver(*this, CActive::EPriorityUserInput);
41 CMMFSwCodecRecordDataPath::~CMMFSwCodecRecordDataPath()
43 delete iAudioRecorder;
44 delete iSoundDeviceErrorReceiver;
46 TRequestStatus status;
47 iSoundDevice->CloseDevice(iDeviceUid, status);
48 //TODO there should be a timeout for the line below
49 User::WaitForRequest(status);
53 delete iSoundDeviceBuffer;
54 if (!iCodec->IsNullCodec())
61 #ifdef __USE_MMF_TRANSFERBUFFERS__
62 delete iTransferWindow;
66 iTransferBuffer->Close();
67 delete iTransferBuffer;
71 #ifdef __USE_MMF_PTRBUFFERS__
72 delete iPtrBufferMemoryBlock;
78 TInt CMMFSwCodecRecordDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
81 if (iHwDeviceObserver)
83 error = KErrAlreadyExists;
87 iHwDeviceObserver = &aObserver;
94 TInt CMMFSwCodecRecordDataPath::AddCodec(CMMFSwCodec& aCodec)
98 return KErrNotSupported; //doesn't support multiple codecs
104 iSinkBufferSize = iCodec->SinkBufferSize();
105 iSoundDevBufferSize = iCodec->SourceBufferSize();
107 if ((!iSinkBufferSize)||(!iSoundDevBufferSize))
109 err = KErrArgument; //codec plugin has not specified buffer size
114 #ifdef __USE_MMF_TRANSFERBUFFERS__
115 TRAP(err,iSoundDeviceBuffer = CreateTransferBufferL(iSoundDevBufferSize, static_cast<CMMFTransferBuffer*>(iSoundDeviceBuffer)));
118 #ifdef __USE_MMF_PTRBUFFERS__
119 TRAP(err,iSoundDeviceBuffer = CreatePtrBufferL(iSoundDevBufferSize));
121 TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
127 // Allocate data buffer
128 if (iCodec->IsNullCodec())
129 {//don't need a separate sink buffer if null codec
130 iSinkBuffer = NULL; //sink buffer is the sound device buffer
133 {//need a separate sink buffer for the codec
134 TRAP(err,iSinkBuffer = CMMFDataBuffer::NewL(iSinkBufferSize));
141 TInt CMMFSwCodecRecordDataPath::Start()
143 TInt startError = KErrNone;
144 if (!iCodec || !(iSoundDevice->Handle()))
145 {//check that a codec has been added and the sound device has been opened
146 startError = KErrNotReady;
151 // Start the player objects
152 iAudioRecorder->Start();
153 iSoundDeviceErrorReceiver->Start();
154 iSoundDeviceBuffer->SetLastBuffer(EFalse);
155 TRAP(startError, FillSoundDeviceBufferL()); //get audio recorder to fill buffer
156 if (startError == KErrNone)
158 iRecordedBytesCount = 0; //used for debug purposes
166 // *** Main Play Loop ***
167 void CMMFSwCodecRecordDataPath::FillSoundDeviceBufferL()
169 #ifdef __CYCLE_MMF_DATABUFFERS__
170 // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
171 // If the creation fails, we carry on regardless as the original buffer will not have been
172 // destroyed. Must do this as alloc fail tests will not run.
173 if(iSoundDeviceBuffer)
175 iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
177 #endif // __CYCLE_MMF_DATABUFFERS__
178 iAudioRecorder->RecordData(*iSoundDeviceBuffer);
182 void CMMFSwCodecRecordDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
184 iSoundDeviceBuffer = &aBuffer;
185 iSoundDeviceBuffer->SetStatus(EFull);
186 // Store this to avoid casting several times
187 TUint length = iSoundDeviceBuffer->BufferSize();
188 // Update bytes recorded
189 iRecordedBytesCount += length;
191 //If paused then sound driver will keep sending buffers till
192 //its flushed - if last buffer then set last buffer flag
193 if (length < iSoundDevBufferSize)
194 {//assume it's the last buffer
195 iSoundDeviceBuffer->SetLastBuffer(ETrue);
198 //buffer ok can send to sink
199 FillSinkBufferL(); //convert to sink data type using codec
200 User::LeaveIfError(iHwDeviceObserver->EmptyThisHwBuffer(*iSinkBuffer)); //pass onto sink
207 * Function to take the data from an already full source buffer and by using
208 * a codec if necessary fills the sink buffer
211 void CMMFSwCodecRecordDataPath::FillSinkBufferL()
213 CMMFSwCodec::TCodecProcessResult codecProcessResult;
215 if (iCodec->IsNullCodec())
216 {//no codec so sound device buffer can be used directly as sink buffer
217 iSinkBuffer = iSoundDeviceBuffer;
218 iSinkBuffer->SetStatus(EFull); //sink buffer is full
222 //pass buffer to codec for processing
223 codecProcessResult = iCodec->ProcessL(*iSoundDeviceBuffer, *iSinkBuffer);
224 if (iSoundDeviceBuffer->LastBuffer()) //if sound device is last buffer so is sound dev
226 iSinkBuffer->SetLastBuffer(ETrue);
228 if ((!iSinkBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
229 {//the codec has added data but not set the buffer length
230 iSinkBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
232 //only supports EProcessComplete
233 switch (codecProcessResult.iCodecProcessStatus)
235 case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
236 //finished procesing source data - all data in sink buffer
238 iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
239 iSinkBuffer->SetStatus(EFull); //sink buffer is full
242 case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
243 //finished procesing source data - sink buffer not full could be EOF
245 iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
246 iSinkBuffer->SetStatus(EFull); //sink buffer may not really be full however
249 case CMMFSwCodec::TCodecProcessResult::EEndOfData:
250 //no more data - send what we've got to the sink
251 //note we can't always rely on this - in many cases the codec will not know when
252 //it has reached the end of data.
254 iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
255 iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
256 //doesn't matter if sink buffer is not full
260 Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
266 void CMMFSwCodecRecordDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
268 if (&aBuffer != iSinkBuffer)
270 Panic(EMMFSwCodecWrapperBadBuffer);
272 if (!aBuffer.LastBuffer())
274 FillSoundDeviceBufferL();
276 //else the last buffer has been emptied - the observer should stop the
280 //*** End of Main Play Loop ***
283 void CMMFSwCodecRecordDataPath::Stop()
285 iAudioRecorder->Stop();//stop audio reocrder
287 iSoundDeviceErrorReceiver->Cancel(); //stop receiving events
289 TRequestStatus status;
290 iSoundDevice->CloseDevice(iDeviceUid, status);
291 User::WaitForRequest(status);
293 #ifdef __CYCLE_MMF_DATABUFFERS__
294 // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
295 // If the creation fails, we carry on regardless as the original buffer will not have been
296 // destroyed. Must do this as alloc fail tests will not run.
297 if(iSoundDeviceBuffer)
299 iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
301 #endif // __CYCLE_MMF_DATABUFFERS__
307 void CMMFSwCodecRecordDataPath::Pause()
309 // flush it anyway, whether we're active or not
310 // if we are active, then this should result in a call to RunL() pretty soon
311 //note that the Pause() in the context of record means buffers are
312 //continued to be obtained from the sound driver that have already
313 //been recorded - it just doesn't record any new audio data
315 RDebug::Print(_L("CMMFSwcodecRecordDataPath::Pause"));
317 iSoundDevice->FlushBuffer();
320 CRoutingSoundRecordDevice* CMMFSwCodecRecordDataPath::Device()
326 void CMMFSwCodecRecordDataPath::SoundDeviceException(TInt aError)
328 //this closes RMdaDevSound.
331 //inform devsound so it can update policy
332 iHwDeviceObserver->Stopped();
334 // Inform the observer of the exception condition
335 // We inform the hw device observer after the policy has been
336 // updated incase the observer relied on the error to assume
337 // the policy has been updated
338 iHwDeviceObserver->Error(aError);
341 TUint CMMFSwCodecRecordDataPath::RecordedBytesCount()
343 return iRecordedBytesCount;
347 /************************************************************************
348 * CDataPathRecorder *
349 ************************************************************************/
351 CDataPathRecorder::CDataPathRecorder(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
352 : CActive(aPriority), iParent(aParent)
354 CActiveScheduler::Add(this);
358 CDataPathRecorder::~CDataPathRecorder()
364 void CDataPathRecorder::Start()
370 void CDataPathRecorder::RecordData(CMMFDataBuffer& aData)
372 iDataFromSource = &aData;
375 iParent.Device()->RecordData(aData.Data(), iStatus);
381 void CDataPathRecorder::Stop()
384 RDebug::Print(_L("CDataPathRecorder Stop"));
390 void CDataPathRecorder::RunL()
393 RDebug::Print(_L("CDataPathRecorder::RunL error[%d]"), iStatus.Int());
397 iParent.BufferFilledL((CMMFDataBuffer&)*iDataFromSource);
399 //if we don't have a sound driver handle then we have stopped
400 //but the client still thinks we are recording so swallow error
401 else if (iStatus.Int() != KErrBadHandle)
403 iParent.SoundDeviceException(iStatus.Int());
408 TInt CDataPathRecorder::RunError(TInt aError)
415 void CDataPathRecorder::DoCancel()
418 RDebug::Print(_L("CDataPathRecorder Cancel"));
420 if (iParent.Device()->Handle())
422 iParent.Device()->CancelRecordData();
423 iParent.Device()->FlushBuffer();
428 void CDataPathRecorder::Error(TInt aError)
430 iParent.SoundDeviceException(aError);
434 /************************************************************************
435 * CSoundDevRecordErrorReceiver *
436 ************************************************************************/
438 CSoundDevRecordErrorReceiver::CSoundDevRecordErrorReceiver(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
439 : CActive(aPriority), iParent(aParent)
441 CActiveScheduler::Add(this);
445 CSoundDevRecordErrorReceiver::~CSoundDevRecordErrorReceiver()
451 void CSoundDevRecordErrorReceiver::Start()
455 iParent.Device()->NotifyError(iStatus);
461 void CSoundDevRecordErrorReceiver::Stop()
467 void CSoundDevRecordErrorReceiver::RunL()
469 // An error has been returned--Flush to release mic.
470 iParent.Device()->FlushBuffer();
471 iParent.SoundDeviceException(iStatus.Int());
475 void CSoundDevRecordErrorReceiver::DoCancel()
477 iParent.Device()->CancelNotifyError();