mmlibs/mmfw/src/Plugin/AudioOutput/MmfAudioOutput.cpp
changeset 0 b8ed18f6c07b
equal deleted inserted replaced
-1:000000000000 0:b8ed18f6c07b
       
     1 // Copyright (c) 2005-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 "MmfAudioOutput.h"
       
    17 #include <ecom/implementationproxy.h>
       
    18 #include <mmf/server/mmfformat.h>
       
    19 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    20 #include <mmf/common/mmfhelper.h>
       
    21 #endif
       
    22 #include <mmf/plugin/mmfaudioiointerfaceuids.hrh>
       
    23 
       
    24 void Panic(TInt aPanicCode)
       
    25 	{
       
    26 	_LIT(KMMFAudioOutputPanicCategory, "MMFAudioOutput");
       
    27 	User::Panic(KMMFAudioOutputPanicCategory, aPanicCode);
       
    28 	}
       
    29 
       
    30 /**
       
    31 Allocates and constructs a new audio output sink.
       
    32 
       
    33 Static standard SymbianOS 2 phase constuction method.
       
    34 
       
    35 @return A pointer to the new sink.
       
    36 */
       
    37 MDataSink* CMMFAudioOutput::NewSinkL()
       
    38 	{
       
    39 	CMMFAudioOutput* self = new (ELeave) CMMFAudioOutput ;
       
    40 	CleanupStack::PushL(self);
       
    41 	self->ConstructL();
       
    42 	CleanupStack::Pop();
       
    43 	return STATIC_CAST( MDataSink*, self ) ;
       
    44 	}
       
    45 
       
    46 /**
       
    47 Standard SymbianOS ConstructL.
       
    48 
       
    49 Used to initialise member varibles with device specific behaviour.
       
    50 */
       
    51 void CMMFAudioOutput::ConstructL()
       
    52 	{
       
    53 	iInitializeState = KErrNone;
       
    54 	iDataTypeCode = KMMFFourCCCodePCM16;
       
    55 	iNeedsSWConversion = EFalse;
       
    56 	iSourceSampleRate = 0;
       
    57 	iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait;
       
    58 	}
       
    59 
       
    60 /**
       
    61 Overridable constuction specific to this datasource.
       
    62 
       
    63 The default implementation does nothing.
       
    64 
       
    65 @param  aInitData
       
    66         The initialisation data.
       
    67 */
       
    68 void CMMFAudioOutput::ConstructSinkL( const TDesC8& /*aInitData*/ )
       
    69 	{
       
    70 	}
       
    71 
       
    72 
       
    73 /**
       
    74 @deprecated
       
    75 
       
    76 Gets audio from hardware device abstracted MMFDevsound (not used).
       
    77 
       
    78 @param  aBuffer
       
    79         The data to write out to a Hardware Device.
       
    80 @param  aSupplier
       
    81         The MDataSource consuming the data contained in aBuffer
       
    82 */
       
    83 void CMMFAudioOutput::HWEmptyBufferL(CMMFBuffer* /*aBuffer*/, MDataSource* /*aSupplier*/)
       
    84 	{
       
    85 	}
       
    86 
       
    87 /**
       
    88 Sends audio to MMFDevsound.
       
    89 
       
    90 @param  aBuffer
       
    91         The data to write out.
       
    92 @param  aSupplier
       
    93         The search criteria for the supplier.
       
    94 @param  aMediaId
       
    95         The type of data supplied - currently ignored.
       
    96 */
       
    97 void CMMFAudioOutput::EmptyBufferL(CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId /*aMediaId*/)
       
    98 	{
       
    99 	iSupplier = aSupplier;
       
   100 
       
   101 	if (!iMMFDevSound)
       
   102 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   103 
       
   104 	if (aSupplier == NULL)
       
   105 		User::Leave(KErrArgument);
       
   106 
       
   107 	// In order to avoid changes at the datapath data transfer state machine 
       
   108 	// EmptyBufferL is still being called even
       
   109 	// if the first time there is no buffer to send
       
   110 	if (!iCanSendBuffers)
       
   111 		{
       
   112 		
       
   113 		iCanSendBuffers = ETrue;
       
   114 		return;
       
   115 		}
       
   116 
       
   117 	if (iNeedsSWConversion)
       
   118 		{//need to perform channel & sample rate conversion before writing to clip
       
   119 		CMMFDataBuffer* audio;
       
   120 
       
   121 		//need to make sure aBuffer is not null before it is used
       
   122 		if (aBuffer == NULL)
       
   123 			{
       
   124 			User::Leave(KErrArgument);
       
   125 			}
       
   126 		
       
   127 		//buffer check is placed here before possible use of the buffer
       
   128 		if (!CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
       
   129 			{
       
   130 			User::Leave(KErrNotSupported);
       
   131 			}
       
   132 		
       
   133 		iConvertBuffer = CMMFDataBuffer::NewL(((CMMFDataBuffer*)aBuffer)->Data().Length());
       
   134 		iChannelAndSampleRateConverter->Convert(*(CMMFDataBuffer*)aBuffer, *iConvertBuffer);
       
   135 		audio = iConvertBuffer;
       
   136 
       
   137 		//copy our converted data back into the real buffer to return to datapath
       
   138 		TDes8& dest = STATIC_CAST( CMMFDataBuffer*, aBuffer )->Data() ;
       
   139 		dest.SetLength(0);
       
   140 		dest.Copy(audio->Data());
       
   141 		}
       
   142 
       
   143 	if (iState != EDevSoundReady && iState != EPaused) // If we're paused we still feed a buffer to DevSound
       
   144 		User::Leave(KErrNotReady);
       
   145 
       
   146 	iMMFDevSound->PlayData();
       
   147 
       
   148 #if defined(__AUDIO_PROFILING)
       
   149 	RDebug::ProfileEnd(0);
       
   150 	User::Leave(KErrEof);
       
   151 #endif  // defined(__AUDIO_PROFILING)
       
   152 
       
   153 
       
   154 	// The following will never have been allocated unless
       
   155 	// software conversion was required, and due to certain DevSound
       
   156 	// implementations, this requirement can change dynamically.
       
   157 	delete iConvertBuffer;
       
   158 	iConvertBuffer = NULL;
       
   159 	}
       
   160 
       
   161 
       
   162 
       
   163 /**
       
   164 Negotiates with the source to set, for example, the sample rate and number of channels.
       
   165 
       
   166 Called if the sink's setup depends on source.
       
   167 
       
   168 @param  aSource
       
   169         The data source with which to negotiate.
       
   170 */
       
   171 void CMMFAudioOutput::NegotiateL(MDataSource& aSource)
       
   172 	{
       
   173 	if (aSource.DataSourceType() == KUidMmfFormatDecode)
       
   174 		{//source is a clip so for now set sink settings to match source
       
   175 		iSourceSampleRate = ((CMMFFormatDecode&)aSource).SampleRate();
       
   176 		iSourceChannels = ((CMMFFormatDecode&)aSource).NumChannels(); 
       
   177 		iSourceFourCC.Set(aSource.SourceDataTypeCode(TMediaId(KUidMediaTypeAudio)));
       
   178 	
       
   179 		((CMMFFormatDecode&)aSource).SuggestSourceBufferSize(KAudioOutputDefaultFrameSize);
       
   180 		}
       
   181 
       
   182 	// Query DevSound capabilities and Try to use DevSound sample rate and 
       
   183 	// mono/stereo capability
       
   184 	if (!iMMFDevSound)
       
   185 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   186 
       
   187 	TMMFState prioritySettingsState = iPrioritySettings.iState; //should be EMMFStatePlaying
       
   188 	//to use the GetSupportedInputDatatypes but we'll save it just in case it's not
       
   189 	iPrioritySettings.iState = EMMFStatePlaying; //if playing does not support any output data types
       
   190 	RArray<TFourCC> supportedDataTypes;
       
   191 	//note Input data types becuase if we are playing audio ie audio output
       
   192 	//the data is sent as an input to DevSound
       
   193 	TRAPD(err, iMMFDevSound->GetSupportedInputDataTypesL(supportedDataTypes, iPrioritySettings));
       
   194 	iPrioritySettings.iState = prioritySettingsState;
       
   195 	if (err == KErrNone)
       
   196 		{
       
   197 		if (supportedDataTypes.Find(iSourceFourCC) == KErrNotFound)
       
   198 			{//the source fourCC code could not be found in the list of 
       
   199 			//data types supported by the Devsound therefor default to pcm16
       
   200 			iDataTypeCode = KMMFFourCCCodePCM16;	
       
   201 			}
       
   202 		else
       
   203 			{
       
   204 			//the DevSound does support the same datatype as the source 
       
   205 			//so set the fourcc to that of the source
       
   206 			iDataTypeCode = iSourceFourCC;
       
   207 			}
       
   208 		}
       
   209 	supportedDataTypes.Close();
       
   210 	if (err == KErrNotSupported)
       
   211 		{//if the Devsound does not support the GetSupportedOutputDataTypesL method
       
   212 		//then assume that the DevSound is pcm16 only
       
   213 		iDataTypeCode = KMMFFourCCCodePCM16;	
       
   214 		}
       
   215 	else if (err != KErrNone) //we had a real leave error from GetSupportedOuputDataTypesL
       
   216 		{
       
   217 		User::Leave(err);
       
   218 		}
       
   219 		
       
   220 	// Prevent defect when SinkPrimeL is called before NegotiateL()
       
   221 	// since characterization is ambiguous
       
   222 	if(iState == EDevSoundReady)
       
   223 		{
       
   224 		iState = EIdle;
       
   225 		}
       
   226 	//INC40817 do the initialize here as capabilities may depend on datatype
       
   227 	//note this implies client of audiooutput must call negotiate
       
   228 	iMMFDevSound->InitializeL(*this, iDataTypeCode, EMMFStatePlaying);
       
   229 
       
   230 	// In some implementations InitializeComplete is sent
       
   231 	// in context, so check before starting activeSchedulerWait.
       
   232 	if (iState != EDevSoundReady)
       
   233 		{
       
   234 		iInitializeState = KRequestPending;
       
   235 		iActiveSchedulerWait->Start();
       
   236 		}
       
   237 		
       
   238 	User::LeaveIfError(iInitializeState);
       
   239 	
       
   240 	// Reset the following flag in case DevSound's capabilities have
       
   241 	// changed since we were last here: INC037165
       
   242 	iNeedsSWConversion = EFalse;
       
   243 	TMMFCapabilities devSoundCaps;
       
   244 	devSoundCaps = iMMFDevSound->Capabilities();
       
   245 	// Default PCM16
       
   246 	iDevSoundConfig.iEncoding = EMMFSoundEncoding16BitPCM;
       
   247 	// 1 = Monophonic and 2 == Stereo
       
   248 	if (((iSourceChannels == 1) && (devSoundCaps.iChannels & EMMFMono)) ||
       
   249 		((iSourceChannels == 2) && (devSoundCaps.iChannels & EMMFStereo)))
       
   250 		iDevSoundConfig.iChannels = iSourceChannels;
       
   251 	else //default or SW conversion, e.g. stereo on mono support
       
   252 		{
       
   253 		iDevSoundConfig.iChannels = EMMFMono;
       
   254 		iNeedsSWConversion = ETrue;
       
   255 		iSWConvertChannels = 1;
       
   256 		iSWConvertSampleRate = iSourceSampleRate;
       
   257 		}
       
   258 
       
   259 	// Check for std sample rates.
       
   260 	if ((iSourceSampleRate == 96000) && (devSoundCaps.iRate & EMMFSampleRate96000Hz))
       
   261 		iDevSoundConfig.iRate = EMMFSampleRate96000Hz;
       
   262 	else if ((iSourceSampleRate == 88200) && (devSoundCaps.iRate & EMMFSampleRate88200Hz))
       
   263 		iDevSoundConfig.iRate = EMMFSampleRate88200Hz;
       
   264 	else if ((iSourceSampleRate == 64000) && (devSoundCaps.iRate & EMMFSampleRate64000Hz))
       
   265 		iDevSoundConfig.iRate = EMMFSampleRate64000Hz;
       
   266 	else if ((iSourceSampleRate == 48000) && (devSoundCaps.iRate & EMMFSampleRate48000Hz))
       
   267 		iDevSoundConfig.iRate = EMMFSampleRate48000Hz;
       
   268 	else if ((iSourceSampleRate == 44100) && (devSoundCaps.iRate & EMMFSampleRate44100Hz))
       
   269 		iDevSoundConfig.iRate = EMMFSampleRate44100Hz;
       
   270 	else if ((iSourceSampleRate == 32000) && (devSoundCaps.iRate & EMMFSampleRate32000Hz))
       
   271 		iDevSoundConfig.iRate = EMMFSampleRate32000Hz;
       
   272 	else if ((iSourceSampleRate == 24000) && (devSoundCaps.iRate & EMMFSampleRate24000Hz))
       
   273 		iDevSoundConfig.iRate = EMMFSampleRate24000Hz;
       
   274 	else if ((iSourceSampleRate == 22050) && (devSoundCaps.iRate & EMMFSampleRate22050Hz))
       
   275 		iDevSoundConfig.iRate = EMMFSampleRate22050Hz;
       
   276 	else if ((iSourceSampleRate == 16000) && (devSoundCaps.iRate & EMMFSampleRate16000Hz))
       
   277 		iDevSoundConfig.iRate = EMMFSampleRate16000Hz;
       
   278 	else if ((iSourceSampleRate == 12000) && (devSoundCaps.iRate & EMMFSampleRate12000Hz))
       
   279 		iDevSoundConfig.iRate = EMMFSampleRate12000Hz;
       
   280 	else if ((iSourceSampleRate == 11025) && (devSoundCaps.iRate & EMMFSampleRate11025Hz))
       
   281 		iDevSoundConfig.iRate = EMMFSampleRate11025Hz;
       
   282 	else if ((iSourceSampleRate == 8000) && (devSoundCaps.iRate & EMMFSampleRate8000Hz))
       
   283 		iDevSoundConfig.iRate = EMMFSampleRate8000Hz;
       
   284 	else // non standard sample rate
       
   285 		{
       
   286 		iNeedsSWConversion = ETrue;
       
   287 		// we need to choose to the closest, and smaller standard sample rate
       
   288 		// and eventually convert the audio samples to this standard sample rate
       
   289 		//NB: this list must be in ascending order
       
   290 		const TInt KNumSampleRates = 12;
       
   291 		static const TUint supportedSR[KNumSampleRates][2] = {{8000,  EMMFSampleRate8000Hz},
       
   292 									{11025, EMMFSampleRate11025Hz},
       
   293 									{12000, EMMFSampleRate12000Hz},
       
   294 									{16000, EMMFSampleRate16000Hz},
       
   295 									{22050, EMMFSampleRate22050Hz},
       
   296 									{24000, EMMFSampleRate24000Hz},
       
   297 									{32000, EMMFSampleRate32000Hz},
       
   298 									{44100, EMMFSampleRate44100Hz},
       
   299 									{48000, EMMFSampleRate48000Hz},
       
   300 									{64000, EMMFSampleRate64000Hz},
       
   301 									{88200, EMMFSampleRate88200Hz},
       
   302 									{96000, EMMFSampleRate96000Hz}};
       
   303 
       
   304 		//Only support down sampling
       
   305    		if (iSourceSampleRate < supportedSR[0][0]) 
       
   306    			User::Leave(KErrNotSupported);
       
   307    		
       
   308    		
       
   309    		TInt sampleRateIndex = KNumSampleRates;
       
   310    
       
   311    		//find the source sampleRateIndex
       
   312    		for (sampleRateIndex--; sampleRateIndex > -1; sampleRateIndex--)
       
   313    			{
       
   314    			if(iSourceSampleRate >= supportedSR[sampleRateIndex][0])
       
   315    				{
       
   316    				break;
       
   317    				}
       
   318    			}
       
   319    
       
   320    		//find the highest sink sample rate below the source rate
       
   321    		for (; sampleRateIndex > -1; sampleRateIndex--)
       
   322    			{
       
   323    			if(devSoundCaps.iRate & supportedSR[sampleRateIndex][1])
       
   324    				{
       
   325    				iSWConvertSampleRate = supportedSR[sampleRateIndex][0];
       
   326    				iDevSoundConfig.iRate = supportedSR[sampleRateIndex][1];
       
   327    				break;
       
   328    				}
       
   329    			}
       
   330    
       
   331    		//if a suitable sink sample rate is not available
       
   332    		if (sampleRateIndex < 0) 
       
   333    			User::Leave(KErrNotSupported);
       
   334    
       
   335    		// set the channels as well
       
   336    		iSWConvertChannels = iDevSoundConfig.iChannels;
       
   337    		} // else // non standard sample rate
       
   338 
       
   339 	if (iNeedsSWConversion)
       
   340 		{//can only software convert if datatype is pcm16
       
   341 		//note cannot set non standard sample rates on DevSound API
       
   342 		//as the API does not allow this
       
   343 		//we need to reinitialize the devsound with pcm16 in this case
       
   344 		iDataTypeCode = KMMFFourCCCodePCM16;
       
   345 		iState = EIdle;
       
   346 		iMMFDevSound->InitializeL(*this, iDataTypeCode, EMMFStatePlaying);
       
   347 		
       
   348 		// In some implementations InitializeComplete is called
       
   349 		// in context, so check before starting activeSchedulerWait.
       
   350 		if (iState != EDevSoundReady)
       
   351 			{
       
   352 			iInitializeState = KRequestPending;
       
   353 			iActiveSchedulerWait->Start();
       
   354 			}
       
   355 			
       
   356 		User::LeaveIfError(iInitializeState);
       
   357 		}
       
   358 	}
       
   359 
       
   360 /**
       
   361 Sets the sink's priority settings.
       
   362 
       
   363 @param  aPrioritySettings
       
   364         The sink's priority settings. Takes enumerations to determine audio playback priority. 
       
   365         Higher numbers mean high priority (can interrupt lower priorities).
       
   366 */
       
   367 void CMMFAudioOutput::SetSinkPrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
       
   368 	{
       
   369 	iPrioritySettings = aPrioritySettings;
       
   370 	if (!iMMFDevSound)
       
   371 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   372 	else
       
   373 		iMMFDevSound->SetPrioritySettings(iPrioritySettings);
       
   374 	}
       
   375 
       
   376 /**
       
   377 Gets the sink's data type code.
       
   378 
       
   379 Used by datapath MDataSource / MDataSink for codec matching.
       
   380 
       
   381 @param  aMediaId
       
   382         The Media ID. Optional parameter to specifiy specific stream when datasource contains more
       
   383         than one stream of data.
       
   384 
       
   385 @return	The 4CC of the data expected by this sink.
       
   386 */
       
   387 TFourCC CMMFAudioOutput::SinkDataTypeCode(TMediaId /*aMediaId*/)
       
   388 	{
       
   389 	return iDataTypeCode;
       
   390 	}
       
   391 
       
   392 /**
       
   393 Sets the sink's data type code.
       
   394 
       
   395 @param  aSinkFourCC
       
   396         The 4CC of the data to be supplied to this sink.
       
   397 @param  aMediaId
       
   398         The Media ID. Optional parameter to specifiy specific stream when datasource contains more 
       
   399         than one stream of data.
       
   400 
       
   401 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   402         another of the system-wide error codes.
       
   403 */
       
   404 TInt CMMFAudioOutput::SetSinkDataTypeCode(TFourCC aSinkFourCC, TMediaId /*aMediaId*/)
       
   405 	{//will check with devsound to see if aSinkFourCC is supported
       
   406 	 //when this is added to devsound
       
   407 	iDataTypeCode = aSinkFourCC;
       
   408 	return KErrNone;
       
   409 	}
       
   410 
       
   411 /**
       
   412 Primes the sink.
       
   413 
       
   414 This is a virtual function that each derived class must implement, but may be left blank for default 
       
   415 behaviour.
       
   416 
       
   417 Called by CMMFDataPath::PrimeL().
       
   418 */
       
   419 void CMMFAudioOutput::SinkPrimeL()
       
   420 	{
       
   421 	if(iPlayStarted != EFalse)
       
   422 		{
       
   423 		return;
       
   424 		}
       
   425 	iPlayStarted = EFalse;
       
   426 	iCanSendBuffers = EFalse;
       
   427 	if (iState == EIdle)
       
   428 		{
       
   429 		if (!iMMFDevSound) 
       
   430 			{
       
   431 			User::Leave(KErrNotReady);
       
   432 			}
       
   433 		iState = EDevSoundReady;
       
   434 		}
       
   435 	}
       
   436 
       
   437 /**
       
   438 Pauses the sink.
       
   439 
       
   440 This is a virtual function that each derived class must implement, but may be left blank for default 
       
   441 behaviour.
       
   442 */
       
   443 void CMMFAudioOutput::SinkPauseL()
       
   444 	{
       
   445 	if (!iMMFDevSound)
       
   446 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   447 	else
       
   448 		iMMFDevSound->Pause();
       
   449 	iPlayStarted = EFalse;
       
   450 	iState = EPaused;
       
   451 	}
       
   452 
       
   453 /**
       
   454 Starts playing the sink.
       
   455 
       
   456 This is a virtual function that each derived class must implement, but may be left blank for default
       
   457 behaviour.
       
   458 */
       
   459 void CMMFAudioOutput::SinkPlayL()
       
   460 	{
       
   461 	if (iState == EPaused)
       
   462 		{
       
   463 		TBool isResumeSupported = iMMFDevSound->IsResumeSupported();
       
   464 		// CMMFAudioOutput is not supposed to be paused 
       
   465 		// if Resume is not supported by DevSound
       
   466 		if(!isResumeSupported)
       
   467 			{
       
   468 			User::Leave(KErrNotSupported);
       
   469 			}
       
   470 		
       
   471 		User::LeaveIfError(iMMFDevSound->Resume());
       
   472 		iPlayStarted = ETrue;
       
   473 		}
       
   474 	else if (iPlayStarted == EFalse)
       
   475 		{
       
   476 		ConfigDevSoundL();	
       
   477 
       
   478 		// This is a one-shot to "prime" MMFDevSound as first buffer uninitialised
       
   479 		iMMFDevSound->PlayInitL();
       
   480 		iPlayStarted = ETrue;
       
   481 		}
       
   482 	if ((iNeedsSWConversion)&&(iSourceChannels>0))
       
   483 		{//can only do SW convert  - therefore need to do a conversion
       
   484 		//currently only pcm16 is supported so return with an error if format not pcm16
       
   485 		if (!iChannelAndSampleRateConverterFactory)
       
   486 			{
       
   487 			iChannelAndSampleRateConverterFactory
       
   488 				= new(ELeave)CMMFChannelAndSampleRateConverterFactory;
       
   489 			iChannelAndSampleRateConverter =
       
   490 				iChannelAndSampleRateConverterFactory->CreateConverterL( iSourceSampleRate, iSourceChannels,
       
   491 																		iSWConvertSampleRate, iSWConvertChannels);
       
   492 			}
       
   493 		//need to create an intermediate buffer in which to place the converted data
       
   494 		}
       
   495 	iState = EDevSoundReady;
       
   496 	}
       
   497 
       
   498 /**
       
   499 Stops the sink.
       
   500 
       
   501 This is a virtual function that each derived class must implement, but may be left blank for default
       
   502 behaviour.
       
   503 */
       
   504 void CMMFAudioOutput::SinkStopL()
       
   505 	{
       
   506 	if (iState == EDevSoundReady)
       
   507 		{//not waiting on a buffer being played so stop devsound now
       
   508 		iState = EIdle;
       
   509 		if (iPlayStarted)
       
   510 			{
       
   511 			if (!iMMFDevSound)
       
   512 				{
       
   513 				Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   514 				}
       
   515 			else
       
   516 				{
       
   517 				iPlayStarted = EFalse;
       
   518 				iMMFDevSound->Stop();
       
   519 				}
       
   520 			}
       
   521 		}
       
   522 	else if (iState == EPaused)	//DEF46250 need to handle pause separately as we should always stop regardless of the state of iFirstBufferSent
       
   523 		{
       
   524 		iPlayStarted = EFalse;
       
   525 		iMMFDevSound->Stop();
       
   526 		iState = EIdle; 
       
   527 		}
       
   528 	iCanSendBuffers = EFalse;
       
   529 	} 
       
   530 
       
   531 /**
       
   532 Returns the playback state (EStopped, EPlaying, EPaused etc) of this sink
       
   533 */
       
   534 TInt CMMFAudioOutput::State()
       
   535 	{
       
   536 	return iState;
       
   537 	}
       
   538 
       
   539 /**
       
   540 Logs on the sink's thread.
       
   541 
       
   542 Thread specific initialization procedure for this device. Runs automatically on thread construction.
       
   543 
       
   544 @param  aEventHandler
       
   545         The event handler.
       
   546 
       
   547 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   548         another of the system-wide error codes.
       
   549 */
       
   550 TInt CMMFAudioOutput::SinkThreadLogon(MAsyncEventHandler& aEventHandler)
       
   551 	{
       
   552 	iEventHandler = &aEventHandler;
       
   553 	TInt err = KErrNone;
       
   554 	if (!iDevSoundLoaded)
       
   555 		TRAP(err, LoadL());
       
   556 	return err;
       
   557 	}
       
   558 
       
   559 /**
       
   560 Logs off the sink thread.
       
   561 
       
   562 Thread specific destruction procedure for this device. Runs automatically on thread destruction.
       
   563 */
       
   564 void CMMFAudioOutput::SinkThreadLogoff()
       
   565 	{
       
   566 	if(iMMFDevSound)
       
   567 		{
       
   568 		iMMFDevSound->Stop();
       
   569 		delete iMMFDevSound;
       
   570 		iMMFDevSound = NULL;
       
   571 		}
       
   572 	iDevSoundLoaded = EFalse;
       
   573 	iState = EIdle;
       
   574 	}
       
   575 
       
   576 /**
       
   577 Called by MDataSource to pass back a full buffer to the sink. 
       
   578 
       
   579 Should never be called by a sink, as sinks empty buffers, not fill them.
       
   580 
       
   581 @param  aBuffer
       
   582         The filled buffer.
       
   583 */
       
   584 void CMMFAudioOutput::BufferFilledL(CMMFBuffer* /*aBuffer*/)
       
   585 	{
       
   586 	Panic(EMMFAudioOutputPanicBufferFilledLNotSupported);
       
   587 	}
       
   588 
       
   589 /**
       
   590 Tests whether a sink buffer can be created.
       
   591 
       
   592 The default implementation returns true.
       
   593 
       
   594 @return A boolean indicating if the sink buffer can be created. ETrue if it can, otherwise EFalse.
       
   595 */
       
   596 TBool CMMFAudioOutput::CanCreateSinkBuffer()
       
   597 	{
       
   598 	return ETrue;
       
   599 	}
       
   600 
       
   601 /**
       
   602 Creates a sink buffer.
       
   603 
       
   604 Intended for asynchronous usage (buffers supplied by Devsound device)
       
   605 
       
   606 @param  aMediaId
       
   607         The Media ID.
       
   608 @param	aReference
       
   609 		A boolean indicating if MDataSink owns the buffer. ETrue if does, otherwise EFalse.
       
   610 
       
   611 @return A sink buffer.
       
   612 */
       
   613 CMMFBuffer* CMMFAudioOutput::CreateSinkBufferL(TMediaId /*aMediaId*/, TBool &aReference)
       
   614 	{
       
   615 	//iDevSoundBuffer = CMMFDataBuffer::NewL(KAudioOutputDefaultFrameSize);
       
   616 	iDevSoundBuffer = NULL;		//DevSound supplies this buffer in first callback
       
   617 	aReference = ETrue;
       
   618 	if ( iNeedsSWConversion )
       
   619 		return iConvertBuffer;
       
   620 	else
       
   621 		return iDevSoundBuffer;
       
   622 	}
       
   623 
       
   624 /**
       
   625 Standard SymbianOS destructor.
       
   626 */
       
   627 CMMFAudioOutput::~CMMFAudioOutput()
       
   628 	{
       
   629 	// The following will never have been allocated unless
       
   630 	// software conversion was required, and due to certain DevSound
       
   631 	// implementations, this requirement can change dynamically.
       
   632 	delete iChannelAndSampleRateConverterFactory;
       
   633 	delete iConvertBuffer;
       
   634 
       
   635 	if (iMMFDevSound)
       
   636 		{
       
   637 		iMMFDevSound->Stop();
       
   638 		delete iMMFDevSound;
       
   639 		}
       
   640 	delete iActiveSchedulerWait;
       
   641 	}
       
   642 
       
   643 void CMMFAudioOutput::ConfigDevSoundL()
       
   644 	{
       
   645 	iMMFDevSound->SetConfigL(iDevSoundConfig);
       
   646 	}
       
   647 
       
   648 
       
   649 /**
       
   650 @deprecated
       
   651 
       
   652 This method should not be used - it is provided to maintain SC with v7.0s.
       
   653 
       
   654 @param  aAudioType
       
   655         The 4CC of the data supplied by this source.
       
   656 */
       
   657 void CMMFAudioOutput::SetDataTypeL(TFourCC aAudioType)
       
   658 	{
       
   659 	if (aAudioType != KMMFFourCCCodePCM16)
       
   660 		{
       
   661 		User::Leave(KErrNotSupported);
       
   662 		}
       
   663 	}
       
   664 
       
   665 
       
   666 /**
       
   667 @deprecated
       
   668 
       
   669 This method should not be used - it is provided to maintain SC with v7.0s.
       
   670 
       
   671 @return The 4CC of the data supplied by this source.
       
   672 */
       
   673 TFourCC CMMFAudioOutput::DataType() const
       
   674 	{
       
   675 	return KMMFFourCCCodePCM16;
       
   676 	}
       
   677 
       
   678 /**
       
   679 Queries about DevSound resume support
       
   680 
       
   681 @return ETrue if DevSound does support resume, EFalse otherwise
       
   682 */
       
   683 TBool CMMFAudioOutput::IsResumeSupported()
       
   684 	{
       
   685 	TBool isSupported = EFalse;
       
   686 	if (iMMFDevSound)
       
   687 		{
       
   688 		isSupported = iMMFDevSound->IsResumeSupported();
       
   689 		}
       
   690 	return isSupported;
       
   691 	}
       
   692 
       
   693 
       
   694 /**
       
   695 Loads audio device drivers and initialise this device.
       
   696 */
       
   697 void CMMFAudioOutput::LoadL()
       
   698 	{
       
   699 	iPlayStarted = EFalse;
       
   700 	if (iState != EDevSoundReady)
       
   701 		iState = EIdle;
       
   702 
       
   703 	iMMFDevSound = CMMFDevSound::NewL();
       
   704 	
       
   705 	//This is done to maintain compatibility with the media server
       
   706 	iMMFDevSound->SetVolume(iMMFDevSound->MaxVolume() - 1);
       
   707 
       
   708 	//note cannot perform further initlaisation here untill the datatype is known
       
   709 
       
   710 	iDevSoundLoaded = ETrue;
       
   711 	}
       
   712 
       
   713 /**
       
   714 DeviceMessage MMFDevSoundObserver
       
   715 */
       
   716 void CMMFAudioOutput::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
       
   717 	{
       
   718 	}
       
   719 
       
   720 
       
   721 /**
       
   722 ToneFinished MMFDevSoundObserver called when a tone has finished or interrupted
       
   723 
       
   724 Should never get called.
       
   725 */
       
   726 void CMMFAudioOutput::ToneFinished(TInt /*aError*/)
       
   727 	{
       
   728 	//we should never get a tone error in MMFAudioOutput!
       
   729 	__ASSERT_DEBUG(EFalse, Panic(EMMFAudioOutputPanicToneFinishedNotSupported));
       
   730 	}
       
   731 
       
   732 
       
   733 /**
       
   734 RecordError MMFDevSoundObserver called when recording has halted.
       
   735 
       
   736 Should never get called.
       
   737 */
       
   738 void CMMFAudioOutput::RecordError(TInt /*aError*/)
       
   739 	{
       
   740 	//we should never get a recording error in MMFAudioOutput!
       
   741 	__ASSERT_DEBUG(EFalse, Panic(EMMFAudioOutputPanicRecordErrorNotSupported));
       
   742 	}
       
   743 
       
   744 /**
       
   745 InitializeComplete MMFDevSoundObserver called when devsound initialisation completed.
       
   746 */
       
   747 void CMMFAudioOutput::InitializeComplete(TInt aError)
       
   748 	{
       
   749 	
       
   750 	if (aError == KErrNone)
       
   751 		{
       
   752 		iState = EDevSoundReady;
       
   753 		}
       
   754 	
       
   755 	if(iInitializeState == KRequestPending)
       
   756 		{
       
   757 		iInitializeState = aError;
       
   758 		iActiveSchedulerWait->AsyncStop();
       
   759 		}
       
   760 	}
       
   761 
       
   762 /**
       
   763 BufferToBeEmptied MMFDevSoundObserver - should never get called.
       
   764 */
       
   765 void CMMFAudioOutput::BufferToBeEmptied(CMMFBuffer* /*aBuffer*/)
       
   766 	{
       
   767 	__ASSERT_DEBUG(EFalse, Panic(EMMFAudioOutputPanicRecordErrorNotSupported));
       
   768 	}
       
   769 
       
   770 /**
       
   771 BufferToBeFilled MMFDevSoundObserver.
       
   772 Called when buffer used up.
       
   773 */
       
   774 void CMMFAudioOutput::BufferToBeFilled(CMMFBuffer* aBuffer)
       
   775 	{
       
   776 	TInt err = KErrNone;
       
   777 
       
   778 	TRAP(err, iSupplier->BufferEmptiedL(aBuffer));
       
   779 
       
   780 	//This error needs handling properly
       
   781 	__ASSERT_DEBUG(!err, Panic(err));
       
   782 	}
       
   783 
       
   784 /**
       
   785 PlayError MMFDevSoundObserver.
       
   786 
       
   787 Called when stopped due to error or EOF.
       
   788 */
       
   789 void CMMFAudioOutput::PlayError(TInt aError)
       
   790 	{
       
   791 	iMMFDevsoundError = aError;
       
   792 
       
   793 	//send EOF to client
       
   794 	TMMFEvent event(KMMFEventCategoryPlaybackComplete, aError);
       
   795 	SendEventToClient(event);
       
   796 
       
   797 	//stop stack overflow / looping problem - AD
       
   798 	if (aError == KErrCancel)
       
   799 		return;
       
   800 
       
   801 	// NB KErrInUse, KErrDied OR KErrAccessDenied may be returned by the policy server
       
   802 	// to indicate that the sound device is in use by another higher priority client.
       
   803 	if (aError == KErrInUse || aError == KErrDied || aError == KErrAccessDenied)
       
   804 		return;
       
   805 
       
   806 	if (iState == EIdle)
       
   807 		{//probably have stopped audio output and have got an underflow from last buffer
       
   808 		iMMFDevSound->Stop();
       
   809 		iPlayStarted = EFalse;
       
   810 		iCanSendBuffers = EFalse;
       
   811 		}
       
   812 	}
       
   813 
       
   814 
       
   815 /**
       
   816 ConvertError MMFDevSoundObserver.
       
   817 
       
   818 Should never get called.
       
   819 */
       
   820 void CMMFAudioOutput::ConvertError(TInt /*aError*/)
       
   821 	{
       
   822 	}
       
   823 
       
   824 
       
   825 /**
       
   826 Returns the number of bytes played.
       
   827 
       
   828 @return	The number of bytes played. If 16-bit divide this number returned by 2 to get word length.
       
   829 */
       
   830 TInt CMMFAudioOutput::BytesPlayed()
       
   831 	{
       
   832 	if (!iMMFDevSound)
       
   833 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   834 	return iMMFDevSound->SamplesPlayed();
       
   835 	}
       
   836 
       
   837 /**
       
   838 Returns the sound device.
       
   839 
       
   840 Accessor function exposing public CMMFDevsound methods.
       
   841 
       
   842 @return	A reference to a CMMFDevSound objector.
       
   843 */
       
   844 CMMFDevSound& CMMFAudioOutput::SoundDevice()
       
   845 	{
       
   846 	if (!iMMFDevSound)
       
   847 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   848 	return *iMMFDevSound;
       
   849 	}
       
   850 
       
   851 void CMMFAudioOutput::SendEventToClient(const TMMFEvent& aEvent)
       
   852 	{
       
   853 	iEventHandler->SendEventToClient(aEvent);
       
   854 	}
       
   855 // __________________________________________________________________________
       
   856 // Exported proxy for instantiation method resolution
       
   857 // Define the interface UIDs
       
   858 
       
   859 
       
   860 
       
   861 const TImplementationProxy ImplementationTable[] =
       
   862 	{
       
   863 		IMPLEMENTATION_PROXY_ENTRY(KMmfUidAudioOutputInterface,	CMMFAudioOutput::NewSinkL)
       
   864 	};
       
   865 
       
   866 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
       
   867 	{
       
   868 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
       
   869 
       
   870 	return ImplementationTable;
       
   871 	}
       
   872