1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/swcodecwrapper/mmfBtSwCodecRecordDataPath.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,480 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// source\server\MmfBtSwCodecRecordDatapath.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include "mmfBtSwCodecRecordDataPath.h"
1.22 +#include "mmfbtswcodecwrapper.h"
1.23 +#include <mmfpaniccodes.h>
1.24 +#include "MMFBtRoutingSoundDevice.h"
1.25 +
1.26 +
1.27 +CMMFSwCodecRecordDataPath* CMMFSwCodecRecordDataPath::NewL(CRoutingSoundRecordDevice* aSoundDevice)
1.28 + {
1.29 + CMMFSwCodecRecordDataPath* self = new(ELeave) CMMFSwCodecRecordDataPath(aSoundDevice);
1.30 + CleanupStack::PushL(self);
1.31 + self->ConstructL();
1.32 + CleanupStack::Pop();
1.33 + return self;
1.34 + }
1.35 +
1.36 +
1.37 +void CMMFSwCodecRecordDataPath::ConstructL()
1.38 + {
1.39 + iAudioRecorder = new (ELeave) CDataPathRecorder(*this,CActive::EPriorityUserInput);
1.40 + iSoundDeviceErrorReceiver = new (ELeave) CSoundDevRecordErrorReceiver(*this, CActive::EPriorityUserInput);
1.41 + }
1.42 +
1.43 +
1.44 +CMMFSwCodecRecordDataPath::~CMMFSwCodecRecordDataPath()
1.45 + {
1.46 + delete iAudioRecorder;
1.47 + delete iSoundDeviceErrorReceiver;
1.48 +
1.49 + TRequestStatus status;
1.50 + iSoundDevice->CloseDevice(iDeviceUid, status);
1.51 + //TODO there should be a timeout for the line below
1.52 + User::WaitForRequest(status);
1.53 +
1.54 + if (iCodec)
1.55 + {
1.56 + delete iSoundDeviceBuffer;
1.57 + if (!iCodec->IsNullCodec())
1.58 + {
1.59 + delete iSinkBuffer;
1.60 + }
1.61 + }
1.62 +
1.63 +
1.64 +#ifdef __USE_MMF_TRANSFERBUFFERS__
1.65 + delete iTransferWindow;
1.66 +
1.67 + if(iTransferBuffer)
1.68 + {
1.69 + iTransferBuffer->Close();
1.70 + delete iTransferBuffer;
1.71 + }
1.72 +#endif
1.73 +
1.74 +#ifdef __USE_MMF_PTRBUFFERS__
1.75 + delete iPtrBufferMemoryBlock;
1.76 +#endif
1.77 +
1.78 + }
1.79 +
1.80 +
1.81 +TInt CMMFSwCodecRecordDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
1.82 + {
1.83 + TInt error;
1.84 + if (iHwDeviceObserver)
1.85 + {
1.86 + error = KErrAlreadyExists;
1.87 + }
1.88 + else
1.89 + {
1.90 + iHwDeviceObserver = &aObserver;
1.91 + error = KErrNone;
1.92 + }
1.93 + return error;
1.94 + }
1.95 +
1.96 +
1.97 +TInt CMMFSwCodecRecordDataPath::AddCodec(CMMFSwCodec& aCodec)
1.98 + {
1.99 + if (iCodec)
1.100 + {
1.101 + return KErrNotSupported; //doesn't support multiple codecs
1.102 + }
1.103 +
1.104 + TInt err = KErrNone;
1.105 + iCodec = &aCodec;
1.106 +
1.107 + iSinkBufferSize = iCodec->SinkBufferSize();
1.108 + iSoundDevBufferSize = iCodec->SourceBufferSize();
1.109 +
1.110 + if ((!iSinkBufferSize)||(!iSoundDevBufferSize))
1.111 + {
1.112 + err = KErrArgument; //codec plugin has not specified buffer size
1.113 + }
1.114 +
1.115 + if (err == KErrNone)
1.116 + {
1.117 +#ifdef __USE_MMF_TRANSFERBUFFERS__
1.118 + TRAP(err,iSoundDeviceBuffer = CreateTransferBufferL(iSoundDevBufferSize, static_cast<CMMFTransferBuffer*>(iSoundDeviceBuffer)));
1.119 +#endif
1.120 +
1.121 +#ifdef __USE_MMF_PTRBUFFERS__
1.122 + TRAP(err,iSoundDeviceBuffer = CreatePtrBufferL(iSoundDevBufferSize));
1.123 +#else
1.124 + TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
1.125 +#endif
1.126 + }
1.127 +
1.128 + if (err == KErrNone)
1.129 + {
1.130 + // Allocate data buffer
1.131 + if (iCodec->IsNullCodec())
1.132 + {//don't need a separate sink buffer if null codec
1.133 + iSinkBuffer = NULL; //sink buffer is the sound device buffer
1.134 + }
1.135 + else
1.136 + {//need a separate sink buffer for the codec
1.137 + TRAP(err,iSinkBuffer = CMMFDataBuffer::NewL(iSinkBufferSize));
1.138 + }
1.139 + }
1.140 + return err;
1.141 + }
1.142 +
1.143 +
1.144 +TInt CMMFSwCodecRecordDataPath::Start()
1.145 + {
1.146 + TInt startError = KErrNone;
1.147 + if (!iCodec || !(iSoundDevice->Handle()))
1.148 + {//check that a codec has been added and the sound device has been opened
1.149 + startError = KErrNotReady;
1.150 + }
1.151 +
1.152 + if (!startError)
1.153 + {
1.154 + // Start the player objects
1.155 + iAudioRecorder->Start();
1.156 + iSoundDeviceErrorReceiver->Start();
1.157 + iSoundDeviceBuffer->SetLastBuffer(EFalse);
1.158 + TRAP(startError, FillSoundDeviceBufferL()); //get audio recorder to fill buffer
1.159 + if (startError == KErrNone)
1.160 + {
1.161 + iRecordedBytesCount = 0; //used for debug purposes
1.162 + iState = EPlaying;
1.163 + }
1.164 + }
1.165 + return startError;
1.166 + }
1.167 +
1.168 +
1.169 +// *** Main Play Loop ***
1.170 +void CMMFSwCodecRecordDataPath::FillSoundDeviceBufferL()
1.171 + {
1.172 +#ifdef __CYCLE_MMF_DATABUFFERS__
1.173 + // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
1.174 + // If the creation fails, we carry on regardless as the original buffer will not have been
1.175 + // destroyed. Must do this as alloc fail tests will not run.
1.176 + if(iSoundDeviceBuffer)
1.177 + {
1.178 + iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
1.179 + }
1.180 +#endif // __CYCLE_MMF_DATABUFFERS__
1.181 + iAudioRecorder->RecordData(*iSoundDeviceBuffer);
1.182 + }
1.183 +
1.184 +
1.185 +void CMMFSwCodecRecordDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
1.186 + {
1.187 + iSoundDeviceBuffer = &aBuffer;
1.188 + iSoundDeviceBuffer->SetStatus(EFull);
1.189 + // Store this to avoid casting several times
1.190 + TUint length = iSoundDeviceBuffer->BufferSize();
1.191 + // Update bytes recorded
1.192 + iRecordedBytesCount += length;
1.193 +
1.194 + //If paused then sound driver will keep sending buffers till
1.195 + //its flushed - if last buffer then set last buffer flag
1.196 + if (length < iSoundDevBufferSize)
1.197 + {//assume it's the last buffer
1.198 + iSoundDeviceBuffer->SetLastBuffer(ETrue);
1.199 + }
1.200 +
1.201 + //buffer ok can send to sink
1.202 + FillSinkBufferL(); //convert to sink data type using codec
1.203 + User::LeaveIfError(iHwDeviceObserver->EmptyThisHwBuffer(*iSinkBuffer)); //pass onto sink
1.204 + }
1.205 +
1.206 +
1.207 +/*
1.208 + * FillSinkBufferL
1.209 + *
1.210 + * Function to take the data from an already full source buffer and by using
1.211 + * a codec if necessary fills the sink buffer
1.212 + * @internalComponent
1.213 + */
1.214 +void CMMFSwCodecRecordDataPath::FillSinkBufferL()
1.215 + {
1.216 + CMMFSwCodec::TCodecProcessResult codecProcessResult;
1.217 +
1.218 + if (iCodec->IsNullCodec())
1.219 + {//no codec so sound device buffer can be used directly as sink buffer
1.220 + iSinkBuffer = iSoundDeviceBuffer;
1.221 + iSinkBuffer->SetStatus(EFull); //sink buffer is full
1.222 + }
1.223 + else
1.224 + {
1.225 + //pass buffer to codec for processing
1.226 + codecProcessResult = iCodec->ProcessL(*iSoundDeviceBuffer, *iSinkBuffer);
1.227 + if (iSoundDeviceBuffer->LastBuffer()) //if sound device is last buffer so is sound dev
1.228 + {
1.229 + iSinkBuffer->SetLastBuffer(ETrue);
1.230 + }
1.231 + if ((!iSinkBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
1.232 + {//the codec has added data but not set the buffer length
1.233 + iSinkBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
1.234 + }
1.235 + //only supports EProcessComplete
1.236 + switch (codecProcessResult.iCodecProcessStatus)
1.237 + {
1.238 + case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
1.239 + //finished procesing source data - all data in sink buffer
1.240 + {
1.241 + iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
1.242 + iSinkBuffer->SetStatus(EFull); //sink buffer is full
1.243 + }
1.244 + break;
1.245 + case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
1.246 + //finished procesing source data - sink buffer not full could be EOF
1.247 + {
1.248 + iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
1.249 + iSinkBuffer->SetStatus(EFull); //sink buffer may not really be full however
1.250 + }
1.251 + break;
1.252 + case CMMFSwCodec::TCodecProcessResult::EEndOfData:
1.253 + //no more data - send what we've got to the sink
1.254 + //note we can't always rely on this - in many cases the codec will not know when
1.255 + //it has reached the end of data.
1.256 + {
1.257 + iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
1.258 + iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
1.259 + //doesn't matter if sink buffer is not full
1.260 + }
1.261 + break;
1.262 + default:
1.263 + Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
1.264 + }
1.265 + }
1.266 + }
1.267 +
1.268 +
1.269 +void CMMFSwCodecRecordDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
1.270 + {
1.271 + if (&aBuffer != iSinkBuffer)
1.272 + {
1.273 + Panic(EMMFSwCodecWrapperBadBuffer);
1.274 + }
1.275 + if (!aBuffer.LastBuffer())
1.276 + {
1.277 + FillSoundDeviceBufferL();
1.278 + }
1.279 + //else the last buffer has been emptied - the observer should stop the
1.280 + //hw device.
1.281 + }
1.282 +
1.283 +//*** End of Main Play Loop ***
1.284 +
1.285 +
1.286 +void CMMFSwCodecRecordDataPath::Stop()
1.287 + {
1.288 + iAudioRecorder->Stop();//stop audio reocrder
1.289 +
1.290 + iSoundDeviceErrorReceiver->Cancel(); //stop receiving events
1.291 +
1.292 + TRequestStatus status;
1.293 + iSoundDevice->CloseDevice(iDeviceUid, status);
1.294 + User::WaitForRequest(status);
1.295 +
1.296 +#ifdef __CYCLE_MMF_DATABUFFERS__
1.297 + // Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
1.298 + // If the creation fails, we carry on regardless as the original buffer will not have been
1.299 + // destroyed. Must do this as alloc fail tests will not run.
1.300 + if(iSoundDeviceBuffer)
1.301 + {
1.302 + iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
1.303 + }
1.304 +#endif // __CYCLE_MMF_DATABUFFERS__
1.305 +
1.306 + iState = EStopped;
1.307 + }
1.308 +
1.309 +
1.310 +void CMMFSwCodecRecordDataPath::Pause()
1.311 + {
1.312 + // flush it anyway, whether we're active or not
1.313 + // if we are active, then this should result in a call to RunL() pretty soon
1.314 + //note that the Pause() in the context of record means buffers are
1.315 + //continued to be obtained from the sound driver that have already
1.316 + //been recorded - it just doesn't record any new audio data
1.317 +#ifdef _SCW_DEBUG
1.318 + RDebug::Print(_L("CMMFSwcodecRecordDataPath::Pause"));
1.319 +#endif
1.320 + iSoundDevice->FlushBuffer();
1.321 + }
1.322 +
1.323 +CRoutingSoundRecordDevice* CMMFSwCodecRecordDataPath::Device()
1.324 + {
1.325 + return iSoundDevice;
1.326 + }
1.327 +
1.328 +
1.329 +void CMMFSwCodecRecordDataPath::SoundDeviceException(TInt aError)
1.330 + {
1.331 + //this closes RMdaDevSound.
1.332 + Stop();
1.333 +
1.334 + //inform devsound so it can update policy
1.335 + iHwDeviceObserver->Stopped();
1.336 +
1.337 + // Inform the observer of the exception condition
1.338 + // We inform the hw device observer after the policy has been
1.339 + // updated incase the observer relied on the error to assume
1.340 + // the policy has been updated
1.341 + iHwDeviceObserver->Error(aError);
1.342 + }
1.343 +
1.344 +TUint CMMFSwCodecRecordDataPath::RecordedBytesCount()
1.345 + {
1.346 + return iRecordedBytesCount;
1.347 + }
1.348 +
1.349 +
1.350 +/************************************************************************
1.351 + * CDataPathRecorder *
1.352 + ************************************************************************/
1.353 +
1.354 +CDataPathRecorder::CDataPathRecorder(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
1.355 +: CActive(aPriority), iParent(aParent)
1.356 + {
1.357 + CActiveScheduler::Add(this);
1.358 + }
1.359 +
1.360 +
1.361 +CDataPathRecorder::~CDataPathRecorder()
1.362 + {
1.363 + Cancel();
1.364 + }
1.365 +
1.366 +
1.367 +void CDataPathRecorder::Start()
1.368 + {
1.369 + // No implementation
1.370 + }
1.371 +
1.372 +
1.373 +void CDataPathRecorder::RecordData(CMMFDataBuffer& aData)
1.374 + {
1.375 + iDataFromSource = &aData;
1.376 + if (!IsActive())
1.377 + {
1.378 + iParent.Device()->RecordData(aData.Data(), iStatus);
1.379 + SetActive();
1.380 + }
1.381 + }
1.382 +
1.383 +
1.384 +void CDataPathRecorder::Stop()
1.385 + {
1.386 +#ifdef _SCW_DEBUG
1.387 + RDebug::Print(_L("CDataPathRecorder Stop"));
1.388 +#endif
1.389 + Cancel();
1.390 + }
1.391 +
1.392 +
1.393 +void CDataPathRecorder::RunL()
1.394 + {
1.395 +#ifdef _SCW_DEBUG
1.396 + RDebug::Print(_L("CDataPathRecorder::RunL error[%d]"), iStatus.Int());
1.397 +#endif
1.398 + if (!iStatus.Int())
1.399 + {
1.400 + iParent.BufferFilledL((CMMFDataBuffer&)*iDataFromSource);
1.401 + }
1.402 + //if we don't have a sound driver handle then we have stopped
1.403 + //but the client still thinks we are recording so swallow error
1.404 + else if (iStatus.Int() != KErrBadHandle)
1.405 + {
1.406 + iParent.SoundDeviceException(iStatus.Int());
1.407 + }
1.408 + }
1.409 +
1.410 +
1.411 +TInt CDataPathRecorder::RunError(TInt aError)
1.412 + {
1.413 + Error(aError);
1.414 + return KErrNone;
1.415 + }
1.416 +
1.417 +
1.418 +void CDataPathRecorder::DoCancel()
1.419 + {
1.420 +#ifdef _SCW_DEBUG
1.421 + RDebug::Print(_L("CDataPathRecorder Cancel"));
1.422 +#endif
1.423 + if (iParent.Device()->Handle())
1.424 + {
1.425 + iParent.Device()->CancelRecordData();
1.426 + iParent.Device()->FlushBuffer();
1.427 + }
1.428 + }
1.429 +
1.430 +
1.431 +void CDataPathRecorder::Error(TInt aError)
1.432 + {
1.433 + iParent.SoundDeviceException(aError);
1.434 + }
1.435 +
1.436 +
1.437 +/************************************************************************
1.438 + * CSoundDevRecordErrorReceiver *
1.439 + ************************************************************************/
1.440 +
1.441 +CSoundDevRecordErrorReceiver::CSoundDevRecordErrorReceiver(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
1.442 +: CActive(aPriority), iParent(aParent)
1.443 + {
1.444 + CActiveScheduler::Add(this);
1.445 + }
1.446 +
1.447 +
1.448 +CSoundDevRecordErrorReceiver::~CSoundDevRecordErrorReceiver()
1.449 + {
1.450 + Cancel();
1.451 + }
1.452 +
1.453 +
1.454 +void CSoundDevRecordErrorReceiver::Start()
1.455 + {
1.456 + if (!IsActive())
1.457 + {
1.458 + iParent.Device()->NotifyError(iStatus);
1.459 + SetActive();
1.460 + }
1.461 + }
1.462 +
1.463 +
1.464 +void CSoundDevRecordErrorReceiver::Stop()
1.465 + {
1.466 + Cancel();
1.467 + }
1.468 +
1.469 +
1.470 +void CSoundDevRecordErrorReceiver::RunL()
1.471 + {
1.472 + // An error has been returned--Flush to release mic.
1.473 + iParent.Device()->FlushBuffer();
1.474 + iParent.SoundDeviceException(iStatus.Int());
1.475 + }
1.476 +
1.477 +
1.478 +void CSoundDevRecordErrorReceiver::DoCancel()
1.479 + {
1.480 + iParent.Device()->CancelNotifyError();
1.481 + }
1.482 +
1.483 +