// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include "a3fcistubextn.h"
#include <ecom/ecom.h>
#include <ecom/implementationproxy.h>
#include "a3fcistubextn.hrh"

#include <a3f/maudiocontext.h>
#include <a3f/maudiostream.h>
#include <a3f/maudioprocessingunit.h>
#include <a3f/maudiogaincontrol.h>
#include <a3f/audioprocessingunittypeuids.h>

//      
#include "a3fbackdooraccess.h"
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <mmf/common/mmfipcserver.h>
#endif


// __________________________________________________________________________
// Client-side extension

MDevSoundCIClientExtension* CA3fClientCiStubExtn::NewL()
	{
	CA3fClientCiStubExtn* self = new (ELeave) CA3fClientCiStubExtn;
	return self;
	}
	
CA3fClientCiStubExtn::~CA3fClientCiStubExtn()
	{
	delete iDummyBuffer;
	REComSession::DestroyedImplementation(iKey);
	}
	
TInt CA3fClientCiStubExtn::Setup(MCustomCommand& aCustomCommand)
	{
	iCommand = &aCustomCommand;
	iDummyBuffer=KNullDesC().Alloc(); // dummy buffer simulates some allocs
	if (!iDummyBuffer)
		{
		return KErrNoMemory;
		}
	return KErrNone;
	}
	
TInt CA3fClientCiStubExtn::CustomInterfaceExtension(TUid aUid, TAny*& aInterface)
	{
	if (aUid==KUidTestSetVolIf)
		{
		MTestSetVolIf* interface = this;
		aInterface = interface;
		return KErrNone;
		}
	return KErrNotSupported;
	}
	
void CA3fClientCiStubExtn::Release()
	{
	delete this;
	}

void CA3fClientCiStubExtn::PassDestructorKey(TUid aDestructorKey)
	{
	iKey = aDestructorKey;
	}
	
TInt CA3fClientCiStubExtn::SetVol(TInt aVol)
	{
	// the key here is the destination package, which represets SetVol. Apart from value
	// the rest of the parameters can be ignored
	TPckgBuf<TInt> volumePkg (aVol);
	TMMFMessageDestinationPckg setVolDest (TMMFMessageDestination(KUidTestSetVolIf, 0));
	TInt result = iCommand->CustomCommandSync(setVolDest, 0, volumePkg, KNullDesC8);
	return result;
	}

// __________________________________________________________________________
// Server-side extension

MDevSoundCIServerExtension* CA3fServerCiStubExtn::NewL()
	{
	CA3fServerCiStubExtn* self = new (ELeave) CA3fServerCiStubExtn;
	return self;
	}
	
CA3fServerCiStubExtn::~CA3fServerCiStubExtn()
	{
	delete iDummyBuffer;
	delete iSetVol;
	REComSession::DestroyedImplementation(iKey);
	}
	
TInt CA3fServerCiStubExtn::Setup(MCustomInterface& aCustomInterface)
	{
	iInterface = &aCustomInterface;
	iDummyBuffer=KNullDesC().Alloc(); // dummy buffer simulates some allocs
	if (!iDummyBuffer)
		{
		return KErrNoMemory;
		}
	return KErrNone;
	}
	
TInt CA3fServerCiStubExtn::HandleMessageL(const RMmfIpcMessage& aMessage)
	{
	TMMFMessageDestinationPckg destinationPckg;
	MmfMessageUtil::ReadL(aMessage, 0, destinationPckg);
	if (destinationPckg().InterfaceId()==KUidTestSetVolIf)
		{
		CSetVol* volHandler = CSetVol::NewL(*iInterface);
		CleanupStack::PushL(volHandler);
		TInt result = volHandler->HandleMessageL(aMessage);
		CleanupStack::Pop(volHandler);
		return result;
		}

	return KErrNotSupported;
	}
	
void CA3fServerCiStubExtn::Release()
	{
	delete this;
	}

void CA3fServerCiStubExtn::PassDestructorKey(TUid aDestructorKey)
	{
	iKey = aDestructorKey;
	}
	
// CSetVol

CSetVol* CSetVol::NewL(MCustomInterface& aCustomInterface)
	{
	CSetVol* self = new (ELeave) CSetVol(aCustomInterface);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}
	
CSetVol::CSetVol(MCustomInterface& aCustomInterface):
	iInterface(&aCustomInterface)
	{
	// do nothing
	}
		
void CSetVol::ConstructL()
	{
	iWait = new (ELeave) CActiveSchedulerWait();
	}
	
CSetVol::~CSetVol()
	{
	delete iWait;
	}
	
TInt CSetVol::HandleMessageL(const RMmfIpcMessage& aMessage)
	{
	TPckgBuf<TInt> volPckg;
	MmfMessageUtil::ReadL(aMessage, 1, volPckg);
	UpdateA3fPointers(); // grab pointers to context, stream etc
	SetVolumeL(volPckg());
	
	User::LeaveIfError(iContext->RegisterAudioContextObserver(*this));
	
	TInt error = iContext->Commit();
	if (!error)
		{
		iError = KErrNone;
		iWait->Start();
		error = iError;
		}
	(void) iContext->UnregisterAudioContextObserver(*this);
	
	aMessage.Complete(error); 
	return KErrNone; // KErrNone says we've handled the message
	}
	
void CSetVol::UpdateA3fPointers()
	{
	MA3FBackdoorAccessIf* backdoor = 
		static_cast<MA3FBackdoorAccessIf*>(iInterface->CustomInterface(KA3FBackdoorAccessIfUid));
	if (backdoor)
		{
		iContext = backdoor->AudioContext();
		iStream = backdoor->AudioStream();
		iGain = backdoor->ProcessingUnit(KUidAudioGainControl);
		}
	else
		{
		iContext = NULL;
		iStream = NULL;
		iGain = NULL;
		}
	}
	
void CSetVol::SetVolumeL(TInt aVolume)
	{
	RArray<TAudioChannelGain>	channelGains;
	CleanupClosePushL(channelGains);
	TAudioChannelGain left;
	TAudioChannelGain right;	
	left.iLocation = TAudioChannelGain::ELeft;
	right.iLocation = TAudioChannelGain::ERight;
	left.iGain = right.iGain = aVolume;
	User::LeaveIfError(channelGains.Append(left)); // assumed element 0 in rest of code
	User::LeaveIfError(channelGains.Append(right)); // assumed element 1 in rest of code

	MAudioGainControl* gainControl = static_cast<MAudioGainControl*>(iGain->Interface(KUidAudioGainControl));
	User::LeaveIfError(gainControl->SetGain(channelGains));	
	CleanupStack::PopAndDestroy(&channelGains);
	}
	
void CSetVol::ContextEvent(TUid aEvent, TInt aError)
	{
	if (aEvent==KUidA3FContextUpdateComplete || aEvent==KUidA3FContextAbort)
		{
		// we are going to assume the SetGain() works and use the end of
		// the ContextEvent. Really should observe the gain itself
		if (aError)
			{
			iError = aError;
			}
		iWait->AsyncStop();
		}
	}
		
//
// ImplementationTable
//

const TImplementationProxy ImplementationTable[] = 
	{
	IMPLEMENTATION_PROXY_ENTRY(KUidA3fClientCiStubExtn, CA3fClientCiStubExtn::NewL),
	IMPLEMENTATION_PROXY_ENTRY(KUidA3fServerCiStubExtn, CA3fServerCiStubExtn::NewL),
	};


//
// ImplementationGroupProxy
//
//

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
	{
	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);

	return ImplementationTable;
	}


