sl@0: // tonehwdevice.cpp sl@0: // Copyright (c) 2006-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: sl@0: sl@0: // INCLUDE FILES sl@0: #include sl@0: #include "tonehwdevice.hrh" //for KUidToneHwDevice sl@0: #include // For making it ECom plugin sl@0: #include "tonehwdevice.h" sl@0: sl@0: sl@0: // EXTERNAL DATA STRUCTURES sl@0: sl@0: // EXTERNAL FUNCTION PROTOTYPES sl@0: sl@0: // CONSTANTS sl@0: const TImplementationProxy ImplementationTable[] = sl@0: { sl@0: IMPLEMENTATION_PROXY_ENTRY(KUidToneHwDevice, CToneHwDevice::NewL), sl@0: }; sl@0: //current supported sample rate sl@0: const TInt KSupportedSampleRate = 8000; sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // Default constructor sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: CToneHwDevice::CToneHwDevice() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::CToneHwDevice *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: DP_OUT(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // Symbian 2nd phase constructor sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CToneHwDevice::ConstructL() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::ConstructL *CD0*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: iHwDataBufferFill = CMMFDataBuffer::NewL(sizeof(TToneData)); sl@0: iHwDataBufferFill->SetLastBuffer(EFalse); sl@0: iHwDataBufferFill->Data().SetLength(sizeof(TToneData)); sl@0: iHwDataBufferFill->SetRequestSizeL(sizeof(TToneData)); sl@0: sl@0: iCodec = new(ELeave)CToneCodec(); sl@0: sl@0: DP_OUT(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // Symbian constructor sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CToneHwDevice* CToneHwDevice::NewL() sl@0: { sl@0: DP_STATIC_CONTEXT(CToneHwDevice::NewL *CD0*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: CToneHwDevice* self = new (ELeave) CToneHwDevice(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: DP0_RET(self, "0x%x"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // Destructor sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: CToneHwDevice::~CToneHwDevice() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::~CToneHwDevice *CD0*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: delete iHwDataBufferFill; sl@0: delete iCodec; sl@0: delete iPlayCustomInterface; sl@0: sl@0: if(iDataPath) sl@0: { sl@0: delete iDataPath; sl@0: } sl@0: sl@0: if(iToneBuffer1) sl@0: { sl@0: delete iToneBuffer1; sl@0: } sl@0: if(iToneBuffer2) sl@0: { sl@0: delete iToneBuffer2; sl@0: } sl@0: DP_OUT(); sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Codec sl@0: * sl@0: */ sl@0: CToneCodec& CToneHwDevice::Codec() sl@0: { sl@0: return *iCodec; sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::Init sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::Init(THwDeviceInitParams& aDevInfo) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Init *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: if (!iToneInitialized) // Check if tones is not initialized yet. sl@0: { sl@0: iToneInitialized = ETrue; sl@0: } sl@0: sl@0: // [ precondition that aDevInfo has a valid observer ] sl@0: if (!aDevInfo.iHwDeviceObserver) sl@0: { sl@0: DP0_RET(KErrArgument, "%d"); sl@0: } sl@0: sl@0: iHwDeviceObserver = aDevInfo.iHwDeviceObserver; sl@0: sl@0: //[ assert the post condition ] sl@0: if (!iCodec) sl@0: { sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::Start sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::Start(TDeviceFunc /*aFuncCmd*/, TDeviceFlow /*aFlowCmd*/) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Start *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TInt error = KErrNone; sl@0: sl@0: // Start for first time OR resuming sl@0: if (!iTonePlaying || iDataPath->State() == CToneDataPath::EPaused) sl@0: { sl@0: iLastBuffer = EFalse; sl@0: //[ assert precondition that play custom interface is present] sl@0: //if there is no tone play custom interface then the user of the CToneHwDevice sl@0: //cannot have set any of the custom settings such as sample rate. sl@0: if (!iPlayCustomInterface) sl@0: { sl@0: DP0_RET(KErrNotReady, "%d"); sl@0: } sl@0: sl@0: //play sl@0: if (!iDataPath) sl@0: { sl@0: //create a datapath sl@0: TRAP(error,iDataPath = CToneDataPath::NewL()); sl@0: if ((iDataPath)&&(error == KErrNone)) sl@0: { sl@0: ASSERT(iHwDeviceObserver); sl@0: iDataPath->SetObserver(*this); sl@0: error = iDataPath->AddCodec(*iCodec); sl@0: if (error == KErrNone) sl@0: { sl@0: iDeviceBufferSize = (iCodec->SinkBufferSize()); sl@0: } sl@0: } sl@0: } sl@0: if ((error == KErrNone) && (iDataPath->State() != CToneDataPath::EPlaying)) sl@0: { sl@0: //datapath was created ok and we are not playing sl@0: if (iDataPath->State() == CToneDataPath::EStopped) sl@0: { sl@0: // starting from 'fresh so set sound device settings sl@0: if (!iDataPath->Device().Handle()) sl@0: { sl@0: //if Device() is called then we need a valid sound device handle sl@0: error = iDataPath->Device().Open(); sl@0: if (error != KErrNone) sl@0: { sl@0: DP0_RET(error, "%d"); sl@0: } sl@0: sl@0: } sl@0: static_cast(iPlayCustomInterface)->SetDevice(&(iDataPath->Device())); sl@0: sl@0: TUint iVol = iPlayCustomInterface->Volume(); sl@0: iDataPath->Device().SetPlayVolume(iVol); sl@0: sl@0: soundDeviceSettings().iRate = iSampleRate; sl@0: sl@0: //this would normally be pcm16 sl@0: soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: sl@0: //1 = mono 2 = stereo sl@0: soundDeviceSettings().iChannels = iChannels; sl@0: sl@0: //tell sound driver what buffer size to expect sl@0: //it is up the the implementor to make use the device can support sl@0: //the required buffer size sl@0: soundDeviceSettings().iBufferSize = iDeviceBufferSize; sl@0: error = iDataPath->Device().SetPlayFormat(soundDeviceSettings); sl@0: sl@0: } // End of iDataPath->State() == CToneDataPath::EStopped sl@0: sl@0: //else resuming from pause sl@0: if ((error == KErrNone)||(error == KErrInUse)) sl@0: { sl@0: // Hw device hasn't played anything yet so don't change sl@0: // active buffer. This is checked in FillThisHwBuffer. sl@0: if(iDataPath->State() != CToneDataPath::EPaused) sl@0: { sl@0: iFirstCallFromHwDevice = ETrue; sl@0: } sl@0: iTonePlaying = ETrue; sl@0: error = iDataPath->Start(); sl@0: } sl@0: }//status == KErrNone sl@0: } sl@0: else // if tone playback is already ongoing do nothing sl@0: { sl@0: DP0(DLINFO,"Previous tone call is not completed yet"); sl@0: } sl@0: DP0_RET(error, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::Stop sl@0: // --------------------------------------------------------------------------- sl@0: TInt CToneHwDevice::Stop() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Stop *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: if (iTonePlaying) sl@0: { sl@0: iTonePlaying = EFalse; sl@0: } sl@0: sl@0: if (!iDataPath) sl@0: { sl@0: DP0_RET(KErrNotReady, "%d"); sl@0: } sl@0: sl@0: delete iDataPath; sl@0: iDataPath = NULL; sl@0: sl@0: //Setting device to NULL since after stop it doesn't exists any more sl@0: if(iPlayCustomInterface) sl@0: { sl@0: static_cast(iPlayCustomInterface)->SetDevice(NULL); sl@0: } sl@0: sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::Pause sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::Pause() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Pause *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: if (!iDataPath) sl@0: { sl@0: DP0_RET(KErrNotReady, "%d"); sl@0: } sl@0: iDataPath->Pause(); sl@0: sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::StopAndDeleteCodec sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::StopAndDeleteCodec() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::StopAndDeleteCodec *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::DeleteCodec sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::DeleteCodec() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::DeleteCodec *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::SetConfig sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::SetConfig(TTaskConfig& aConfig) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::SetConfig *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: if (aConfig.iUid != KUidRefDevSoundTaskConfig) sl@0: { sl@0: DP0_RET(KErrArgument, "%d"); sl@0: } sl@0: sl@0: if (aConfig.iRate != KSupportedSampleRate ) sl@0: { sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: iSampleRate = aConfig.iRate; sl@0: sl@0: if (aConfig.iStereoMode == ETaskMono) sl@0: { sl@0: iChannels = 1; sl@0: } sl@0: else if (aConfig.iStereoMode == ETaskInterleaved || aConfig.iStereoMode == ETaskNonInterleaved) sl@0: { sl@0: iChannels = 2; sl@0: } sl@0: else sl@0: { sl@0: DP0_RET(KErrArgument, "%d"); sl@0: } sl@0: sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: // CToneHwDevice::FillThisHwBuffer sl@0: // --------------------------------------------------------------------------- sl@0: TInt CToneHwDevice::FillThisHwBuffer(CMMFBuffer& aHwBuffer) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::FillThisHwBuffer *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TInt err(KErrNone); sl@0: sl@0: if(iFirstCallFromHwDevice) sl@0: { sl@0: err = iHwDeviceObserver->FillThisHwBuffer(aHwBuffer); sl@0: } sl@0: else sl@0: { sl@0: err = ThisHwBufferFilled(aHwBuffer); sl@0: } sl@0: DP0_RET(err,"%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::ThisHwBufferFilled sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TInt CToneHwDevice::ThisHwBufferFilled(CMMFBuffer& aMmfBuffer) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::ThisHwBufferFilled *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TInt err = KErrNone; sl@0: CMMFDataBuffer* myBuffer = static_cast (&aMmfBuffer); sl@0: // Set the request length, From HwDevice this comes with buffer sl@0: // length. sl@0: TInt len = myBuffer->Data().MaxLength(); sl@0: // Ignore error. since buffer size = Buffer Length sl@0: TRAP(err, myBuffer->SetRequestSizeL(len)); sl@0: sl@0: if(iFirstCallFromHwDevice) sl@0: { sl@0: myBuffer->SetLastBuffer(EFalse); sl@0: sl@0: Mem::Copy((TAny*)(&myToneData), (TAny*)(myBuffer->Data().Ptr()), sizeof(TToneData)); sl@0: sl@0: err = ReadToneData(); sl@0: if(err==KErrNone) sl@0: { sl@0: err= GenerateBufferData(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Hw device will call this method right after its Start was called. sl@0: // When it calls this for the first time it hasn't played one single sl@0: // buffer yet so check that. sl@0: // In this case there's no need to set the active buffer as it's already sl@0: // waiting to be played. sl@0: SetActiveToneBuffer(); sl@0: } sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: // If there is no data in the active buffer, tone play is finished. sl@0: // DevSound just have to wait for completion event from audio device. sl@0: if (iActiveToneBuffer->Data().Length() == 0) sl@0: { sl@0: iActiveToneBuffer->SetLastBuffer(ETrue); sl@0: myBuffer->SetLastBuffer(ETrue); sl@0: iLastBuffer=ETrue; sl@0: } sl@0: sl@0: TInt tonelen = iActiveToneBuffer->Data().Length(); sl@0: sl@0: // don't enter more data than can be handled by the receiving buffer sl@0: if (len >= tonelen) sl@0: { sl@0: len = tonelen; sl@0: } sl@0: sl@0: // Copy data from tone buffer to hw device buffer sl@0: Mem::Copy((TAny*)(myBuffer->Data().Ptr()), (TAny*)(iActiveToneBuffer->Data().Ptr()), len); sl@0: sl@0: myBuffer->Data().SetLength(len); sl@0: sl@0: //Play data and try to generate next data block sl@0: TRAP(err,iDataPath->BufferFilledL(static_cast (*myBuffer))); sl@0: if(err == KErrNone) sl@0: { sl@0: if(iLastBuffer) sl@0: { sl@0: // coverity[check_after_deref] sl@0: if(myBuffer) sl@0: { sl@0: myBuffer = NULL; sl@0: } sl@0: FreeBuffers(); sl@0: iFirstCallFromHwDevice = EFalse; sl@0: } sl@0: else sl@0: { sl@0: // Check again whether this is the first call from Hw device. sl@0: // FillFreeToneBuffer assumes the iActiveToneBuffer has already sl@0: // been played. sl@0: if (!iFirstCallFromHwDevice) sl@0: { sl@0: err = FillFreeToneBuffer(); sl@0: } sl@0: else sl@0: { sl@0: iFirstCallFromHwDevice = EFalse; // Reset flag sl@0: } sl@0: } sl@0: } sl@0: } sl@0: if ( err != KErrNone ) sl@0: { sl@0: myBuffer->SetLastBuffer(ETrue); sl@0: myBuffer->Data().SetLength(0); sl@0: //Use error additional variable for sending last buffer so can still send Error(err) sl@0: TRAPD(datapathErr, iDataPath->BufferFilledL(static_cast (*myBuffer))); sl@0: // coverity[check_after_deref] sl@0: if(myBuffer) sl@0: { sl@0: myBuffer = NULL; sl@0: } sl@0: FreeBuffers(); sl@0: iFirstCallFromHwDevice = EFalse; sl@0: if ( datapathErr != KErrNone ) sl@0: { sl@0: iHwDeviceObserver->Error(datapathErr); sl@0: DP0_RET(datapathErr, "%d"); sl@0: } sl@0: iHwDeviceObserver->Error(err); sl@0: } sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class MMMFHwDeviceObserver sl@0: // CToneHwDevice::ThisHwBufferEmptied sl@0: // --------------------------------------------------------------------------- sl@0: TInt CToneHwDevice::ThisHwBufferEmptied(CMMFBuffer& /*aMmfBuffer*/) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::ThisHwBufferEmptied *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class MMMFHwDeviceObserver sl@0: // CToneHwDevice::EmptyThisHwBuffer sl@0: // --------------------------------------------------------------------------- sl@0: TInt CToneHwDevice::EmptyThisHwBuffer(CMMFBuffer& /*aMmfBuffer*/) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::EmptyThisHwBuffer *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class MMMFHwDeviceObserver sl@0: // CToneHwDevice::MsgFromHwDevice sl@0: // --------------------------------------------------------------------------- sl@0: TInt CToneHwDevice::MsgFromHwDevice(TUid aMessageType, const TDesC8& aMsg) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::MsgFromHwDevice *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: TInt err(KErrNone); sl@0: err = iHwDeviceObserver->MsgFromHwDevice(aMessageType, aMsg); sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class MMMFHwDeviceObserver sl@0: // CToneHwDevice::Stopped sl@0: // --------------------------------------------------------------------------- sl@0: void CToneHwDevice::Stopped() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Stopped *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: iHwDeviceObserver->Stopped(); sl@0: DP_OUT(); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class MMMFHwDeviceObserver sl@0: // CToneHwDevice::Error sl@0: // --------------------------------------------------------------------------- sl@0: void CToneHwDevice::Error(TInt aError) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::Error *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: iHwDeviceObserver->Error(aError); sl@0: DP_OUT(); sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CMMFHwDevice sl@0: // CToneHwDevice::CustomInterface sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TAny* CToneHwDevice::CustomInterface(TUid aInterfaceUid) sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::CustomInterface *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TAny* ret = NULL; sl@0: TInt err = KErrNone; sl@0: sl@0: if (aInterfaceUid.iUid == KMmfPlaySettingsCustomInterface) sl@0: { sl@0: if (!iPlayCustomInterface) sl@0: { sl@0: TRAP(err,iPlayCustomInterface = new(ELeave)TToneCustomInterface()); sl@0: } sl@0: if (err) sl@0: { sl@0: ret = NULL; sl@0: } sl@0: else sl@0: { sl@0: ret = static_cast(iPlayCustomInterface); sl@0: } sl@0: } sl@0: else if (aInterfaceUid == KIgnoreUnderflowCustomInterfaceTypeUid) sl@0: { sl@0: if (!iDataPath) sl@0: { sl@0: ret = NULL; sl@0: } sl@0: else sl@0: { sl@0: ret = static_cast(iDataPath)->CustomInterface(aInterfaceUid); sl@0: } sl@0: } sl@0: sl@0: DP_OUT(); sl@0: return ret; sl@0: } sl@0: sl@0: TInt CToneHwDevice::ReadToneData() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::ReadToneData *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TUint vol; sl@0: myToneData.GetType(iToneType); sl@0: TInt64 zeroInt64(0); sl@0: iFrequency1 = myToneData.GetFrequencyOne(); sl@0: iFrequency2 = myToneData.GetFrequencyTwo(); sl@0: myToneData.GetDuration(iDuration); sl@0: sl@0: myToneData.GetRepeatTrailingSilence(iRepeatTrailingSilence); sl@0: iRepeatCount = myToneData.GetRepeatCount(); sl@0: iRampDuration = iPlayCustomInterface->VolumeRamp(); sl@0: vol = iPlayCustomInterface->Volume(); sl@0: iDataPath->Device().SetPlayVolume(vol); sl@0: switch (iToneType) sl@0: { sl@0: case TToneData::ESimple: sl@0: DP0(DLINFO, "Playing simple tone"); sl@0: iDataPath->Device().GetPlayFormat(soundDeviceSettings); sl@0: if((iFrequency1<0) || (iDuration.Int64() < zeroInt64)) sl@0: { sl@0: iHwDeviceObserver->Error(KErrArgument); sl@0: DP0_RET(KErrArgument, "%d"); sl@0: } sl@0: iToneGen.SetFrequencyAndDuration(iFrequency1,iDuration); sl@0: // Configure tone generator sl@0: iToneGen.Configure( sl@0: soundDeviceSettings().iRate, sl@0: soundDeviceSettings().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*soundDeviceSettings().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*soundDeviceSettings().iRate)/1000000) sl@0: ); sl@0: iCurrentGenerator = &iToneGen; sl@0: break; sl@0: case TToneData::EDual: sl@0: DP0(DLINFO, "Playing dual tone"); sl@0: iDataPath->Device().GetPlayFormat(soundDeviceSettings); sl@0: if((iFrequency1<0) || (iFrequency2<0) || (iDuration.Int64() < zeroInt64)) sl@0: { sl@0: iHwDeviceObserver->Error(KErrArgument); sl@0: DP0_RET(KErrArgument, "%d"); sl@0: } sl@0: iDualToneGen.SetFrequencyAndDuration(iFrequency1, iFrequency2, iDuration); sl@0: // Configure dual tone generator sl@0: iDualToneGen.Configure( sl@0: soundDeviceSettings().iRate, sl@0: soundDeviceSettings().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*soundDeviceSettings().iRate)/KOneMillionMicroSeconds), sl@0: I64LOW((iRampDuration.Int64()*soundDeviceSettings().iRate)/KOneMillionMicroSeconds) sl@0: ); sl@0: iCurrentGenerator = &iDualToneGen; sl@0: break; sl@0: case TToneData::EDtmfString: sl@0: DP0(DLINFO, "Playing DTMF string"); sl@0: myToneData.GetDtmfLenghts(myToneOnLength, myToneOffLength, myPauseLength); sl@0: iDTMFGen.SetToneDurations(myToneOnLength, myToneOffLength, myPauseLength); sl@0: iDTMFString = myToneData.GetDTMFString(); sl@0: if(!ValidDTMFString(const_cast(*iDTMFString))) sl@0: { sl@0: DP0(DLINFO, "Invalid DTMF String"); sl@0: iHwDeviceObserver->Error(KErrCorrupt); sl@0: DP0_RET(KErrCorrupt, "%d"); sl@0: } sl@0: iDTMFGen.SetString(const_cast(*iDTMFString)); sl@0: iDataPath->Device().GetPlayFormat(soundDeviceSettings); sl@0: iDTMFGen.Configure( sl@0: soundDeviceSettings().iRate, sl@0: soundDeviceSettings().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*soundDeviceSettings().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*soundDeviceSettings().iRate)/1000000) sl@0: ); sl@0: iCurrentGenerator = &iDTMFGen; sl@0: break; sl@0: case TToneData::ESequence: sl@0: DP0(DLINFO, "Playing tone sequence"); sl@0: iSequenceData = myToneData.GetSequenceData(); sl@0: // Check whether the sequence is signed or not sl@0: if (!RecognizeSequence(*iSequenceData)) sl@0: { sl@0: DP0(DLINFO, "Invalid Sequence Sign"); sl@0: iHwDeviceObserver->Error(KErrCorrupt); sl@0: DP0_RET(KErrCorrupt, "%d"); sl@0: } sl@0: iSequenceGen.SetSequenceData(*iSequenceData); sl@0: iDataPath->Device().GetPlayFormat(soundDeviceSettings); sl@0: iSequenceGen.Configure( sl@0: soundDeviceSettings().iRate, sl@0: soundDeviceSettings().iChannels, sl@0: iRepeatCount, sl@0: I64LOW((iRepeatTrailingSilence.Int64()*soundDeviceSettings().iRate)/1000000), sl@0: I64LOW((iRampDuration.Int64()*soundDeviceSettings().iRate)/1000000) sl@0: ); sl@0: iCurrentGenerator = &iSequenceGen; sl@0: break; sl@0: case TToneData::EFixedSequence: sl@0: DP0(DLINFO, "Playing FixedSequnce"); sl@0: iHwDeviceObserver->Error(KErrNotSupported); sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: default: sl@0: DP0_RET(KErrNotSupported, "%d"); sl@0: } sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Creates buffer and begin playback using the specified tone generator. sl@0: * sl@0: */ sl@0: TInt CToneHwDevice::GenerateBufferData() sl@0: { sl@0: DP_CONTEXT(CToneHwDevice::GenerateBufferData *CD1*, CtxDevSound, DPLOCAL); sl@0: DP_IN(); sl@0: sl@0: TInt err; sl@0: err = KErrNone; sl@0: sl@0: // Delete any buffer from previous call and try to create maximum buffer sl@0: // size. Double Buffer the Tone data. sl@0: if (iToneBuffer1) sl@0: { sl@0: delete iToneBuffer1; sl@0: iToneBuffer1 = NULL; sl@0: } sl@0: //note the tone buffer needs to be the same as the pcm16->pcm16 'null' sl@0: //hw device plugin sl@0: // Buffer size = (SampleRate * BytesPerSample * Channels) / 4 sl@0: TInt useBufferOfSize = ((SamplingFrequency() * 2 * NumberOfChannels())/KDevSoundFramesPerSecond + (KDevSoundDeltaFrameSize-1)) &~ (KDevSoundDeltaFrameSize-1); sl@0: //clamp buffer to desired limits sl@0: if(useBufferOfSize < KDevSoundMinFrameSize) sl@0: { sl@0: useBufferOfSize = KDevSoundMinFrameSize; sl@0: } sl@0: else if(useBufferOfSize > KDevSoundMaxFrameSize) sl@0: { sl@0: useBufferOfSize = KDevSoundMaxFrameSize; sl@0: } sl@0: sl@0: TRAP(err, iToneBuffer1 = CMMFDataBuffer::NewL(useBufferOfSize)); sl@0: if ( err != KErrNone ) sl@0: { sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data()); sl@0: if(err!=KErrNone) sl@0: { sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: if (iToneBuffer2) sl@0: { sl@0: delete iToneBuffer2; sl@0: iToneBuffer2 = NULL; sl@0: } sl@0: sl@0: TRAP(err, iToneBuffer2 = CMMFDataBuffer::NewL(useBufferOfSize)); sl@0: if ( err != KErrNone ) sl@0: { sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data()); sl@0: if(err!=KErrNone) sl@0: { sl@0: DP0_RET(err, "%d"); sl@0: } sl@0: sl@0: // Assign active buffer sl@0: iActiveToneBuffer = iToneBuffer1; sl@0: DP0_RET(KErrNone, "%d"); sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * This method assigns the other buffer as active buffer. The tone audio sl@0: * generator should fill data in the other buffer by now. sl@0: * sl@0: */ sl@0: void CToneHwDevice::SetActiveToneBuffer() sl@0: { sl@0: if (iActiveToneBuffer == iToneBuffer1) sl@0: iActiveToneBuffer = iToneBuffer2; sl@0: else if (iActiveToneBuffer == iToneBuffer2) sl@0: iActiveToneBuffer = iToneBuffer1; sl@0: } sl@0: sl@0: sl@0: void CToneHwDevice::FreeBuffers() sl@0: { sl@0: if(iToneBuffer1) sl@0: { sl@0: delete iToneBuffer1; sl@0: iToneBuffer1 = NULL; sl@0: } sl@0: if(iToneBuffer2) sl@0: { sl@0: delete iToneBuffer2; sl@0: iToneBuffer2 = NULL; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns an integer representing Sampling Frequency the device is currently sl@0: * configured to. sl@0: * sl@0: * @return "TInt" sl@0: * Sampling Frequency. sl@0: * sl@0: */ sl@0: TInt CToneHwDevice::SamplingFrequency() sl@0: { sl@0: return iSampleRate; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * Returns an integer representing number of channels the device is currently sl@0: * configured to. sl@0: * sl@0: * @return "TInt" sl@0: * Number of audio channels 1 if mono, 2 if stereo. sl@0: * sl@0: */ sl@0: TInt CToneHwDevice::NumberOfChannels() sl@0: { sl@0: if(iChannels == EMMFMono) sl@0: return 1; sl@0: else sl@0: return 2; sl@0: } sl@0: sl@0: /* sl@0: * sl@0: * This method fills data into the free buffer. sl@0: * sl@0: * @return "TInt" sl@0: * Error code. KErrNone if success. sl@0: * sl@0: */ sl@0: TInt CToneHwDevice::FillFreeToneBuffer() sl@0: { sl@0: TInt err(KErrNone); sl@0: if (iActiveToneBuffer == iToneBuffer1) sl@0: { sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data()); sl@0: } sl@0: else if (iActiveToneBuffer == iToneBuffer2) sl@0: { sl@0: err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data()); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: TBool CToneHwDevice::RecognizeSequence(const TDesC8& aData) sl@0: { sl@0: // Reference plug-in only supports its own sequence format sl@0: _LIT8(KSequenceSignature,"SQNC"); sl@0: if (aData.Length() > 4) sl@0: { sl@0: if (aData.Left(4) == KSequenceSignature) sl@0: { sl@0: return ETrue; sl@0: } sl@0: } sl@0: // Didn't recognise sl@0: return EFalse; sl@0: } sl@0: sl@0: TBool CToneHwDevice::ValidDTMFString(const TDesC& aDTMFString) sl@0: { sl@0: const TDesC* stringDTMF = &aDTMFString;; sl@0: TInt stringPos = 0; sl@0: if (stringPos == stringDTMF->Length()) sl@0: { sl@0: return EFalse; // Finished. Nothing to do sl@0: } sl@0: do sl@0: { sl@0: TChar c((*stringDTMF)[stringPos++]); sl@0: if (static_cast (c)=='#' || static_cast (c)=='*' || static_cast (c)==',' || c.IsHexDigit() || c.IsSpace()) sl@0: { sl@0: //Do nothing, valid character sl@0: } sl@0: else sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: } sl@0: while(stringPos < stringDTMF->Length()); sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: /************************************************************************ sl@0: * TToneCustomInterface * sl@0: ************************************************************************/ sl@0: /** sl@0: * This method is not be exported as it is only sl@0: * intended to be called within this DLL. sl@0: * It's purpose is to assign an RMdaDevSound to the play sl@0: * custom interface sl@0: * @internalComponent sl@0: */ sl@0: void TToneCustomInterface::SetDevice(RMdaDevSound* aDevice) sl@0: { sl@0: iDevice = aDevice; sl@0: } sl@0: sl@0: void TToneCustomInterface::SetVolume(TUint aVolume) sl@0: { sl@0: iVolume = aVolume; sl@0: if (iDevice && iDevice->Handle()!=0) sl@0: { sl@0: iDevice->SetPlayVolume(aVolume); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * Procedure to get the number of bytes played by the device driver sl@0: * If there is no handle available to the device driver then the sl@0: * procedure returns the last known value sl@0: * @released sl@0: * @return number of bytes played sl@0: */ sl@0: TUint TToneCustomInterface::BytesPlayed() sl@0: { sl@0: if(iDevice) sl@0: { sl@0: if (iDevice->Handle()) sl@0: { sl@0: iBytesPlayed = iDevice->BytesPlayed(); sl@0: } sl@0: } sl@0: return iBytesPlayed; sl@0: } sl@0: sl@0: sl@0: // sl@0: // class CToneCodec // sl@0: // sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::CToneCodec sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: CToneCodec::CToneCodec() sl@0: { sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::~CToneCodec sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: CToneCodec::~CToneCodec() sl@0: { sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::ConstructL sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: void CToneCodec::ConstructL() sl@0: { sl@0: } sl@0: sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::ProcessL sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: CToneCodec::TCodecProcessResult CToneCodec::ProcessL(const CMMFBuffer& /*aSource*/, CMMFBuffer& /*aDest*/) sl@0: { sl@0: //no processing required for null codec sl@0: User::Leave(KErrNotSupported); sl@0: //to keep compiler happy sl@0: TCodecProcessResult result; sl@0: result.iCodecProcessStatus = TCodecProcessResult::EEndOfData; sl@0: result.iSrcBytesProcessed = 0; sl@0: result.iDstBytesAdded = 0; sl@0: return result; sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::SourceBufferSize sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TUint CToneCodec::SourceBufferSize() sl@0: { sl@0: return KPCM16ToPCM16BufferSize; sl@0: } sl@0: sl@0: // --------------------------------------------------------------------------- sl@0: // from class CToneCodec sl@0: // CToneCodec::SinkBufferSize sl@0: // --------------------------------------------------------------------------- sl@0: // sl@0: TUint CToneCodec::SinkBufferSize() sl@0: { sl@0: return KPCM16ToPCM16BufferSize; sl@0: } sl@0: sl@0: sl@0: // ========================== OTHER EXPORTED FUNCTIONS ========================= sl@0: /** sl@0: * ImplementationGroupProxy sl@0: * is called to get a pointer to the plugin's implementation table, or table sl@0: * of functions used to instantiate the plugin. sl@0: * @since sl@0: * @param aTableCount returns the number of functions in the table. sl@0: * @return retuns a pointer to the table. sl@0: */ sl@0: EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) sl@0: { sl@0: aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); sl@0: return ImplementationTable; sl@0: }