os/mm/devsound/devsoundrefplugin/src/platsec/SoundDevice/SoundDeviceBody.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2001-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/plugin/mmfhwdeviceimplementationuids.hrh>
    17 #include "SoundDeviceBody.h"
    18 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh> // KUidRefDevSoundTaskConfig
    19 
    20 const TInt KMaxMessageQueueItems = 8;
    21 
    22 /*
    23  *
    24  *	Default Constructor.
    25  *
    26  *	No default implementation. CMMFDevSound implements 2-phase construction.
    27  *
    28  */
    29 CMMFDevSoundClientImp::CMMFDevSoundClientImp()
    30 	{
    31 	}
    32 
    33 /*
    34  *
    35  *	Destructor.
    36  *
    37  *	Deletes all objects and releases all resource owned by this
    38  *	instance.
    39  *
    40  */
    41 CMMFDevSoundClientImp::~CMMFDevSoundClientImp()
    42 	{
    43 	// clear the array of custom interfaces
    44 	for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
    45 		{
    46 		iCustomInterfaceArray[i].iInterface->Release();
    47 		}
    48 	iCustomInterfaceArray.Reset();
    49 	iCustomInterfaceArray.Close();
    50 
    51 	// delete the MUX utility
    52 	delete iMuxUtility;
    53 
    54 	if (iMsgQueueHandler && iMsgQueueHandler->IsActive())
    55 		{
    56 		iMsgQueueHandler->Cancel();
    57 		}
    58 	delete iMsgQueueHandler;
    59 
    60 	iMsgQueue.Close();	
    61 
    62 	if( iDevSoundProxy != NULL)
    63 		{
    64 		iDevSoundProxy->Close();
    65 		delete iDevSoundProxy;
    66 		}
    67 	}
    68 
    69 /*
    70  *
    71  *	Constructs, and returns a pointer to, a new CMMFDevSound object.
    72  *
    73  *	Leaves on failure.
    74  *
    75  */
    76 CMMFDevSoundClientImp* CMMFDevSoundClientImp::NewL()
    77 	{
    78 	CMMFDevSoundClientImp* self = new (ELeave) CMMFDevSoundClientImp();
    79 	CleanupStack::PushL(self);
    80 	self->ConstructL();
    81 	CleanupStack::Pop(self);
    82 	return self;
    83 	}
    84 
    85 /*
    86  *
    87  *	2nd phase constructor - assumes that iParent has already been set up properly.
    88  *
    89  */
    90 void CMMFDevSoundClientImp::ConstructL()
    91 	{
    92 	// all these data properties should be NULL, but add ASSERTs to verify
    93 
    94 	ASSERT(iDevSoundProxy==NULL);
    95 	iDevSoundProxy = new (ELeave) RMMFDevSoundProxy();
    96 
    97 	TInt err = iMsgQueue.CreateGlobal(KNullDesC, KMaxMessageQueueItems);	// global, accessible to all that have its handle
    98 	User::LeaveIfError(err);
    99 	err = iDevSoundProxy->Open(iMsgQueue);
   100 	if(err)
   101 		{
   102 		delete iDevSoundProxy;
   103 		iDevSoundProxy = NULL;
   104 		}
   105 
   106 	User::LeaveIfError(err);
   107 
   108 	// create MUX utility
   109 	iMuxUtility = CMMFDevSoundCIMuxUtility::NewL(this);
   110 	}
   111 
   112 
   113 /*
   114  *
   115  *	Initializes CMMFDevSound object to play and record PCM16 raw audio data
   116  *	with sampling rate of 8 KHz.
   117  *
   118  *	On completion of Initialization, calls InitializeComplete() on
   119  *	aDevSoundObserver.
   120  *
   121  *	Leaves on failure.
   122  *
   123  *	@param	"MDevSoundObserver& aDevSoundObserver"
   124  *			A reference to DevSound Observer instance.
   125  *
   126  *	@param	"TMMFState aMode"
   127  *			Mode for which this object will be used.
   128  *
   129  */
   130 void CMMFDevSoundClientImp::InitializeL(MDevSoundObserver& aDevSoundObserver, TMMFState aMode)
   131 
   132 	{
   133 	TInt initError = KErrNone;
   134 	iDevSoundObserver = &aDevSoundObserver;
   135 	initError = iDevSoundProxy->InitializeL(aMode);
   136 
   137 	if (initError)
   138 		{
   139 		User::Leave(initError);
   140 		}
   141 
   142 	if (iMsgQueueHandler)
   143 		{
   144 		iMsgQueueHandler->Cancel();
   145 		iMsgQueueHandler->SetObserver(*iDevSoundObserver);
   146 		}
   147 	else
   148 		{
   149 		iMsgQueueHandler = CMsgQueueHandler::NewL(iDevSoundProxy, *iDevSoundObserver, &iMsgQueue, *this);
   150 		}
   151 
   152 	iMsgQueueHandler->ReceiveEvents();
   153 	}
   154 
   155 /*
   156  *
   157  *	Configure CMMFDevSound object for the settings in aConfig.
   158  *
   159  *	Use this to set sampling rate, Encoding and Mono/Stereo.
   160  *
   161  *	@param	"TMMFCapabilities& aConfig"
   162  *			Attribute values to which CMMFDevSound object will be configured to.
   163  *
   164  *  As part of defect 20796, the iRecordFormat has been set under the iPlayFormat, 
   165  *  before it was not set at all.
   166  *
   167  */
   168 void CMMFDevSoundClientImp::SetConfigL(const TMMFCapabilities& aConfig)
   169 	{
   170 	iDevSoundProxy->SetConfigL(aConfig);
   171 	}
   172 
   173 /*
   174  *
   175  *	Changes the current playback volume to a specified value.
   176  *
   177  *	The volume can be changed before or during playback and is effective
   178  *	immediately.
   179  *
   180  *	@param	"TInt aVolume"
   181  *			The volume setting. This can be any value from zero to the value
   182  *			returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
   183  *			volume is not within this range, the volume is automatically set to
   184  *			minimum or maximum value based on the value that is being passed.
   185  *			Setting a zero value mutes the sound. Setting the maximum value
   186  *			results in the loudest possible sound.
   187  *
   188  */
   189 void CMMFDevSoundClientImp::SetVolume(TInt aVolume)
   190 	{
   191 	iDevSoundProxy->SetVolume(aVolume);
   192 	}
   193 
   194 /*
   195  *
   196  *	Changes the current recording gain to a specified value.
   197  *
   198  *	The gain can be changed before or during recording and is effective
   199  *	immediately.
   200  *
   201  *	@param	"TInt aGain"
   202  *			The volume setting. This can be any value from zero to the value
   203  *			returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
   204  *			volume is not within this range, the gain is automatically set to
   205  *			minimum or maximum value based on the value that is being passed.
   206  *			Setting a zero value mutes the sound. Setting the maximum value
   207  *			results in the loudest possible sound.
   208  *
   209  */
   210 void CMMFDevSoundClientImp::SetGain(TInt aGain)
   211 	{
   212 	iDevSoundProxy->SetGain(aGain);
   213 	}
   214 
   215 /*
   216  *
   217  *	Sets the speaker balance for playing.
   218  *
   219  *	The speaker balance can be changed before or during playback and is
   220  *	effective immediately.
   221  *
   222  *	@param	"TInt& aLeftPercentage"
   223  *			On return contains left speaker volume perecentage. This can be any
   224  *			value from zero to 100. Setting a zero value mutes the sound on left
   225  *			speaker.
   226  *
   227  *	@param	"TInt& aRightPercentage"
   228  *			On return contains right speaker volume perecentage. This can be any
   229  *			value from zero to 100. Setting a zero value mutes the sound on
   230  *			right speaker.
   231  *
   232  */
   233 void CMMFDevSoundClientImp::SetPlayBalanceL(TInt aLeftPercentage, TInt aRightPercentage)
   234 	{
   235 	iDevSoundProxy->SetPlayBalanceL(aLeftPercentage, aRightPercentage);
   236 	}
   237 
   238 /*
   239  *
   240  *	Sets the microphone gain balance for recording.
   241  *
   242  *	The microphone gain balance can be changed before or during recording and
   243  *	is effective immediately.
   244  *
   245  *	@param	"TInt aLeftPercentage"
   246  *			Left microphone gain precentage. This can be any value from zero to
   247  *			100. Setting a zero value mutes the gain on left microphone.
   248  *
   249  *	@param	"TInt aRightPercentage"
   250  *			Right microphone gain precentage. This can be any value from zero to
   251  *			100. Setting a zero value mutes the gain on right microphone.
   252  *
   253  */
   254 void CMMFDevSoundClientImp::SetRecordBalanceL(TInt aLeftPercentage, TInt aRightPercentage)
   255 	{
   256 	iDevSoundProxy->SetRecordBalanceL(aLeftPercentage, aRightPercentage);
   257 	}
   258 
   259 /*
   260  *
   261  *	Initializes audio device and start play process. This method queries and
   262  *	acquires the audio policy before initializing audio device. If there was an
   263  *	error during policy initialization, PlayError() method will be called on
   264  *	the observer with error code KErrAccessDenied, otherwise BufferToBeFilled()
   265  *	method will be called with a buffer reference. After reading data into the
   266  *	buffer reference passed, the client should call PlayData() to play data.
   267  *
   268  *	The amount of data that can be played is specified in
   269  *	CMMFBuffer::RequestSize(). Any data that is read into buffer beyond this
   270  *	size will be ignored.
   271  *
   272  *	Leaves on failure.
   273  *
   274  */
   275 void CMMFDevSoundClientImp::PlayInitL()
   276 	{
   277 	if (!iDevSoundObserver)
   278 		User::Leave(KErrNotReady);
   279 	iDevSoundProxy->PlayInitL();
   280 	}
   281 
   282 /*
   283  *
   284  *	Initializes audio device and start record process. This method queries and
   285  *	acquires the audio policy before initializing audio device. If there was an
   286  *	error during policy initialization, RecordError() method will be called on
   287  *	the observer with error code KErrAccessDenied, otherwise BufferToBeEmptied()
   288  *	method will be called with a buffer reference. This buffer contains recorded
   289  *	or encoded data. After processing data in the buffer reference passed, the
   290  *	client should call RecordData() to continue recording process.
   291  *
   292  *	The amount of data that is available is specified in
   293  *	CMMFBuffer::RequestSize().
   294  *
   295  *	Leaves on failure.
   296  *
   297  */
   298 void CMMFDevSoundClientImp::RecordInitL()
   299 	{
   300 
   301 	if (!iDevSoundObserver)
   302 		User::Leave(KErrNotReady);
   303 	iDevSoundProxy->RecordInitL();
   304 	}
   305 
   306 /*
   307  *
   308  *	Plays data in the buffer at the current volume. The client should fill
   309  *	the buffer with audio data before calling this method. The Observer gets
   310  *	reference to buffer along with callback BufferToBeFilled(). When playing of
   311  *	the audio sample is complete, successfully or otherwise, the method
   312  *	PlayError() on observer is called.
   313  *
   314  */
   315 void CMMFDevSoundClientImp::PlayData()
   316 	{
   317 	ASSERT(iDevSoundObserver);
   318 	iDevSoundProxy->PlayData();
   319 	}
   320 
   321 /*
   322  *
   323  *	Stops the ongoing operation (Play, Record, TonePlay, Convert)
   324  *
   325  */
   326 void CMMFDevSoundClientImp::Stop()
   327 	{
   328 	iDevSoundProxy->Stop();
   329 	}
   330 
   331 /*
   332  *
   333  *	Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert)
   334  *
   335  */
   336 void CMMFDevSoundClientImp::Pause()
   337 	{
   338 	iDevSoundProxy->Pause();
   339 	}
   340 
   341 /*
   342  *
   343  *	Returns the sample recorded so far.
   344  *
   345  *	@return "TInt"
   346  *			Returns the samples recorded.
   347  *
   348  */
   349 TInt CMMFDevSoundClientImp::SamplesRecorded()
   350 	{
   351 	return iDevSoundProxy->SamplesRecorded();
   352 	}
   353 
   354 /*
   355  *
   356  *	Returns the sample played so far.
   357  *
   358  *	@return "TInt"
   359  *			Returns the samples recorded.
   360  *
   361  */
   362 TInt CMMFDevSoundClientImp::SamplesPlayed()
   363 	{
   364 	return iDevSoundProxy->SamplesPlayed();
   365 	}
   366 
   367 
   368 /*
   369  *
   370  *	Initializes audio device and start playing tone. Tone is played with
   371  *	frequency and for duration specified.
   372  *
   373  *	Leaves on failure.
   374  *
   375  *	@param	"TInt aFrequency"
   376  *			Frequency at with the tone will be played.
   377  *
   378  *	@param	"TTimeIntervalMicroSeconds& aDuration"
   379  *			The period over which the tone will be played. A zero value causes
   380  *			the no tone to be played (Verify this with test app).
   381  *
   382  */
   383 void CMMFDevSoundClientImp::PlayToneL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
   384 	{
   385 	iDevSoundProxy->PlayToneL(aFrequency, aDuration);
   386 	}
   387 
   388 /*
   389  *	Initializes audio device and start playing a dual tone. 
   390  *  The tone consists of two sine waves of different frequencies summed together
   391  *  Dual Tone is played with specified frequencies and for specified duration.
   392  *
   393  *	@param	"aFrequencyOne"
   394  *			First frequency of dual tone
   395  *
   396  *	@param	"aFrequencyTwo"
   397  *			Second frequency of dual tone
   398  *
   399  *	@param	"aDuration"
   400  *			The period over which the tone will be played. A zero value causes
   401  *			the no tone to be played (Verify this with test app).
   402  */
   403 void CMMFDevSoundClientImp::PlayDualToneL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
   404 	{
   405 	iDevSoundProxy->PlayDualToneL(aFrequencyOne, aFrequencyTwo, aDuration);
   406 	}
   407 
   408 /*
   409  *
   410  *	Initializes audio device and start playing DTMF string aDTMFString.
   411  *
   412  *	Leaves on failure.
   413  *
   414  *	@param	"TDesC& aDTMFString"
   415  *			DTMF sequence in a descriptor.
   416  *
   417  */
   418 void CMMFDevSoundClientImp::PlayDTMFStringL(const TDesC& aDTMFString)
   419 	{
   420 	if (!iDevSoundObserver)
   421 		User::Leave(KErrNotReady);
   422 
   423 	iDevSoundProxy->PlayDTMFStringL(aDTMFString);
   424 	}
   425 
   426 /*
   427  *
   428  *	Initializes audio device and start playing tone sequence.
   429  *
   430  *	Leaves on failure.
   431  *
   432  *	@param	"TDesC8& aData"
   433  *			Tone sequence in a descriptor.
   434  *
   435  */
   436 void CMMFDevSoundClientImp::PlayToneSequenceL(const TDesC8& aData)
   437 	{
   438 	if (!iDevSoundObserver)
   439 		User::Leave(KErrNotReady);
   440 
   441 	iDevSoundProxy->PlayToneSequenceL(aData);
   442 	}
   443 
   444 /*
   445  *
   446  *	Initializes audio device and start playing the specified pre-defined tone
   447  *	sequence.
   448  *
   449  *	Leaves on failure.
   450  *
   451  *	@param	"TInt aSequenceNumber"
   452  *			The index identifying the specific pre-defined tone sequence. Index
   453  *			values are relative to zero.
   454  *			This can be any value from zero to the value returned by a call to
   455  *			CMdaAudioPlayerUtility::FixedSequenceCount() - 1.
   456  *			The function raises a panic if sequence number is not within this
   457  *			range.
   458  *
   459  */
   460 void CMMFDevSoundClientImp::PlayFixedSequenceL(TInt aSequenceNumber)
   461 	{
   462 	if (!iDevSoundObserver)
   463 		User::Leave(KErrNotReady);
   464 
   465 	iDevSoundProxy->PlayFixedSequenceL(aSequenceNumber);
   466 	}
   467 
   468 /*
   469  *
   470  *	Defines the duration of tone on, tone off and tone pause to be used during the
   471  *	DTMF tone playback operation.
   472  *
   473  *	Supported only during tone playing.
   474  *
   475  *	@param	"TTimeIntervalMicroSeconds32& aToneOnLength"
   476  *			The period over which the tone will be played. If this is set to
   477  *			zero, then the tone is not played.
   478  *
   479  *	@param	"TTimeIntervalMicroSeconds32& aToneOffLength"
   480  *			The period over which the no tone will be played.
   481  *
   482  *	@param	"TTimeIntervalMicroSeconds32& aPauseLength"
   483  *			The period over which the tone playing will be paused.
   484  *
   485  */
   486 void CMMFDevSoundClientImp::SetDTMFLengths(TTimeIntervalMicroSeconds32& aToneOnLength,
   487 								TTimeIntervalMicroSeconds32& aToneOffLength,
   488 								TTimeIntervalMicroSeconds32& aPauseLength) 
   489 	{
   490 	iDevSoundProxy->SetDTMFLengths(aToneOnLength, aToneOffLength, aPauseLength);
   491 	}
   492 
   493 /*
   494  *
   495  *	Defines the period over which the volume level is to rise smoothly from
   496  *	nothing to the normal volume level.
   497  *
   498  *	@param	"TTimeIntervalMicroSeconds& aRampDuration"
   499  *			The period over which the volume is to rise. A zero value causes 
   500  *			the tone sample to be played at the normal level for the full
   501  *			duration of the playback. A value, which is longer than the duration
   502  *			of the tone sample, that the sample never reaches its normal
   503  *			volume level.
   504  *
   505  *
   506  */
   507 void CMMFDevSoundClientImp::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
   508 	{
   509 	iDevSoundProxy->SetVolumeRamp(aRampDuration);
   510 	}
   511 
   512 
   513 /**
   514  *	@see sounddevice.h
   515  */
   516 void CMMFDevSoundClientImp::GetSupportedInputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& aPrioritySettings) const
   517 	{
   518 	iDevSoundProxy->GetSupportedInputDataTypesL(aSupportedDataTypes, aPrioritySettings);
   519 	}
   520 
   521 /**
   522  *	@see sounddevice.h
   523  */
   524 void CMMFDevSoundClientImp::GetSupportedOutputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& aPrioritySettings) const
   525 	{
   526 	iDevSoundProxy->GetSupportedOutputDataTypesL(aSupportedDataTypes, aPrioritySettings);
   527 	}
   528 
   529 /**
   530  *	@see sounddevice.h
   531  */
   532 TInt CMMFDevSoundClientImp::SetClientThreadInfo(TThreadId aTid)
   533 	{
   534 	return iDevSoundProxy->SetClientThreadInfo(aTid);
   535 	}
   536 
   537 
   538 TInt CMMFDevSoundClientImp::RegisterAsClient(TUid aEventType, const TDesC8& aNotificationRegistrationData)
   539 	{
   540 	return iDevSoundProxy->RegisterAsClient(aEventType,aNotificationRegistrationData);
   541 	}
   542 	
   543 TInt CMMFDevSoundClientImp::CancelRegisterAsClient(TUid aEventType)
   544 	{
   545 	return iDevSoundProxy->CancelRegisterAsClient(aEventType);
   546 	}
   547 	
   548 TInt CMMFDevSoundClientImp::GetResourceNotificationData(TUid aEventType,TDes8& aNotificationData)
   549 	{
   550 	return iDevSoundProxy->GetResourceNotificationData(aEventType,aNotificationData);
   551 	}
   552 	
   553 TInt CMMFDevSoundClientImp::WillResumePlay()
   554 	{
   555 	return iDevSoundProxy->WillResumePlay();
   556 	}
   557 
   558 TInt CMMFDevSoundClientImp::EmptyBuffers()
   559 	{
   560 	return iDevSoundProxy->EmptyBuffers();
   561 	}
   562 
   563 TInt CMMFDevSoundClientImp::GetTimePlayed(TTimeIntervalMicroSeconds& aTime)
   564 	{
   565 	return iDevSoundProxy->GetTimePlayed(aTime);
   566 	}
   567 /*
   568  *
   569  *	Returns a given Custom Interface on the DevSound based on the UID
   570  *  If this is not recognised then the custominterface is created by
   571  *  a pair of ECOM plugins.
   572  *
   573  *  @released
   574  *  @param	"TUid aInterfaceId"
   575  *			The UID of the required Custom Interface
   576  *  @return a pointer to the custom interface
   577  *
   578  */
   579 TAny* CMMFDevSoundClientImp::CustomInterface(TUid aInterfaceId)
   580 	{
   581 	// check if this UID refers to auto/pause/resume
   582 	if (aInterfaceId == KMmfUidDevSoundAudioResourceCustomInterface)
   583 		{
   584 		MAutoPauseResumeSupport* result = this; 
   585 		return result;
   586 		}
   587 	if (aInterfaceId == KMmfUidDevSoundEmptyBuffersCustomInterface)
   588 		{
   589 		MMMFDevSoundEmptyBuffers* result = this; 
   590 		return result;
   591 		}		
   592 	if (aInterfaceId == KMmfUidDevSoundAudioClientThreadInfoCustomInterface)
   593 		{
   594 		MAudioClientThreadInfo* result = this;
   595 		return result;
   596 		}
   597 
   598 	if (aInterfaceId == KMmfUidDevSoundTimePlayedCustomInterface)
   599 		{
   600 		MMMFDevSoundTimePlayed* result = this;
   601 		return result;
   602 		}	
   603 		
   604 	// we are being asked for a Custom Interface not natively supported 
   605 	// by the DevSound plugin.  
   606 	
   607 	// first check if we already have resolved a custom interface of this type
   608 	TInt index = FindCustomInterface(aInterfaceId);
   609 	
   610 	MMMFDevSoundCustomInterfaceMuxPlugin* ptr = NULL;
   611 		
   612 	// if we found the interface, take a copy of this instead
   613 	if (index != KNullHandle)
   614 		{
   615 		// check our index is valid
   616 		ptr = iCustomInterfaceArray[index-1].iInterface;
   617 		if (ptr)		
   618 			{
   619 			return ptr->CustomInterface(aInterfaceId);
   620 			}
   621 		else
   622 			{
   623 			// we may not need this code because this 
   624 			// *should* be impossible to reach
   625 			return NULL;
   626 			}
   627 		}
   628 	else
   629 		{
   630 		// else try and instantiate a plugin tunnelling
   631 		// pair to support this Custom Interface
   632 		TRAPD(err, ptr = iMuxUtility->CreateCustomInterfaceMuxL(aInterfaceId));
   633 	
   634 		if (ptr && (err == KErrNone))
   635 			{
   636 			TMMFDevSoundCustomInterfaceData data;
   637 			data.iInterface = ptr;
   638 			data.iId = aInterfaceId;
   639 			
   640 			// attempt to open remote demux
   641 			// this will store a handle in the mux plugin if successful
   642 			// and also return it here - invalid handle = -1
   643 			data.iHandle = ptr->OpenInterface(aInterfaceId);
   644 			
   645 			// if the handle is greater than zero then we know we have
   646 			// successfully opened the interface
   647 			if (data.iHandle > KNullHandle)
   648 				{	
   649 				// append this to the current interface list
   650 				TInt err = KErrNone;
   651 				err = iCustomInterfaceArray.Append(data);
   652 				if (err == KErrNone)
   653 					{
   654 					// return the custom interface on the ptr
   655 					return ptr->CustomInterface(aInterfaceId);
   656 					}
   657 				}
   658 					
   659 				// no memory or other problem so shut down interface
   660 				ptr->Release();
   661 				ptr = NULL;
   662 			}
   663 		}
   664 		
   665 		// if code gets here then we don't support the interface
   666 		// so we can pass it onto the DevSound proxy so that we 
   667 		// can attempt to resolve the interface externally
   668 		return iDevSoundProxy->CustomInterface(aInterfaceId);	
   669 	}
   670 
   671 TInt CMMFDevSoundClientImp::FindCustomInterface(TUid aInterfaceId)
   672 	{
   673 	TInt index = KNullHandle;
   674 	
   675 	for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
   676 		{
   677 		if (iCustomInterfaceArray[i].iId == aInterfaceId)
   678 			{
   679 			index = i+1; // use index+1 as the handle, so 0 is undefined/not-found
   680 			break;
   681 			}
   682 		}
   683 	
   684 	return index;
   685 	}
   686 
   687 void CMMFDevSoundClientImp::CloseCustomInterface(TInt aIndex)
   688 	{
   689 	for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
   690 		{
   691 		if(iCustomInterfaceArray[i].iHandle == aIndex)
   692 			{
   693 			iCustomInterfaceArray[i].iInterface->Release();	
   694 			iCustomInterfaceArray.Remove(i);
   695 			break;
   696 			}
   697 		}
   698 	}