sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: #include "a3fcistubextn.h"
sl@0: #include <ecom/ecom.h>
sl@0: #include <ecom/implementationproxy.h>
sl@0: #include "a3fcistubextn.hrh"
sl@0: 
sl@0: #include <a3f/maudiocontext.h>
sl@0: #include <a3f/maudiostream.h>
sl@0: #include <a3f/maudioprocessingunit.h>
sl@0: #include <a3f/maudiogaincontrol.h>
sl@0: #include <a3f/audioprocessingunittypeuids.h>
sl@0: 
sl@0: //      
sl@0: #include "a3fbackdooraccess.h"
sl@0: #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
sl@0: #include <mmf/common/mmfipcserver.h>
sl@0: #endif
sl@0: 
sl@0: 
sl@0: // __________________________________________________________________________
sl@0: // Client-side extension
sl@0: 
sl@0: MDevSoundCIClientExtension* CA3fClientCiStubExtn::NewL()
sl@0: 	{
sl@0: 	CA3fClientCiStubExtn* self = new (ELeave) CA3fClientCiStubExtn;
sl@0: 	return self;
sl@0: 	}
sl@0: 	
sl@0: CA3fClientCiStubExtn::~CA3fClientCiStubExtn()
sl@0: 	{
sl@0: 	delete iDummyBuffer;
sl@0: 	REComSession::DestroyedImplementation(iKey);
sl@0: 	}
sl@0: 	
sl@0: TInt CA3fClientCiStubExtn::Setup(MCustomCommand& aCustomCommand)
sl@0: 	{
sl@0: 	iCommand = &aCustomCommand;
sl@0: 	iDummyBuffer=KNullDesC().Alloc(); // dummy buffer simulates some allocs
sl@0: 	if (!iDummyBuffer)
sl@0: 		{
sl@0: 		return KErrNoMemory;
sl@0: 		}
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 	
sl@0: TInt CA3fClientCiStubExtn::CustomInterfaceExtension(TUid aUid, TAny*& aInterface)
sl@0: 	{
sl@0: 	if (aUid==KUidTestSetVolIf)
sl@0: 		{
sl@0: 		MTestSetVolIf* interface = this;
sl@0: 		aInterface = interface;
sl@0: 		return KErrNone;
sl@0: 		}
sl@0: 	return KErrNotSupported;
sl@0: 	}
sl@0: 	
sl@0: void CA3fClientCiStubExtn::Release()
sl@0: 	{
sl@0: 	delete this;
sl@0: 	}
sl@0: 
sl@0: void CA3fClientCiStubExtn::PassDestructorKey(TUid aDestructorKey)
sl@0: 	{
sl@0: 	iKey = aDestructorKey;
sl@0: 	}
sl@0: 	
sl@0: TInt CA3fClientCiStubExtn::SetVol(TInt aVol)
sl@0: 	{
sl@0: 	// the key here is the destination package, which represets SetVol. Apart from value
sl@0: 	// the rest of the parameters can be ignored
sl@0: 	TPckgBuf<TInt> volumePkg (aVol);
sl@0: 	TMMFMessageDestinationPckg setVolDest (TMMFMessageDestination(KUidTestSetVolIf, 0));
sl@0: 	TInt result = iCommand->CustomCommandSync(setVolDest, ETestSetVolIfSetVolCommand, volumePkg, KNullDesC8);
sl@0: 	return result;
sl@0: 	}
sl@0: 
sl@0: TInt CA3fClientCiStubExtn::Vol(TInt aMaxVol)
sl@0:     {
sl@0:     // again the key is is the destination package
sl@0:     TPckgBuf<TInt> maxVolPkg (aMaxVol);
sl@0:     TMMFMessageDestinationPckg setVolDest (TMMFMessageDestination(KUidTestSetVolIf, 0));
sl@0:     TInt result = iCommand->CustomCommandSync(setVolDest, ETestSetVolIfVolCommand, maxVolPkg, KNullDesC8);
sl@0:     return result;
sl@0:     }
sl@0: 
sl@0: // __________________________________________________________________________
sl@0: // Server-side extension
sl@0: 
sl@0: MDevSoundCIServerExtension* CA3fServerCiStubExtn::NewL()
sl@0: 	{
sl@0: 	CA3fServerCiStubExtn* self = new (ELeave) CA3fServerCiStubExtn;
sl@0: 	return self;
sl@0: 	}
sl@0: 	
sl@0: CA3fServerCiStubExtn::~CA3fServerCiStubExtn()
sl@0: 	{
sl@0: 	delete iDummyBuffer;
sl@0: 	delete iSetVol;
sl@0: 	REComSession::DestroyedImplementation(iKey);
sl@0: 	}
sl@0: 	
sl@0: TInt CA3fServerCiStubExtn::Setup(MCustomInterface& aCustomInterface)
sl@0: 	{
sl@0: 	iInterface = &aCustomInterface;
sl@0: 	iDummyBuffer=KNullDesC().Alloc(); // dummy buffer simulates some allocs
sl@0: 	if (!iDummyBuffer)
sl@0: 		{
sl@0: 		return KErrNoMemory;
sl@0: 		}
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 	
sl@0: TInt CA3fServerCiStubExtn::HandleMessageL(const RMmfIpcMessage& aMessage)
sl@0: 	{
sl@0: 	TMMFMessageDestinationPckg destinationPckg;
sl@0: 	MmfMessageUtil::ReadL(aMessage, 0, destinationPckg);
sl@0: 	if (destinationPckg().InterfaceId()==KUidTestSetVolIf)
sl@0: 		{
sl@0: 		CSetVol* volHandler = CSetVol::NewL(*iInterface);
sl@0: 		CleanupStack::PushL(volHandler);
sl@0: 		TInt result = volHandler->HandleMessageL(aMessage);
sl@0: 		CleanupStack::Pop(volHandler);
sl@0: 		return result;
sl@0: 		}
sl@0: 
sl@0: 	return KErrNotSupported;
sl@0: 	}
sl@0: 	
sl@0: void CA3fServerCiStubExtn::Release()
sl@0: 	{
sl@0: 	delete this;
sl@0: 	}
sl@0: 
sl@0: void CA3fServerCiStubExtn::PassDestructorKey(TUid aDestructorKey)
sl@0: 	{
sl@0: 	iKey = aDestructorKey;
sl@0: 	}
sl@0: 	
sl@0: // CSetVol
sl@0: 
sl@0: CSetVol* CSetVol::NewL(MCustomInterface& aCustomInterface)
sl@0: 	{
sl@0: 	CSetVol* self = new (ELeave) CSetVol(aCustomInterface);
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL();
sl@0: 	CleanupStack::Pop(self);
sl@0: 	return self;
sl@0: 	}
sl@0: 	
sl@0: CSetVol::CSetVol(MCustomInterface& aCustomInterface):
sl@0: 	iInterface(&aCustomInterface)
sl@0: 	{
sl@0: 	// do nothing
sl@0: 	}
sl@0: 		
sl@0: void CSetVol::ConstructL()
sl@0: 	{
sl@0: 	iWait = new (ELeave) CActiveSchedulerWait();
sl@0: 	}
sl@0: 	
sl@0: CSetVol::~CSetVol()
sl@0: 	{
sl@0: 	delete iWait;
sl@0: 	}
sl@0: 	
sl@0: TInt CSetVol::HandleMessageL(const RMmfIpcMessage& aMessage)
sl@0: 	{
sl@0:     switch (aMessage.Function())
sl@0:         {
sl@0:         case ETestSetVolIfSetVolCommand:
sl@0:             {
sl@0:             TPckgBuf<TInt> volPckg;
sl@0:             MmfMessageUtil::ReadL(aMessage, 1, volPckg);
sl@0:             UpdateA3fPointers(); // grab pointers to context, stream etc
sl@0:             SetVolumeL(volPckg());
sl@0: 
sl@0:             User::LeaveIfError(iContext->RegisterAudioContextObserver(*this));
sl@0: 
sl@0:             TInt error = iContext->Commit();
sl@0:             if (!error)
sl@0:                 {
sl@0:                 iError = KErrNone;
sl@0:                 iWait->Start();
sl@0:                 error = iError;
sl@0:                 }
sl@0:             (void) iContext->UnregisterAudioContextObserver(*this);
sl@0: 
sl@0:             aMessage.Complete(error);
sl@0:             return KErrNone; // KErrNone says we've handled the message
sl@0:             }
sl@0:         case ETestSetVolIfVolCommand:
sl@0:             {
sl@0:             TPckgBuf<TInt> maxVolPckg;
sl@0:             MmfMessageUtil::ReadL(aMessage, 1, maxVolPckg);
sl@0:             UpdateA3fPointers(); // grab pointers to context, stream etc
sl@0:             TInt result = VolumeL(maxVolPckg());
sl@0:             aMessage.Complete(result);
sl@0:             return KErrNone; // KErrNone says we've handled the message
sl@0:             }
sl@0:         default:
sl@0:             return KErrArgument;
sl@0:         }
sl@0: 	}
sl@0: 	
sl@0: void CSetVol::UpdateA3fPointers()
sl@0: 	{
sl@0: 	MA3FBackdoorAccessIf* backdoor = 
sl@0: 		static_cast<MA3FBackdoorAccessIf*>(iInterface->CustomInterface(KA3FBackdoorAccessIfUid));
sl@0: 	if (backdoor)
sl@0: 		{
sl@0: 		iContext = backdoor->AudioContext();
sl@0: 		iStream = backdoor->AudioStream();
sl@0: 		iGain = backdoor->ProcessingUnit(KUidAudioGainControl);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		iContext = NULL;
sl@0: 		iStream = NULL;
sl@0: 		iGain = NULL;
sl@0: 		}
sl@0: 	}
sl@0: 	
sl@0: void CSetVol::SetVolumeL(TInt aVolume)
sl@0: 	{
sl@0: 	RArray<TAudioChannelGain>	channelGains;
sl@0: 	CleanupClosePushL(channelGains);
sl@0: 	TAudioChannelGain left;
sl@0: 	TAudioChannelGain right;	
sl@0: 	left.iLocation = TAudioChannelGain::ELeft;
sl@0: 	right.iLocation = TAudioChannelGain::ERight;
sl@0: 	left.iGain = right.iGain = aVolume;
sl@0: 	User::LeaveIfError(channelGains.Append(left)); // assumed element 0 in rest of code
sl@0: 	User::LeaveIfError(channelGains.Append(right)); // assumed element 1 in rest of code
sl@0: 
sl@0: 	MAudioGainControl* gainControl = static_cast<MAudioGainControl*>(iGain->Interface(KUidAudioGainControl));
sl@0: 	User::LeaveIfError(gainControl->SetGain(channelGains));	
sl@0: 	CleanupStack::PopAndDestroy(&channelGains);
sl@0: 	}
sl@0: 
sl@0: TInt CSetVol::VolumeL(TInt aMaxVolume)
sl@0:     {
sl@0:     RArray<TAudioChannelGain>   channelGains;
sl@0:     CleanupClosePushL(channelGains);
sl@0:     TInt maxGain;
sl@0: 
sl@0:     MAudioGainControl* gainControl = static_cast<MAudioGainControl*>(iGain->Interface(KUidAudioGainControl));
sl@0:     User::LeaveIfError(gainControl->GetGain(channelGains));
sl@0:     User::LeaveIfError(gainControl->GetMaxGain(maxGain));
sl@0: 
sl@0:     TInt basicVolume = (channelGains[0].iGain + channelGains[1].iGain) / 2;
sl@0:     TInt result = basicVolume * aMaxVolume / maxGain; // scale to 0 to maxVolume
sl@0: 
sl@0:     CleanupStack::PopAndDestroy(&channelGains);
sl@0:     return result;
sl@0:     }
sl@0: 	
sl@0: void CSetVol::ContextEvent(TUid aEvent, TInt aError)
sl@0: 	{
sl@0: 	if (aEvent==KUidA3FContextUpdateComplete || aEvent==KUidA3FContextAbort)
sl@0: 		{
sl@0: 		// we are going to assume the SetGain() works and use the end of
sl@0: 		// the ContextEvent. Really should observe the gain itself
sl@0: 		if (aError)
sl@0: 			{
sl@0: 			iError = aError;
sl@0: 			}
sl@0: 		iWait->AsyncStop();
sl@0: 		}
sl@0: 	}
sl@0: 		
sl@0: //
sl@0: // ImplementationTable
sl@0: //
sl@0: 
sl@0: const TImplementationProxy ImplementationTable[] = 
sl@0: 	{
sl@0: 	IMPLEMENTATION_PROXY_ENTRY(KUidA3fClientCiStubExtn, CA3fClientCiStubExtn::NewL),
sl@0: 	IMPLEMENTATION_PROXY_ENTRY(KUidA3fServerCiStubExtn, CA3fServerCiStubExtn::NewL),
sl@0: 	};
sl@0: 
sl@0: 
sl@0: //
sl@0: // ImplementationGroupProxy
sl@0: //
sl@0: //
sl@0: 
sl@0: EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
sl@0: 	{
sl@0: 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
sl@0: 
sl@0: 	return ImplementationTable;
sl@0: 	}
sl@0: 
sl@0: