First public contribution.
     1 // Copyright (c) 2002-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.
 
    16 #include "mmfclientaudioinputstream.h"
 
    17 #include "mmfclientaudiostreamutils.h"
 
    18 #include <mmf/server/devsoundstandardcustominterfaces.h>
 
    19 #include <mmf/common/mmfpaniccodes.h>
 
    21 #include <mdaaudioinputstream.h>
 
    23 const TInt KMicroSecsInOneSec = 1000000;
 
    26 enum TMmfAudioInputPanic
 
    28 	EAudioInputPanicNotSupported
 
    31 _LIT(KAudioInputStreamCategory, "CMMFMdaAudioInputStream");
 
    32 LOCAL_C void Panic(const TMmfAudioInputPanic aPanic)
 
    34 	User::Panic(KAudioInputStreamCategory, aPanic);
 
    41  * @return CMdaAudioInputStream*
 
    44 EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
 
    46 	return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
 
    53  * @return CMdaAudioInputStream*
 
    56 EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
 
    58 	CMdaAudioInputStream* self = new(ELeave) CMdaAudioInputStream();
 
    59 	CleanupStack::PushL(self);
 
    60 	self->iProperties = CMMFMdaAudioInputStream::NewL(aCallback, aPriority, aPref);
 
    61 	CleanupStack::Pop(self);
 
    65 CMdaAudioInputStream::CMdaAudioInputStream()
 
    69 CMdaAudioInputStream::~CMdaAudioInputStream()
 
    73 		iProperties->ShutDown();	
 
    79 EXPORT_C void CMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
 
    82 	iProperties->SetAudioPropertiesL(aSampleRate, aChannels);
 
    85 EXPORT_C void CMdaAudioInputStream::Open(TMdaPackage* aSettings)
 
    88 	iProperties->Open(aSettings);
 
    91 EXPORT_C void CMdaAudioInputStream::SetGain(TInt aNewGain)
 
    94 	iProperties->SetGain(aNewGain);
 
    97 EXPORT_C TInt CMdaAudioInputStream::Gain()  const
 
   100 	return iProperties->Gain();
 
   103 EXPORT_C TInt CMdaAudioInputStream::MaxGain()  const
 
   106 	return iProperties->MaxGain();
 
   109 EXPORT_C void CMdaAudioInputStream::SetBalanceL(TInt aBalance)
 
   112 	iProperties->SetBalanceL(aBalance);
 
   115 EXPORT_C TInt CMdaAudioInputStream::GetBalanceL() const
 
   118 	return iProperties->GetBalanceL();
 
   121 EXPORT_C void CMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
 
   124 	iProperties->SetPriority(aPriority, aPref);
 
   127 EXPORT_C void CMdaAudioInputStream::ReadL(TDes8& aData)
 
   130 	iProperties->ReadL(aData);
 
   133 EXPORT_C void CMdaAudioInputStream::Stop()
 
   139 EXPORT_C void CMdaAudioInputStream::RequestStop()
 
   142 	iProperties->RequestStop();
 
   145 EXPORT_C const TTimeIntervalMicroSeconds& CMdaAudioInputStream::Position()
 
   148 	return iProperties->Position();
 
   151 EXPORT_C TInt CMdaAudioInputStream::GetBytes()
 
   154 	return iProperties->GetBytes();
 
   157 EXPORT_C void CMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
 
   160 	iProperties->SetSingleBufferMode(aSingleMode);
 
   166 EXPORT_C void CMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
 
   169 	iProperties->SetDataTypeL(aAudioType);
 
   175 EXPORT_C TFourCC CMdaAudioInputStream::DataType() const
 
   178 	return iProperties->DataType();
 
   182 EXPORT_C TInt CMdaAudioInputStream::BitRateL() const
 
   185 	return iProperties->BitRateL();
 
   188 EXPORT_C void CMdaAudioInputStream::SetBitRateL(TInt aBitRate)
 
   191 	iProperties->SetBitRateL(aBitRate);
 
   195 EXPORT_C void CMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
 
   198 	iProperties->GetSupportedBitRatesL(aSupportedBitRates);
 
   201 EXPORT_C TAny* CMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
 
   204 	return iProperties->CustomInterface(aInterfaceId);
 
   209 CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
 
   211 	return CMMFMdaAudioInputStream::NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
 
   214 CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
 
   216 	CMMFMdaAudioInputStream* self = new(ELeave) CMMFMdaAudioInputStream(aCallback);
 
   217 	CleanupStack::PushL(self);
 
   218 	self->ConstructL(aPriority, aPref);
 
   219 	CleanupStack::Pop(self);
 
   226  * @param	"MMdaAudioInputStreamCallback&"
 
   227  *			a reference to MMdaAudioInputStreamCallback
 
   231 CMMFMdaAudioInputStream::CMMFMdaAudioInputStream(MMdaAudioInputStreamCallback& aCallback)
 
   232 	: iCallback(aCallback), iStorageItem (NULL, 0), iBufferPtr(NULL, 0)
 
   233 	// Depending on zero for construction (i.e. attribute of CBase)
 
   234 	//   iSingleBuffer (EFalse)
 
   237 	//   iCallbackMade(EFalse)
 
   238 	//   iAudioDataStored(EFalse)
 
   240 	iDataTypeCode.Set(TFourCC(' ','P','1','6'));
 
   245  *	Second phase constructor
 
   248 void CMMFMdaAudioInputStream::ConstructL(TInt aPriority, TInt aPref)
 
   250 	iDevSound = CMMFDevSound::NewL();
 
   251 	SetPriority(aPriority, aPref);
 
   252 	iFifo = new(ELeave) CMMFFifo<TDes8>();
 
   253 	iActiveCallback = new(ELeave) CActiveCallback(iCallback);
 
   254 	iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait;
 
   262 CMMFMdaAudioInputStream::~CMMFMdaAudioInputStream()
 
   266 	delete iActiveCallback;
 
   267 	delete iActiveSchedulerWait;
 
   272  *  Set audio input stream properties	
 
   274  *	@param	"TInt aSampleRate"	
 
   275  *			a specified priority value
 
   276  *	@param	"TInt aChannels"		
 
   277  *			a specified preference value
 
   280 void CMMFMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
 
   282 	if (iIsOpenState == EIsOpen)
 
   284 		RealSetAudioPropertiesL(aSampleRate, aChannels);
 
   288 		// cache for application later
 
   289 		iSettings.iSampleRate = aSampleRate;
 
   290 		iSettings.iChannels = aChannels;
 
   291 		iAudioDataStored = ETrue;
 
   295 void CMMFMdaAudioInputStream::RealSetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
 
   297 	TMMFCapabilities capabilities = iDevSound->Config();
 
   298 	capabilities.iChannels = StreamUtils::MapChannelsMdaToMMFL(aChannels);
 
   299 	capabilities.iRate = StreamUtils::MapSampleRateMdaToMMFL(aSampleRate);
 
   300 	iDevSound->SetConfigL(capabilities);
 
   305  *  Open a audio ouptut stream	
 
   307  *	@param	"TMdaPackage* Settings"	
 
   308  *			a pointer point to TMdaPackage
 
   311 void CMMFMdaAudioInputStream::Open(TMdaPackage* aSettings)
 
   313 	iIsOpenState = EIsOpening;
 
   315 	if (aSettings && (aSettings->Type().iUid == KUidMdaDataTypeSettingsDefine))
 
   317 		TMdaAudioDataSettings* tmpSettings = STATIC_CAST(TMdaAudioDataSettings*, aSettings);
 
   318 		iSettings = *tmpSettings;
 
   319 		iAudioDataStored = ETrue;
 
   321 	TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording));
 
   324 		// Signal for the MaiscOpenComplete callback to be called asynchronously
 
   325 		iActiveCallback->Signal(err);
 
   326 		iIsOpenState = EIsNotOpen;
 
   327 		iAudioDataStored = EFalse; // reset - if was set we throw away due to failure
 
   333  *  To get the maximum gain level	
 
   336  *			the maximum gain value in integer
 
   339 TInt CMMFMdaAudioInputStream::MaxGain() const
 
   341 	return iDevSound->MaxGain();
 
   346  *  To get the current gain level	
 
   349  *			the current gain value in integer
 
   352 TInt CMMFMdaAudioInputStream::Gain() const
 
   354 	return iDevSound->Gain();
 
   359  *  Set audio input stream gain to the specified value
 
   361  *	@param	"TInt aGain"	
 
   362  *			a specified gain value
 
   365 void CMMFMdaAudioInputStream::SetGain(TInt aGain)
 
   367 	iDevSound->SetGain(aGain);
 
   372  *  Set audio input stream balance	
 
   374  *	@param	"TInt aBalance"	
 
   375  *			a specified balance value
 
   378 void CMMFMdaAudioInputStream::SetBalanceL(TInt aBalance)
 
   380 	// test and clip balance to min / max range [-100 <-> 100]
 
   381 	// clip rather than leave as this isn't a leaving function
 
   382 	if (aBalance < KMMFBalanceMaxLeft) aBalance = KMMFBalanceMaxLeft;
 
   383 	if (aBalance > KMMFBalanceMaxRight) aBalance = KMMFBalanceMaxRight;
 
   385 	// separate out left and right balance
 
   388 	StreamUtils::CalculateLeftRightBalance( left, right, aBalance );
 
   390 	// send the balance to SoundDevice
 
   391 	iDevSound->SetRecordBalanceL(left, right);
 
   396  *  To get the current balance value.This function may not return the same value 
 
   397  *	as passed to SetBalanceL depending on the internal implementation in 
 
   398  *	the underlying components.
 
   401  *			the current balance value in integer
 
   404 TInt CMMFMdaAudioInputStream::GetBalanceL() const
 
   406 	TInt rightBalance = 0;
 
   407 	TInt leftBalance  = 0;
 
   408 	iDevSound->GetRecordBalanceL(leftBalance, rightBalance);
 
   410 	StreamUtils::CalculateBalance( balance, leftBalance, rightBalance );
 
   416  *  Set audio input stream priority	
 
   418  *	@param	"TInt aPriority"	
 
   419  *			a specified priority value
 
   420  *	@param	"TInt aPref"		
 
   421  *			a specified preference value
 
   424 void CMMFMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
 
   426 	TMMFPrioritySettings settings;
 
   427 	settings.iPriority = aPriority;
 
   428 	settings.iPref = aPref;
 
   429 	iDevSound->SetPrioritySettings(settings);
 
   435  *  To read data from input stream 	
 
   437  *	@param	"TDesC8& aData"	
 
   440  *  @capability	UserEnvironment
 
   441  *			For recording - the requesting client process must have the 
 
   442  *			UserEnvironment capability.
 
   444 void CMMFMdaAudioInputStream::ReadL(TDes8& aData)
 
   446 	User::LeaveIfError(Read(aData));
 
   448 	if (iState == EStopped)
 
   450 		iDevSound->RecordInitL();
 
   457  *  To read data from input stream 	
 
   459  *	@param	"TDesC8& aData"	
 
   462  *  @capability	UserEnvironment
 
   463  *			For recording - the requesting client process must have the 
 
   464  *			UserEnvironment capability.
 
   466 TInt CMMFMdaAudioInputStream::Read(TDes8& aData)
 
   468 	TMMFFifoItem<TDes8>* item = new TMMFFifoItem<TDes8>(aData);
 
   474 	iFifo->AddToFifo(*item);	// no issue with memory alloc
 
   475 								// each element contains storage space for link to the next
 
   481  *  To stop write data to stream 	
 
   484 void CMMFMdaAudioInputStream::Stop()
 
   486 	// Need to take for the case where Stop is invoked directly after a call to RequestStop.
 
   487 	// We have chosen to allow the Stop to go through as this could be more important.
 
   488 	// This is non-reentrant code but will suffice for our needs.
 
   489 	if (iState != EStopped)
 
   491 		// Amend the state so RequestStop or Stop initiated by it (indirectly) won't function
 
   494 		if (iSingleBuffer && iStorageItem.Ptr() != NULL)
 
   496 			iCallback.MaiscBufferCopied(KErrAbort, iStorageItem);
 
   497 			iStorageItem.Set (NULL,0,0);
 
   500 		// Delete all buffers in the fifo and notify the observer
 
   501 		TMMFFifoItem<TDes8>* firstItem;
 
   502 		while((firstItem = iFifo->Get()) != NULL)
 
   504 			iFifo->RemoveFirstItem();
 
   507 				iCallback.MaiscBufferCopied(KErrAbort,firstItem->GetData());		 		 		 		 
 
   519  *  To pause write data to stream 
 
   520  *  Allow yet unprocessed buffers to be processed and passed back via BufferToBeEmptied.
 
   521  *  When the last (empty) buffer arrives, Stop is called.
 
   523 void CMMFMdaAudioInputStream::RequestStop()
 
   525 	// [ precondition that we are not already stopped 
 
   526 	// && if we are stopped do nothing.
 
   527 	// If we are stopping a recording, we need to give the server a chance to 
 
   528 	// process that data which has already been captured. We therefore stay in the EPause
 
   530 	if (iState != EStopped)
 
   532 		if (iState != EStopping)
 
   534 			// We can only be Recording, if we have other states later they can be tested here.
 
   544  *  To get the current position in the data stream	
 
   546  *	@return	"TTimeIntervalMicroSeconds&"	
 
   547  *			the current position in integer
 
   550 const TTimeIntervalMicroSeconds& CMMFMdaAudioInputStream::Position()
 
   552 	TInt64 position = iDevSound->SamplesRecorded();
 
   553 	position = position * KMicroSecsInOneSec / StreamUtils::SampleRateAsValue(iDevSound->Config());
 
   554 	iPosition = (iState == ERecording) ? position : 0; // Shouldn't need to check for playing but CMMFDevSound doesn't reset bytes played after a stop
 
   562  *  To return the current number of bytes recorded by audio hardware
 
   563  *	@return "the current current number of bytes rendered by audio hardware in integer"	
 
   566 TInt CMMFMdaAudioInputStream::GetBytes()
 
   568 	return iBytesRecorded;
 
   571 void CMMFMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
 
   573 	if(iState != EStopped)
 
   574 		User::Leave(KErrServerBusy);
 
   576 	if(aAudioType == iDataTypeCode)
 
   579 	TMMFPrioritySettings prioritySettings ; 	
 
   580 	prioritySettings.iState = EMMFStateRecording;
 
   582 	RArray<TFourCC> supportedDataTypes;
 
   584 	CleanupClosePushL(supportedDataTypes);
 
   586 	TRAPD(err, iDevSound->GetSupportedOutputDataTypesL(supportedDataTypes, prioritySettings));
 
   590 		if (supportedDataTypes.Find(aAudioType) == KErrNotFound)
 
   592 			User::Leave(KErrNotSupported);	
 
   594 		//if match, set the 4CC of AudioType to match
 
   595 		iDataTypeCode.Set(aAudioType);
 
   597 	else //we had a real leave error from GetSupportedInputDataTypesL
 
   601 	CleanupStack::PopAndDestroy(&supportedDataTypes);
 
   603 	if(iIsOpenState!=EIsNotOpen)
 
   605 		// need to recall or restart InitializeL() process
 
   606 		iDevSound->CancelInitialize(); // call just in case mid-InitializeL. No harm if not. 
 
   607 									   // if not supported then assume old DevSound behaviour anyway
 
   608 									   // where InitializeL() implicitly cancels, so no harm either way
 
   609 		iIsOpenState = EIsOpening;
 
   610 		iInitCallFrmSetDataType = ETrue;
 
   611 		TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording));
 
   615 			iIsOpenState = EIsNotOpen;
 
   616 			iInitCallFrmSetDataType = EFalse;
 
   619 		// In some implementations InitializeComplete is sent 
 
   620 		// in context, so check before starting activeSchedulerWait.
 
   621 		else if(iIsOpenState == EIsOpening)
 
   623 			iInitializeState = KRequestPending;
 
   624 			iActiveSchedulerWait->Start();
 
   626 		iInitCallFrmSetDataType = EFalse;
 
   627 		User::LeaveIfError(iInitializeState);
 
   634 TFourCC CMMFMdaAudioInputStream::DataType() const
 
   636 	return iDataTypeCode;
 
   639 TInt CMMFMdaAudioInputStream::BitRateL() const
 
   641 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
 
   643 		User::Leave(KErrNotSupported);
 
   645 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
 
   646 	return bitrate->BitRateL();
 
   650 void CMMFMdaAudioInputStream::SetBitRateL(TInt aBitRate)
 
   652 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
 
   654 		User::Leave(KErrNotSupported);
 
   656 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
 
   657 	bitrate->SetBitRateL(aBitRate);
 
   660 void CMMFMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
 
   662 	// ensure that the array is empty before passing it in
 
   663 	aSupportedBitRates.Reset();
 
   664 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
 
   666 		User::Leave(KErrNotSupported);
 
   667 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
 
   668 	bitrate->GetSupportedBitRatesL(aSupportedBitRates);
 
   674 CMMFMdaAudioInputStream::CActiveCallback::CActiveCallback(MMdaAudioInputStreamCallback& aCallback)
 
   675 	: CActive(EPriorityStandard), iCallback(aCallback)
 
   677 	CActiveScheduler::Add(this);
 
   680 CMMFMdaAudioInputStream::CActiveCallback::~CActiveCallback()
 
   685 void CMMFMdaAudioInputStream::CActiveCallback::RunL()
 
   687 	iCallback.MaiscOpenComplete(iStatus.Int());
 
   690 void CMMFMdaAudioInputStream::CActiveCallback::DoCancel()
 
   694 void CMMFMdaAudioInputStream::CActiveCallback::Signal(const TInt aReason)
 
   698 	// Signal ourselves to run with the given completion code
 
   699 	TRequestStatus* status = &iStatus;
 
   700 	User::RequestComplete(status, aReason);
 
   708  *  To be called when intialize stream complete	
 
   710  *	@param	"TInt aError"	
 
   711  *			error code, initialize stream succeed when aError = 0
 
   714 void CMMFMdaAudioInputStream::InitializeComplete(TInt aError)
 
   717 	if(iIsOpenState == EIsOpening)
 
   721 			// Use settings to set audio properties after the dev sound has been
 
   722 			// successfully initialised
 
   725 				TRAP(err, RealSetAudioPropertiesL(iSettings.iSampleRate, iSettings.iChannels));
 
   730 		// Signal for the MaiscOpenComplete callback to be called asynchronously.Ignore if InitializeL is called from SetDataTypeL
 
   731 		if(!iInitCallFrmSetDataType)
 
   733 			iActiveCallback->Signal(err);
 
   735 		iIsOpenState = err ? EIsNotOpen : EIsOpen;
 
   736 		//reset iAudioDataStored flag if set - whatever don't want to use next time
 
   737 		iAudioDataStored = EFalse;
 
   738 		if(iInitializeState == KRequestPending)
 
   740 			iInitializeState = err;
 
   741 			iActiveSchedulerWait->AsyncStop();
 
   745 			iInitializeState = err;//Set the error.		
 
   755 void CMMFMdaAudioInputStream::ToneFinished(TInt /*aError*/)
 
   757 	Panic(EAudioInputPanicNotSupported);
 
   762  *  Called when sound device has filled data buffer
 
   764  *	@param	"CMMFBuffer* aBuffer"	
 
   765  *			a pointer point to CMMFBuffer, which is used for recieved data
 
   768 void CMMFMdaAudioInputStream::BufferToBeEmptied(CMMFBuffer* aBuffer)
 
   770 	// Simply put, tries to copy the data from aBuffer into the clients storage buffers. 
 
   772 	// The input stream iFifo data member is used to store the clients storage buffers
 
   773 	// that are passed to it via a call to ReadL.
 
   775 	// If iSingleBuffer is False, the first buffer on the fifo is copied to. 
 
   776 	// This buffer is then removed off the fifo.
 
   777 	// The callback MaiscBufferCopied is invoked after each copy, passing that buffer.
 
   778 	// If the data is greater than the buffer then this process repeats with the next buffer.
 
   780 	// If iSingleBuffer is True, it is assumed only one buffer is on the fifo.
 
   781 	// The behaviour is the same as above except that a descriptor representing the 
 
   782 	// buffers empty part is placed at the end of the fifo, and the callback 
 
   783 	// MaiscBufferCopied is invoked only when the buffer is full.
 
   785 	// If the client sets iSingleBuffer to True and places more than one buffer on the fifo
 
   786 	// the behaviour is undefined and unsupported.
 
   788 	// If there are no more storage buffers on the fifo, the callback 
 
   789 	// MaiscRecordComplete(KErrOverflow) is invoked.
 
   791 	const TDesC8& buffer = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();
 
   793 	TInt lengthCopied = 0;
 
   794 	iBytesRecorded += buffer.Length();
 
   796 	// A stop was requested after all the data has been received
 
   797 	if (iState == EStopping && buffer.Length() == 0)
 
   800 		iCallback.MaiscRecordComplete(KErrNone);
 
   805 		// The fifo may have multiple storage buffers, i.e. one in each of its entries.
 
   806 		// Fill what we can in each. If we get an empty buffer then we have finished recording.
 
   807 		while (lengthCopied < buffer.Length())
 
   809 			// Chop up aBuffer into slices the buffers in iFifo can handle
 
   810 			TMMFFifoItem<TDes8>* firstItem = iFifo->Get();
 
   812 			if(firstItem != NULL)
 
   814 				TDes8& writeBuf = firstItem->GetData();
 
   816 				// We have a spare buffer slot
 
   817 				TInt slotLength = Min(buffer.Length()-lengthCopied, writeBuf.MaxLength());
 
   818 				writeBuf = buffer.Mid(lengthCopied, slotLength);
 
   819 				lengthCopied += slotLength;
 
   821 				// Determine whether to callback the client or not.
 
   822 				// I.e. if we have multiple small buffers that we want to process quickly or
 
   823 				// when a singular buffer is FULL.
 
   824 				// Note: That if the client asks to Stop, the buffer may not be filled!
 
   827 					// Remember this item for later. 
 
   828 					// We really only want the first item as this covers the entire
 
   829 					// client storage buffer. We will adjust the actual length later.
 
   830 					if (iStorageItem.Ptr() == NULL)
 
   832 						iStorageItem.Set (const_cast<TUint8*>(writeBuf.Ptr()), 0, writeBuf.MaxLength());
 
   835 					// In this iteration we may just be looking at a right-part of the original
 
   836 					// buffer. Update the actual length of data.
 
   837 					TInt actualLength = (writeBuf.Ptr()-iStorageItem.Ptr()) + writeBuf.Length();
 
   838 					iStorageItem.SetLength(actualLength);
 
   840 					// Is the buffer full?
 
   841 					if (writeBuf.Length() == writeBuf.MaxLength())
 
   843 						// The singular buffer has been filled so pass it back to the client
 
   844 						iCallback.MaiscBufferCopied(KErrNone, iStorageItem);
 
   845 						iStorageItem.Set (NULL,0,0);
 
   849 						// Create a window to the 'remaining' free section of the storage buffer
 
   850 						iBufferPtr.Set (const_cast<TUint8*>(writeBuf.Ptr())+lengthCopied, 0, writeBuf.MaxLength()-lengthCopied);
 
   852 						// Add the window to the fifo
 
   853 						TInt err = Read(iBufferPtr);
 
   857 							iCallback.MaiscRecordComplete(err);
 
   860 						ASSERT(iState == ERecording);
 
   866 					iCallback.MaiscBufferCopied(KErrNone, writeBuf);
 
   868 				//Check if client called Stop from the MaiscBufferCopied. 
 
   869 				//If so, we should neither continue this loop nor delete the first item. Stop cleans up all the buffers
 
   870 				if(iState == EStopped)
 
   876 					// Remove this storage buffer from the fifo as we want to have access to any others behind it.
 
   877 					iFifo->RemoveFirstItem();
 
   883 				// run out of buffers - report an overflow error
 
   885 				iCallback.MaiscRecordComplete(KErrOverflow);
 
   891 	// Keep recording if there are free buffers
 
   892 	if (!iFifo->IsEmpty())
 
   893 		iDevSound->RecordData();
 
   898  *  Called when record operation complete, successfully or otherwise	
 
   900  *	@param	"TInt aError"	
 
   901  *			an error value which will indicate playing successfully complete
 
   902  *			if error value is 0
 
   905 void CMMFMdaAudioInputStream::PlayError(TInt /*aError*/)
 
   907 	Panic(EAudioInputPanicNotSupported);
 
   916 void CMMFMdaAudioInputStream::BufferToBeFilled(CMMFBuffer* /*aBuffer*/)
 
   918 	Panic(EAudioInputPanicNotSupported);
 
   926 void CMMFMdaAudioInputStream::RecordError(TInt aError)
 
   928 	if (iState == ERecording)
 
   930 		if (aError != KErrCancel)
 
   932 			iCallback.MaiscRecordComplete(aError);
 
   934 		// else must have been cancelled by client. Doesn't need to be notified
 
   945 void CMMFMdaAudioInputStream::ConvertError(TInt /*aError*/)
 
   947 	Panic(EAudioInputPanicNotSupported);
 
   955 void CMMFMdaAudioInputStream::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
 
   957 	Panic(EAudioInputPanicNotSupported);
 
   960 // CustomInferface - just pass on to DevSound. 
 
   961 TAny* CMMFMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
 
   963 	return iDevSound->CustomInterface(aInterfaceId);
 
   967 void CMMFMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
 
   969 	iSingleBuffer = aSingleMode;
 
   972 void CMMFMdaAudioInputStream::ShutDown()
 
   974 	// Need to take for the case where Stop is invoked from the destructor of CMdaAudioInputStream 
 
   975 	// Need to ensure that there are no callbacks to the client at this stage
 
   976 	if (iState != EStopped)
 
   980 		if (iSingleBuffer && iStorageItem.Ptr() != NULL)
 
   982 			iStorageItem.Set (NULL,0,0);
 
   985 		// Delete all buffers in the fifo
 
   986 		TMMFFifoItem<TDes8>* firstItem;
 
   987 		while((firstItem = iFifo->Get()) != NULL)
 
   989 			iFifo->RemoveFirstItem();