devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecWrapper.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2003-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 <mmf/server/mmfswcodecwrapper.h>
       
    17 #include "mmfSwCodecPlayDataPath.h"
       
    18 #include "mmfSwCodecRecordDataPath.h"
       
    19 #include "mmfSwCodecConvertDataPath.h"
       
    20 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh>
       
    21 #include "mmfswcodecwrapperCustomInterfaces.h"
       
    22 #include <mmf/common/mmfpaniccodes.h>
       
    23 
       
    24 
       
    25 
       
    26 /**
       
    27  * Internal panic
       
    28  * @internalComponent
       
    29  */
       
    30 void Panic(TInt aPanicCode)
       
    31 	{
       
    32 	_LIT(KMMFSwCodecWrapperPanicCategory, "MMFSwCodecWrapper");
       
    33 	User::Panic(KMMFSwCodecWrapperPanicCategory, aPanicCode);
       
    34 	}
       
    35 
       
    36 
       
    37 /**
       
    38  * This method is not be exported as it is only 
       
    39  * intended to be called within this DLL.
       
    40  * It's purpose is to assign an RMdaDevSound to the play
       
    41  * custom interface
       
    42  * @internalComponent
       
    43  */
       
    44 void TPlayCustomInterface::SetDevice(RMdaDevSound* aDevice)
       
    45 	{
       
    46 	iDevice = aDevice;
       
    47 	}
       
    48 
       
    49 void TPlayCustomInterface::SetVolume(TUint aVolume)
       
    50 	{
       
    51 	iVolume = aVolume;
       
    52 	if (iDevice && iDevice->Handle())
       
    53 		iDevice->SetPlayVolume(iVolume);
       
    54 	}
       
    55 	
       
    56 /**
       
    57  * Procedure to get the number of bytes played by the device driver
       
    58  * If there is no handle available to the device driver then the 
       
    59  * procedure returns the last known value
       
    60  * @released
       
    61  * @return number of bytes played
       
    62  */
       
    63 TUint TPlayCustomInterface::BytesPlayed()
       
    64 	{
       
    65 	if(iDevice)
       
    66 		{
       
    67 		if (iDevice->Handle())
       
    68 			iBytesPlayed = iDevice->BytesPlayed();
       
    69 		}
       
    70 	return iBytesPlayed;
       
    71 	}
       
    72 
       
    73 /**
       
    74  * Procedure to get the number of bytes recorded by the device  
       
    75  * @released
       
    76  * @return The number of bytes recorded by an existing datapath.  If there
       
    77  * is no datapath, then the last known number of bytes recorded will be returned.
       
    78  */
       
    79 TUint TRecordCustomInterface::BytesRecorded()
       
    80 	{
       
    81 	if(iDataPath)
       
    82 		{
       
    83 		iBytesRecorded = iDataPath->RecordedBytesCount();
       
    84 		}
       
    85 	return iBytesRecorded;
       
    86 	}
       
    87 	
       
    88 /**
       
    89 Constructor.
       
    90 */
       
    91 EXPORT_C CMMFSwCodecWrapper::CMMFSwCodecWrapper()
       
    92 	{
       
    93 	}
       
    94 
       
    95 /**
       
    96 Destructor.
       
    97 
       
    98 The destructor is called by ECom framework allowing derived classes
       
    99 to clean up implementation specific resources. The sound
       
   100 device drivers are freed.
       
   101 */
       
   102 EXPORT_C CMMFSwCodecWrapper::~CMMFSwCodecWrapper()
       
   103 	{
       
   104 	delete iDataPath;
       
   105 	delete iCodec;
       
   106 	delete iPlayCustomInterface;
       
   107 	delete iRecordCustomInterface;
       
   108 	}
       
   109 
       
   110 /**
       
   111 Initializes the hardware device tasks - in the case of a
       
   112 sw codec wrapper 'hardware device' this consits of loading the
       
   113 sound device drivers and creating the CMMFSwCodec.
       
   114 
       
   115 @param  aDevInfo
       
   116         Device initialization parameters.
       
   117         Only the iHwDeviceObserver is used for CMFSwCodecWrapper
       
   118         derived CMMFHwDevices.
       
   119 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   120         another of the system-wide error codes.
       
   121 */
       
   122 EXPORT_C TInt CMMFSwCodecWrapper::Init(THwDeviceInitParams &aDevInfo)
       
   123 	{
       
   124 
       
   125 	// [ precondition that aDevInfo has a valid observer ]
       
   126 	if (!aDevInfo.iHwDeviceObserver) 
       
   127 		return KErrArgument;
       
   128 
       
   129 	iHwDeviceObserver = aDevInfo.iHwDeviceObserver;
       
   130 #ifndef SYMBIAN_MDF_SHAREDCHUNK_SOUNDDRIVER //Adapter loads the drivers
       
   131 	// Try to load the audio physical driver
       
   132     TInt ret = User::LoadPhysicalDevice(KPddFileName);
       
   133 	if ((ret!=KErrNone) && (ret!=KErrAlreadyExists))
       
   134         return ret;
       
   135 
       
   136     // Try to load the audio logical driver
       
   137 	ret = User::LoadLogicalDevice(KLddFileName);
       
   138     if ((ret!=KErrNone) && (ret!=KErrAlreadyExists))
       
   139         return ret;
       
   140 #endif
       
   141 	iCodec = &(Codec()); //create codec
       
   142 
       
   143 	//[ assert the post condition ]
       
   144 	if (!iCodec) 
       
   145 		return KErrNotSupported;
       
   146 
       
   147 	return KErrNone;
       
   148 	}
       
   149 
       
   150 
       
   151 /**
       
   152 Starts Encoding or Decoding task(s) based on the parameter specified.
       
   153 
       
   154 @param  aFuncCmd
       
   155         The device function specifying the requested service i.e. decode or encode
       
   156         where EDevEncode = Record, EDevDecode = Play and EDevNullFunc = Convert.
       
   157 @param  aFlowCmd
       
   158         The device flow directions for requested service.
       
   159         This parameter is ignored for CMMFSwCodecWrapper CMMFHwDevicePlugins
       
   160 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   161         another of the system-wide error codes.
       
   162 */
       
   163 EXPORT_C TInt CMMFSwCodecWrapper::Start(TDeviceFunc aFuncCmd, TDeviceFlow /*aFlowCmd*/)
       
   164 	{
       
   165 	TInt error = KErrNone;
       
   166 
       
   167 	// [ precondition that aFuncCmd is valid]
       
   168 	if (!((aFuncCmd == EDevEncode)|(aFuncCmd == EDevDecode)|(aFuncCmd == EDevNullFunc)))
       
   169 		return KErrArgument;
       
   170 
       
   171 	// [ precondition that iCodec is present]
       
   172 	if (!iCodec)
       
   173 		return KErrNotReady; //make sure the codec has been added
       
   174 
       
   175     switch (aFuncCmd)
       
   176         {
       
   177         case EDevEncode: // Audio record
       
   178 			{
       
   179 			error = StartEncode();
       
   180 			}
       
   181             break;
       
   182         case EDevDecode: // Audio play
       
   183 			{
       
   184 			error = StartDecode();
       
   185 			}
       
   186             break;
       
   187 		case EDevNullFunc: //Audio Convert
       
   188 			{
       
   189 			error = StartConvert();
       
   190 			}
       
   191 			break;
       
   192         default:
       
   193             error = KErrNotSupported;
       
   194             break;
       
   195 		}
       
   196 
       
   197 	//[ assert the post conditions ]
       
   198 #ifdef DEBUG
       
   199 	if (!error)
       
   200 		{//only assert if no error otherwise post consitions not valid
       
   201 		__ASSERT_DEBUG(iDataPath, Panic(EMMFSwCodecWrapperNoDataPath));
       
   202 		if ((aFuncCmd == EDevEncode)||(aFuncCmd == EDevDecode))
       
   203 			__ASSERT_DEBUG(iDataPath->Device().Handle(), Panic(EMMFSwCodecWrapperNoDevice));
       
   204 		}
       
   205 #endif
       
   206 	if(error != KErrNone && iDataPath && aFuncCmd!=EDevEncode)
       
   207 		{//if error happens after opening LDD close it
       
   208 		if (iDataPath->Device().Handle()!= KNullHandle)
       
   209 			{
       
   210 			iDataPath->Device().Close();
       
   211 			}
       
   212 		}
       
   213 
       
   214 	return error;
       
   215 	}
       
   216 
       
   217 
       
   218 TInt CMMFSwCodecWrapper::StartDecode()
       
   219 	{
       
   220 	TInt error = KErrNone;
       
   221 
       
   222 	//[ assert precondition that play custom interface is present]
       
   223 	//if there is no play custom interface then the user of the CMMFSwCodecWrapper
       
   224 	//cannot have set any of the custom settings such as sample rate.
       
   225 	if (!iPlayCustomInterface)
       
   226 		return KErrNotReady;
       
   227 
       
   228 	//play
       
   229 	if (!iDataPath)
       
   230 		{//create a datapath
       
   231 		TRAP(error,iDataPath = CMMFSwCodecPlayDataPath::NewL());
       
   232 		//if datapath could not be created, return error code
       
   233 		if (error != KErrNone)
       
   234 			{
       
   235 			return error;
       
   236 			}
       
   237 		
       
   238 		//here we are sure iDataPath has been correctly allocated		
       
   239 		iDataPath->SetObserver(*iHwDeviceObserver);
       
   240 		error = iDataPath->AddCodec(*iCodec);
       
   241 		if (error == KErrNone)
       
   242 			{
       
   243 			iDeviceBufferSize = (iCodec->SinkBufferSize());
       
   244 			static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->SetPlayCustomInterface(*iPlayCustomInterface);
       
   245 			}
       
   246 		else
       
   247 			{
       
   248 			// if could not add codec to datapath, return error code
       
   249 			return error;
       
   250 			}
       
   251 		}
       
   252 		
       
   253 	//Here we know that error is KerrNone, now we can check the state of the datapath	
       
   254 	if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying)
       
   255 		{//datapath was created ok and we are not playing
       
   256 		if (iDataPath->State() == CMMFSwCodecDataPath::EStopped)
       
   257 			{//starting from 'fresh so set sound device settings
       
   258 			if (!iDataPath->Device().Handle())
       
   259   				{//if Device() is called then we need a valid sound device handle
       
   260   				error = iDataPath->Device().Open();
       
   261 				if (error != KErrNone)
       
   262 					return error;
       
   263 				}
       
   264 			static_cast<TPlayCustomInterface*>(iPlayCustomInterface)->SetDevice(&(iDataPath->Device()));
       
   265 			iDataPath->Device().SetPlayVolume(iPlayCustomInterface->Volume());
       
   266 			RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
       
   267 			soundDeviceSettings().iRate = iSampleRate;
       
   268 			//this would normally be pcm16
       
   269 			soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
       
   270 			//1 = mono 2 = stereo
       
   271 			soundDeviceSettings().iChannels = iChannels;
       
   272 			//tell sound driver what buffer size to expect
       
   273 			//it is up the the implementor to make use the device can support
       
   274 			//the required buffer size
       
   275 			soundDeviceSettings().iBufferSize = iDeviceBufferSize;
       
   276 			error = iDataPath->Device().SetPlayFormat(soundDeviceSettings);	
       
   277 			}//iDataPath->State() == CMMFSwCodecDataPath::EStopped
       
   278 		//else resuming from pause	
       
   279 		if ((error == KErrNone)||(error == KErrInUse))
       
   280 			error = iDataPath->Start();
       
   281 		}//status == KErrNone
       
   282 	return error;
       
   283 	}
       
   284 
       
   285 
       
   286 TInt CMMFSwCodecWrapper::StartEncode()
       
   287 	{//record
       
   288 
       
   289 	//[ assert precondition that record custom interface is present]
       
   290 	//if there is no record custom interface then the user of the CMMFSwCodecWrapper
       
   291 	//cannot have set any of the custom settings such as sample rate.
       
   292 	if (!iRecordCustomInterface)
       
   293 		return KErrNotReady;
       
   294 
       
   295 	TInt error = KErrNone;
       
   296 	if (!iDataPath)
       
   297 		{
       
   298 		TRAP(error,iDataPath = CMMFSwCodecRecordDataPath::NewL());
       
   299 		//if datapath could not be created, return error code
       
   300 		if (error != KErrNone)
       
   301 			{
       
   302 			return error;
       
   303 			}
       
   304 
       
   305 		//here we are sure iDataPath has been correctly allocated
       
   306 		iDataPath->SetObserver(*iHwDeviceObserver);
       
   307 		error = iDataPath->AddCodec(*iCodec);
       
   308 		if (error == KErrNone)
       
   309 			{
       
   310 			iDeviceBufferSize = (iCodec->SourceBufferSize());
       
   311 			static_cast<TRecordCustomInterface*>(iRecordCustomInterface)->SetDataPath(static_cast<CMMFSwCodecRecordDataPath*>(iDataPath));
       
   312 			}
       
   313 		else
       
   314 			{
       
   315 			// if could not add codec to datapath, return error code
       
   316 			return error;
       
   317 			}
       
   318 		}
       
   319 	
       
   320 	//Here we know that error is KerrNone, now we can check the state of the datapath
       
   321 	if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying)
       
   322 		{
       
   323 		if (iDataPath->State() == CMMFSwCodecDataPath::EStopped)
       
   324 			{
       
   325 			MSwSetParamInterface* setParams = 
       
   326 				static_cast<MSwSetParamInterface*>(iDataPath->CustomInterface(KUidSwSetParamInterface));
       
   327 			ASSERT(!error); // should not get here if error set
       
   328 			error = setParams->SetGain(iRecordCustomInterface->Gain());
       
   329 			if (!error)
       
   330 				{
       
   331 				error = setParams->SetNumChannels(iChannels);
       
   332 				}
       
   333 			if (!error)
       
   334 				{
       
   335 				error = setParams->SetSampleRate(iSampleRate);
       
   336 				}
       
   337 			}
       
   338 		if (error == KErrNone)
       
   339 			{
       
   340 			error = iDataPath->Start();
       
   341 			}
       
   342 		}
       
   343 	return error;
       
   344 	}
       
   345 
       
   346 
       
   347 TInt CMMFSwCodecWrapper::StartConvert()
       
   348 	{//convert
       
   349 
       
   350 	TInt error = KErrNone;
       
   351 	if (!iDataPath)
       
   352 		{
       
   353 		TRAP(error,iDataPath = CMMFSwCodecConvertDataPath::NewL());
       
   354 		if (error != KErrNone)
       
   355 			{
       
   356 			return error;
       
   357 			}
       
   358 		}
       
   359 	
       
   360 	//Here we know we are not dereferencing a null pointer as iDataPath has been correctly initialised
       
   361 	iDataPath->SetObserver(*iHwDeviceObserver);
       
   362 	error = iDataPath->AddCodec(*iCodec);
       
   363 	
       
   364     if (error == KErrNone)
       
   365 		{
       
   366 		error = iDataPath->Start();	
       
   367 		}
       
   368 		
       
   369 	return error;
       
   370 	}
       
   371 
       
   372 /**
       
   373 Temporarily suspends the current task of decoding or encoding.
       
   374 
       
   375 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   376         another of the system-wide error codes.
       
   377 */
       
   378 EXPORT_C TInt CMMFSwCodecWrapper::Pause()
       
   379 	{
       
   380 	// [ precondition that datapath exists ]
       
   381 	if (!iDataPath) 
       
   382 		return KErrNotReady;
       
   383 
       
   384 	iDataPath->Pause();
       
   385 	return KErrNone;
       
   386 	}
       
   387 
       
   388 /**
       
   389 Stops the current on-going task.
       
   390 
       
   391 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   392         another of the system-wide error codes.
       
   393 */
       
   394 EXPORT_C TInt CMMFSwCodecWrapper::Stop()
       
   395 	{
       
   396 	// [ precondition that datapath exists ]
       
   397 	if (!iDataPath)
       
   398 		return KErrNotReady;
       
   399 
       
   400 	iDataPath->Stop();
       
   401 	return KErrNone;
       
   402 	}
       
   403 
       
   404 
       
   405 /**
       
   406 Stops and deletes the codec.
       
   407 
       
   408 This default implementation simply calls DeleteCodec() and then Stop()
       
   409 but real hardware devices might use this method to free up resources.
       
   410 
       
   411 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   412         another of the system-wide error codes.
       
   413 */
       
   414 EXPORT_C TInt CMMFSwCodecWrapper::StopAndDeleteCodec()
       
   415 	{
       
   416 	TInt stopError = Stop();
       
   417 	TInt deleteError = DeleteCodec();
       
   418 
       
   419 	if (stopError != KErrNone)
       
   420 		return stopError;
       
   421 	else
       
   422 		return deleteError;
       
   423 	}
       
   424 
       
   425 /**
       
   426 Deletes the codec
       
   427 This default implementation does nothing
       
   428 but real hardware devices might use this method to free up resources.
       
   429 @return		Error code. KErrNone if successful
       
   430 */
       
   431 EXPORT_C TInt CMMFSwCodecWrapper::DeleteCodec()
       
   432 	{
       
   433 	return KErrNone;
       
   434 	}
       
   435 
       
   436 /**
       
   437 Call this function to notify hardware device implementation that
       
   438 data is available in aFillBufferPtr for decoding.
       
   439 
       
   440 @param aFillBufferPtr
       
   441        The data buffer filled by the observer.
       
   442 
       
   443 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   444         another of the system-wide error codes.
       
   445 */
       
   446 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferFilled(CMMFBuffer& aFillBufferPtr)
       
   447 	{
       
   448 	TRAPD(err,iDataPath->BufferFilledL(STATIC_CAST(CMMFDataBuffer&, aFillBufferPtr)));
       
   449 	return err;
       
   450 	}
       
   451 
       
   452 /**
       
   453 Call this function to notify hardware device implementation that
       
   454 data in aEmptyBufferPtr from encoding is processed.
       
   455 
       
   456 @param  aBuffer
       
   457         The data buffer processed by observer.
       
   458 
       
   459 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
       
   460         another of the system-wide error codes.
       
   461 */
       
   462 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferEmptied(CMMFBuffer& aBuffer)
       
   463 	{
       
   464 	TRAPD(err,iDataPath->BufferEmptiedL(STATIC_CAST(CMMFDataBuffer&, aBuffer)));
       
   465 	return err;
       
   466 	}
       
   467 
       
   468 
       
   469 /**
       
   470 Retrieves a custom interface to the device.
       
   471 The reference CMMFSwCodecWrapper supports two standard custom interfaces,
       
   472 MPlayCustomInterface and MRecordCustomInterface.
       
   473 
       
   474 @param	aInterface
       
   475 		Interface UID, defined with the custom interface.
       
   476 		aInterface = KMmfPlaySettingsCustomInterface for MPlayCustomInterface,
       
   477 		aInterface = KMmfRecordSettingsCustomInterface for MRecordCustomInterface.
       
   478 		aInterface = KMmfUidEmptyBuffersCustomInterface for MEmptyBuffersCustomInterface
       
   479 		Actual device implementations of CMMFSwCodecWrapper may do this differently however.
       
   480 @return A pointer to the interface implementation, or NULL if the device can not
       
   481 		implement the interface requested. The return value must be cast to the
       
   482 		correct type by the user.
       
   483 */
       
   484 EXPORT_C TAny* CMMFSwCodecWrapper::CustomInterface(TUid aInterface)
       
   485 	{
       
   486 	TAny* ret = NULL;
       
   487 	TInt err = KErrNone;
       
   488 	if (aInterface.iUid == KMmfPlaySettingsCustomInterface)
       
   489 		{
       
   490 		if (!iPlayCustomInterface)
       
   491 			TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface());
       
   492 		if (err)
       
   493 			ret = NULL;
       
   494 		else
       
   495 			ret = static_cast<TAny*>(iPlayCustomInterface);
       
   496 		}
       
   497 	else if (aInterface.iUid == KMmfRecordSettingsCustomInterface)
       
   498 		{
       
   499 		if (!iRecordCustomInterface)
       
   500 			TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface());
       
   501 		if (err)
       
   502 			ret = NULL;
       
   503 		else 
       
   504 			ret = static_cast<TAny*>(iRecordCustomInterface);
       
   505 		}
       
   506 		
       
   507 	else if (aInterface.iUid == KMmfUidEmptyBuffersCustomInterface || aInterface == KTimePlayedCustomInterfaceTypeUid || aInterface == KIgnoreUnderflowCustomInterfaceTypeUid)
       
   508 		{
       
   509 		if (!iDataPath)
       
   510 			{
       
   511 			ret = NULL;			
       
   512 			}
       
   513 		else
       
   514 			{
       
   515 			ret = static_cast<CMMFSwCodecDataPath*>(iDataPath)->CustomInterface(aInterface);	
       
   516 			}	
       
   517 		}
       
   518 
       
   519 	return ret;
       
   520 	}
       
   521 
       
   522 
       
   523 /**
       
   524 Used to configure the sample rate and stereo mode of a CMMFHwDevice plugin.
       
   525 
       
   526 The configuration of HwDevices is device specific and is not used in any of the reference
       
   527 devices that return KErrNotSupported.
       
   528 
       
   529 @param  aConfig
       
   530         The device configuration.
       
   531 */
       
   532 EXPORT_C TInt CMMFSwCodecWrapper::SetConfig(TTaskConfig& aConfig)
       
   533 	{
       
   534 	if (aConfig.iUid != KUidRefDevSoundTaskConfig)
       
   535 		return KErrArgument;
       
   536 	iSampleRate = aConfig.iRate;
       
   537 	
       
   538 	if (aConfig.iStereoMode == ETaskMono)
       
   539 		{
       
   540 		iChannels = 1;
       
   541 		}
       
   542 	else if (aConfig.iStereoMode == ETaskInterleaved || aConfig.iStereoMode == ETaskNonInterleaved)
       
   543 		{
       
   544 		iChannels = 2;
       
   545 		}
       
   546 	else
       
   547 		{
       
   548 		return KErrArgument;
       
   549 		}
       
   550 	return KErrNone;
       
   551 	}
       
   552 
       
   553 /**
       
   554 Used to set iVbrFlag on the datapath.
       
   555 
       
   556 This method is used to set the iVbrFlag in datapath. This flag is added to datapath to avail the 
       
   557 alternative dataflow wherein datapath makes sure that destinationbuffer is filled to its maximum length
       
   558 before sending it to the sound driver. Sending the buffer directly to the device causes underflow incase of VBR codecs.
       
   559 */
       
   560 EXPORT_C void CMMFSwCodecWrapper::SetVbrFlag()
       
   561 	{
       
   562 	if(iDataPath)
       
   563 		{
       
   564 		TUid cUid = TUid::Uid(KSetVbrFlagCustomInterfaceTypeUid);
       
   565 		iDataPath->CustomInterface(cUid);
       
   566 		}
       
   567 	}
       
   568 
       
   569