diff -r 000000000000 -r 79dd3e2336a0 mmdevicefw/mdf/src/audio/AudioDevice/audiodevice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmdevicefw/mdf/src/audio/AudioDevice/audiodevice.cpp Fri Oct 08 19:40:43 2010 +0100 @@ -0,0 +1,749 @@ +// Copyright (c) 2005-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 +#include "audiodevice.hrh" +#include "audiodevice.h" +#include +#include +#include + +// we need 16k to hold a pcm packet +const TInt KBufferSize = 16384; + +const TInt KDefaultSampleRate = 8000; +const TInt KDefaultNumberChannels = 1; +_LIT(KAudioDevicePanic, "CAudioDevice Panic"); + +enum TAudioDevicePanics + { + EObserverNotSet, + EInvalidUsage + }; + +const TInt KInputPortIndex = 0; +const TInt KOutputPortIndex = 1; + +// ------------------------------------------------------------------------------------------ +// CAudioDevice::CInput port class implementation + + +CAudioDevice::CInputPort::CInputPort(CAudioDevice& aParent) + : CActive(EPriorityNormal), + iParent(aParent), + iSampleRate(KDefaultSampleRate), + iChannels(KDefaultNumberChannels), + iBufferSize(KBufferSize) + { + } + +CAudioDevice::CInputPort::~CInputPort() + { + Cancel(); + iBuffers.Close(); + } + +CAudioDevice::CInputPort* CAudioDevice::CInputPort::NewL(CAudioDevice& aParent) + { + CInputPort* self = new (ELeave) CInputPort(aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CAudioDevice::CInputPort::ConstructL() + { + CActiveScheduler::Add(this); + } + +TInt CAudioDevice::CInputPort::MipConfigure(const TPuConfig& aConfig) + { + if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig)) + { + const TTaskConfig* config = TPuTaskConfig::GetStructure(aConfig); + + iSampleRate = config->iRate; + iChannels = (config->iStereoMode & ETaskMono)? 1 : 2; + iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse; + return KErrNone; + } + + if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig2)) + { + const TTaskConfig2* config = TPuTaskConfig2::GetStructure(aConfig); + + iSampleRate = config->iRate; + iChannels = config->iNumberOfChannels; + iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse; + return KErrNone; + } + + return KErrNotSupported; + } + +TInt CAudioDevice::CInputPort::MipGetConfig(TPuConfig& /*aConfig*/) + { + return KErrNotSupported; + } + +TInt CAudioDevice::CInputPort::MipTunnelRequest(const MMdfOutputPort& aOutputPortToBeConnectedTo, + TTunnelFlags& /*aTunnelFlags*/, TSupplierType& /*aSupplierType*/) + { + if ((iParent.State()!=EProcessingUnitLoaded) && (!iStopped)) + { + // invalid state + return EInvalidState; + } + + if (iPortConnectedTo) + { + // the port is already connected, return an error + return EPortAlreadyTunnelled; + } + iPortConnectedTo = const_cast(&aOutputPortToBeConnectedTo); + return KErrNone; + } + +void CAudioDevice::CInputPort::MipWriteData(CMMFBuffer& aInputBuffer) + { + TInt err = iBuffers.Append(&aInputBuffer); + if (err == KErrNone) + { + if (iParent.State() == EProcessingUnitExecuting && !IsActive()) + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + } + else + { + if (iObserver) + { + iObserver->MipoWriteDataComplete(this, &aInputBuffer, err); + } + } + } + +void CAudioDevice::CInputPort::Execute() + { + if (!IsActive() && iBuffers.Count()>0) + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + } + +TBool CAudioDevice::CInputPort::MipIsTunnelled() const + { + if (iPortConnectedTo) + { + return ETrue; + } + else + { + return EFalse; + } + } + +TInt CAudioDevice::CInputPort::MipIndex() const + { + return KInputPortIndex; + } + +CMMFBuffer* CAudioDevice::CInputPort::MipCreateBuffer(TInt /*aBufferSize*/) + { + __ASSERT_ALWAYS(EFalse, User::Panic(KAudioDevicePanic, EInvalidUsage)); + return NULL; + } + +TInt CAudioDevice::CInputPort::MipUseBuffer(CMMFBuffer& /*aBuffer*/) + { + return KErrNone; + } + +TInt CAudioDevice::CInputPort::MipFreeBuffer(CMMFBuffer* /*aBuffer*/) + { + return KErrNone; + } + +void CAudioDevice::CInputPort::MipDisconnectTunnel() + { + } + +void CAudioDevice::CInputPort::MipRestartTunnel() + { + } + +TUint32 CAudioDevice::CInputPort::MipBufferSize() const + { + return iBufferSize; + } + +void CAudioDevice::CInputPort::Pause() + { + if (iParent.SoundDevice().Handle()) + { + iParent.SoundDevice().PausePlayBuffer(); + } + } + +void CAudioDevice::CInputPort::Stop() + { + Cancel(); + } + +TInt CAudioDevice::CInputPort::MipCreateCustomInterface(TUid aUid) + { + if (aUid.iUid == KMmfPlaySettingsCustomInterface) + { + return KErrNone; + } + return KErrNotSupported; + } + +TAny* CAudioDevice::CInputPort::MipCustomInterface(TUid aUid) + { + if (aUid.iUid == KMmfPlaySettingsCustomInterface) + { + return static_cast(this); + } + return NULL; + } + +void CAudioDevice::CInputPort::SetVolume(TUint aVolume) + { + iVolume = aVolume; + } + +TUint CAudioDevice::CInputPort::Volume() + { + return iVolume; + } + +TUint CAudioDevice::CInputPort::BytesPlayed() + { + return iBytesPlayed; + } + +void CAudioDevice::CInputPort::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) + { + iRampDuration = aRampDuration; + } + +TTimeIntervalMicroSeconds& CAudioDevice::CInputPort::VolumeRamp() + { + return iRampDuration; + } + +void CAudioDevice::CInputPort::RunL() + { + if (iCurrentBuffer != NULL) + { + // If we've been signalled with a buffer, callback that we've completed the writing of the + // buffer + if (iObserver) + { + iObserver->MipoWriteDataComplete(this, iCurrentBuffer, iStatus.Int()); + if (iCurrentBuffer->LastBuffer()) + { + iParent.Observer()->ExecuteComplete(&iParent, KErrUnderflow); + iParent.SoundDevice().Close(); + } + } + iCurrentBuffer = NULL; + } + // only process the next buffer if there is no error + // error callbacks were handled in the previous block + if (iStatus == KErrNone) + { + if (iBuffers.Count()>0) + { + iCurrentBuffer = iBuffers[0]; + iBuffers.Remove(0); + + if (CMMFBuffer::IsSupportedDataBuffer(iCurrentBuffer->Type())) + { + TDes8& aBufferDes = (static_cast(iCurrentBuffer))->Data(); + iStatus = KRequestPending; + iParent.SoundDevice().PlayData(iStatus, aBufferDes); + SetActive(); + } + } + } + } + +void CAudioDevice::CInputPort::DoCancel() + { + if (iParent.SoundDevice().Handle()) + { + iParent.SoundDevice().CancelPlayData(); + iParent.SoundDevice().FlushPlayBuffer(); + } + } + +// CAudioDevice::CInput port class implementation +CAudioDevice::COutputPort::COutputPort(CAudioDevice& aParent) + : CActive(EPriorityNormal), + iParent(aParent), + iSampleRate(KDefaultSampleRate), + iChannels(KDefaultNumberChannels), + iBufferSize(KBufferSize) + { + } + +TInt CAudioDevice::CInputPort::SampleRate() + { + return iSampleRate; + } + +TInt CAudioDevice::CInputPort::Channels() + { + return iChannels; + } + +void CAudioDevice::CInputPort::MipInitialize() + { + // Nothing to do + } + +CAudioDevice::COutputPort* CAudioDevice::COutputPort::NewL(CAudioDevice& aParent) + { + COutputPort* self = new (ELeave) COutputPort(aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CAudioDevice::COutputPort::ConstructL() + { + CActiveScheduler::Add(this); + } + +TInt CAudioDevice::COutputPort::MopConfigure(const TPuConfig& aConfig) + { + if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig)) + { + const TTaskConfig* config = TPuTaskConfig::GetStructure(aConfig); + + iSampleRate = config->iRate; + iChannels = (config->iStereoMode & ETaskMono)? 1 : 2; + iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse; + return KErrNone; + } + + if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig2)) + { + const TTaskConfig2* config = TPuTaskConfig2::GetStructure(aConfig); + + iSampleRate = config->iRate; + iChannels = config->iNumberOfChannels; + iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse; + return KErrNone; + } + return KErrNotSupported; + } + +TInt CAudioDevice::COutputPort::MopGetConfig(TPuConfig& /*aConfig*/) + { + return KErrNotSupported; + } + +void CAudioDevice::COutputPort::MopInitialize() + { + // Nothing to do + } + +TInt CAudioDevice::COutputPort::MopTunnelRequest(const MMdfInputPort& /*aInputPortToBeConnectedTo*/, + TTunnelFlags& /*aTunnelFlags*/, TSupplierType& /*aSupplierType*/) + { + return KErrNone; + } + +void CAudioDevice::COutputPort::MopReadData(CMMFBuffer& aOutputBuffer) + { + TInt err = iBuffers.Append(&aOutputBuffer); + if (err == KErrNone) + { + if ((iParent.State() == EProcessingUnitExecuting || iParent.State() == EProcessingUnitPaused) && !IsActive()) + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + } + else + { + if (iObserver) + { + iObserver->MopoReadDataComplete(this, &aOutputBuffer, err); + } + } + } + +TBool CAudioDevice::COutputPort::MopIsTunnelled() const + { + return EFalse; + } + +TInt CAudioDevice::COutputPort::MopIndex() const + { + return KOutputPortIndex; + } + +CMMFBuffer* CAudioDevice::COutputPort::MopCreateBuffer(TInt /*aBufferSize*/) + { + return NULL; + } + +TInt CAudioDevice::COutputPort::MopUseBuffer(CMMFBuffer& /*aBuffer*/) + { + return KErrNone; + } + +TInt CAudioDevice::COutputPort::MopFreeBuffer(CMMFBuffer* /*aBuffer*/) + { + return KErrNone; + } + +void CAudioDevice::COutputPort::Execute() + { + if (!IsActive() && iBuffers.Count()>0) + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + } + +void CAudioDevice::COutputPort::Pause() + { + if(iParent.SoundDevice().Handle()) + { + iParent.SoundDevice().FlushRecordBuffer(); + } + } + +void CAudioDevice::COutputPort::Stop() + { + Cancel(); + } + +void CAudioDevice::COutputPort::MopDisconnectTunnel() + { + // Find the last buffer in the array and set it as the 'LastBuffer' + if(iBuffers.Count() > 0) + { + (iBuffers[iBuffers.Count() - 1])->SetLastBuffer(ETrue); + } + // Still have to send callback and cancel driver + iObserver->MopoDisconnectTunnelComplete(this, KErrNone); + iParent.SoundDevice().CancelRecordData(); + } + +void CAudioDevice::COutputPort::MopRestartTunnel() + { + } + +TUint32 CAudioDevice::COutputPort::MopBufferSize() const + { + return iBufferSize; + } + +void CAudioDevice::CInputPort::MipSetObserver(const MMdfInputPortObserver& aObserver) + { + iObserver = const_cast(&aObserver); + } + +void CAudioDevice::COutputPort::MopSetObserver(const MMdfOutputPortObserver& aObserver) + { + iObserver = const_cast(&aObserver); + } + +TInt CAudioDevice::COutputPort::MopCreateCustomInterface(TUid aUid) + { + if (aUid.iUid == KMmfRecordSettingsCustomInterface) + { + return KErrNone; + } + return KErrNotSupported; + } + +TAny* CAudioDevice::COutputPort::MopCustomInterface(TUid aUid) + { + if (aUid.iUid == KMmfRecordSettingsCustomInterface) + { + return dynamic_cast(this); + } + + return NULL; + } + +void CAudioDevice::COutputPort::RunL() + { + if (iCurrentBuffer != NULL) + { + // If we've been signalled with a buffer, callback that we've completed the writing of the + // buffer + if (iObserver) + { + TInt length = iCurrentBuffer->BufferSize(); + iBytesRecorded += length; + if (lengthSetLastBuffer(ETrue); + iParent.SoundDevice().CancelRecordData(); // Required so that a resume of an encode functions correctly + } + + iObserver->MopoReadDataComplete(this, iCurrentBuffer, iStatus.Int()); + + } + iCurrentBuffer = NULL; + } + + if (iStatus == KErrNone) + { + if (iBuffers.Count()>0) + { + iCurrentBuffer = iBuffers[0]; + iBuffers.Remove(0); + + if (CMMFBuffer::IsSupportedDataBuffer(iCurrentBuffer->Type())) + { + TDes8& aBufferDes = (static_cast(iCurrentBuffer))->Data(); + iStatus = KRequestPending; + iParent.SoundDevice().RecordData(iStatus, aBufferDes); + SetActive(); + } + } + } + } + +void CAudioDevice::COutputPort::DoCancel() + { + if (iParent.SoundDevice().Handle()) + { + iParent.SoundDevice().CancelRecordData(); + iParent.SoundDevice().FlushRecordBuffer(); + } + } + +TInt CAudioDevice::COutputPort::SampleRate() + { + return iSampleRate; + } + +TInt CAudioDevice::COutputPort::Channels() + { + return iChannels; + } + +CAudioDevice::COutputPort::~COutputPort() + { + Cancel(); + iBuffers.Close(); + } + +// from MRecordCustomInterface +void CAudioDevice::COutputPort::SetGain(TUint aGain) + { + iGain = aGain; + } +TUint CAudioDevice::COutputPort::Gain() + { + return iGain; + } + +TUint CAudioDevice::COutputPort::BytesRecorded() + { + return iBytesRecorded; + } + +// ------------------------------------------------------------------------------------------ +// CAudioDevice Implementation + + +CAudioDevice::CAudioDevice() + { + } + +CAudioDevice::~CAudioDevice() + { + delete iInputPort; + delete iOutputPort; + iSoundDevice.Close(); + } + +void CAudioDevice::Execute() + { + __ASSERT_ALWAYS(iObserver, User::Panic(KAudioDevicePanic, EObserverNotSet)); + TInt err = KErrNone; + if(!iSoundDevice.Handle()) + { + err = iSoundDevice.Open(); + } + + RMdaDevSound::TCurrentSoundFormatBuf buf; + if (err == KErrNone) + { + if(iState == EProcessingUnitPaused) + { + iSoundDevice.ResumePlaying(); + } + else + { + // Set play format (for input port) + iSoundDevice.GetPlayFormat(buf); + buf().iRate = iInputPort->SampleRate(); + buf().iChannels = iInputPort->Channels(); + buf().iBufferSize = KBufferSize; + buf().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; + err = iSoundDevice.SetPlayFormat(buf); + } + } + iState = EProcessingUnitExecuting; + if (err == KErrNone) + { + // Set record format (for output format) + iSoundDevice.GetRecordFormat(buf); + buf().iRate = iOutputPort->SampleRate(); + buf().iChannels = iOutputPort->Channels(); + buf().iBufferSize = KBufferSize; + buf().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; + iSoundDevice.SetRecordFormat(buf); + iInputPort->Execute(); + iOutputPort->Execute(); + } + else + { + iObserver->ExecuteComplete(this, err); + } + } + +TInt CAudioDevice::Pause() + { + iState = EProcessingUnitPaused; + iInputPort->Pause(); + iOutputPort->Pause(); + return KErrNone; + } + +void CAudioDevice::Stop() + { + if(iState == EProcessingUnitExecuting || iState == EProcessingUnitPaused) + { + // Cancel and flush the device driver + iInputPort->Stop(); + iOutputPort->Stop(); + iState = EProcessingUnitIdle; + + // Close the sound device + iSoundDevice.Close(); + } + } + +CAudioDevice* CAudioDevice::NewL() + { + CAudioDevice* self = new (ELeave) CAudioDevice; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +TInt CAudioDevice::Create(const MMdfProcessingUnitObserver& aObserver) + { + iObserver = const_cast(&aObserver); + return KErrNone; + } + +TInt CAudioDevice::Configure(const TPuConfig& /*aConfigurationSetup*/) + { + return KErrNotSupported; + } + +TInt CAudioDevice::GetConfig(TPuConfig& /*aConfigurationSetup*/) + { + return KErrNotSupported; + } + +TInt CAudioDevice::GetInputPorts(RPointerArray& aComponentInputPorts ) + { + return aComponentInputPorts.Append(iInputPort); + } + +TInt CAudioDevice::GetOutputPorts(RPointerArray& aComponentOutputPorts ) + { + return aComponentOutputPorts.Append(iOutputPort); + } + +void CAudioDevice::ConstructL() + { + iInputPort = CInputPort::NewL(*this); + iOutputPort = COutputPort::NewL(*this); + iState = EProcessingUnitLoaded; + } + +void CAudioDevice::Initialize() + { + __ASSERT_ALWAYS(iObserver, User::Panic(KAudioDevicePanic, EObserverNotSet)); + + iObserver->InitializeComplete(this, KErrNone); + iState = EProcessingUnitIdle; + } + +MMdfProcessingUnitObserver* CAudioDevice::Observer() + { + return iObserver; + } + +TProcessingUnitState CAudioDevice::State() + { + return iState; + } + +RMdaDevSound& CAudioDevice::SoundDevice() + { + return iSoundDevice; + } + +TAny* CAudioDevice::CustomInterface(TUid /*aUid*/) + { + return NULL; + } + +TInt CAudioDevice::CreateCustomInterface(TUid /*aUid*/) + { + return KErrNotSupported; + } + +// ------------------------------------------------------------------------------------------ +// ECOM Implementation table entry + +const TImplementationProxy ImplementationTable[] = + { + IMPLEMENTATION_PROXY_ENTRY(KUidPUAudioDevice, CAudioDevice::NewL), + }; + +EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) + { + aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); + return ImplementationTable; + } +