--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmdevicefw/mdf/src/audio/AudioDevice/audiodevice.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -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 <ecom/implementationproxy.h>
+#include <mmf/server/mmfdatabuffer.h>
+#include "audiodevice.hrh"
+#include "audiodevice.h"
+#include <e32debug.h>
+#include <mdf/mdfpuconfig.h>
+#include <mda/common/audio.h>
+
+// 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<MMdfOutputPort*>(&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<MPlayCustomInterface*>(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<CMMFDataBuffer*>(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<MMdfInputPortObserver*>(&aObserver);
+ }
+
+void CAudioDevice::COutputPort::MopSetObserver(const MMdfOutputPortObserver& aObserver)
+ {
+ iObserver = const_cast<MMdfOutputPortObserver*>(&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<MRecordCustomInterface*>(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 (length<iBufferSize)
+ {
+ iCurrentBuffer->SetLastBuffer(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<CMMFDataBuffer*>(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<MMdfProcessingUnitObserver*>(&aObserver);
+ return KErrNone;
+ }
+
+TInt CAudioDevice::Configure(const TPuConfig& /*aConfigurationSetup*/)
+ {
+ return KErrNotSupported;
+ }
+
+TInt CAudioDevice::GetConfig(TPuConfig& /*aConfigurationSetup*/)
+ {
+ return KErrNotSupported;
+ }
+
+TInt CAudioDevice::GetInputPorts(RPointerArray<MMdfInputPort>& aComponentInputPorts )
+ {
+ return aComponentInputPorts.Append(iInputPort);
+ }
+
+TInt CAudioDevice::GetOutputPorts(RPointerArray<MMdfOutputPort>& 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;
+ }
+