diff -r 000000000000 -r b8ed18f6c07b mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp Thu Oct 07 22:34:12 2010 +0100 @@ -0,0 +1,995 @@ +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "mmfclientaudioinputstream.h" +#include "mmfclientaudiostreamutils.h" +#include +#include +#include "MmfFifo.h" +#include + +const TInt KMicroSecsInOneSec = 1000000; + + +enum TMmfAudioInputPanic + { + EAudioInputPanicNotSupported + }; + +_LIT(KAudioInputStreamCategory, "CMMFMdaAudioInputStream"); +LOCAL_C void Panic(const TMmfAudioInputPanic aPanic) + { + User::Panic(KAudioInputStreamCategory, aPanic); + } + +/** + * + * Static NewL + * + * @return CMdaAudioInputStream* + * + */ +EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback) + { + return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality); + } + +/** + * + * Static NewL + * + * @return CMdaAudioInputStream* + * + */ +EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref) + { + CMdaAudioInputStream* self = new(ELeave) CMdaAudioInputStream(); + CleanupStack::PushL(self); + self->iProperties = CMMFMdaAudioInputStream::NewL(aCallback, aPriority, aPref); + CleanupStack::Pop(self); + return self; + } + +CMdaAudioInputStream::CMdaAudioInputStream() + { + } + +CMdaAudioInputStream::~CMdaAudioInputStream() + { + if(iProperties) + { + iProperties->ShutDown(); + } + + delete iProperties; + } + +EXPORT_C void CMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels) + { + ASSERT(iProperties); + iProperties->SetAudioPropertiesL(aSampleRate, aChannels); + } + +EXPORT_C void CMdaAudioInputStream::Open(TMdaPackage* aSettings) + { + ASSERT(iProperties); + iProperties->Open(aSettings); + } + +EXPORT_C void CMdaAudioInputStream::SetGain(TInt aNewGain) + { + ASSERT(iProperties); + iProperties->SetGain(aNewGain); + } + +EXPORT_C TInt CMdaAudioInputStream::Gain() const + { + ASSERT(iProperties); + return iProperties->Gain(); + } + +EXPORT_C TInt CMdaAudioInputStream::MaxGain() const + { + ASSERT(iProperties); + return iProperties->MaxGain(); + } + +EXPORT_C void CMdaAudioInputStream::SetBalanceL(TInt aBalance) + { + ASSERT(iProperties); + iProperties->SetBalanceL(aBalance); + } + +EXPORT_C TInt CMdaAudioInputStream::GetBalanceL() const + { + ASSERT(iProperties); + return iProperties->GetBalanceL(); + } + +EXPORT_C void CMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref) + { + ASSERT(iProperties); + iProperties->SetPriority(aPriority, aPref); + } + +EXPORT_C void CMdaAudioInputStream::ReadL(TDes8& aData) + { + ASSERT(iProperties); + iProperties->ReadL(aData); + } + +EXPORT_C void CMdaAudioInputStream::Stop() + { + ASSERT(iProperties); + iProperties->Stop(); + } + +EXPORT_C void CMdaAudioInputStream::RequestStop() + { + ASSERT(iProperties); + iProperties->RequestStop(); + } + +EXPORT_C const TTimeIntervalMicroSeconds& CMdaAudioInputStream::Position() + { + ASSERT(iProperties); + return iProperties->Position(); + } + +EXPORT_C TInt CMdaAudioInputStream::GetBytes() + { + ASSERT(iProperties); + return iProperties->GetBytes(); + } + +EXPORT_C void CMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode) + { + ASSERT(iProperties); + iProperties->SetSingleBufferMode(aSingleMode); + } + +/** + +*/ +EXPORT_C void CMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType) + { + ASSERT(iProperties); + iProperties->SetDataTypeL(aAudioType); + } + +/** + +*/ +EXPORT_C TFourCC CMdaAudioInputStream::DataType() const + { + ASSERT(iProperties); + return iProperties->DataType(); + } + + +EXPORT_C TInt CMdaAudioInputStream::BitRateL() const + { + ASSERT(iProperties); + return iProperties->BitRateL(); + } + +EXPORT_C void CMdaAudioInputStream::SetBitRateL(TInt aBitRate) + { + ASSERT(iProperties); + iProperties->SetBitRateL(aBitRate); + } + + +EXPORT_C void CMdaAudioInputStream::GetSupportedBitRatesL(RArray& aSupportedBitRates) + { + ASSERT(iProperties); + iProperties->GetSupportedBitRatesL(aSupportedBitRates); + } + +EXPORT_C TAny* CMdaAudioInputStream::CustomInterface(TUid aInterfaceId) + { + ASSERT(iProperties); + return iProperties->CustomInterface(aInterfaceId); + } + +// + +CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback) + { + return CMMFMdaAudioInputStream::NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality); + } + +CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref) + { + CMMFMdaAudioInputStream* self = new(ELeave) CMMFMdaAudioInputStream(aCallback); + CleanupStack::PushL(self); + self->ConstructL(aPriority, aPref); + CleanupStack::Pop(self); + return self; + } +/** + * + * Construct + * + * @param "MMdaAudioInputStreamCallback&" + * a reference to MMdaAudioInputStreamCallback + * a perference value + * + */ +CMMFMdaAudioInputStream::CMMFMdaAudioInputStream(MMdaAudioInputStreamCallback& aCallback) + : iCallback(aCallback), iStorageItem (NULL, 0), iBufferPtr(NULL, 0) + // Depending on zero for construction (i.e. attribute of CBase) + // iSingleBuffer (EFalse) + // iState(EStopped) + // iIsOpened(EFalse) + // iCallbackMade(EFalse) + // iAudioDataStored(EFalse) + { + iDataTypeCode.Set(TFourCC(' ','P','1','6')); + } + +/** + * + * Second phase constructor + * + */ +void CMMFMdaAudioInputStream::ConstructL(TInt aPriority, TInt aPref) + { + iDevSound = CMMFDevSound::NewL(); + SetPriority(aPriority, aPref); + iFifo = new(ELeave) CMMFFifo(); + iActiveCallback = new(ELeave) CActiveCallback(iCallback); + iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait; + } + +/** + * + * Destructor + * + */ +CMMFMdaAudioInputStream::~CMMFMdaAudioInputStream() + { + delete iFifo; + delete iDevSound; + delete iActiveCallback; + delete iActiveSchedulerWait; + } + +/** + * + * Set audio input stream properties + * + * @param "TInt aSampleRate" + * a specified priority value + * @param "TInt aChannels" + * a specified preference value + * + */ +void CMMFMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels) + { + if (iIsOpenState == EIsOpen) + { + RealSetAudioPropertiesL(aSampleRate, aChannels); + } + else + { + // cache for application later + iSettings.iSampleRate = aSampleRate; + iSettings.iChannels = aChannels; + iAudioDataStored = ETrue; + } + } + +void CMMFMdaAudioInputStream::RealSetAudioPropertiesL(TInt aSampleRate, TInt aChannels) + { + TMMFCapabilities capabilities = iDevSound->Config(); + capabilities.iChannels = StreamUtils::MapChannelsMdaToMMFL(aChannels); + capabilities.iRate = StreamUtils::MapSampleRateMdaToMMFL(aSampleRate); + iDevSound->SetConfigL(capabilities); + } + +/** + * + * Open a audio ouptut stream + * + * @param "TMdaPackage* Settings" + * a pointer point to TMdaPackage + * + */ +void CMMFMdaAudioInputStream::Open(TMdaPackage* aSettings) + { + iIsOpenState = EIsOpening; + //store aSettings + if (aSettings && (aSettings->Type().iUid == KUidMdaDataTypeSettingsDefine)) + { + TMdaAudioDataSettings* tmpSettings = STATIC_CAST(TMdaAudioDataSettings*, aSettings); + iSettings = *tmpSettings; + iAudioDataStored = ETrue; + } + TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording)); + if (err != KErrNone) + { + // Signal for the MaiscOpenComplete callback to be called asynchronously + iActiveCallback->Signal(err); + iIsOpenState = EIsNotOpen; + iAudioDataStored = EFalse; // reset - if was set we throw away due to failure + } + } + +/** + * + * To get the maximum gain level + * + * @return "TInt" + * the maximum gain value in integer + * + */ +TInt CMMFMdaAudioInputStream::MaxGain() const + { + return iDevSound->MaxGain(); + } + +/** + * + * To get the current gain level + * + * @return "TInt" + * the current gain value in integer + * + */ +TInt CMMFMdaAudioInputStream::Gain() const + { + return iDevSound->Gain(); + } + +/** + * + * Set audio input stream gain to the specified value + * + * @param "TInt aGain" + * a specified gain value + * + */ +void CMMFMdaAudioInputStream::SetGain(TInt aGain) + { + iDevSound->SetGain(aGain); + } + +/** + * + * Set audio input stream balance + * + * @param "TInt aBalance" + * a specified balance value + * + */ +void CMMFMdaAudioInputStream::SetBalanceL(TInt aBalance) + { + // test and clip balance to min / max range [-100 <-> 100] + // clip rather than leave as this isn't a leaving function + if (aBalance < KMMFBalanceMaxLeft) aBalance = KMMFBalanceMaxLeft; + if (aBalance > KMMFBalanceMaxRight) aBalance = KMMFBalanceMaxRight; + + // separate out left and right balance + TInt left = 0; + TInt right = 0; + StreamUtils::CalculateLeftRightBalance( left, right, aBalance ); + + // send the balance to SoundDevice + iDevSound->SetRecordBalanceL(left, right); + } + +/** + * + * To get the current balance value.This function may not return the same value + * as passed to SetBalanceL depending on the internal implementation in + * the underlying components. + * + * @return "TInt" + * the current balance value in integer + * + */ +TInt CMMFMdaAudioInputStream::GetBalanceL() const + { + TInt rightBalance = 0; + TInt leftBalance = 0; + iDevSound->GetRecordBalanceL(leftBalance, rightBalance); + TInt balance = 0; + StreamUtils::CalculateBalance( balance, leftBalance, rightBalance ); + return balance; + } + +/** + * + * Set audio input stream priority + * + * @param "TInt aPriority" + * a specified priority value + * @param "TInt aPref" + * a specified preference value + * + */ +void CMMFMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref) + { + TMMFPrioritySettings settings; + settings.iPriority = aPriority; + settings.iPref = aPref; + iDevSound->SetPrioritySettings(settings); + } + + +/** + * + * To read data from input stream + * + * @param "TDesC8& aData" + * a stream data + * + * @capability UserEnvironment + * For recording - the requesting client process must have the + * UserEnvironment capability. + */ +void CMMFMdaAudioInputStream::ReadL(TDes8& aData) + { + User::LeaveIfError(Read(aData)); + + if (iState == EStopped) + { + iDevSound->RecordInitL(); + iState = ERecording; + } + } + +/** + * + * To read data from input stream + * + * @param "TDesC8& aData" + * a stream data + * + * @capability UserEnvironment + * For recording - the requesting client process must have the + * UserEnvironment capability. + */ +TInt CMMFMdaAudioInputStream::Read(TDes8& aData) + { + TMMFFifoItem* item = new TMMFFifoItem(aData); + if (!item) + { + return KErrNoMemory; + } + + iFifo->AddToFifo(*item); // no issue with memory alloc + // each element contains storage space for link to the next + return KErrNone; + } + +/** + * + * To stop write data to stream + * + */ +void CMMFMdaAudioInputStream::Stop() + { + // Need to take for the case where Stop is invoked directly after a call to RequestStop. + // We have chosen to allow the Stop to go through as this could be more important. + // This is non-reentrant code but will suffice for our needs. + if (iState != EStopped) + { + // Amend the state so RequestStop or Stop initiated by it (indirectly) won't function + iState = EStopped; + + if (iSingleBuffer && iStorageItem.Ptr() != NULL) + { + iCallback.MaiscBufferCopied(KErrAbort, iStorageItem); + iStorageItem.Set (NULL,0,0); + } + + // Delete all buffers in the fifo and notify the observer + TMMFFifoItem* firstItem; + while((firstItem = iFifo->Get()) != NULL) + { + iFifo->RemoveFirstItem(); + if (!iSingleBuffer) + { + iCallback.MaiscBufferCopied(KErrAbort,firstItem->GetData()); + } + delete firstItem; + } + + iDevSound->Stop(); + } + } + + +/** + * + * To pause write data to stream + * Allow yet unprocessed buffers to be processed and passed back via BufferToBeEmptied. + * When the last (empty) buffer arrives, Stop is called. + */ +void CMMFMdaAudioInputStream::RequestStop() + { + // [ precondition that we are not already stopped + // && if we are stopped do nothing. + // If we are stopping a recording, we need to give the server a chance to + // process that data which has already been captured. We therefore stay in the EPause + // state. + if (iState != EStopped) + { + if (iState != EStopping) + { + // We can only be Recording, if we have other states later they can be tested here. + iDevSound->Pause(); + iState = EStopping; + } + } + } + + +/** + * + * To get the current position in the data stream + * + * @return "TTimeIntervalMicroSeconds&" + * the current position in integer + * + */ +const TTimeIntervalMicroSeconds& CMMFMdaAudioInputStream::Position() + { + TInt64 position = iDevSound->SamplesRecorded(); + position = position * KMicroSecsInOneSec / StreamUtils::SampleRateAsValue(iDevSound->Config()); + iPosition = (iState == ERecording) ? position : 0; // Shouldn't need to check for playing but CMMFDevSound doesn't reset bytes played after a stop + return iPosition; + } + + + +/** + * + * To return the current number of bytes recorded by audio hardware + * @return "the current current number of bytes rendered by audio hardware in integer" + * + */ +TInt CMMFMdaAudioInputStream::GetBytes() + { + return iBytesRecorded; + } + +void CMMFMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType) + { + if(iState != EStopped) + User::Leave(KErrServerBusy); + + if(aAudioType == iDataTypeCode) + return; + + TMMFPrioritySettings prioritySettings ; + prioritySettings.iState = EMMFStateRecording; + + RArray supportedDataTypes; + + CleanupClosePushL(supportedDataTypes); + + TRAPD(err, iDevSound->GetSupportedOutputDataTypesL(supportedDataTypes, prioritySettings)); + + if (err == KErrNone) + { + if (supportedDataTypes.Find(aAudioType) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + //if match, set the 4CC of AudioType to match + iDataTypeCode.Set(aAudioType); + } + else //we had a real leave error from GetSupportedInputDataTypesL + { + User::Leave(err); + } + CleanupStack::PopAndDestroy(&supportedDataTypes); + + if(iIsOpenState!=EIsNotOpen) + { + // need to recall or restart InitializeL() process + iDevSound->CancelInitialize(); // call just in case mid-InitializeL. No harm if not. + // if not supported then assume old DevSound behaviour anyway + // where InitializeL() implicitly cancels, so no harm either way + iIsOpenState = EIsOpening; + iInitCallFrmSetDataType = ETrue; + TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording)); + if (err != KErrNone) + { + // Leave if error. + iIsOpenState = EIsNotOpen; + iInitCallFrmSetDataType = EFalse; + User::Leave(err); + } + // In some implementations InitializeComplete is sent + // in context, so check before starting activeSchedulerWait. + else if(iIsOpenState == EIsOpening) + { + iInitializeState = KRequestPending; + iActiveSchedulerWait->Start(); + } + iInitCallFrmSetDataType = EFalse; + User::LeaveIfError(iInitializeState); + } + } + +/** + +*/ +TFourCC CMMFMdaAudioInputStream::DataType() const + { + return iDataTypeCode; + } + +TInt CMMFMdaAudioInputStream::BitRateL() const + { + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate); + if (ptr == NULL) + User::Leave(KErrNotSupported); + + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast(ptr); + return bitrate->BitRateL(); + } + + +void CMMFMdaAudioInputStream::SetBitRateL(TInt aBitRate) + { + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate); + if (ptr == NULL) + User::Leave(KErrNotSupported); + + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast(ptr); + bitrate->SetBitRateL(aBitRate); + } + +void CMMFMdaAudioInputStream::GetSupportedBitRatesL(RArray& aSupportedBitRates) + { + // ensure that the array is empty before passing it in + aSupportedBitRates.Reset(); + TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate); + if (ptr == NULL) + User::Leave(KErrNotSupported); + MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast(ptr); + bitrate->GetSupportedBitRatesL(aSupportedBitRates); + } + + +// + +CMMFMdaAudioInputStream::CActiveCallback::CActiveCallback(MMdaAudioInputStreamCallback& aCallback) + : CActive(EPriorityStandard), iCallback(aCallback) + { + CActiveScheduler::Add(this); + } + +CMMFMdaAudioInputStream::CActiveCallback::~CActiveCallback() + { + Cancel(); + } + +void CMMFMdaAudioInputStream::CActiveCallback::RunL() + { + iCallback.MaiscOpenComplete(iStatus.Int()); + } + +void CMMFMdaAudioInputStream::CActiveCallback::DoCancel() + { + } + +void CMMFMdaAudioInputStream::CActiveCallback::Signal(const TInt aReason) + { + ASSERT(!IsActive()); + + // Signal ourselves to run with the given completion code + TRequestStatus* status = &iStatus; + User::RequestComplete(status, aReason); + SetActive(); + } + +// + +/** + * + * To be called when intialize stream complete + * + * @param "TInt aError" + * error code, initialize stream succeed when aError = 0 + * + */ +void CMMFMdaAudioInputStream::InitializeComplete(TInt aError) + { + TInt err = aError; + if(iIsOpenState == EIsOpening) + { + if (err == KErrNone) + { + // Use settings to set audio properties after the dev sound has been + // successfully initialised + if(iAudioDataStored) + { + TRAP(err, RealSetAudioPropertiesL(iSettings.iSampleRate, iSettings.iChannels)); + } + + } + + // Signal for the MaiscOpenComplete callback to be called asynchronously.Ignore if InitializeL is called from SetDataTypeL + if(!iInitCallFrmSetDataType) + { + iActiveCallback->Signal(err); + } + iIsOpenState = err ? EIsNotOpen : EIsOpen; + //reset iAudioDataStored flag if set - whatever don't want to use next time + iAudioDataStored = EFalse; + if(iInitializeState == KRequestPending) + { + iInitializeState = err; + iActiveSchedulerWait->AsyncStop(); + } + else + { + iInitializeState = err;//Set the error. + } + } + } + +/** + * + * Do not support + * + */ +void CMMFMdaAudioInputStream::ToneFinished(TInt /*aError*/) + { + Panic(EAudioInputPanicNotSupported); + } + +/** + * + * Called when sound device has filled data buffer + * + * @param "CMMFBuffer* aBuffer" + * a pointer point to CMMFBuffer, which is used for recieved data + * + */ +void CMMFMdaAudioInputStream::BufferToBeEmptied(CMMFBuffer* aBuffer) + { + // Simply put, tries to copy the data from aBuffer into the clients storage buffers. + // + // The input stream iFifo data member is used to store the clients storage buffers + // that are passed to it via a call to ReadL. + // + // If iSingleBuffer is False, the first buffer on the fifo is copied to. + // This buffer is then removed off the fifo. + // The callback MaiscBufferCopied is invoked after each copy, passing that buffer. + // If the data is greater than the buffer then this process repeats with the next buffer. + // + // If iSingleBuffer is True, it is assumed only one buffer is on the fifo. + // The behaviour is the same as above except that a descriptor representing the + // buffers empty part is placed at the end of the fifo, and the callback + // MaiscBufferCopied is invoked only when the buffer is full. + // + // If the client sets iSingleBuffer to True and places more than one buffer on the fifo + // the behaviour is undefined and unsupported. + // + // If there are no more storage buffers on the fifo, the callback + // MaiscRecordComplete(KErrOverflow) is invoked. + + const TDesC8& buffer = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data(); + + TInt lengthCopied = 0; + iBytesRecorded += buffer.Length(); + + // A stop was requested after all the data has been received + if (iState == EStopping && buffer.Length() == 0) + { + Stop(); + iCallback.MaiscRecordComplete(KErrNone); + return; + } + else + { + // The fifo may have multiple storage buffers, i.e. one in each of its entries. + // Fill what we can in each. If we get an empty buffer then we have finished recording. + while (lengthCopied < buffer.Length()) + { + // Chop up aBuffer into slices the buffers in iFifo can handle + TMMFFifoItem* firstItem = iFifo->Get(); + + if(firstItem != NULL) + { + TDes8& writeBuf = firstItem->GetData(); + + // We have a spare buffer slot + TInt slotLength = Min(buffer.Length()-lengthCopied, writeBuf.MaxLength()); + writeBuf = buffer.Mid(lengthCopied, slotLength); + lengthCopied += slotLength; + + // Determine whether to callback the client or not. + // I.e. if we have multiple small buffers that we want to process quickly or + // when a singular buffer is FULL. + // Note: That if the client asks to Stop, the buffer may not be filled! + if (iSingleBuffer) + { + // Remember this item for later. + // We really only want the first item as this covers the entire + // client storage buffer. We will adjust the actual length later. + if (iStorageItem.Ptr() == NULL) + { + iStorageItem.Set (const_cast(writeBuf.Ptr()), 0, writeBuf.MaxLength()); + } + + // In this iteration we may just be looking at a right-part of the original + // buffer. Update the actual length of data. + TInt actualLength = (writeBuf.Ptr()-iStorageItem.Ptr()) + writeBuf.Length(); + iStorageItem.SetLength(actualLength); + + // Is the buffer full? + if (writeBuf.Length() == writeBuf.MaxLength()) + { + // The singular buffer has been filled so pass it back to the client + iCallback.MaiscBufferCopied(KErrNone, iStorageItem); + iStorageItem.Set (NULL,0,0); + } + else + { + // Create a window to the 'remaining' free section of the storage buffer + iBufferPtr.Set (const_cast(writeBuf.Ptr())+lengthCopied, 0, writeBuf.MaxLength()-lengthCopied); + + // Add the window to the fifo + TInt err = Read(iBufferPtr); + if (err) + { + Stop(); + iCallback.MaiscRecordComplete(err); + return; + } + ASSERT(iState == ERecording); + } + } + else + { + // Notify client + iCallback.MaiscBufferCopied(KErrNone, writeBuf); + } + //Check if client called Stop from the MaiscBufferCopied. + //If so, we should neither continue this loop nor delete the first item. Stop cleans up all the buffers + if(iState == EStopped) + { + break; + } + else + { + // Remove this storage buffer from the fifo as we want to have access to any others behind it. + iFifo->RemoveFirstItem(); + delete firstItem; + } + } + else + { + // run out of buffers - report an overflow error + Stop(); + iCallback.MaiscRecordComplete(KErrOverflow); + return; + } + }// while + } // else + + // Keep recording if there are free buffers + if (!iFifo->IsEmpty()) + iDevSound->RecordData(); + } + +/** + * + * Called when record operation complete, successfully or otherwise + * + * @param "TInt aError" + * an error value which will indicate playing successfully complete + * if error value is 0 + * + */ +void CMMFMdaAudioInputStream::PlayError(TInt /*aError*/) + { + Panic(EAudioInputPanicNotSupported); + } + + +/** + * + * Do not support + * + */ +void CMMFMdaAudioInputStream::BufferToBeFilled(CMMFBuffer* /*aBuffer*/) + { + Panic(EAudioInputPanicNotSupported); + } + +/** + * + * Do not support + * + */ +void CMMFMdaAudioInputStream::RecordError(TInt aError) + { + if (iState == ERecording) + { + if (aError != KErrCancel) + { + iCallback.MaiscRecordComplete(aError); + } + // else must have been cancelled by client. Doesn't need to be notified + + iState = EStopped; + } + } + +/** + * + * Do not support + * + */ +void CMMFMdaAudioInputStream::ConvertError(TInt /*aError*/) + { + Panic(EAudioInputPanicNotSupported); + } + +/** + * + * Do not support + * + */ +void CMMFMdaAudioInputStream::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/) + { + Panic(EAudioInputPanicNotSupported); + } + +// CustomInferface - just pass on to DevSound. +TAny* CMMFMdaAudioInputStream::CustomInterface(TUid aInterfaceId) + { + return iDevSound->CustomInterface(aInterfaceId); + } + + +void CMMFMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode) + { + iSingleBuffer = aSingleMode; + } + +void CMMFMdaAudioInputStream::ShutDown() + { + // Need to take for the case where Stop is invoked from the destructor of CMdaAudioInputStream + // Need to ensure that there are no callbacks to the client at this stage + if (iState != EStopped) + { + iState = EStopped; + + if (iSingleBuffer && iStorageItem.Ptr() != NULL) + { + iStorageItem.Set (NULL,0,0); + } + + // Delete all buffers in the fifo + TMMFFifoItem* firstItem; + while((firstItem = iFifo->Get()) != NULL) + { + iFifo->RemoveFirstItem(); + delete firstItem; + } + + iDevSound->Stop(); + } + }