os/mm/mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "mmfclientaudioinputstream.h"
    17 #include "mmfclientaudiostreamutils.h"
    18 #include <mmf/server/devsoundstandardcustominterfaces.h>
    19 #include <mmf/common/mmfpaniccodes.h>
    20 #include "MmfFifo.h"
    21 #include <mdaaudioinputstream.h>
    22 
    23 const TInt KMicroSecsInOneSec = 1000000;
    24 
    25 
    26 enum TMmfAudioInputPanic
    27 	{
    28 	EAudioInputPanicNotSupported
    29 	};
    30 
    31 _LIT(KAudioInputStreamCategory, "CMMFMdaAudioInputStream");
    32 LOCAL_C void Panic(const TMmfAudioInputPanic aPanic)
    33 	{
    34 	User::Panic(KAudioInputStreamCategory, aPanic);
    35 	}
    36 
    37 /**
    38  *
    39  * Static NewL
    40  *
    41  * @return CMdaAudioInputStream*
    42  *
    43  */
    44 EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
    45 	{
    46 	return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
    47 	}
    48 
    49 /**
    50  *
    51  * Static NewL
    52  *
    53  * @return CMdaAudioInputStream*
    54  *
    55  */
    56 EXPORT_C CMdaAudioInputStream* CMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
    57 	{
    58 	CMdaAudioInputStream* self = new(ELeave) CMdaAudioInputStream();
    59 	CleanupStack::PushL(self);
    60 	self->iProperties = CMMFMdaAudioInputStream::NewL(aCallback, aPriority, aPref);
    61 	CleanupStack::Pop(self);
    62 	return self;
    63 	}
    64 
    65 CMdaAudioInputStream::CMdaAudioInputStream()
    66 	{
    67 	}
    68 
    69 CMdaAudioInputStream::~CMdaAudioInputStream()
    70 	{
    71 	if(iProperties)
    72 		{
    73 		iProperties->ShutDown();	
    74 		}
    75 	
    76 	delete iProperties;
    77 	}
    78 
    79 EXPORT_C void CMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
    80 	{
    81 	ASSERT(iProperties);
    82 	iProperties->SetAudioPropertiesL(aSampleRate, aChannels);
    83 	}
    84 
    85 EXPORT_C void CMdaAudioInputStream::Open(TMdaPackage* aSettings)
    86 	{
    87 	ASSERT(iProperties);
    88 	iProperties->Open(aSettings);
    89 	}
    90 
    91 EXPORT_C void CMdaAudioInputStream::SetGain(TInt aNewGain)
    92 	{
    93 	ASSERT(iProperties);
    94 	iProperties->SetGain(aNewGain);
    95 	}
    96 
    97 EXPORT_C TInt CMdaAudioInputStream::Gain()  const
    98 	{
    99 	ASSERT(iProperties);
   100 	return iProperties->Gain();
   101 	}
   102 
   103 EXPORT_C TInt CMdaAudioInputStream::MaxGain()  const
   104 	{
   105 	ASSERT(iProperties);
   106 	return iProperties->MaxGain();
   107 	}
   108 
   109 EXPORT_C void CMdaAudioInputStream::SetBalanceL(TInt aBalance)
   110 	{
   111 	ASSERT(iProperties);
   112 	iProperties->SetBalanceL(aBalance);
   113 	}
   114 
   115 EXPORT_C TInt CMdaAudioInputStream::GetBalanceL() const
   116 	{
   117 	ASSERT(iProperties);
   118 	return iProperties->GetBalanceL();
   119 	}
   120 
   121 EXPORT_C void CMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
   122 	{
   123 	ASSERT(iProperties);
   124 	iProperties->SetPriority(aPriority, aPref);
   125 	}
   126 
   127 EXPORT_C void CMdaAudioInputStream::ReadL(TDes8& aData)
   128 	{
   129 	ASSERT(iProperties);
   130 	iProperties->ReadL(aData);
   131 	}
   132 
   133 EXPORT_C void CMdaAudioInputStream::Stop()
   134 	{
   135 	ASSERT(iProperties);
   136 	iProperties->Stop();
   137 	}
   138 
   139 EXPORT_C void CMdaAudioInputStream::RequestStop()
   140 	{
   141 	ASSERT(iProperties);
   142 	iProperties->RequestStop();
   143 	}
   144 
   145 EXPORT_C const TTimeIntervalMicroSeconds& CMdaAudioInputStream::Position()
   146 	{
   147 	ASSERT(iProperties);
   148 	return iProperties->Position();
   149 	}
   150 
   151 EXPORT_C TInt CMdaAudioInputStream::GetBytes()
   152 	{
   153 	ASSERT(iProperties);
   154 	return iProperties->GetBytes();
   155 	}
   156 
   157 EXPORT_C void CMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
   158 	{
   159 	ASSERT(iProperties);
   160 	iProperties->SetSingleBufferMode(aSingleMode);
   161 	}
   162 
   163 /**
   164 
   165 */
   166 EXPORT_C void CMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
   167 	{
   168 	ASSERT(iProperties);
   169 	iProperties->SetDataTypeL(aAudioType);
   170 	}	
   171 
   172 /**
   173 
   174 */
   175 EXPORT_C TFourCC CMdaAudioInputStream::DataType() const
   176 	{
   177 	ASSERT(iProperties);
   178 	return iProperties->DataType();
   179 	}
   180 	
   181 	
   182 EXPORT_C TInt CMdaAudioInputStream::BitRateL() const
   183 	{
   184 	ASSERT(iProperties);
   185 	return iProperties->BitRateL();
   186 	}
   187 	
   188 EXPORT_C void CMdaAudioInputStream::SetBitRateL(TInt aBitRate)
   189 	{
   190 	ASSERT(iProperties);
   191 	iProperties->SetBitRateL(aBitRate);
   192 	}
   193 
   194 	
   195 EXPORT_C void CMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
   196 	{
   197 	ASSERT(iProperties);
   198 	iProperties->GetSupportedBitRatesL(aSupportedBitRates);
   199 	}
   200 
   201 EXPORT_C TAny* CMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
   202 	{
   203 	ASSERT(iProperties);
   204 	return iProperties->CustomInterface(aInterfaceId);
   205 	}
   206 
   207 //
   208 
   209 CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback)
   210 	{
   211 	return CMMFMdaAudioInputStream::NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
   212 	}
   213 
   214 CMMFMdaAudioInputStream* CMMFMdaAudioInputStream::NewL(MMdaAudioInputStreamCallback& aCallback, TInt aPriority, TInt aPref)
   215 	{
   216 	CMMFMdaAudioInputStream* self = new(ELeave) CMMFMdaAudioInputStream(aCallback);
   217 	CleanupStack::PushL(self);
   218 	self->ConstructL(aPriority, aPref);
   219 	CleanupStack::Pop(self);
   220 	return self;
   221 	}
   222 /**
   223  *
   224  * Construct
   225  *
   226  * @param	"MMdaAudioInputStreamCallback&"
   227  *			a reference to MMdaAudioInputStreamCallback
   228  *			a perference value
   229  *
   230  */
   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)
   235 	//   iState(EStopped)
   236 	//   iIsOpened(EFalse)
   237 	//   iCallbackMade(EFalse)
   238 	//   iAudioDataStored(EFalse)
   239 	{
   240 	iDataTypeCode.Set(TFourCC(' ','P','1','6'));
   241 	}
   242 
   243 /**
   244  *
   245  *	Second phase constructor
   246  *
   247  */
   248 void CMMFMdaAudioInputStream::ConstructL(TInt aPriority, TInt aPref)
   249 	{
   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;
   255 	}
   256 
   257 /**
   258  *
   259  *	Destructor
   260  *
   261  */
   262 CMMFMdaAudioInputStream::~CMMFMdaAudioInputStream()
   263 	{
   264 	delete iFifo;
   265 	delete iDevSound;
   266 	delete iActiveCallback;
   267 	delete iActiveSchedulerWait;
   268 	}
   269 
   270 /**
   271  *
   272  *  Set audio input stream properties	
   273  *
   274  *	@param	"TInt aSampleRate"	
   275  *			a specified priority value
   276  *	@param	"TInt aChannels"		
   277  *			a specified preference value
   278  *
   279  */
   280 void CMMFMdaAudioInputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
   281 	{
   282 	if (iIsOpenState == EIsOpen)
   283 		{
   284 		RealSetAudioPropertiesL(aSampleRate, aChannels);
   285 		}
   286 	else
   287 		{
   288 		// cache for application later
   289 		iSettings.iSampleRate = aSampleRate;
   290 		iSettings.iChannels = aChannels;
   291 		iAudioDataStored = ETrue;
   292 		}
   293 	}
   294 	
   295 void CMMFMdaAudioInputStream::RealSetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
   296 	{
   297 	TMMFCapabilities capabilities = iDevSound->Config();
   298 	capabilities.iChannels = StreamUtils::MapChannelsMdaToMMFL(aChannels);
   299 	capabilities.iRate = StreamUtils::MapSampleRateMdaToMMFL(aSampleRate);
   300 	iDevSound->SetConfigL(capabilities);
   301 	}
   302 
   303 /**
   304  *
   305  *  Open a audio ouptut stream	
   306  *
   307  *	@param	"TMdaPackage* Settings"	
   308  *			a pointer point to TMdaPackage
   309  *
   310  */
   311 void CMMFMdaAudioInputStream::Open(TMdaPackage* aSettings)
   312 	{
   313 	iIsOpenState = EIsOpening;
   314 	//store aSettings
   315 	if (aSettings && (aSettings->Type().iUid == KUidMdaDataTypeSettingsDefine))
   316 		{
   317 		TMdaAudioDataSettings* tmpSettings = STATIC_CAST(TMdaAudioDataSettings*, aSettings);
   318 		iSettings = *tmpSettings;
   319 		iAudioDataStored = ETrue;
   320 		}
   321 	TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording));
   322 	if (err != KErrNone)
   323 		{
   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
   328 		}
   329 	}
   330 
   331 /**
   332  *
   333  *  To get the maximum gain level	
   334  *
   335  *	@return	"TInt"	
   336  *			the maximum gain value in integer
   337  *
   338  */
   339 TInt CMMFMdaAudioInputStream::MaxGain() const
   340 	{
   341 	return iDevSound->MaxGain();
   342 	}
   343 
   344 /**
   345  *
   346  *  To get the current gain level	
   347  *
   348  *	@return	"TInt"	
   349  *			the current gain value in integer
   350  *
   351  */
   352 TInt CMMFMdaAudioInputStream::Gain() const
   353 	{
   354 	return iDevSound->Gain();
   355 	} 
   356 
   357 /**
   358  *
   359  *  Set audio input stream gain to the specified value
   360  *
   361  *	@param	"TInt aGain"	
   362  *			a specified gain value
   363  *
   364  */
   365 void CMMFMdaAudioInputStream::SetGain(TInt aGain)
   366 	{
   367 	iDevSound->SetGain(aGain);
   368 	}
   369 
   370 /**
   371  *
   372  *  Set audio input stream balance	
   373  *
   374  *	@param	"TInt aBalance"	
   375  *			a specified balance value
   376  *
   377  */
   378 void CMMFMdaAudioInputStream::SetBalanceL(TInt aBalance)
   379 	{
   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;
   384 
   385 	// separate out left and right balance
   386 	TInt left  = 0;
   387 	TInt right = 0;
   388 	StreamUtils::CalculateLeftRightBalance( left, right, aBalance );
   389 
   390 	// send the balance to SoundDevice
   391 	iDevSound->SetRecordBalanceL(left, right);
   392 	}
   393 
   394 /**
   395  *
   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.
   399  *
   400  *	@return	"TInt"	
   401  *			the current balance value in integer
   402  *
   403  */
   404 TInt CMMFMdaAudioInputStream::GetBalanceL() const
   405 	{
   406 	TInt rightBalance = 0;
   407 	TInt leftBalance  = 0;
   408 	iDevSound->GetRecordBalanceL(leftBalance, rightBalance);
   409 	TInt balance  = 0;
   410 	StreamUtils::CalculateBalance( balance, leftBalance, rightBalance );
   411 	return balance;
   412 	}
   413 
   414 /**
   415  *
   416  *  Set audio input stream priority	
   417  *
   418  *	@param	"TInt aPriority"	
   419  *			a specified priority value
   420  *	@param	"TInt aPref"		
   421  *			a specified preference value
   422  *
   423  */
   424 void CMMFMdaAudioInputStream::SetPriority(TInt aPriority, TInt aPref)
   425 	{
   426 	TMMFPrioritySettings settings;
   427 	settings.iPriority = aPriority;
   428 	settings.iPref = aPref;
   429 	iDevSound->SetPrioritySettings(settings);
   430 	}
   431 
   432 
   433 /**
   434  *
   435  *  To read data from input stream 	
   436  *
   437  *	@param	"TDesC8& aData"	
   438  *			a stream data 
   439  * 
   440  *  @capability	UserEnvironment
   441  *			For recording - the requesting client process must have the 
   442  *			UserEnvironment capability.
   443  */
   444 void CMMFMdaAudioInputStream::ReadL(TDes8& aData)
   445 	{
   446 	User::LeaveIfError(Read(aData));
   447 
   448 	if (iState == EStopped)
   449 		{
   450 		iDevSound->RecordInitL();
   451 		iState = ERecording;
   452 		}
   453 	}
   454 
   455 /**
   456  *
   457  *  To read data from input stream 	
   458  *
   459  *	@param	"TDesC8& aData"	
   460  *			a stream data 
   461  * 
   462  *  @capability	UserEnvironment
   463  *			For recording - the requesting client process must have the 
   464  *			UserEnvironment capability.
   465  */
   466 TInt CMMFMdaAudioInputStream::Read(TDes8& aData)
   467 	{
   468 	TMMFFifoItem<TDes8>* item = new TMMFFifoItem<TDes8>(aData);
   469 	if (!item)
   470 		{
   471 		return KErrNoMemory;
   472 		}
   473 
   474 	iFifo->AddToFifo(*item);	// no issue with memory alloc
   475 								// each element contains storage space for link to the next
   476 	return KErrNone;
   477 	}
   478 
   479 /**
   480  *
   481  *  To stop write data to stream 	
   482  *
   483  */
   484 void CMMFMdaAudioInputStream::Stop()
   485 	{
   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)
   490 		{
   491 		// Amend the state so RequestStop or Stop initiated by it (indirectly) won't function
   492 		iState = EStopped;
   493 
   494 		if (iSingleBuffer && iStorageItem.Ptr() != NULL)
   495 			{
   496 			iCallback.MaiscBufferCopied(KErrAbort, iStorageItem);
   497 			iStorageItem.Set (NULL,0,0);
   498 			}
   499 	 
   500 		// Delete all buffers in the fifo and notify the observer
   501 		TMMFFifoItem<TDes8>* firstItem;
   502 		while((firstItem = iFifo->Get()) != NULL)
   503 			{
   504 			iFifo->RemoveFirstItem();
   505 			if (!iSingleBuffer)
   506 				{
   507 				iCallback.MaiscBufferCopied(KErrAbort,firstItem->GetData());		 		 		 		 
   508 				}
   509 			delete firstItem;
   510 			}
   511 	 
   512 		iDevSound->Stop();
   513 		}
   514 	}
   515 
   516 
   517 /**
   518  *
   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.
   522  */
   523 void CMMFMdaAudioInputStream::RequestStop()
   524 	{
   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
   529 	// state.
   530 	if (iState != EStopped)
   531 		{
   532 		if (iState != EStopping)
   533 			{
   534 			// We can only be Recording, if we have other states later they can be tested here.
   535 			iDevSound->Pause();
   536 			iState = EStopping;
   537 			}
   538 		}
   539 	}
   540 
   541 
   542 /**
   543  *
   544  *  To get the current position in the data stream	
   545  *
   546  *	@return	"TTimeIntervalMicroSeconds&"	
   547  *			the current position in integer
   548  *
   549  */
   550 const TTimeIntervalMicroSeconds& CMMFMdaAudioInputStream::Position()
   551 	{
   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
   555 	return iPosition;
   556 	}
   557 
   558 
   559 
   560 /**
   561  *
   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"	
   564  *
   565  */
   566 TInt CMMFMdaAudioInputStream::GetBytes()
   567 	{
   568 	return iBytesRecorded;
   569 	}
   570 
   571 void CMMFMdaAudioInputStream::SetDataTypeL(TFourCC aAudioType)
   572 	{
   573 	if(iState != EStopped)
   574 		User::Leave(KErrServerBusy);
   575 
   576 	if(aAudioType == iDataTypeCode)
   577 		return;
   578 
   579 	TMMFPrioritySettings prioritySettings ; 	
   580 	prioritySettings.iState = EMMFStateRecording;
   581 	
   582 	RArray<TFourCC> supportedDataTypes;
   583 	
   584 	CleanupClosePushL(supportedDataTypes);
   585 
   586 	TRAPD(err, iDevSound->GetSupportedOutputDataTypesL(supportedDataTypes, prioritySettings));
   587 
   588 	if (err == KErrNone)
   589 		{
   590 		if (supportedDataTypes.Find(aAudioType) == KErrNotFound)
   591 			{
   592 			User::Leave(KErrNotSupported);	
   593 			}
   594 		//if match, set the 4CC of AudioType to match
   595 		iDataTypeCode.Set(aAudioType);
   596 		}
   597 	else //we had a real leave error from GetSupportedInputDataTypesL
   598 		{
   599 		User::Leave(err);	
   600 		}
   601 	CleanupStack::PopAndDestroy(&supportedDataTypes);
   602 
   603 	if(iIsOpenState!=EIsNotOpen)
   604 		{
   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));
   612 		if (err != KErrNone)
   613 			{
   614 			// Leave if error.
   615 			iIsOpenState = EIsNotOpen;
   616 			iInitCallFrmSetDataType = EFalse;
   617 			User::Leave(err);
   618 			}
   619 		// In some implementations InitializeComplete is sent 
   620 		// in context, so check before starting activeSchedulerWait.
   621 		else if(iIsOpenState == EIsOpening)
   622 			{
   623 			iInitializeState = KRequestPending;
   624 			iActiveSchedulerWait->Start();
   625 			}
   626 		iInitCallFrmSetDataType = EFalse;
   627 		User::LeaveIfError(iInitializeState);
   628 		}	
   629 	}
   630 
   631 /**
   632 
   633 */
   634 TFourCC CMMFMdaAudioInputStream::DataType() const
   635 	{
   636 	return iDataTypeCode;
   637 	}
   638 	
   639 TInt CMMFMdaAudioInputStream::BitRateL() const
   640 	{
   641 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
   642 	if (ptr == NULL)
   643 		User::Leave(KErrNotSupported);
   644 	
   645 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
   646 	return bitrate->BitRateL();
   647 	}
   648 	
   649 	
   650 void CMMFMdaAudioInputStream::SetBitRateL(TInt aBitRate)
   651 	{
   652 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
   653 	if (ptr == NULL)
   654 		User::Leave(KErrNotSupported);
   655 	
   656 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
   657 	bitrate->SetBitRateL(aBitRate);
   658 	}
   659 	
   660 void CMMFMdaAudioInputStream::GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
   661 	{
   662 	// ensure that the array is empty before passing it in
   663 	aSupportedBitRates.Reset();
   664 	TAny* ptr = iDevSound->CustomInterface(KUidCustomInterfaceDevSoundBitRate);
   665 	if (ptr == NULL)
   666 		User::Leave(KErrNotSupported);
   667 	MMMFDevSoundCustomInterfaceBitRate* bitrate = static_cast<MMMFDevSoundCustomInterfaceBitRate*>(ptr);
   668 	bitrate->GetSupportedBitRatesL(aSupportedBitRates);
   669 	}
   670 
   671 
   672 //
   673 
   674 CMMFMdaAudioInputStream::CActiveCallback::CActiveCallback(MMdaAudioInputStreamCallback& aCallback)
   675 	: CActive(EPriorityStandard), iCallback(aCallback)
   676 	{
   677 	CActiveScheduler::Add(this);
   678 	}
   679 
   680 CMMFMdaAudioInputStream::CActiveCallback::~CActiveCallback()
   681 	{
   682 	Cancel();
   683 	}
   684 
   685 void CMMFMdaAudioInputStream::CActiveCallback::RunL()
   686 	{
   687 	iCallback.MaiscOpenComplete(iStatus.Int());
   688 	}
   689 
   690 void CMMFMdaAudioInputStream::CActiveCallback::DoCancel()
   691 	{
   692 	}
   693 
   694 void CMMFMdaAudioInputStream::CActiveCallback::Signal(const TInt aReason)
   695 	{
   696 	ASSERT(!IsActive());
   697 
   698 	// Signal ourselves to run with the given completion code
   699 	TRequestStatus* status = &iStatus;
   700 	User::RequestComplete(status, aReason);
   701 	SetActive();
   702 	}
   703 
   704 //
   705 
   706 /**
   707  *
   708  *  To be called when intialize stream complete	
   709  *
   710  *	@param	"TInt aError"	
   711  *			error code, initialize stream succeed when aError = 0
   712  *
   713  */
   714 void CMMFMdaAudioInputStream::InitializeComplete(TInt aError)
   715 	{
   716 	TInt err = aError;
   717 	if(iIsOpenState == EIsOpening)
   718 		{
   719 		if (err == KErrNone)
   720 			{
   721 			// Use settings to set audio properties after the dev sound has been
   722 			// successfully initialised
   723 			if(iAudioDataStored)
   724 				{
   725 				TRAP(err, RealSetAudioPropertiesL(iSettings.iSampleRate, iSettings.iChannels));
   726 				}
   727 
   728 			}
   729 			
   730 		// Signal for the MaiscOpenComplete callback to be called asynchronously.Ignore if InitializeL is called from SetDataTypeL
   731 		if(!iInitCallFrmSetDataType)
   732 			{
   733 			iActiveCallback->Signal(err);
   734 			}
   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)
   739 			{
   740 			iInitializeState = err;
   741 			iActiveSchedulerWait->AsyncStop();
   742 			}
   743 		else
   744 			{
   745 			iInitializeState = err;//Set the error.		
   746 			}
   747 		}
   748 	}
   749 
   750 /**
   751  *
   752  *  Do not support
   753  *
   754  */
   755 void CMMFMdaAudioInputStream::ToneFinished(TInt /*aError*/)
   756 	{
   757 	Panic(EAudioInputPanicNotSupported);
   758 	}
   759 
   760 /**
   761  *
   762  *  Called when sound device has filled data buffer
   763  *
   764  *	@param	"CMMFBuffer* aBuffer"	
   765  *			a pointer point to CMMFBuffer, which is used for recieved data
   766  *
   767  */
   768 void CMMFMdaAudioInputStream::BufferToBeEmptied(CMMFBuffer* aBuffer)
   769 	{
   770 	// Simply put, tries to copy the data from aBuffer into the clients storage buffers. 
   771 	//
   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.
   774 	//
   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.
   779 	//
   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.
   784 	//
   785 	// If the client sets iSingleBuffer to True and places more than one buffer on the fifo
   786 	// the behaviour is undefined and unsupported.
   787 	//
   788 	// If there are no more storage buffers on the fifo, the callback 
   789 	// MaiscRecordComplete(KErrOverflow) is invoked.
   790 
   791 	const TDesC8& buffer = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();
   792 	
   793 	TInt lengthCopied = 0;
   794 	iBytesRecorded += buffer.Length();
   795 
   796 	// A stop was requested after all the data has been received
   797 	if (iState == EStopping && buffer.Length() == 0)
   798 		{
   799 	 	Stop();
   800 		iCallback.MaiscRecordComplete(KErrNone);
   801 		return;
   802 		}
   803 	else
   804 		{
   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())
   808 			{
   809 			// Chop up aBuffer into slices the buffers in iFifo can handle
   810 			TMMFFifoItem<TDes8>* firstItem = iFifo->Get();
   811 			
   812 			if(firstItem != NULL)
   813 				{
   814 				TDes8& writeBuf = firstItem->GetData();
   815 						
   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;
   820 				
   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!
   825 				if (iSingleBuffer)
   826 					{
   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)
   831 						{
   832 						iStorageItem.Set (const_cast<TUint8*>(writeBuf.Ptr()), 0, writeBuf.MaxLength());
   833 						}
   834 					
   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);
   839 
   840 					// Is the buffer full?
   841 					if (writeBuf.Length() == writeBuf.MaxLength())
   842 						{
   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);
   846 						}
   847 					else
   848 						{
   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);
   851 						
   852 						// Add the window to the fifo
   853 						TInt err = Read(iBufferPtr);
   854 						if (err)
   855 							{
   856 							Stop();
   857 							iCallback.MaiscRecordComplete(err);
   858 							return;
   859 							}
   860 						ASSERT(iState == ERecording);
   861 						}
   862 					}
   863 				else
   864 					{
   865 					// Notify client
   866 					iCallback.MaiscBufferCopied(KErrNone, writeBuf);
   867 					}
   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)
   871 					{
   872 					break;
   873 					}
   874 				else
   875 					{
   876 					// Remove this storage buffer from the fifo as we want to have access to any others behind it.
   877 					iFifo->RemoveFirstItem();
   878 					delete firstItem;						
   879 					}
   880 				}
   881 			else
   882 				{
   883 				// run out of buffers - report an overflow error
   884 				Stop();
   885 				iCallback.MaiscRecordComplete(KErrOverflow);
   886 				return;
   887 				}
   888 			}// while
   889 		} // else
   890 		
   891 	// Keep recording if there are free buffers
   892 	if (!iFifo->IsEmpty())
   893 		iDevSound->RecordData();
   894 	}
   895 
   896 /**
   897  *
   898  *  Called when record operation complete, successfully or otherwise	
   899  *
   900  *	@param	"TInt aError"	
   901  *			an error value which will indicate playing successfully complete
   902  *			if error value is 0
   903  *
   904  */
   905 void CMMFMdaAudioInputStream::PlayError(TInt /*aError*/)
   906 	{
   907 	Panic(EAudioInputPanicNotSupported);
   908 	}
   909 
   910 
   911 /**
   912  *
   913  *  Do not support
   914  *
   915  */
   916 void CMMFMdaAudioInputStream::BufferToBeFilled(CMMFBuffer* /*aBuffer*/)
   917 	{
   918 	Panic(EAudioInputPanicNotSupported);
   919 	}
   920 
   921 /**
   922  *
   923  *  Do not support
   924  *
   925  */
   926 void CMMFMdaAudioInputStream::RecordError(TInt aError)
   927 	{
   928 	if (iState == ERecording)
   929 		{
   930 		if (aError != KErrCancel)
   931 			{
   932 			iCallback.MaiscRecordComplete(aError);
   933 			}
   934 		// else must have been cancelled by client. Doesn't need to be notified
   935 
   936 		iState = EStopped;
   937 		}
   938 	}
   939 
   940 /**
   941  *
   942  *  Do not support
   943  *
   944  */
   945 void CMMFMdaAudioInputStream::ConvertError(TInt /*aError*/)
   946 	{
   947 	Panic(EAudioInputPanicNotSupported);
   948 	}
   949 
   950 /**
   951  *
   952  *  Do not support
   953  *
   954  */
   955 void CMMFMdaAudioInputStream::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
   956 	{
   957 	Panic(EAudioInputPanicNotSupported);
   958 	}
   959 
   960 // CustomInferface - just pass on to DevSound. 
   961 TAny* CMMFMdaAudioInputStream::CustomInterface(TUid aInterfaceId)
   962 	{
   963 	return iDevSound->CustomInterface(aInterfaceId);
   964 	}
   965 	
   966 
   967 void CMMFMdaAudioInputStream::SetSingleBufferMode(TBool aSingleMode)
   968 	{
   969 	iSingleBuffer = aSingleMode;
   970 	}
   971 
   972 void CMMFMdaAudioInputStream::ShutDown()
   973 	{
   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)
   977 		{
   978 		iState = EStopped;
   979 
   980 		if (iSingleBuffer && iStorageItem.Ptr() != NULL)
   981 			{
   982 			iStorageItem.Set (NULL,0,0);
   983 			}
   984 	 
   985 		// Delete all buffers in the fifo
   986 		TMMFFifoItem<TDes8>* firstItem;
   987 		while((firstItem = iFifo->Get()) != NULL)
   988 			{
   989 			iFifo->RemoveFirstItem();
   990 			delete firstItem;
   991 			}
   992 	 
   993 		iDevSound->Stop();
   994 		}
   995 	}