mmlibs/mmfw/src/Client/Audio/mmfclientaudiooutputstream.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 <mdaaudiooutputstream.h>
       
    17 #include <mda/common/audio.h>
       
    18 #include "mmfclientaudiooutputstream.h"
       
    19 #include "mmfclientaudiostreamutils.h"
       
    20 #include "MmfFifo.h"
       
    21 #include <mmf/common/mmfpaniccodes.h>
       
    22 
       
    23 #define WAIT_FOR_READY_ACTIVE_OBJECTS
       
    24 
       
    25 const TInt KMicroSecsInOneSec = 1000000; 
       
    26 const TInt KUnknownVolume = -1; // means "don't set", must be negative
       
    27 const TInt KShutDownTimeInterval = 100000; //100 milli seconds
       
    28 
       
    29 /**
       
    30  *
       
    31  * Static NewL
       
    32  *
       
    33  * @return CMdaAudioOutputStream*
       
    34  *
       
    35  */
       
    36 EXPORT_C CMdaAudioOutputStream* CMdaAudioOutputStream::NewL(MMdaAudioOutputStreamCallback& aCallback,
       
    37 															CMdaServer* /*aServer = NULL*/)
       
    38 	{
       
    39 	return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
       
    40 	}
       
    41 
       
    42 /**
       
    43  *
       
    44  * Static NewL
       
    45  *
       
    46  * @return CMdaAudioOutputStream*
       
    47  *
       
    48  */
       
    49 EXPORT_C CMdaAudioOutputStream* CMdaAudioOutputStream::NewL(MMdaAudioOutputStreamCallback& aCallback,
       
    50 															TInt aPriority,
       
    51 															TInt aPref /*=EMdaPriorityPreferenceTimeAndQuality*/)
       
    52 	{
       
    53 	CMdaAudioOutputStream* self = new(ELeave) CMdaAudioOutputStream();
       
    54 	CleanupStack::PushL(self);
       
    55 	self->iProperties = CMMFMdaAudioOutputStream::NewL(aCallback, aPriority, aPref);
       
    56 	CleanupStack::Pop(self);
       
    57 	return self;
       
    58 	}
       
    59 
       
    60 CMdaAudioOutputStream::CMdaAudioOutputStream()
       
    61 	{
       
    62 	}
       
    63 
       
    64 CMdaAudioOutputStream::~CMdaAudioOutputStream()
       
    65 	{
       
    66 	delete iProperties;
       
    67 	}
       
    68 
       
    69 void CMdaAudioOutputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
       
    70 	{
       
    71 	ASSERT(iProperties);
       
    72 	iProperties->SetAudioPropertiesL(aSampleRate, aChannels);
       
    73 	}
       
    74 
       
    75 void CMdaAudioOutputStream::Open(TMdaPackage* aSettings)
       
    76 	{
       
    77 	ASSERT(iProperties);
       
    78 	iProperties->Open(aSettings);
       
    79 	}
       
    80 
       
    81 TInt CMdaAudioOutputStream::MaxVolume()
       
    82 	{
       
    83 	ASSERT(iProperties);
       
    84 	return iProperties->MaxVolume();
       
    85 	}
       
    86 
       
    87 TInt CMdaAudioOutputStream::Volume()
       
    88 	{
       
    89 	ASSERT(iProperties);
       
    90 	return iProperties->Volume();
       
    91 	}
       
    92 
       
    93 void CMdaAudioOutputStream::SetVolume(const TInt aNewVolume)
       
    94 	{
       
    95 	ASSERT(iProperties);
       
    96 	iProperties->SetVolume(aNewVolume);
       
    97 	}
       
    98 
       
    99 void CMdaAudioOutputStream::SetPriority(TInt aPriority, TInt aPref)
       
   100 	{
       
   101 	ASSERT(iProperties);
       
   102 	iProperties->SetPriority(aPriority, aPref);
       
   103 	}
       
   104 
       
   105 void CMdaAudioOutputStream::WriteL(const TDesC8& aData)
       
   106 	{
       
   107 	ASSERT(iProperties);
       
   108 	iProperties->WriteL(aData);
       
   109 	}
       
   110 
       
   111 void CMdaAudioOutputStream::Stop()
       
   112 	{
       
   113 	ASSERT(iProperties);
       
   114 	iProperties->Stop();
       
   115 	}
       
   116 
       
   117 EXPORT_C TInt CMdaAudioOutputStream::Pause()
       
   118 	{
       
   119 	ASSERT(iProperties);
       
   120 	return iProperties->Pause();
       
   121 	}
       
   122 
       
   123 EXPORT_C TInt CMdaAudioOutputStream::Resume()
       
   124 	{
       
   125 	ASSERT(iProperties);
       
   126 	return iProperties->Resume();
       
   127 	}
       
   128 
       
   129 const TTimeIntervalMicroSeconds& CMdaAudioOutputStream::Position()
       
   130 	{
       
   131 	ASSERT(iProperties);
       
   132 	return iProperties->Position();
       
   133 	}
       
   134 
       
   135 EXPORT_C void CMdaAudioOutputStream::SetBalanceL(TInt aBalance)
       
   136 	{
       
   137 	ASSERT(iProperties);
       
   138 	iProperties->SetBalanceL(aBalance);
       
   139 	}
       
   140 
       
   141 EXPORT_C TInt CMdaAudioOutputStream::GetBalanceL() const
       
   142 	{
       
   143 	ASSERT(iProperties);
       
   144 	return iProperties->GetBalanceL();
       
   145 	}
       
   146 
       
   147 EXPORT_C TInt CMdaAudioOutputStream::GetBytes()
       
   148 	{
       
   149 	ASSERT(iProperties);
       
   150 	return iProperties->GetBytes();
       
   151 	}
       
   152 
       
   153 EXPORT_C TInt CMdaAudioOutputStream::KeepOpenAtEnd()
       
   154 	{
       
   155 	ASSERT(iProperties);
       
   156 	return iProperties->KeepOpenAtEnd();
       
   157 	}
       
   158 
       
   159 EXPORT_C TInt CMdaAudioOutputStream::RequestStop()
       
   160 	{
       
   161 	ASSERT(iProperties);
       
   162 	return iProperties->RequestStop();
       
   163 	}	
       
   164 	
       
   165 /**
       
   166 
       
   167 */
       
   168 EXPORT_C void CMdaAudioOutputStream::SetDataTypeL(TFourCC aAudioType)
       
   169 	{
       
   170 	ASSERT(iProperties);
       
   171 	iProperties->SetDataTypeL(aAudioType);
       
   172 	}	
       
   173 
       
   174 
       
   175 /**
       
   176 
       
   177 */
       
   178 EXPORT_C TFourCC CMdaAudioOutputStream::DataType() const
       
   179 	{
       
   180 	ASSERT(iProperties);
       
   181 	return iProperties->DataType();
       
   182 	}
       
   183 	
       
   184 EXPORT_C TAny* CMdaAudioOutputStream::CustomInterface(TUid aInterfaceId)
       
   185 	{
       
   186 	ASSERT(iProperties);
       
   187 	return iProperties->CustomInterface(aInterfaceId);
       
   188 	}
       
   189 	
       
   190 
       
   191 /**
       
   192 Registers the Event for Notification when resource is avaliable.
       
   193 
       
   194 @param  aCallback
       
   195 		The audio player observer interface.
       
   196 @param  aNotificationEventUid
       
   197 		The event uid to notify the client.
       
   198 @param  aNotificationRegistrationData
       
   199 		Notification registration specific data.
       
   200 
       
   201 @return An error code indicating if the registration was successful. KErrNone on success, 
       
   202 		otherwise another of the system-wide error codes.
       
   203 */
       
   204 EXPORT_C TInt CMdaAudioOutputStream::RegisterAudioResourceNotification(MMMFAudioResourceNotificationCallback& aCallback,
       
   205 																		TUid aNotificationEventUid,
       
   206 																		const TDesC8& aNotificationRegistrationData)
       
   207 	{
       
   208 	ASSERT(iProperties);
       
   209 	return iProperties->RegisterAudioResourceNotification(aCallback,aNotificationEventUid,aNotificationRegistrationData);
       
   210 	}
       
   211 
       
   212 /**
       
   213 Cancels the registered notification event.
       
   214 
       
   215 @param  aNotificationEventUid
       
   216 	The Event to notify the client.
       
   217 	
       
   218 @return An error code indicating if the registration was successful. KErrNone on success, 
       
   219 	otherwise another of the system-wide error codes.
       
   220 */
       
   221 EXPORT_C TInt CMdaAudioOutputStream::CancelRegisterAudioResourceNotification(TUid aNotificationEventUid)	
       
   222 	{
       
   223 	ASSERT(iProperties);
       
   224 	return iProperties->CancelRegisterAudioResourceNotification(aNotificationEventUid);
       
   225 	}
       
   226 
       
   227 /**
       
   228 Waits for the client to resume the play even after the default timer expires.
       
   229 
       
   230 @return An error code indicating if the registration was successful. KErrNone on success, 
       
   231 		otherwise another of the system-wide error codes.
       
   232 */
       
   233 EXPORT_C TInt CMdaAudioOutputStream::WillResumePlay()	
       
   234 	{
       
   235 	ASSERT(iProperties);
       
   236 	return iProperties->WillResumePlay();
       
   237 	}
       
   238 
       
   239 enum TMmAosPanic
       
   240 	{
       
   241 	EToneFinishedNotSupported,
       
   242 	EBufferToBeEmptiedNotSupported,
       
   243 	ERecordErrorNotSupported,
       
   244 	EConvertErrorNotSupported,
       
   245 	EDeviceMessageNotSupported,
       
   246 	EReservedCall,
       
   247 	EAOSStoppingError
       
   248 	};
       
   249 
       
   250 _LIT(KMmfMdaAosCategory, "CMmfMdaAudioOutputStream");
       
   251 LOCAL_C void Panic(const TMmAosPanic aReason)
       
   252 	{
       
   253 	User::Panic(KMmfMdaAosCategory, aReason);
       
   254 	}
       
   255 
       
   256 /**
       
   257  *
       
   258  * 2 phase construction function
       
   259  *
       
   260  */
       
   261 CMMFMdaAudioOutputStream* CMMFMdaAudioOutputStream::NewL(MMdaAudioOutputStreamCallback& aCallback)
       
   262 	{
       
   263 	return NewL(aCallback, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
       
   264 	}
       
   265 
       
   266 CMMFMdaAudioOutputStream* CMMFMdaAudioOutputStream::NewL(MMdaAudioOutputStreamCallback& aCallback, TInt aPriority, TInt aPref)
       
   267 	{
       
   268 	CMMFMdaAudioOutputStream* self = new(ELeave) CMMFMdaAudioOutputStream(aCallback);
       
   269 	CleanupStack::PushL(self);
       
   270 	self->ConstructL(aPriority, aPref);
       
   271 	CleanupStack::Pop(); // self
       
   272 	return self;
       
   273 	}
       
   274 
       
   275 /**
       
   276  *
       
   277  * Construct
       
   278  *
       
   279  * @param	"MMdaAudioOutputStreamCallback&"
       
   280  *			a reference to MMdaAudioOutputStreamCallback
       
   281  * @param	"TInt aPriority"
       
   282  *			a priority value			
       
   283  * @param	"TInt aPref"
       
   284  *			a perference value
       
   285  *
       
   286  */
       
   287 CMMFMdaAudioOutputStream::CMMFMdaAudioOutputStream(MMdaAudioOutputStreamCallback& aCallback)
       
   288 	: iCallback(aCallback), iState(EStopped)
       
   289 	{
       
   290 	iDataTypeCode.Set(TFourCC(' ','P','1','6'));
       
   291 	}
       
   292 
       
   293 /**
       
   294  *
       
   295  *	Second phase constructor
       
   296  *
       
   297  */
       
   298 void CMMFMdaAudioOutputStream::ConstructL(TInt aPriority, TInt aPref)
       
   299 	{
       
   300 	iDevSound = CMMFDevSound::NewL();
       
   301 	SetPriority(aPriority, aPref);
       
   302 	iDevSoundIgnoresUnderflow = iDevSound->QueryIgnoresUnderflow();
       
   303 	iFifo = new(ELeave) CMMFFifo<const TDesC8>();
       
   304 	iActiveCallback = new(ELeave) CActiveCallback(iCallback);
       
   305 	iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait;
       
   306 	iShutDownTimer = CPeriodic::NewL(CActive::EPriorityStandard);
       
   307 	}
       
   308 
       
   309 /**
       
   310  *
       
   311  *	Destructor
       
   312  *
       
   313  */
       
   314 CMMFMdaAudioOutputStream::~CMMFMdaAudioOutputStream()
       
   315 	{
       
   316 	delete iFifo;
       
   317 	delete iDevSound;
       
   318 	delete iActiveCallback;
       
   319 	delete iActiveSchedulerWait;
       
   320 	delete iShutDownTimer;
       
   321 	}
       
   322 
       
   323 /**
       
   324  *
       
   325  *  Set audio output stream properties	
       
   326  *
       
   327  *	@param	"TInt aSampleRate"	
       
   328  *			a specified priority value
       
   329  *	@param	"TInt aChannels"		
       
   330  *			a specified preference value
       
   331  *
       
   332  */
       
   333 void CMMFMdaAudioOutputStream::SetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
       
   334 	{
       
   335 	if (iIsOpenState==EIsOpen)
       
   336 		{
       
   337 		RealSetAudioPropertiesL(aSampleRate, aChannels);
       
   338 		}
       
   339 	else
       
   340 		{
       
   341 		// cache params for application later
       
   342 		iSampleRate = aSampleRate;
       
   343 		iChannels = aChannels;
       
   344 		iVolume = KUnknownVolume;
       
   345 		iValuesCached = ETrue;
       
   346 		}
       
   347 	}
       
   348 
       
   349 void CMMFMdaAudioOutputStream::RealSetAudioPropertiesL(TInt aSampleRate, TInt aChannels)
       
   350 	{
       
   351 	TMMFCapabilities config = iDevSound->Config();
       
   352 	config.iChannels = StreamUtils::MapChannelsMdaToMMFL(aChannels);
       
   353 	config.iRate = StreamUtils::MapSampleRateMdaToMMFL(aSampleRate);
       
   354 	iDevSound->SetConfigL(config);
       
   355 	}
       
   356 
       
   357 /**
       
   358  *
       
   359  *  Open a audio ouptut stream	
       
   360  *
       
   361  *	@param	"TMdaPackage* Settings"	
       
   362  *			a pointer point to TMdaPackage
       
   363  *
       
   364  */
       
   365 void CMMFMdaAudioOutputStream::Open(TMdaPackage* aSettings)
       
   366 	{
       
   367 	iIsOpenState = EIsOpening;
       
   368 	
       
   369 	// Use settings to set audio properties after the dev sound has been
       
   370 	// successfully initialised. Note if the InitializeL() fails, something calls
       
   371 	// InitializeComplete() and the iValuesCached flag is cleared. Also note
       
   372 	// that if SetAudioPropertiesL() has already been called, there may already
       
   373 	// be cached values
       
   374 	if (aSettings && aSettings->Type().iUid == KUidMdaDataTypeSettingsDefine)
       
   375 		{
       
   376 		TMdaAudioDataSettings& audioSettings = *STATIC_CAST(TMdaAudioDataSettings*, aSettings);
       
   377 		//Caching these values, which are later set in InitializeComplete
       
   378 		iSampleRate = audioSettings.iSampleRate;
       
   379 		iChannels = audioSettings.iChannels;
       
   380 		iVolume = audioSettings.iVolume;
       
   381 		iValuesCached = ETrue;
       
   382 		}
       
   383 
       
   384 	TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStatePlaying));
       
   385 	if (err != KErrNone)
       
   386 		{
       
   387 		InitializeComplete(err);
       
   388 		}
       
   389 	}
       
   390 
       
   391 /**
       
   392  *
       
   393  *  To get the maximum volume level	
       
   394  *
       
   395  *	@return	"TInt"	
       
   396  *			the maximum volume value in integer
       
   397  *
       
   398  */
       
   399 TInt CMMFMdaAudioOutputStream::MaxVolume()
       
   400 	{
       
   401 	return iDevSound->MaxVolume();
       
   402 	}
       
   403 
       
   404 /**
       
   405  *
       
   406  *  To get the current volume level	
       
   407  *
       
   408  *	@return	"TInt"	
       
   409  *			the current volume value in integer
       
   410  *
       
   411  */
       
   412 TInt CMMFMdaAudioOutputStream::Volume()
       
   413 	{
       
   414 	return iDevSound->Volume();
       
   415 	} 
       
   416 
       
   417 /**
       
   418  *
       
   419  *  Set audio output stream volume to the specified value
       
   420  *
       
   421  *	@param	"TInt aVolume"	
       
   422  *			a specified volume value
       
   423  *
       
   424  */
       
   425 void CMMFMdaAudioOutputStream::SetVolume(TInt aVolume)
       
   426 	{
       
   427 	iDevSound->SetVolume(aVolume);
       
   428 	}
       
   429 
       
   430 /**
       
   431  *
       
   432  *  Set audio output stream balance	
       
   433  *
       
   434  *	@param	"TInt aBalance"	
       
   435  *			a specified balance value
       
   436  *
       
   437  */
       
   438 void CMMFMdaAudioOutputStream::SetBalanceL(TInt aBalance)
       
   439 	{
       
   440 	// test and clip balance to min / max range [-100 <-> 100]
       
   441 	// clip rather than leave as this isn't a leaving function
       
   442 	if (aBalance < KMMFBalanceMaxLeft) aBalance = KMMFBalanceMaxLeft;
       
   443 	if (aBalance > KMMFBalanceMaxRight) aBalance = KMMFBalanceMaxRight;
       
   444 
       
   445 	// separate out left and right balance
       
   446 	TInt left  = 0;
       
   447 	TInt right = 0;
       
   448 	StreamUtils::CalculateLeftRightBalance( left, right, aBalance );
       
   449 
       
   450 	// send the balance to SoundDevice
       
   451 	iDevSound->SetPlayBalanceL(left, right);
       
   452 	}
       
   453 
       
   454 /**
       
   455  *
       
   456  *  To get the current balance value. This function may not return the same value 
       
   457  *	as passed to SetBalanceL depending on the internal implementation in 
       
   458  *	the underlying components.
       
   459  *	
       
   460  *	@return	"TInt"	
       
   461  *			the current balance value in integer
       
   462  *
       
   463  */
       
   464 TInt CMMFMdaAudioOutputStream::GetBalanceL() const
       
   465 	{
       
   466 	TInt rightBalance = 0;
       
   467 	TInt leftBalance  = 0;
       
   468 	iDevSound->GetPlayBalanceL(leftBalance, rightBalance);
       
   469 	TInt balance  = 0;
       
   470 	StreamUtils::CalculateBalance( balance, leftBalance, rightBalance );
       
   471 	return balance;
       
   472 	}
       
   473 
       
   474 /**
       
   475  *
       
   476  *  Set audio output stream priority	
       
   477  *
       
   478  *	@param	"TInt aPriority"	
       
   479  *			a specified priority value
       
   480  *	@param	"TMdaPriorityPreference aPref"		
       
   481  *			a specified preference value
       
   482  *
       
   483  */
       
   484 void CMMFMdaAudioOutputStream::SetPriority(TInt aPriority, TInt aPref)
       
   485 	{
       
   486 	TMMFPrioritySettings settings;
       
   487 	settings.iPriority = aPriority;
       
   488 	settings.iPref = aPref;
       
   489 	iDevSound->SetPrioritySettings(settings);
       
   490 	}
       
   491 
       
   492 /**
       
   493  *
       
   494  *  To write data to output stream 	
       
   495  *  Note that if framed data eg gsm610 is being streamed then the buffer
       
   496  *  size of aData should contain an intiger number of frames
       
   497  *
       
   498  *	@param	"const TDesC8& aData"	
       
   499  *			a stream data 
       
   500  *
       
   501  */
       
   502 void CMMFMdaAudioOutputStream::WriteL(const TDesC8& aData)
       
   503 	{
       
   504 	if(iState==EStopping)
       
   505 		{
       
   506 		User::Leave(KErrNotReady);
       
   507 		}
       
   508 	iShutDownTimer->Cancel();
       
   509 	
       
   510 	TMMFFifoItem<const TDesC8>* item = new(ELeave) TMMFFifoItem<const TDesC8>(aData);
       
   511 	iFifo->AddToFifo(*item);
       
   512 
       
   513 	if(iState == EStopped)
       
   514 		StartPlayL();
       
   515 	else if((iState == EPlaying) && (iBuffer != NULL))
       
   516 		{ //if we are playing and we have a buffer waiting for data, use it.
       
   517 		BufferToBeFilled(iBuffer);
       
   518 		iBuffer = NULL;
       
   519 		}
       
   520 	if(iEventHolder != KNullUid)
       
   521 		{
       
   522 		TInt err = iDevSound->RegisterAsClient(iEventHolder,iNotificationDataHolder);
       
   523 		iEventHolder = KNullUid;
       
   524 		iNotificationDataHolder = KNullDesC8;
       
   525 		if(err != KErrNone)
       
   526 			{
       
   527 			iCallback.MaoscPlayComplete(err);
       
   528 			}
       
   529 		}
       
   530 	}
       
   531 
       
   532 /**
       
   533  *
       
   534  * If the audio stream is stopped, then notify the CDevSound to initilised play.
       
   535  * The CDevSound will automatically start calling back for buffers.
       
   536  */
       
   537 void CMMFMdaAudioOutputStream::StartPlayL()
       
   538 {
       
   539 	if (iState == EStopped)
       
   540 		{
       
   541 		iFifoItemPos = 0;
       
   542 		iCurrentSamplesPlayed = 0;
       
   543 		iDevSound->PlayInitL();
       
   544 		iState = EPlaying;
       
   545 		iBuffer = NULL;
       
   546 		}
       
   547 }
       
   548 
       
   549 
       
   550 /**
       
   551  *
       
   552  *  To stop write data to stream 	
       
   553  *
       
   554  */
       
   555 void CMMFMdaAudioOutputStream::Stop()
       
   556 	{
       
   557 	iShutDownTimer->Cancel();
       
   558 	EmptyFifo(KErrAbort);
       
   559 
       
   560 	if(iState == EStopped)
       
   561 		{
       
   562 		return;
       
   563 		}
       
   564 		
       
   565 	// stop the operation
       
   566 	iDevSound->Stop();
       
   567 	iState = EStopped;
       
   568 	iBuffer = NULL;
       
   569 
       
   570 	iCallback.MaoscPlayComplete(KErrCancel);
       
   571 	}
       
   572 
       
   573 TInt CMMFMdaAudioOutputStream::RequestStop()
       
   574 	{
       
   575 	if(!iKeepOpenAtEnd)
       
   576 		{
       
   577 		return KErrNotSupported;
       
   578 		}
       
   579 	
       
   580 	if(iState==EStopped || iState==EStopping)
       
   581 		{
       
   582 		return KErrNotReady;
       
   583 		}
       
   584 		
       
   585 	if(iBuffer)
       
   586 		{//means all the client buffers are used up and waiting for more data
       
   587 		CMMFDataBuffer* dataBuffer = static_cast<CMMFDataBuffer*>(iBuffer);
       
   588 		dataBuffer->Data().SetLength(0);
       
   589 		dataBuffer->SetLastBuffer(ETrue);
       
   590 		iDevSound->PlayData();
       
   591 		iBuffer=NULL;
       
   592 		}
       
   593 	iState = EStopping;
       
   594 	return KErrNone;
       
   595 	}
       
   596 
       
   597 TInt CMMFMdaAudioOutputStream::KeepOpenAtEnd()
       
   598 	{
       
   599 	if(!iDevSoundIgnoresUnderflow)
       
   600 		{
       
   601 		return KErrNotSupported;
       
   602 		}
       
   603 	else
       
   604 		{
       
   605 		iKeepOpenAtEnd = ETrue;
       
   606 		return KErrNone;
       
   607 		}
       
   608 	}
       
   609 
       
   610 /**
       
   611  *
       
   612  *  To pause send data to stream 	
       
   613  *
       
   614  */
       
   615 TInt CMMFMdaAudioOutputStream::Pause()
       
   616 	{
       
   617 	if(iState != EPlaying)
       
   618 		{
       
   619 		return KErrNotReady;
       
   620 		}
       
   621 
       
   622 	else if(!iDevSound->IsResumeSupported())
       
   623 		{
       
   624 		return KErrNotSupported;
       
   625 		}
       
   626 	
       
   627 	// pause the operation
       
   628 	iDevSound->Pause();
       
   629 	iState = EPaused;
       
   630 	return KErrNone;
       
   631 	}
       
   632 
       
   633 /**
       
   634  *
       
   635  *  To resume send data to stream 	
       
   636  *
       
   637  */
       
   638 TInt CMMFMdaAudioOutputStream::Resume()
       
   639 	{
       
   640 	TInt err = KErrNone;
       
   641 	if(iState != EPaused)
       
   642 		{
       
   643 		err = KErrNotReady;
       
   644 		}
       
   645 	else if(!iDevSound->IsResumeSupported())
       
   646 		{
       
   647 		err = KErrNotSupported;
       
   648 		}
       
   649 	
       
   650 	// resume the operation
       
   651 	if(err == KErrNone)
       
   652 		{
       
   653 		err = iDevSound->Resume();
       
   654 		}
       
   655 	if(err == KErrNone)
       
   656 		{
       
   657 		iState = EPlaying;
       
   658 		}
       
   659 
       
   660 	return err;
       
   661 	}
       
   662 
       
   663 
       
   664 /**
       
   665  *
       
   666  *  To get the current position in the data stream	
       
   667  *
       
   668  *	@return	"TTimeIntervalMicroSeconds&"	
       
   669  *			the current position in integer
       
   670  *
       
   671  */
       
   672 const TTimeIntervalMicroSeconds& CMMFMdaAudioOutputStream::Position()
       
   673 	{
       
   674 	TInt64 position = iDevSound->SamplesPlayed();
       
   675 	position = position * KMicroSecsInOneSec / StreamUtils::SampleRateAsValue(iDevSound->Config());
       
   676 	iPosition = (iState == EPlaying || iState == EStopping || iState == EPaused) ? position : 0; // Shouldn't need to check for playing but CMMFDevSound doesn't reset bytes played after a stop
       
   677 	return iPosition;
       
   678 	}
       
   679 
       
   680 /**
       
   681  *
       
   682  *  To return the current number of bytes rendered by audio hardware
       
   683  *	@return "the current current number of bytes rendered by audio hardware in integer"	
       
   684  *
       
   685  */
       
   686 TInt CMMFMdaAudioOutputStream::GetBytes()
       
   687 	{
       
   688 	return iDevSound->SamplesPlayed() * StreamUtils::BytesPerSample(iDevSound->Config());
       
   689 	}
       
   690 
       
   691 /**
       
   692 
       
   693 */
       
   694 void CMMFMdaAudioOutputStream::SetDataTypeL(TFourCC aAudioType)
       
   695 	{
       
   696 	if(iState != EStopped)
       
   697 		User::Leave(KErrServerBusy);
       
   698 
       
   699 	if(aAudioType == iDataTypeCode)
       
   700 		return;
       
   701 
       
   702 	TMMFPrioritySettings prioritySettings; 	
       
   703 	prioritySettings.iState = EMMFStatePlaying;
       
   704 	RArray<TFourCC> supportedDataTypes;
       
   705 		
       
   706 	CleanupClosePushL(supportedDataTypes);
       
   707 	
       
   708 	TRAPD(err, iDevSound->GetSupportedInputDataTypesL(supportedDataTypes, prioritySettings));
       
   709 
       
   710 	if (err == KErrNone)
       
   711 		{
       
   712 		if (supportedDataTypes.Find(aAudioType) == KErrNotFound)
       
   713 			{
       
   714 			User::Leave(KErrNotSupported);	
       
   715 			}
       
   716 		//if match, set the 4CC of AudioType to match
       
   717 		iDataTypeCode.Set(aAudioType);
       
   718 		}
       
   719 	else  //we had a real leave error from GetSupportedOuputDataTypesL
       
   720 		{
       
   721 		User::Leave(err);
       
   722 		}
       
   723 	
       
   724 	CleanupStack::PopAndDestroy(&supportedDataTypes);
       
   725 
       
   726 	if(iIsOpenState!=EIsNotOpen)
       
   727 		{
       
   728 		// need to recall or restart InitializeL() process
       
   729 		iDevSound->CancelInitialize(); // call just in case mid-InitializeL. No harm if not. 
       
   730 									   // if not supported then assume old DevSound behaviour anyway
       
   731 									   // where InitializeL() implicitly cancels, so no harm either way
       
   732 		iIsOpenState = EIsOpening;
       
   733 		iInitCallFrmSetDataType = ETrue;
       
   734 		TRAPD(err, iDevSound->InitializeL(*this, iDataTypeCode, EMMFStatePlaying));
       
   735 		if (err != KErrNone)
       
   736 			{
       
   737 			// Leave if error.
       
   738 			iIsOpenState = EIsNotOpen;
       
   739 			iInitCallFrmSetDataType = EFalse;
       
   740 			User::Leave(err);
       
   741 			}
       
   742 		// In some implementations InitializeComplete is sent 
       
   743 		// in context, so check before starting activeSchedulerWait.
       
   744 		else if(iIsOpenState == EIsOpening)
       
   745 			{
       
   746 			iInitializeState = KRequestPending;
       
   747 			iActiveSchedulerWait->Start();
       
   748 			}
       
   749 		iInitCallFrmSetDataType = EFalse;
       
   750 		User::LeaveIfError(iInitializeState);
       
   751 		}	
       
   752 	}
       
   753 
       
   754 /**
       
   755 
       
   756 */
       
   757 TFourCC CMMFMdaAudioOutputStream::DataType() const
       
   758 	{
       
   759 	return iDataTypeCode;
       
   760 	}
       
   761 
       
   762 TInt CMMFMdaAudioOutputStream::RegisterAudioResourceNotification(MMMFAudioResourceNotificationCallback& aCallback,TUid aNotificationEventUid,const TDesC8& aNotificationRegistrationData)
       
   763 	{
       
   764 	iAudioResourceNotificationCallBack = &aCallback;
       
   765 	TInt err = iDevSound->RegisterAsClient(aNotificationEventUid,aNotificationRegistrationData);
       
   766 	if(err == KErrNotReady)
       
   767 		{
       
   768 		iEventHolder = 	aNotificationEventUid;
       
   769 		iNotificationDataHolder = aNotificationRegistrationData;
       
   770 		return KErrNone;
       
   771 		}
       
   772 	iEventHolder = KNullUid;
       
   773 	iNotificationDataHolder = KNullDesC8;
       
   774 	return err;
       
   775 	}
       
   776 
       
   777 TInt CMMFMdaAudioOutputStream::CancelRegisterAudioResourceNotification(TUid aNotificationEventId)
       
   778 	{
       
   779 	TInt err = iDevSound->CancelRegisterAsClient(aNotificationEventId);
       
   780 	if(err == KErrNotReady)
       
   781 		{
       
   782 		if(aNotificationEventId != KMMFEventCategoryAudioResourceAvailable)	
       
   783 			{
       
   784 			return KErrNotSupported;
       
   785 			}
       
   786 		if(iEventHolder == KNullUid)	
       
   787 			{
       
   788 			return KErrCancel;
       
   789 			}		
       
   790 		iEventHolder = KNullUid;
       
   791 		iNotificationDataHolder = KNullDesC8;
       
   792 		return KErrNone;
       
   793 		}
       
   794 	return err;
       
   795 	}
       
   796 	
       
   797 TInt CMMFMdaAudioOutputStream::WillResumePlay()
       
   798 	{
       
   799 	return iDevSound->WillResumePlay();
       
   800 	}
       
   801 
       
   802 /**
       
   803  *
       
   804  *  To be called when intialize stream complete	
       
   805  *
       
   806  *	@param	"TInt aError"	
       
   807  *			error code, initialize stream succeed when aError = 0
       
   808  *
       
   809  */
       
   810 void CMMFMdaAudioOutputStream::InitializeComplete(TInt aError)
       
   811 	{
       
   812 	TInt err = aError;
       
   813 	if(err == KErrNone && iValuesCached)
       
   814 		{
       
   815 		TRAP(err, RealSetAudioPropertiesL(iSampleRate, iChannels));
       
   816 		if(err == KErrNone && iVolume>=0)
       
   817 			{
       
   818 			SetVolume(iVolume);
       
   819 			}
       
   820 		}
       
   821 	iValuesCached = EFalse; // whatever clear our cache
       
   822 	if(iIsOpenState == EIsOpening)
       
   823 		{
       
   824 		// Signal for the MaoscOpenComplete callback to be called asynchronously.Ignore if InitializeL is called from SetDataTypeL
       
   825 		if(!iInitCallFrmSetDataType)
       
   826 			{
       
   827 			iActiveCallback->Signal(err);
       
   828 			}
       
   829 		iIsOpenState = err ? EIsNotOpen : EIsOpen;
       
   830 		if(iInitializeState == KRequestPending)
       
   831 			{
       
   832 			iInitializeState = err;
       
   833 			iActiveSchedulerWait->AsyncStop();
       
   834 			}
       
   835 		else
       
   836 			{
       
   837 			iInitializeState = err;//Set the error if InitializeComplete is called in context of InitializeL.
       
   838 			}
       
   839 		}
       
   840 	}
       
   841 
       
   842 /**
       
   843  *
       
   844  *  Do not support
       
   845  *
       
   846  */
       
   847 void CMMFMdaAudioOutputStream::ToneFinished(TInt /*aError*/)
       
   848 	{
       
   849 	Panic(EToneFinishedNotSupported);
       
   850 	}
       
   851 
       
   852 /**
       
   853  *
       
   854  *  Called when sound device need data	
       
   855  *
       
   856  *	@param	"CMMFBuffer* aBuffer"	
       
   857  *			a pointer point to CMMFBuffer, which is used to stored data
       
   858  *
       
   859  */
       
   860 void CMMFMdaAudioOutputStream::BufferToBeFilled(CMMFBuffer* aBuffer)
       
   861 	{
       
   862 	if (iState == EPlaying || iState == EStopping)
       
   863 		{
       
   864 		TMMFFifoItem<const TDesC8>* firstItem = iFifo->Get();
       
   865 		//ASSERT firstItem != NULL
       
   866 		if (iFifoItemPos >= firstItem->GetData().Length())
       
   867 			{
       
   868 			// We've played all segments of the first buffer in the fifo so we can delete it
       
   869 			iFifo->RemoveFirstItem();
       
   870 			iCallback.MaoscBufferCopied(KErrNone, firstItem->GetData());
       
   871 			delete firstItem;
       
   872 			iFifoItemPos = 0;
       
   873 			}
       
   874 		}
       
   875 	TMMFFifoItem<const TDesC8>* firstItem = iFifo->Get();
       
   876 
       
   877 	if (firstItem)
       
   878 		{
       
   879 		// Fill aBuffer with the next segment of the first buffer in the fifo
       
   880 		TDes8& fillDes = STATIC_CAST(CMMFDataBuffer*, aBuffer)->Data();
       
   881 		const TDesC8& readDes = firstItem->GetData();
       
   882 		TInt readLen = Min(readDes.Length()-iFifoItemPos, aBuffer->RequestSize());
       
   883 		fillDes = readDes.Mid(iFifoItemPos, readLen);
       
   884 		iFifoItemPos+=readLen; // so we know where the next segment in the fifo item starts
       
   885 		// Notify iDevSound the buffer is ready to be played
       
   886 		iDevSound->PlayData();
       
   887 		}
       
   888 	else 
       
   889 		{
       
   890 		if(iBuffer ==NULL)
       
   891 			{
       
   892 			//keep a record of the supplied buffer and use it when/if more user data is in the FIFO
       
   893 			iBuffer = aBuffer; 
       
   894 			}
       
   895 		if(!iKeepOpenAtEnd)
       
   896 			{
       
   897 			if (iDevSoundIgnoresUnderflow)
       
   898 				{
       
   899 				iCurrentSamplesPlayed = iDevSound->SamplesPlayed();
       
   900 				StartShutDownTimer();
       
   901 				}
       
   902 			}
       
   903 		else if(iState==EStopping)
       
   904 			{
       
   905 			CMMFDataBuffer* dataBuffer = static_cast<CMMFDataBuffer*>(aBuffer);
       
   906 			dataBuffer->Data().SetLength(0);
       
   907 			dataBuffer->SetLastBuffer(ETrue);
       
   908 			iDevSound->PlayData();
       
   909 			iBuffer=NULL;
       
   910 			}
       
   911 		}
       
   912 	 
       
   913 	}
       
   914 
       
   915 void CMMFMdaAudioOutputStream::StartShutDownTimer()
       
   916 	{
       
   917 	iShutDownTimer->Start(KShutDownTimeInterval, KShutDownTimeInterval, TCallBack(ShutDownTimerComplete,this));
       
   918 	}
       
   919 	
       
   920 TInt CMMFMdaAudioOutputStream::ShutDownTimerComplete(TAny* aAudioOutputStream)
       
   921 	{
       
   922 	CMMFMdaAudioOutputStream* audioOutputStream = static_cast<CMMFMdaAudioOutputStream*>(aAudioOutputStream);
       
   923 	audioOutputStream->DoShutDownTimerComplete();
       
   924 	return KErrNone;
       
   925 	}
       
   926 
       
   927 void CMMFMdaAudioOutputStream::DoShutDownTimerComplete()
       
   928 	{
       
   929 	iShutDownTimer->Cancel();
       
   930 	TInt samplesPlayed = iDevSound->SamplesPlayed();
       
   931 	if (samplesPlayed == iCurrentSamplesPlayed)
       
   932 		{
       
   933 		iDevSound->Stop();
       
   934 		iState = EStopped;
       
   935 		iBuffer = NULL;
       
   936 		iCallback.MaoscPlayComplete(KErrUnderflow);
       
   937 		}
       
   938 	else
       
   939 		{//desvound has not yet finished playing all the data. So wait for one more cycle
       
   940 		//Restart Timer
       
   941 		iCurrentSamplesPlayed = samplesPlayed;
       
   942 		StartShutDownTimer();
       
   943 		}
       
   944 	}
       
   945 
       
   946 /**
       
   947  *
       
   948  *  Called when play operation complete, successfully or otherwise	
       
   949  *
       
   950  *	@param	"TInt aError"	
       
   951  *			an error value which will indicate playing successfully complete
       
   952  *			if error value is 0
       
   953  *
       
   954  */
       
   955 void CMMFMdaAudioOutputStream::PlayError(TInt aError)
       
   956 	{
       
   957 	TInt err=aError;
       
   958 	 // if iDevSoundIgnoresUnderflow is true, then KErrUnderflow should not be produced by DevSound when we are not stopping 
       
   959 	__ASSERT_DEBUG(!iDevSoundIgnoresUnderflow || !(err==KErrUnderflow && iState!=EStopping), Panic(EAOSStoppingError));
       
   960 	iState = EStopped;
       
   961 	iBuffer = NULL;
       
   962 	iShutDownTimer->Cancel();
       
   963 	if (err == KErrNone || err == KErrUnderflow)
       
   964 		{
       
   965 		if (!iFifo->IsEmpty())
       
   966 			{
       
   967 			// We live again - the Fifo still has some data. The sound device
       
   968 			// will have to be opened again though so there might be an
       
   969 			// audible click.
       
   970 			TRAP(err, StartPlayL());
       
   971 			if (err == KErrNone)
       
   972 				{
       
   973 				return;
       
   974 				}
       
   975 			}
       
   976 		}
       
   977 	
       
   978 	EmptyFifo(err);
       
   979 	
       
   980 	// Note - KErrUnderflow will be reported even when all the buffers have
       
   981 	// successfully played
       
   982 	iCallback.MaoscPlayComplete(err);
       
   983 	}
       
   984 
       
   985 void CMMFMdaAudioOutputStream::EmptyFifo(TInt aError)
       
   986 	{
       
   987 	// Delete all buffers in the fifo and notify the observer
       
   988 	TMMFFifoItem<const TDesC8>* firstItem;
       
   989 	while((firstItem = iFifo->Get()) != NULL)
       
   990 		{
       
   991 		iFifo->RemoveFirstItem();
       
   992 		iCallback.MaoscBufferCopied(aError, firstItem->GetData());
       
   993 		delete firstItem;
       
   994 		}
       
   995 	}
       
   996 
       
   997 void CMMFMdaAudioOutputStream::SendEventToClient(const TMMFEvent& aEvent)
       
   998 	{
       
   999 	if (aEvent.iEventType == KMMFEventCategoryAudioResourceAvailable)
       
  1000 		{
       
  1001 		// Retrieve the number of samples played
       
  1002 		// For the event type KMMFEventCategoryAudioResourceAvailable GetResourceNotificationData() returns
       
  1003 		// a package buffer as TMMFTimeIntervalMicroSecondsPckg, but the contents should be 
       
  1004 		// converted to an integer and interpreted as the data returned is samples played,
       
  1005 		// but not as a microsecond value.
       
  1006 		TBuf8<TMMFAudioConfig::KNotificationDataBufferSize> notificationData;
       
  1007 		if (KErrNone != iDevSound->GetResourceNotificationData(aEvent.iEventType, notificationData))
       
  1008 			{
       
  1009 			notificationData.SetLength(0);
       
  1010 			}
       
  1011 		iAudioResourceNotificationCallBack->MarncResourceAvailable(aEvent.iEventType, notificationData);
       
  1012 		}
       
  1013 	}
       
  1014 
       
  1015 CMMFMdaAudioOutputStream::CActiveCallback::~CActiveCallback()
       
  1016 	{
       
  1017 	Cancel();
       
  1018 	}
       
  1019 
       
  1020 CMMFMdaAudioOutputStream::CActiveCallback::CActiveCallback(MMdaAudioOutputStreamCallback& aCallback)
       
  1021 	: CActive(EPriorityStandard), iCallback(aCallback)
       
  1022 	{
       
  1023 	CActiveScheduler::Add(this);
       
  1024 	}
       
  1025 
       
  1026 void CMMFMdaAudioOutputStream::CActiveCallback::RunL()
       
  1027 	{
       
  1028 	iCallback.MaoscOpenComplete(iStatus.Int());
       
  1029 	}
       
  1030 
       
  1031 void CMMFMdaAudioOutputStream::CActiveCallback::DoCancel()
       
  1032 	{
       
  1033 	}
       
  1034 
       
  1035 void CMMFMdaAudioOutputStream::CActiveCallback::Signal(const TInt aReason)
       
  1036 	{
       
  1037 	ASSERT(!IsActive());
       
  1038 
       
  1039 	// Signal ourselves to run with the given completion code
       
  1040 	TRequestStatus* status = &iStatus;
       
  1041 	User::RequestComplete(status, aReason);
       
  1042 	SetActive();
       
  1043 	}
       
  1044 
       
  1045 
       
  1046 /**
       
  1047  *
       
  1048  *  Do not support
       
  1049  *
       
  1050  */
       
  1051 void CMMFMdaAudioOutputStream::BufferToBeEmptied(CMMFBuffer* /*aBuffer*/)
       
  1052 	{
       
  1053 	Panic(EBufferToBeEmptiedNotSupported);
       
  1054 	}
       
  1055 
       
  1056 /**
       
  1057  *
       
  1058  *  Do not support
       
  1059  *
       
  1060  */
       
  1061 void CMMFMdaAudioOutputStream::RecordError(TInt /*aError*/)
       
  1062 	{
       
  1063 	Panic(ERecordErrorNotSupported);
       
  1064 	}
       
  1065 
       
  1066 /**
       
  1067  *
       
  1068  *  Do not support
       
  1069  *
       
  1070  */
       
  1071 void CMMFMdaAudioOutputStream::ConvertError(TInt /*aError*/)
       
  1072 	{
       
  1073 	Panic(EConvertErrorNotSupported);
       
  1074 	}
       
  1075 
       
  1076 /**
       
  1077  *
       
  1078  *  Do not support
       
  1079  *
       
  1080  */
       
  1081 void CMMFMdaAudioOutputStream::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
       
  1082 	{
       
  1083 	Panic(EDeviceMessageNotSupported);
       
  1084 	}
       
  1085 
       
  1086 // CustomInferface - just pass on to DevSound. 
       
  1087 TAny* CMMFMdaAudioOutputStream::CustomInterface(TUid aInterfaceId)
       
  1088 	{
       
  1089 	return iDevSound->CustomInterface(aInterfaceId);
       
  1090 	}
       
  1091