diff -r 000000000000 -r 40261b775718 devsound/a3fdevsound/src/mmfdevsoundserver/mmfdevsoundsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/a3fdevsound/src/mmfdevsoundserver/mmfdevsoundsession.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,2253 @@ +// Copyright (c) 2006-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 +#include "mmfaudioclientserver.h" +#include "mmfaudioserver.h" +#include "mmfdevsoundserver.h" +#include "mmfdevsoundsession.h" +#include +#include +#ifdef _DEBUG +#include "e32debug.h" + +#define SYMBIAN_DEBPRN0(str) RDebug::Print(str, this) +#define SYMBIAN_DEBPRN1(str, val1) RDebug::Print(str, this, val1) +#define SYMBIAN_DEBPRN2(str, val1, val2) RDebug::Print(str, this, val1, val2) +#else +#define SYMBIAN_DEBPRN0(str) +#define SYMBIAN_DEBPRN1(str, val1) +#define SYMBIAN_DEBPRN2(str, val1, val2) +#endif //_DEBUG + +//Assume that we can have two user request and one callback request +//at the same time (maximum). +const TInt KMaxQueueRequest = 3; + +// MEMBER FUNCTIONS + +TMMFDevSoundRequest::TMMFDevSoundRequest() + : iMessageCompleted(EFalse), + iRequestType(EUndefinedType), + iCallBackPF(KCallbackNone) + { + } + +TMMFDevSoundRequest::TMMFDevSoundRequest(TInt aIsCallBack) + : iMessageCompleted(EFalse), + iRequestType(ECallBackType), + iCallBackPF(aIsCallBack) + { + } + +TMMFDevSoundRequest::TMMFDevSoundRequest(const TMMFDevSoundRequest& aRequest) + : iMessageCompleted(EFalse), + iMessage(aRequest.iMessage), + iCallBackPF(aRequest.iCallBackPF) + { + iRequestType = ResolveType(); + } + +TBool TMMFDevSoundRequest::operator==(const TMMFDevSoundRequest& aRequest) const + { + TBool retval = EFalse; + if ( aRequest.Function() == Function() ) + { + retval = ETrue; + } + else + { + retval = EFalse; + } + return retval; + } + +const RMmfIpcMessage& TMMFDevSoundRequest::Message() + { + return iMessage; + } + +void TMMFDevSoundRequest::SetMessage(const RMmfIpcMessage& aMessage) + { + iMessageCompleted = EFalse; + iMessage = aMessage; + iRequestType = ResolveType(); + } + +void TMMFDevSoundRequest::SetMessageCallback() + { + iMessageCompleted = EFalse; + iRequestType = ECallBackType; + } + +TInt TMMFDevSoundRequest::IsCallBack() const + { + return iCallBackPF; + } + +TMMFDevSoundRequest::TA3FDevSoundRequestType TMMFDevSoundRequest::ResolveType() + { + TA3FDevSoundRequestType type = EUndefinedType; + switch(iMessage.Function()) + { + case EMMFDevSoundProxyInitialize1: + case EMMFDevSoundProxyInitialize2: + case EMMFDevSoundProxyInitialize4: + case EMMFDevSoundProxyPlayInit: + case EMMFDevSoundProxyRecordInit: + case EMMFDevSoundProxyPlayTone: + case EMMFDevSoundProxyPlayDualTone: + case EMMFDevSoundProxyPlayDTMFString: + case EMMFDevSoundProxyPlayToneSequence: + case EMMFDevSoundProxyPlayFixedSequence: + type = EAction_PseudoAsynchronous; + break; + + case EMMFDevSoundProxyStop: + case EMMFDevSoundProxyPause: + case EMMFDevSoundProxyClose: + case EMMFDevSoundProxyCancelInitialize: + case EMMFDevSoundProxyResume: + case EMMFDevSoundProxyEmptyBuffers: + type = EAction_Asynchronous; + break; + + case EMMFDevSoundProxySetConfig: + case EMMFDevSoundProxyPostOpen: // Although this is not a configure operation technically, it has same calling pattern. + case EMMFDevSoundProxySetVolume: + case EMMFDevSoundProxySetGain: + case EMMFDevSoundProxySetPlayBalance: + case EMMFDevSoundProxySetRecordBalance: + case EMMFDevSoundProxySetVolumeRamp: + case EMMFDevSoundProxySetPrioritySettings: + type = EConfigure_Asynchronous; + break; + + case EMMFDevSoundProxySetDTMFLengths: + case EMMFDevSoundProxySetToneRepeats: + type = EConfigure_Synchronous; + break; + case EMMFDevSoundProxyCapabilities: + type = EQuery_Asynchronous; + break; + case EMMFDevSoundProxyMaxVolume: + case EMMFDevSoundProxyMaxGain: + case EMMFDevSoundProxyConfig: + case EMMFDevSoundProxyVolume: + case EMMFDevSoundProxyGain: + case EMMFDevSoundProxyPlayBalance: + case EMMFDevSoundProxyRecordBalance: + case EMMFDevSoundProxyGetSupportedInputDataTypes: + case EMMFDevSoundProxyGetSupportedOutputDataTypes: + case EMMFDevSoundProxyFixedSequenceName: + case EMMFDevSoundProxyFixedSequenceCount: + case EMMFDevSoundProxySamplesRecorded: + case EMMFDevSoundProxySamplesPlayed: + case EMMFDevSoundProxyCopyFourCCArrayData: + case EMMFDevSoundProxyGetTimePlayed: + case EMMFDevSoundProxyIsResumeSupported: + type = EQuery_Synchronous; + break; + + case EMMFDevSoundProxyBTBFData: + case EMMFDevSoundProxyBTBEData: + case EMMFDevSoundProxyPlayData: + case EMMFDevSoundProxyRecordData: + type = EBufferExchangeRelated; + break; + + // Custom Interfaces + case EMMFDevSoundProxySyncCustomCommand: + case EMMFDevSoundProxySyncCustomCommandResult: + case EMMFDevSoundProxyAsyncCustomCommand: + case EMMFDevSoundProxyAsyncCustomCommandResult: + case EMMFDevSoundProxyCustomInterface: + type = ECustomInterfacesRelated; + break; + case RMessage2::EDisConnect: + type = ESessionEvents; + break; + default: + break; + } + return type; + } + + +void TMMFDevSoundRequest::Complete(TInt aError) + { + if(!iMessageCompleted && iRequestType != EUndefinedType && iRequestType != ECallBackType) + { + iMessage.Complete(aError); + iMessageCompleted = ETrue; + iRequestType = EUndefinedType; + } + } + +TInt TMMFDevSoundRequest::Function() const + { + return iMessage.Function(); + } + +TMMFDevSoundRequest::TA3FDevSoundRequestType TMMFDevSoundRequest::Type() const + { + return iRequestType; + } + + +// +// CMMFDevSoundSession::CreateL +// Creates a new object +// +void CMMFDevSoundSession::CreateL(const CMmfIpcServer& aServer) + { + CMmfIpcSession::CreateL(aServer); + CMMFDevSoundServer& server = + const_cast( + static_cast(aServer)); + server.IncrementSessionId(); + iDevSoundSessionId = server.DevSoundSessionId(); + } + +// +// CMMFDevSoundSession::ServiceL +// (other items were commented in a header). +// +void CMMFDevSoundSession::ServiceL(const RMmfIpcMessage& aMessage) + { + SYMBIAN_DEBPRN2(_L("\nCMMFDevSoundSession[0x%x] NEW REQUEST %02x while pending=%d"), aMessage.Function(), iOperationCompletePending); + if( iOperationCompletePending || iAsyncQueueStart->IsActive()) + { + // if not possible to service now, then queue request + EnqueueRequest(aMessage); + } + else + { + // If there is no oustanding operation service inmediately + DoServiceRequestL(aMessage); + } + } + +// +// CMMFDevSoundSession::DoServiceL +// (other items were commented in a header). +// +void CMMFDevSoundSession::DoServiceRequestL(const RMmfIpcMessage& aMessage) + { + iAsyncQueueStart->Cancel(); // just in case. + TMMFMessageDestinationPckg destinationPckg; + MmfMessageUtil::ReadL(aMessage, 0, destinationPckg); + if ((destinationPckg().DestinationHandle() == KMMFObjectHandleDevSound) && + (destinationPckg().InterfaceId() == KUidInterfaceMMFDevSound)) + { + TBool complete = EFalse; + switch(aMessage.Function()) + { + case EMMFDevSoundProxyPostOpen: + complete = DoPostOpenL(aMessage); + break; + case EMMFDevSoundProxyInitialize1: + complete = DoInitialize1L(aMessage); + break; + case EMMFDevSoundProxyInitialize2: + complete = DoInitialize2L(aMessage); + break; + case EMMFDevSoundProxyInitialize4: + complete = DoInitialize4L(aMessage); + break; + case EMMFDevSoundProxyCapabilities: + complete = DoCapabilitiesL(aMessage); + break; + case EMMFDevSoundProxyConfig: + complete = DoConfigL(aMessage); + break; + case EMMFDevSoundProxySetConfig: + complete = DoSetConfigL(aMessage); + break; + case EMMFDevSoundProxyMaxVolume: + complete = DoMaxVolumeL(aMessage); + break; + case EMMFDevSoundProxyVolume: + complete = DoVolumeL(aMessage); + break; + case EMMFDevSoundProxySetVolume: + complete = DoSetVolumeL(aMessage); + break; + case EMMFDevSoundProxyMaxGain: + complete = DoMaxGainL(aMessage); + break; + case EMMFDevSoundProxyGain: + complete = DoGainL(aMessage); + break; + case EMMFDevSoundProxySetGain: + complete = DoSetGainL(aMessage); + break; + case EMMFDevSoundProxyPlayBalance: + complete = DoGetPlayBalanceL(aMessage); + break; + case EMMFDevSoundProxySetPlayBalance: + complete = DoSetPlayBalanceL(aMessage); + break; + case EMMFDevSoundProxyRecordBalance: + complete = DoGetRecordBalanceL(aMessage); + break; + case EMMFDevSoundProxySetRecordBalance: + complete = DoSetRecordBalanceL(aMessage); + break; + case EMMFDevSoundProxyBTBFData: + complete = DoBufferToBeFilledDataL(aMessage); + break; + case EMMFDevSoundProxyBTBEData: + complete = DoBufferToBeEmptiedDataL(aMessage); + break; + case EMMFDevSoundProxyPlayInit: + complete = DoPlayInitL(aMessage); + break; + case EMMFDevSoundProxyRecordInit: + complete = DoRecordInitL(aMessage); + break; + case EMMFDevSoundProxyPlayData: + complete = DoPlayDataL(aMessage); + break; + case EMMFDevSoundProxyRecordData: + complete = DoRecordDataL(aMessage); + break; + case EMMFDevSoundProxyStop: + complete = DoStopL(aMessage); + break; + case EMMFDevSoundProxyPause: + complete = DoPauseL(aMessage); + break; + case EMMFDevSoundProxyPlayTone: + complete = DoPlayToneL(aMessage); + break; + case EMMFDevSoundProxyPlayDualTone: + complete = DoPlayDualToneL(aMessage); + break; + case EMMFDevSoundProxyPlayDTMFString: + complete = DoPlayDTMFStringL(aMessage); + break; + case EMMFDevSoundProxyPlayToneSequence: + complete = DoPlayToneSequenceL(aMessage); + break; + case EMMFDevSoundProxyPlayFixedSequence: + complete = DoPlayFixedSequenceL(aMessage); + break; + case EMMFDevSoundProxySetDTMFLengths: + complete = DoSetDTMFLengthsL(aMessage); + break; + case EMMFDevSoundProxySetVolumeRamp: + complete = DoSetVolumeRampL(aMessage); + break; + case EMMFDevSoundProxyGetSupportedInputDataTypes: + complete = DoGetSupportedInputDataTypesL(aMessage); + break; + case EMMFDevSoundProxyGetSupportedOutputDataTypes: + complete = DoGetSupportedOutputDataTypesL(aMessage); + break; + case EMMFDevSoundProxyCopyFourCCArrayData: + complete = DoCopyFourCCArrayDataL(aMessage); + break; + case EMMFDevSoundProxySamplesRecorded: + complete = DoSamplesRecordedL(aMessage); + break; + case EMMFDevSoundProxySamplesPlayed: + complete = DoSamplesPlayedL(aMessage); + break; + case EMMFDevSoundProxySetToneRepeats: + complete = DoSetToneRepeatsL(aMessage); + break; + case EMMFDevSoundProxySetPrioritySettings: + complete = DoSetPrioritySettingsL(aMessage); + break; + case EMMFDevSoundProxyFixedSequenceCount: + complete = DoFixedSequenceCountL(aMessage); + break; + case EMMFDevSoundProxyCancelInitialize: + complete = DoCancelInitializeL(aMessage); + break; + case EMMFDevSoundProxyEmptyBuffers: + complete = DoEmptyBuffersL(aMessage); + break; + case EMMFDevSoundProxyGetTimePlayed: + complete = DoGetTimePlayedL(aMessage); + break; + case EMMFDevSoundProxyIsResumeSupported: + complete = DoQueryResumeSupportedL(aMessage); + break; + case EMMFDevSoundProxyResume: + complete = DoResumeL(aMessage); + break; + + // DevSound custom command support + case EMMFDevSoundProxySyncCustomCommand: + case EMMFDevSoundProxySyncCustomCommandResult: + case EMMFDevSoundProxyAsyncCustomCommand: + case EMMFDevSoundProxyAsyncCustomCommandResult: + complete = DoCustomCommandL(aMessage); + break; + case EMMFDevSoundProxyClose: + complete = DoPrepareCloseL(aMessage); + break; + case EMMFDevSoundProxyRequestResourceNotification: + complete = DoRegisterAsClientL(aMessage); + break; + case EMMFDevSoundProxyCancelRequestResourceNotification: + complete = DoCancelRegisterAsClientL(aMessage); + break; + case EMMFDevSoundProxyGetResourceNotificationData: + complete = DoGetResourceNotificationDataL(aMessage); + break; + case EMMFDevSoundProxyWillResumePlay: + complete = DoWillResumePlayL(aMessage); + break; + case EMMFDevSoundProxySetClientThreadInfo: + complete = DoSetClientThreadInfoL(aMessage); + break; + default: + User::Leave(KErrNotSupported); + break; + } + + // Check if can complete the message now + if (complete) + { + // Complete the message + // Synchronous requests & Pseudo-asynchronous + aMessage.Complete(KErrNone); + } + // Note: There are operations that not complete the message using the following flag + // So if the message is not completed, cannot be assumed that there is an operation pending + + if(iOperationCompletePending) + { + // Keep a copy of the message for Asynchronous requests & Pseudo-asynchronous + iRequestBeingServiced.SetMessage(aMessage); + } + } + else + { + // If there's a CI extension, see if that handles this request + TInt err = KErrNotSupported; + if (iCIExtension) + { + iOperationCompletePending = ETrue; + TRAPD(err2, err = iCIExtension->HandleMessageL(aMessage)); + if (err2) + { + err = err2; + } + iOperationCompletePending = EFalse; + } + + if (err != KErrNone) + { + // Not been handled, the request is not supported + aMessage.Complete(KErrNotSupported); + } + } + } + + +void CMMFDevSoundSession::EnqueueRequest(const RMmfIpcMessage& aMessage) + { + // Encapsule the request + TMMFDevSoundRequest request; + request.SetMessage(aMessage); + // Append + TInt error = iQueuedRequests.Append(request); + __ASSERT_DEBUG(error == KErrNone, Panic(EQueueRequestsFailedToAppend)); + } + +// +// CMMFDevSoundSession::DoPostOpenL +// +TBool CMMFDevSoundSession::DoPostOpenL(const RMmfIpcMessage& /*aMessage*/) + { + iAdapter->PostOpenL(); + iOperationCompletePending = ETrue; + return EFalse; + } + +// +// CMMFDevSoundSession::DoInitialize1L +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoInitialize1L(const RMmfIpcMessage& aMessage) + { + TInt err = iMsgQueue.Open(aMessage, 2); // a global queue. + User::LeaveIfError(err); + DoSetClientConfigL();// added here instead of the CreateL() + TMMFDevSoundProxySettingsPckg devSoundBuf; + MmfMessageUtil::ReadL(aMessage,1,devSoundBuf); + TMMFState mode = devSoundBuf().iMode; + iAdapter->InitializeL(mode); + iBufferPlay = NULL; + iPlayErrorOccured = EFalse; + // Flag to queue any further request + // but the message can be completed now + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoInitialize2L +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoInitialize2L(const RMmfIpcMessage& aMessage) + { + TInt err = iMsgQueue.Open(aMessage, 2); // a global queue. + User::LeaveIfError(err); + DoSetClientConfigL();// added here instead of the CreateL() + TMMFDevSoundProxySettingsPckg devSoundBuf; + MmfMessageUtil::ReadL(aMessage,1,devSoundBuf); + TUid HWDev = devSoundBuf().iHWDev; + TMMFState mode = devSoundBuf().iMode; + iAdapter->InitializeL(HWDev, mode); + iBufferPlay = NULL; + iPlayErrorOccured = EFalse; + return ETrue; + } + +// +// CMMFDevSoundSession::DoInitialize4L +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoInitialize4L(const RMmfIpcMessage& aMessage) + { + TInt err = iMsgQueue.Open(aMessage, 2); // a global queue. + User::LeaveIfError(err); + DoSetClientConfigL();// added here instead of the CreateL() + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TFourCC desiredFourCC = devSoundBuf().iDesiredFourCC; + TMMFState mode = devSoundBuf().iMode; + iAdapter->InitializeL(desiredFourCC, mode); + iBufferPlay = NULL; + iPlayErrorOccured = EFalse; + // Flag to queue any further request + // but the message can be completed now + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoCancelInitialize +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoCancelInitializeL(const RMmfIpcMessage& aMessage) + { + TInt err=iAdapter->CancelInitialize(); + + if (err != KErrNone) + { + aMessage.Complete(err); + iOperationCompletePending = EFalse; + return ETrue; + } + else + { + iOperationCompletePending = ETrue; + } + return EFalse; + } + +// +// CMMFDevSoundSession::DoCapabilitiesL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoCapabilitiesL(const RMmfIpcMessage& aMessage) + { + TInt err = iAdapter->Capabilities(iDevSoundCapabilities); + if(err != KErrNone) + { + aMessage.Complete(err); + iOperationCompletePending = EFalse; + } + else + { + iOperationCompletePending = ETrue; + } + return EFalse; + } + +// +// CMMFDevSoundSession::DoConfigL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoConfigL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iConfig = iAdapter->Config(); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetConfigL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetConfigL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TMMFCapabilities config = devSoundBuf().iConfig; + iAdapter->SetConfigL(config); + iOperationCompletePending = ETrue; + return EFalse; + } + +// +// CMMFDevSoundSession::axVolumeL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoMaxVolumeL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iMaxVolume = iAdapter->MaxVolume(); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoVolumeL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoVolumeL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iVolume = iAdapter->Volume(); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetVolumeL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetVolumeL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt volume = devSoundBuf().iVolume; + TBool asyncOperation; + User::LeaveIfError(iAdapter->SetVolume(volume, asyncOperation)); + iOperationCompletePending = asyncOperation; + return !asyncOperation; + } + +// +// CMMFDevSoundSession::DoMaxGainL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoMaxGainL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iMaxGain = iAdapter->MaxGain(); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoGainL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGainL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iGain = iAdapter->Gain(); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetGainL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetGainL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt gain = devSoundBuf().iGain; + TBool asyncOperation; + User::LeaveIfError(iAdapter->SetGain(gain, asyncOperation)); + iOperationCompletePending = asyncOperation; + return !asyncOperation; + } + +// +// CMMFDevSoundSession::DoGetPlayBalanceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGetPlayBalanceL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + iAdapter->GetPlayBalanceL(devSoundSet.iLeftPercentage, devSoundSet.iRightPercentage); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetPlayBalanceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetPlayBalanceL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt leftPercentage = devSoundBuf().iLeftPercentage; + TInt rightPercentage = devSoundBuf().iRightPercentage; + TBool asyncOperation; + iAdapter->SetPlayBalanceL(leftPercentage, rightPercentage, asyncOperation); + iOperationCompletePending = asyncOperation; + return !asyncOperation; + } + +// +// CMMFDevSoundSession::DoGetRecordBalanceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGetRecordBalanceL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettings devSoundSet; + iAdapter->GetRecordBalanceL(devSoundSet.iLeftPercentage, devSoundSet.iRightPercentage); + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetRecordBalanceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetRecordBalanceL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt leftPercentage = devSoundBuf().iLeftPercentage; + TInt rightPercentage = devSoundBuf().iRightPercentage; + TBool asyncOperation; + iAdapter->SetRecordBalanceL(leftPercentage, rightPercentage, asyncOperation); + iOperationCompletePending = asyncOperation; + return !asyncOperation; + } + +// +// CMMFDevSoundSession::DoPlayInitL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayInitL(const RMmfIpcMessage& /*aMessage*/) + { + iAdapter->PlayInitL(); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoRecordInitL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoRecordInitL(const RMmfIpcMessage& /*aMessage*/) + { + iAdapter->RecordInitL(); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoPlayDataL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayDataL(const RMmfIpcMessage& aMessage) + { + SYMBIAN_DEBPRN0(_L("CMMFDevSoundSession[0x%x]::DoPlayDataL - Enter")); + + if( iPlayErrorOccured ) + { + SYMBIAN_DEBPRN0(_L("CMMFDevSoundSession[0x%x]::DoPlayDataL - Ignore and Exit")); + return ETrue; + } + + TMMFDevSoundProxyHwBufPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + iBufferPlay->SetLastBuffer(devSoundBuf().iLastBuffer); + + TPtr8 dataPtr(iChunk.Base(), devSoundBuf().iBufferSize, devSoundBuf().iBufferSize); + // Copy data over from chunk + iBufferPlay->Data().Copy(dataPtr); + iAdapter->PlayData(); + SYMBIAN_DEBPRN0(_L("CMMFDevSoundSession[0x%x]::DoPlayDataL - Exit")); + return ETrue; + } + +// +// CMMFDevSoundSession::DoRecordDataL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoRecordDataL(const RMmfIpcMessage& /*aMessage*/) + { + iAdapter->RecordData(); + return ETrue; + } + +// +// CMMFDevSoundSession::DoStopL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoStopL(const RMmfIpcMessage& /*aMessage*/) + { + // Sometimes Stop is not involved on a commit cycle + TBool completed = iAdapter->Stop(); + if (completed) + { + iQueuedRequests.Reset(); + FlushEventQueue(); // completed returned here means we were idle to start with. TODO could possibly skip this flush + iChunk.Close(); + } + iOperationCompletePending = !completed; + return completed; + } + +// +// CMMFDevSoundSession::DoPauseL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPauseL(const RMmfIpcMessage& /*aMessage*/) + { + User::LeaveIfError(iAdapter->Pause()); + iOperationCompletePending = ETrue; + return EFalse; + } + +// +// CMMFDevSoundSession::DoPlayToneL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayToneL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt frequency = devSoundBuf().iFrequencyOne; + TTimeIntervalMicroSeconds duration(devSoundBuf().iDuration); + iAdapter->PlayToneL(frequency, duration); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoPlayDualToneL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayDualToneL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TInt frequencyOne = devSoundBuf().iFrequencyOne; + TInt frequencyTwo = devSoundBuf().iFrequencyTwo; + TTimeIntervalMicroSeconds duration(devSoundBuf().iDuration); + iAdapter->PlayDualToneL(frequencyOne, frequencyTwo, duration); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoPlayDTMFStringL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayDTMFStringL(const RMmfIpcMessage& aMessage) + { + TInt dtmfLength = aMessage.GetDesLength(2); + + if(iDtmfString) + { + delete iDtmfString; + iDtmfString = NULL; + } + + iDtmfString = HBufC::NewL(dtmfLength); + TPtr dtmfPtr = iDtmfString->Des(); + aMessage.ReadL(TInt(2), dtmfPtr); + + iAdapter->PlayDTMFStringL(*iDtmfString); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoPlayToneSequenceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayToneSequenceL(const RMmfIpcMessage& aMessage) + { + TInt toneLength = aMessage.GetDesLength(1); + + if(iToneSeqBuf) + { + delete iToneSeqBuf; + iToneSeqBuf = NULL; + } + + iToneSeqBuf = HBufC8::NewL(toneLength); + TPtr8 toneSeqPtr = iToneSeqBuf->Des(); + aMessage.ReadL(TInt(1), toneSeqPtr); + + iAdapter->PlayToneSequenceL(*iToneSeqBuf); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoPlayFixedSequenceL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoPlayFixedSequenceL(const RMmfIpcMessage& aMessage) + { + TPckgBuf buf; + aMessage.ReadL(TInt(1),buf); + TInt seqNum = buf(); + + iAdapter->PlayFixedSequenceL(seqNum); + iOperationCompletePending = ETrue; + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetDTMFLengthsL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetDTMFLengthsL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TTimeIntervalMicroSeconds32 toneOnLength = devSoundBuf().iToneOnLength; + TTimeIntervalMicroSeconds32 toneOffLength = devSoundBuf().iToneOffLength; + TTimeIntervalMicroSeconds32 pauseLength = devSoundBuf().iPauseLength; + User::LeaveIfError(iAdapter->SetDTMFLengths(toneOnLength, toneOffLength, pauseLength)); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetVolumeRampL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetVolumeRampL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg devSoundBuf; + aMessage.ReadL(TInt(1),devSoundBuf); + TTimeIntervalMicroSeconds duration = devSoundBuf().iDuration; + User::LeaveIfError(iAdapter->SetVolumeRamp(duration)); + iOperationCompletePending = EFalse; // Volume ramp doesn't result on commit + return ETrue; // operation complete + } + +// +// CMMFDevSoundSession::DoGetSupportedInputDataTypesL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGetSupportedInputDataTypesL( + const RMmfIpcMessage& aMessage) + { + iArray.Reset(); + + TMMFPrioritySettingsPckg prioritySetBuf; + aMessage.ReadL(TInt(1),prioritySetBuf); + TMMFPrioritySettings prioritySet = prioritySetBuf(); + + iAdapter->GetSupportedInputDataTypesL(iArray, prioritySet); + + TPckgBuf pckg; + pckg() = iArray.Count(); + aMessage.WriteL(TInt(2),pckg); + + return ETrue; + } + +// +// CMMFDevSoundSession::DoGetSupportedOutputDataTypesL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGetSupportedOutputDataTypesL( + const RMmfIpcMessage& aMessage) + { + iArray.Reset(); + + TMMFPrioritySettingsPckg prioritySetBuf; + aMessage.ReadL(TInt(1),prioritySetBuf); + TMMFPrioritySettings prioritySet = prioritySetBuf(); + + iAdapter->GetSupportedOutputDataTypesL(iArray, prioritySet); + + TPckgBuf pckg; + pckg() = iArray.Count(); + aMessage.WriteL(TInt(2),pckg); + + return ETrue; + } + +// +// CMMFDevSoundSession::DoSamplesRecordedL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSamplesRecordedL(const RMmfIpcMessage& aMessage) + { + TPckgBuf pckg; + pckg() = iAdapter->SamplesRecorded(); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSamplesPlayedL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSamplesPlayedL(const RMmfIpcMessage& aMessage) + { + TPckgBuf pckg; + pckg() = iAdapter->SamplesPlayed(); + aMessage.WriteL(TInt(2),pckg); + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetToneRepeatsL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetToneRepeatsL(const RMmfIpcMessage& aMessage) + { + TPckgBuf countRepeat; + aMessage.ReadL(TInt(1),countRepeat); + + TPckgBuf repeatTS; + aMessage.ReadL(TInt(2),repeatTS); + User::LeaveIfError(iAdapter->SetToneRepeats(countRepeat(), repeatTS())); + + return ETrue; + } + +// +// CMMFDevSoundSession::DoSetPrioritySettingsL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoSetPrioritySettingsL( + const RMmfIpcMessage& aMessage) + { + TPckgBuf prioritySet; + aMessage.ReadL(TInt(1),prioritySet); + + User::LeaveIfError(iAdapter->SetPrioritySettings(prioritySet())); + iOperationCompletePending = EFalse; + return ETrue; + } + +// +// CMMFDevSoundSession::DoFixedSequenceCountL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoFixedSequenceCountL( + const RMmfIpcMessage& aMessage) + { + TPckgBuf fixSeqCountPckg; + TInt fixSeqCount = iAdapter->FixedSequenceCount(); + fixSeqCountPckg = fixSeqCount; + + aMessage.WriteL(TInt(2),fixSeqCountPckg); + return ETrue; + } + + +// +// CMMFDevSoundSession::DoCopyFourCCArrayDataL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoCopyFourCCArrayDataL( + const RMmfIpcMessage& aMessage) + { + const TInt KBufExpandSize8 = 8;//two TInts + CBufFlat* dataCopyBuffer = CBufFlat::NewL(KBufExpandSize8); + CleanupStack::PushL(dataCopyBuffer); + RBufWriteStream stream; + stream.Open(*dataCopyBuffer); + CleanupClosePushL(stream); + + TInt i = 0; + TInt count = iArray.Count(); + + while (i < count) + { + stream.WriteInt32L(iArray[i].FourCC()); + i++; + } + aMessage.WriteL(TInt(2), dataCopyBuffer->Ptr(0)); + stream.Close(); + CleanupStack::PopAndDestroy(&stream); + CleanupStack::PopAndDestroy(dataCopyBuffer); + return ETrue; + } + + +// +// CMMFDevSoundSession::DoBufferToBeFilledDataL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoBufferToBeFilledDataL( + const RMmfIpcMessage& aMessage) + { + // if CMMFDevSoundSession::PlayError() has been called, RChunk would have got closed. + // Need to check if Chunk Handle is still valid. If it is not,complete the message immediately and send a error to the Client. + if(!iChunk.Handle()) + { + aMessage.Complete(KErrBadHandle); + return EFalse; + } + TPckgBuf requestChunkBuf; + MmfMessageUtil::Read(aMessage, TInt(1), requestChunkBuf); + TBool requestChunk = requestChunkBuf(); + if (requestChunk) + { + // if the client requests, always do EOpen + iHwBufPckgFill().iChunkOp = EOpen; + } + TInt err = MmfMessageUtil::Write(aMessage, TInt(2), iHwBufPckgFill); + if ( (err == KErrNone) && (iHwBufPckgFill().iChunkOp == EOpen) ) + { + aMessage.Complete(iChunk); + } + else + { + aMessage.Complete(err); + } + return EFalse; + } + +// CMMFDevSoundSession::DoBufferToBeEmptiedDataL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoBufferToBeEmptiedDataL( + const RMmfIpcMessage& aMessage) + { + // if CMMFDevSoundSession::RecordError() has been called, RChunk would have got closed. + // Need to check if Chunk Handle is still valid. If it is not,complete the message immediately and send a error to the Client. + if(!iChunk.Handle()) + { + aMessage.Complete(KErrBadHandle); + return EFalse; + } + + TInt err = MmfMessageUtil::Write(aMessage, TInt(2), iHwBufPckgEmpty); + if ( (err == KErrNone) && (iHwBufPckgEmpty().iChunkOp == EOpen) ) + { + aMessage.Complete(iChunk); + } + else + { + aMessage.Complete(err); + } + return EFalse; + } + +// +// CMMFDevSoundSession::DoEmptyBuffersL +// (other items were commented in a header). +// + +TBool CMMFDevSoundSession::DoEmptyBuffersL(const RMmfIpcMessage& aMessage) + { + TInt err = KErrNone; + FilterQueueEvent(EMMFDevSoundProxyBTBFEvent); + // This is now asynchronous + err = iAdapter->EmptyBuffers(); + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + iOperationCompletePending = ETrue; + return EFalse; + } +// +// CMMFDevSoundSession::DoGetTimePlayedL +// (other items were commented in a header). +// +TBool CMMFDevSoundSession::DoGetTimePlayedL(const RMmfIpcMessage& aMessage) + { + TInt err = KErrNone; + TTimeIntervalMicroSeconds time(0); + TPckgBuf timePckg(time); + err = iAdapter->GetTimePlayed(timePckg()); + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + aMessage.WriteL(TInt(2),timePckg); + return ETrue; + } + +TBool CMMFDevSoundSession::DoQueryResumeSupportedL(const RMmfIpcMessage& aMessage) + { + TBool isSupported = EFalse; + TPckgBuf isSupportedPckg(isSupported); + isSupportedPckg() = iAdapter->IsResumeSupported(); + aMessage.WriteL(TInt(2),isSupportedPckg); + return ETrue; + } + +TBool CMMFDevSoundSession::DoResumeL(const RMmfIpcMessage& /*aMessage*/) + { + User::LeaveIfError( iAdapter->Resume() ); + iOperationCompletePending = ETrue; + FilterQueueEvent(EMMFDevSoundProxyPausedRecordCompleteEvent); + return EFalse; + } + +TBool CMMFDevSoundSession::DoPrepareCloseL(const RMmfIpcMessage& /*aMessage*/) + { + TBool complete = iAdapter->CloseDevSound(); + if(!complete) + { + iOperationCompletePending = ETrue; + } + return complete; + } + + +TBool CMMFDevSoundSession::DoCustomCommandL(const RMmfIpcMessage& aMessage) + { + TInt retVal = KErrNone; + TRAPD(err, retVal = iDeMuxUtility->ProcessCustomInterfaceCommandL(aMessage)); + if (err != KErrNone) + { + // the framework left with an error condition + // so we complete the message with this error + // irrespective of whether its a Sync or Async custom command + aMessage.Complete(err); + } + else + { + TInt messageType = aMessage.Function(); + if ((messageType == EMMFDevSoundProxySyncCustomCommand) || + (messageType == EMMFDevSoundProxySyncCustomCommandResult)) + { + // If its a sync custom command + // we can pass back valid values here since command + // has been handled by the DeMux framework + aMessage.Complete(retVal); + } + } + + // we complete our own message so don't need the framework to do so + return EFalse; + } + + +// +// CMMFDevSoundSession::CMMFDevSoundSession +// (other items were commented in a header). +// +CMMFDevSoundSession::CMMFDevSoundSession() : + iSetClientConfigApplied (EFalse) + { + } + +// +// CMMFDevSoundSession::~CMMFDevSoundSession +// (other items were commented in a header). +// +CMMFDevSoundSession::~CMMFDevSoundSession() + { + delete iAsyncQueueStart; + // clear the array of custom interfaces + TInt count = iCustomInterfaceArray.Count(); + for (TInt i = 0; i < count; i++) + { + // we could have already deleted interfaces without + // removing them from the array so check for this + // and only delete release plugin if non-null + MMMFDevSoundCustomInterfaceDeMuxPlugin* ptr = iCustomInterfaceArray[i].iInterface; + if (ptr) + { + iCustomInterfaceArray[i].iInterface->Release(); + } + } + iCustomInterfaceArray.Reset(); + iCustomInterfaceArray.Close(); + + delete iDeMuxUtility; + + if (iCIExtension) + { + iCIExtension->Release(); + iCIExtension = NULL; + } + + iMsgQueue.Close(); + iArray.Close(); + iQueuedRequests.Close(); + delete iDtmfString; + delete iToneSeqBuf; + delete iAdapter; + delete iClosingWait; + + CMMFDevSoundServer* server = + const_cast( + static_cast(Server())); + + if (server) + { + server->DecrementSessionId(); + } + +// delete iCustomCommandParserManager; +// delete iMMFObjectContainer; + + // Close chunk + iChunk.Close(); + } + +// +// CMMFDevSoundSession::FlushEventQueue() +// +void CMMFDevSoundSession::FlushEventQueue() + { + if(iMsgQueue.Handle() != 0) + { + TMMFDevSoundQueueItem queueItem; + TInt err = KErrNone; + while(err != KErrUnderflow) + { + err = iMsgQueue.Receive(queueItem); + } + } + } + +void CMMFDevSoundSession::FilterQueueEvent(TMMFDevSoundProxyRequest aRequest) + { + if(iMsgQueue.Handle() != 0) + { + // Pop and push events result at the queue + // can be seen as "circular list" + // set a mark to traverse it safely + TMMFDevSoundQueueItem markItem; + markItem.iRequest = EMMFDevSoundProxyMarkEvent; + // assumes sufficient space in the queue + TInt err = iMsgQueue.Send(markItem); + __ASSERT_DEBUG(err == KErrNone, Panic(EMsgQueueFailedToSendMsg)); + + while(ETrue) + { + // At least the markEvent is at the queue so ignore the error + TMMFDevSoundQueueItem queueItem; + err = iMsgQueue.Receive(queueItem); + if(queueItem.iRequest == EMMFDevSoundProxyMarkEvent) + { + break; + } + // Look for the specific event + else if(queueItem.iRequest != aRequest) + { + // assumes sufficient space in the queue + err = iMsgQueue.Send(queueItem); + } + } + } + } + +// +// CMMFDevSoundSession::Disconnect +// (other items were commented in a header). +// +void CMMFDevSoundSession::Disconnect(const RMessage2& aMessage) + { + TBool complete = iAdapter->CloseDevSound(); + if(!complete) + { + iRequestBeingServiced.SetMessage(aMessage); + iOperationCompletePending = ETrue; + iClosingWait->Start(); + } + CSession2::Disconnect(aMessage); + } + + +// +// CMMFDevSoundSession::NewL +// (other items were commented in a header). +// +CMMFDevSoundSession* CMMFDevSoundSession::NewL(MGlobalProperties& aGlobalProperties) + { + CMMFDevSoundSession* self = new (ELeave) CMMFDevSoundSession; + CleanupStack::PushL(self); + self->ConstructL(aGlobalProperties); + CleanupStack::Pop(self); + return self; + } + +// +// CMMFDevSoundSession::ConstructL +// (other items were commented in a header). +// +void CMMFDevSoundSession::ConstructL(MGlobalProperties& aGlobalProperties) + { + iAdapter = CMMFDevSoundAdaptation::NewL(*this, aGlobalProperties); + + iClosingWait = new(ELeave) CActiveSchedulerWait(); + + // Create the Custom Interface DeMux Utility + iDeMuxUtility = CMMFDevSoundCIDeMuxUtility::NewL(this); + + // Create the Custom Interface extension + TUid implUid = {KMmfUidCIServerExtensionImpl}; + TInt uidAsInteger = implUid.iUid; + const TInt KCIExtTempBufferSize = 20; + TBuf8 tempBuffer; + tempBuffer.Num(uidAsInteger, EHex); + TUid interfaceUid = {KUidDevSoundCIServerExtension}; + TUid destructorKey; + TRAPD(err, iCIExtension = static_cast + (MmPluginUtils::CreateImplementationL(interfaceUid, destructorKey, tempBuffer, KRomOnlyResolverUid))); + if (KErrNotSupported == err) + { + iCIExtension = NULL; + } + else + { + User::LeaveIfError(err); + } + if (iCIExtension) + { + // Extension exists. Complete the setup + iCIExtension->PassDestructorKey(destructorKey); + User::LeaveIfError(iCIExtension->Setup(*this)); + } + + iQueuedRequests.ReserveL(KMaxQueueRequest); + iAsyncQueueStart = new (ELeave) CAsyncCallBack(CActive::EPriorityStandard); + TCallBack asyncCallback(AsyncQueueStartCallback, this); + iAsyncQueueStart->Set(asyncCallback); + } + +// CMMFDevSoundSession::InitializeComplete +// (other items were commented in a header). +// +void CMMFDevSoundSession::InitializeComplete(TInt aError) + { + // this may be a re-initialization and so we need to + // re-get our custom interfaces on the DeMux plugins + TInt count = iCustomInterfaceArray.Count(); + for (TInt i = 0; i < count; i++) + { + // we could have already deleted interfaces without + // removing them from the array so check for this + // and only refresh plugin if non-null + MMMFDevSoundCustomInterfaceDeMuxPlugin* ptr = iCustomInterfaceArray[i].iInterface; + if (ptr) + { + // we can't keep track of.. + // 1. where a custom interface is implemented + // 2. the uid of the custom interface to be refreshed + // so assume all have to be refreshed + TRAPD(err, ptr->RefreshL()); + + // Error indicates this is no longer a valid interface + if (err != KErrNone) + { + TMMFEvent event; + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundCustomCommandCloseMuxDemuxPair; + item.iErrorCode = err; + event.iEventType.iUid = i+1; + item.iEventPckg() = event; + TInt lErr = iMsgQueue.Send(item); + __ASSERT_DEBUG(lErr == KErrNone, Panic(EMsgQueueFailedToSendMsg)); + +// NB proper panic code required here for this part. + } + } + } + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxyICEvent; + item.iErrorCode = aError; + // assumes sufficient space in the queue so ignores the return value + iMsgQueue.Send(item); + } + +// +// CMMFDevSoundSession::ToneFinished +// (other items were commented in a header). +// +void CMMFDevSoundSession::ToneFinished(TInt aError) + { + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxyTFEvent; + item.iErrorCode = aError; + // assumes sufficient space in the queue so ignores the return value + iMsgQueue.Send(item); + } + +// +// CMMFDevSoundSession::BufferToBeFilled +// (other items were commented in a header). +// +void CMMFDevSoundSession::BufferToBeFilled(CMMFBuffer* aBuffer) + { + SYMBIAN_DEBPRN0(_L("CMMFDevSoundSession[0x%x]::BufferToBeFilled - Enter")); + + // Set play error flag to false + iPlayErrorOccured = EFalse; + + // Store pointer to the buffer to use it later with PlayData + iBufferPlay = reinterpret_cast(aBuffer); + TInt status = CreateChunk(iHwBufPckgFill, iBufferPlay->RequestSize()); + iHwBufPckgFill().iRequestSize = iBufferPlay->RequestSize(); + iHwBufPckgFill().iBufferSize = iBufferPlay->Data().MaxLength(); + iHwBufPckgFill().iLastBuffer = iBufferPlay->LastBuffer(); + TMMFDevSoundQueueItem queueItem; + if ( status != KErrNone ) + { + BufferErrorEvent(); + PlayError(status); + } + else + { + queueItem.iRequest = EMMFDevSoundProxyBTBFEvent; + // assumes sufficient space in the queue so ignores the return value + status = iMsgQueue.Send(queueItem); + } + + SYMBIAN_DEBPRN1(_L("CMMFDevSoundSession[0x%x]::BufferToBeFilled - Exit [%d]"), status); + } + +// +// CMMFDevSoundSession::PlayError +// (other items were commented in a header). +// +void CMMFDevSoundSession::PlayError(TInt aError) + { + SYMBIAN_DEBPRN1(_L("CMMFDevSoundSession[0x%x]::PlayError [%d]"), aError); + + // Set play error flag to ignore following PlayData requests + iPlayErrorOccured = ETrue; + + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxyPEEvent; + item.iErrorCode = aError; + iChunk.Close(); + // assumes sufficient space in the queue so ignores the return value + iMsgQueue.Send(item); + } + +// +// CMMFDevSoundSession::BufferToBeEmptied +// (other items were commented in a header). +// +void CMMFDevSoundSession::BufferToBeEmptied(CMMFBuffer* aBuffer) + { + // Store pointer to the buffer to use it later with RecordData + iBufferRecord = reinterpret_cast(aBuffer); + TInt status = CreateChunk(iHwBufPckgEmpty, iBufferRecord->RequestSize()); + + if ( status != KErrNone ) + { + BufferErrorEvent(); + RecordError(status); + } + else + { + iHwBufPckgEmpty().iRequestSize = iBufferRecord->RequestSize(); + iHwBufPckgEmpty().iBufferSize = iBufferRecord->Data().MaxLength(); + iHwBufPckgEmpty().iLastBuffer = iBufferRecord->LastBuffer(); + //copy the data into the chunk + Mem::Copy(iChunk.Base(),iBufferRecord->Data().Ptr(),iBufferRecord->RequestSize()); + TMMFDevSoundQueueItem queueItem; + queueItem.iRequest = EMMFDevSoundProxyBTBEEvent; + // assumes sufficient space in the queue so ignores the return value + iMsgQueue.Send(queueItem); + } + } + +// CMMFDevSoundSession::RecordError +// (other items were commented in a header). +// +void CMMFDevSoundSession::RecordError(TInt aError) + { + SYMBIAN_DEBPRN1(_L("CMMFDevSoundSession[0x%x]::Record Error [%d]"), aError); + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxyREEvent; + item.iErrorCode = aError; + iChunk.Close(); + // assumes sufficient space in the queue so ignores the return value + iMsgQueue.Send(item); + } + +// +// CMMFDevSoundSession::DeviceMessage +// (other items were commented in a header). +// +void CMMFDevSoundSession::DeviceMessage(TUid /*aMessageType*/, + const TDesC8& /*aMsg*/) + { + // Not used + } + +void CMMFDevSoundSession::InterfaceDeleted(TUid aInterfaceId) + { + MMMFDevSoundCustomInterfaceDeMuxPlugin* ptr = InterfaceFromUid(aInterfaceId); + if (ptr == NULL) + { + // Not found + return; + } + TRAPD(err, ptr->RefreshL()); + if (err != KErrNone) + { + // Refresh failed, so tear down Mux/DeMux pair + TMMFEvent event; + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundCustomCommandCloseMuxDemuxPair; + item.iErrorCode = err; + event.iEventType = aInterfaceId; + item.iEventPckg() = event; + iMsgQueue.Send(item); + } + } + +// +// CMMFDevSoundSession::CallbackFromAdaptorReceived +// (other items were commented in a header). +// +void CMMFDevSoundSession::CallbackFromAdaptorReceived(TInt aType, TInt aError) + { + + if(aType == KCallbackRecordPauseComplete) + { + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxyPausedRecordCompleteEvent; + item.iErrorCode = KErrNone; + TInt status = iMsgQueue.Send(item); + } + else if(aType == KCallbackAutoPauseResume) + { + TMMFEvent event; + event.iErrorCode = KErrNone; + event.iEventType = KMMFEventCategoryAudioResourceAvailable; + SendEventToClient(event); + //coverity[uninit_use_in_call] + // Disabled Coverity warning, since it complains about iReserved1 member in TMMFEvent being uninitialised + } + else if (aType == KCallbackFlushComplete) + { + iRequestBeingServiced.Complete(aError); + iOperationCompletePending = EFalse; + } + else + { + if( iOperationCompletePending ) + { + // If not possible to service now, then queue request + // Encapsule the request + TMMFDevSoundRequest request(aType); + // assumes sufficient space in the queue so ignores the return value + iQueuedRequests.Insert(request, 0); + } + else + { + // If there is no oustanding operation service inmediately + if (aType == KCallbackProcessingFinished) + { + DoProcessingFinished(); + } + else if(aType == KCallbackProcessingUnitError) + { + DoProcessingError(); + } + } + } + } + + +// +// CMMFDevSoundSession::PreemptionStartedCallbackReceived +// (other items were commented in a header). +// +void CMMFDevSoundSession::PreemptionStartedCallbackReceived() + { + // Solution: Enqueue any request that arrives before preemption is completed + iOperationCompletePending = ETrue; + } + +// +// CMMFDevSoundSession::PreemptionFinishedCallbackReceived +// (other items were commented in a header). +// +void CMMFDevSoundSession::PreemptionFinishedCallbackReceived(TBool aCanStartNewOperation) + { + iOperationCompletePending = EFalse; + if ( aCanStartNewOperation && iQueuedRequests.Count() != 0 ) + { + DequeueRequest(); + } + } + + +MMMFDevSoundCustomInterfaceDeMuxPlugin* CMMFDevSoundSession::InterfaceFromUid(TUid aUid) + { + TInt count = iCustomInterfaceArray.Count(); + TInt id = aUid.iUid; + MMMFDevSoundCustomInterfaceDeMuxPlugin* interface = NULL; + for (TInt i = 0; i < count; i++) + { + if (id == iCustomInterfaceArray[i].iId.iUid) + { + interface = iCustomInterfaceArray[i].iInterface; + break; + } + } + return interface; + } + +// +// CMMFDevSoundSession::SendEventToClient +// (other items were commented in a header). +// +void CMMFDevSoundSession::SendEventToClient(const TMMFEvent& aEvent) + { + TMMFDevSoundQueueItem item; + item.iRequest = EMMFDevSoundProxySETCEvent; + item.iErrorCode = KErrNone; + item.iEventPckg() = aEvent; + // assumes sufficient space in the queue so ignores the return value + TInt err = iMsgQueue.Send(item); + __ASSERT_DEBUG(err == KErrNone, Panic(EMsgQueueFailedToSendMsg)); + } + +void CMMFDevSoundSession::AsynchronousOperationComplete(TInt aError, TBool aCanStartNewOperation) + { + switch (iRequestBeingServiced.Type()) + { + case TMMFDevSoundRequest::ESessionEvents: + { + SYMBIAN_DEBPRN0(_L("CMMFDevSoundSession[0x%x] ==== ClosingDueException ==== ")); + iOperationCompletePending = EFalse; + if(iClosingWait->IsStarted()) + { + iClosingWait->AsyncStop(); + } + return; + } + // Complete the message for asynchronous requests + case TMMFDevSoundRequest::EConfigure_Asynchronous: + case TMMFDevSoundRequest::EAction_Asynchronous: + case TMMFDevSoundRequest::EQuery_Asynchronous: + case TMMFDevSoundRequest::ECustomInterfacesRelated: + { + if(iOperationCompletePending && aCanStartNewOperation) + { + if (iRequestBeingServiced.Function()==EMMFDevSoundProxyStop) + { + // flush the queue - will have removed any stale items added between initial call and MMRC's reaction + iQueuedRequests.Reset(); + FlushEventQueue(); + iChunk.Close(); + } + + if(iRequestBeingServiced.Function()==EMMFDevSoundProxyCapabilities) + { + TMMFDevSoundProxySettings devSoundSet; + devSoundSet.iCaps = iDevSoundCapabilities; + TMMFDevSoundProxySettingsPckg pckg(devSoundSet); + iRequestBeingServiced.Message().Write(TInt(2),pckg); + } + + if(iRequestBeingServiced.Function()==EMMFDevSoundProxyCancelInitialize) + { + FlushEventQueue(); + } + + iRequestBeingServiced.Complete(aError); + iOperationCompletePending = EFalse; + } + } + break; + case TMMFDevSoundRequest::EAction_PseudoAsynchronous: + { + if(iOperationCompletePending && aCanStartNewOperation) + { + iOperationCompletePending = EFalse; + } + } + break; + case TMMFDevSoundRequest::EQuery_Synchronous: + case TMMFDevSoundRequest::EConfigure_Synchronous: + case TMMFDevSoundRequest::EBufferExchangeRelated: + break; + case TMMFDevSoundRequest::ECallBackType: + { + if(iOperationCompletePending && aCanStartNewOperation) + { + iOperationCompletePending = EFalse; + } + } + break; + default: + break; + } + + SYMBIAN_DEBPRN2(_L("CMMFDevSoundSession[0x%x] AsynchronousOperationComplete %x pending=%d"),iRequestBeingServiced.Function(), iOperationCompletePending ); + + if ( aCanStartNewOperation && iQueuedRequests.Count() != 0 ) + { + DequeueRequest(); + } + } + +void CMMFDevSoundSession::DequeueRequest() + { + TMMFDevSoundRequest msg = iQueuedRequests[0]; + + if (msg.IsCallBack() > 0) + { + iRequestBeingServiced.SetMessageCallback(); + //Call iPf function + SYMBIAN_DEBPRN0(_L("\n CMMFDevSoundSession[0x%x] ======== Service a queued request\n")); + if (msg.IsCallBack() == KCallbackProcessingFinished) + { + iQueuedRequests.Remove(0); + DoProcessingFinished(); + } + else if(msg.IsCallBack() == KCallbackProcessingUnitError) + { + iQueuedRequests.Remove(0); + DoProcessingError(); + } + + } + else + { + // Some rules about what request can be followed + SYMBIAN_DEBPRN0(_L("\n CMMFDevSoundSession[0x%x]======== Flag can service new request\n")); + iAsyncQueueStart->CallBack(); + } + } + +// AsyncQueueStartCallback + + +TInt CMMFDevSoundSession::AsyncQueueStartCallback(TAny* aPtr) + { + CMMFDevSoundSession* self = static_cast(aPtr); + self->AsyncQueueStartCallback(); + return KErrNone; + } + +void CMMFDevSoundSession::AsyncQueueStartCallback() + { + SYMBIAN_DEBPRN0(_L("\n CMMFDevSoundSession[0x%x]======== Service a queued request\n")); + TMMFDevSoundRequest msg = iQueuedRequests[0]; + iQueuedRequests.Remove(0); + TRAPD(err,DoServiceRequestL(msg.Message())); + if(err != KErrNone) + { + msg.Complete(err); + } + if (!iOperationCompletePending && iQueuedRequests.Count() != 0) + { + //dequeue next + DequeueRequest(); + } + } + +// CMMFDevSoundSession::CustomInterface() +// Returns a pointer reference to custom interface implementation returned by +// adaptation::CustomInterface method. +// Note this method is called indirectly by CI server-side plugins - both DeMux and +// CIServerExtension call this variously via MMMFDevSoundCustomInterfaceTarget or MCustomInterface +// +TAny* CMMFDevSoundSession::CustomInterface(TUid aInterfaceId) + { + TInt err = DoSetClientConfig(); // if required, this will connect to MMRC etc + if (err) + { + return NULL; // on any error, return NULL - not much more we can do + } + return iAdapter->CustomInterface(aInterfaceId); + } + +// +// CMMFDevSoundSession::DoProcessingFinished() +// +void CMMFDevSoundSession::DoProcessingFinished() + { + TBool asyncOperation = EFalse; + //ProcessingFinished should never fail + __ASSERT_ALWAYS(KErrNone, iAdapter->ProcessingFinishedReceived(asyncOperation)); + iOperationCompletePending = asyncOperation; + if (iOperationCompletePending) + { + iRequestBeingServiced.SetMessageCallback(); + } + } + +// +// CMMFDevSoundSession::DoProcessingError() +// +void CMMFDevSoundSession::DoProcessingError() + { + TBool asyncOperation = EFalse; + //ProcessingFinished should never fail + __ASSERT_ALWAYS(KErrNone, iAdapter->ProcessingError(asyncOperation)); + iOperationCompletePending = asyncOperation; + if (iOperationCompletePending) + { + iRequestBeingServiced.SetMessageCallback(); + } + } + +// +// CMMFDevSoundSession::DoSetClientConfigL() +// Sets client configuration information to Adaptation. +// +TInt CMMFDevSoundSession::DoSetClientConfig() + { + TInt err = KErrNone; + if(!iSetClientConfigApplied) + { + CMMFDevSoundServer* server = + const_cast( + static_cast(Server())); + + ASSERT(server); // session should always have a server! + + TMMFClientConfig clientConfig; + clientConfig.iProcessId = server->ActualProcessId(); + + err = iAdapter->SetClientConfig(clientConfig); + if (!err) + { + iSetClientConfigApplied = ETrue; + } + } + return err; + } + +// CMMFDevSoundSession::DoSetClientConfigL() +// Sets client configuration information to Adaptation. +// +void CMMFDevSoundSession::DoSetClientConfigL() + { + User::LeaveIfError(DoSetClientConfig()); + } + +// +// CMMFDevSoundSession::CreateChunk() +// Requests kernel to create global RChunk +// +TInt CMMFDevSoundSession::CreateChunk(TMMFDevSoundProxyHwBufPckg& aBufPckg, TInt aRequestedSize) + { + TInt status(KErrNone); + + if ( iChunk.Handle() ) + { + // If the DevSound Adaptation component requests a buffer size + // that can fit into current chunk's size, then re-use chunk. + if ( aRequestedSize <= iChunk.Size() ) + { + if (iForceSendOfChunkHandle) + { + iForceSendOfChunkHandle = EFalse; + aBufPckg().iChunkOp = EOpen; + } + else + { + aBufPckg().iChunkOp = ENull; + } + return status; + } + // The new request size exceeds the current chunk's area, close it. We + // will be creating new one in the following sequences. Note we could + // try to Adjust() the chunk, and see if the existing chunk could be + // extended instead, but this is assumed too rare an event for this + // optimisation + else + { + iChunk.Close(); + } + } + + // Request kernel to create global RChunk if needed + if ( !iChunk.Handle() ) + { + status = iChunk.CreateGlobal(KNullDesC, aRequestedSize, aRequestedSize); + if ( status == KErrNone ) + { + aBufPckg().iChunkOp = EOpen; + } + else + { + aBufPckg().iChunkOp = ENull; + } + } + iForceSendOfChunkHandle = EFalse; + return status; + } + + +// Custom Interface // +TInt CMMFDevSoundSession::DoOpenSlaveL(TUid aInterface, const TDesC8& aPackageBuf) + { + // it shouldn't be necessary to check if we have already instantiated this + // interface since the client would already know - however this is something + // that a licensee could implement if they required additional functionality + // e.g. many : 1 mappings between client and DevSound. + + MMMFDevSoundCustomInterfaceDeMuxPlugin* ptr = NULL; + + // try and instantiate a plugin tunnelling + // pair to support this Custom Interface + ptr = iDeMuxUtility->CreateCustomInterfaceDeMuxL(aInterface); + + TInt handle = KNullHandle; + + if (ptr) + { + TMMFDevSoundCustomInterfaceDeMuxData data; + data.iInterface = ptr; + data.iId = aInterface; + + CleanupReleasePushL(*ptr); + + // setup demux plugin + ptr->SetInterfaceTarget(this); + + // try and open interface + // this will fetch the interface from the svr implementation + ptr->DoOpenSlaveL(aInterface, aPackageBuf); + User::LeaveIfError(iCustomInterfaceArray.Append(data)); + + CleanupStack::Pop(); // ptr + + handle = iCustomInterfaceArray.Count(); + return handle; + } + + // we couldn't set up the interface correctly so return a NULL + // handle to the client + return KNullHandle; + } + +void CMMFDevSoundSession::DoCloseSlaveL(TInt aHandle) + { + if (aHandle==KNullHandle) + { + // null-handle -> NOP + return; + } + + if (aHandle iCustomInterfaceArray.Count()) + { + // handle out of range - should not happen, but leave to show error + User::Leave(KErrBadHandle); + } + + TMMFDevSoundCustomInterfaceDeMuxData& data = iCustomInterfaceArray[aHandle-1]; + + // close and delete the plugin + MMMFDevSoundCustomInterfaceDeMuxPlugin* ptr = data.iInterface; + ptr->DoCloseSlaveL(aHandle); + ptr->Release(); + + // clear the entry + data.iInterface = NULL; + data.iId.iUid = 0; + } + +TInt CMMFDevSoundSession::DoSendSlaveSyncCommandL(const RMmfIpcMessage& aMessage) + { + // use the demux utility to get the handle + TMMFDevSoundCIMessageData data; + iDeMuxUtility->GetSyncMessageDataL(aMessage, data); + + TInt handle = data.iHandle; + + if ((handle <= 0) || (handle > (iCustomInterfaceArray.Count()))) + { + + User::Leave(KErrBadHandle); + } + + // call on demux plugin + return iCustomInterfaceArray[handle-1].iInterface->DoSendSlaveSyncCommandL(aMessage); + } + +TInt CMMFDevSoundSession::DoSendSlaveSyncCommandResultL(const RMmfIpcMessage& aMessage) + { + // use the demux utility to get the handle + TMMFDevSoundCIMessageData data; + iDeMuxUtility->GetSyncMessageDataL(aMessage, data); + + TInt handle = data.iHandle; + + if ((handle <= 0) || (handle > (iCustomInterfaceArray.Count()))) + { + + User::Leave(KErrBadHandle); + } + + // call on demux plugin + return iCustomInterfaceArray[handle-1].iInterface->DoSendSlaveSyncCommandResultL(aMessage); + } + +void CMMFDevSoundSession::DoSendSlaveAsyncCommandL(const RMmfIpcMessage& aMessage) + { + // use the demux utility to get the handle + TMMFDevSoundCIMessageData data; + iDeMuxUtility->GetAsyncMessageDataL(aMessage, data); + + TInt handle = data.iHandle; + + if ((handle <= 0) || (handle > (iCustomInterfaceArray.Count()))) + { + User::Leave(KErrBadHandle); + } + + // call on demux plugin + iCustomInterfaceArray[handle-1].iInterface->DoSendSlaveAsyncCommandL(aMessage); + } + +void CMMFDevSoundSession::DoSendSlaveAsyncCommandResultL(const RMmfIpcMessage& aMessage) + { + // use the demux utility to get the handle + TMMFDevSoundCIMessageData data; + iDeMuxUtility->GetAsyncMessageDataL(aMessage, data); + + TInt handle = data.iHandle; + + if ((handle <= 0) || (handle > (iCustomInterfaceArray.Count()))) + { + User::Leave(KErrBadHandle); + } + + // call on demux plugin + iCustomInterfaceArray[handle-1].iInterface->DoSendSlaveAsyncCommandResultL(aMessage); + } + + +TBool CMMFDevSoundSession::DoRegisterAsClientL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg buf; + aMessage.ReadL(0,buf); + HBufC8* notificationRegistrationData = NULL; + notificationRegistrationData = HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesLengthL(1))); + TPtr8 dataPtr(notificationRegistrationData->Des()); + aMessage.ReadL(1,dataPtr); + DoSetClientConfigL();// added here instead of the CreateL() + TInt err = KErrNone; + err = iAdapter->RegisterAsClient(buf().iNotificationEventUid,dataPtr); + CleanupStack::PopAndDestroy(1); // Notification Registeration data + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + return ETrue; + } + +TBool CMMFDevSoundSession::DoCancelRegisterAsClientL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg buf; + aMessage.ReadL(0,buf); + TInt err = KErrNone; + err = iAdapter->CancelRegisterAsClient(buf().iNotificationEventUid); + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + return ETrue; + } + +TBool CMMFDevSoundSession::DoGetResourceNotificationDataL(const RMmfIpcMessage& aMessage) + { + TMMFDevSoundProxySettingsPckg buf; + aMessage.ReadL(0,buf); + HBufC8* notificationData = NULL; + notificationData = HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesMaxLengthL(2))); + TPtr8 dataPtr(notificationData->Des()); + aMessage.ReadL(2,dataPtr); + TInt err = KErrNone; + err = iAdapter->GetResourceNotificationData(buf().iNotificationEventUid,dataPtr); + aMessage.WriteL(2,*notificationData); + CleanupStack::PopAndDestroy(1); // Notification data + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + return ETrue; + } + +TBool CMMFDevSoundSession::DoWillResumePlayL(const RMmfIpcMessage& aMessage) + { + TInt err = KErrNone; + err = iAdapter->WillResumePlay(); + if (err != KErrNone) + { + aMessage.Complete(err); + return EFalse; + } + return ETrue; + } + +TBool CMMFDevSoundSession::DoSetClientThreadInfoL(const RMmfIpcMessage& aMessage) + { + if(!iSetClientConfigApplied) + { + if (aMessage.HasCapability(ECapabilityMultimediaDD) && aMessage.HasCapability(ECapabilityUserEnvironment)) + { + TPckgBuf threadId; + aMessage.ReadL(1, threadId); + + CMMFDevSoundServer* server = + const_cast(static_cast(Server())); + server->SetClientProcessIdL(threadId()); + } + else + { + User::Leave(KErrPermissionDenied); + } + } + else + { + User::Leave(KErrNotReady); + } + return ETrue; + } + +void CMMFDevSoundSession::Panic(TMMFDevSoundSessionPanicCodes aCode) + { + User::Panic(KMMFDevSoundSessionPanicCategory, aCode); + } + +void CMMFDevSoundSession::BufferErrorEvent() + { + // this will generate an processing error event and callback + iAdapter->BufferErrorEvent(); + } +// End of file