mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -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 <mmf/server/devsoundstandardcustominterfaces.h>
+#include <mmf/common/mmfpaniccodes.h>
+#include "MmfFifo.h"
+#include <mdaaudioinputstream.h>
+
+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<TInt>& 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<TDes8>();
+	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<TDes8>* item = new TMMFFifoItem<TDes8>(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<TDes8>* 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<TFourCC> 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<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
+	return bitrate->BitRateL();
+	}
+	
+	
+void CMMFMdaAudioInputStream::SetBitRateL(TInt aBitRate)
+	{
+	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
+	if (ptr == NULL)
+		User::Leave(KErrNotSupported);
+	
+	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
+	bitrate->SetBitRateL(aBitRate);
+	}
+	
+void CMMFMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& 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<MMMFDevSoundCustomInterfaceBitRate*>(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<TDes8>* 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<TUint8*>(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<TUint8*>(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<TDes8>* firstItem;
+		while((firstItem = iFifo->Get()) != NULL)
+			{
+			iFifo->RemoveFirstItem();
+			delete firstItem;
+			}
+	 
+		iDevSound->Stop();
+		}
+	}