mmlibs/mmfw/src/Client/Audio/mmfclientaudioinputstream.cpp
changeset 0 b8ed18f6c07b
equal deleted inserted replaced
-1:000000000000 0:b8ed18f6c07b
       
     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 	}