Update contrib.
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <ecom/implementationproxy.h>
17 #include <mmf/server/mmfdatabuffer.h>
18 #include "audiodevice.hrh"
19 #include "audiodevice.h"
21 #include <mdf/mdfpuconfig.h>
22 #include <mda/common/audio.h>
24 // we need 16k to hold a pcm packet
25 const TInt KBufferSize = 16384;
27 const TInt KDefaultSampleRate = 8000;
28 const TInt KDefaultNumberChannels = 1;
29 _LIT(KAudioDevicePanic, "CAudioDevice Panic");
31 enum TAudioDevicePanics
37 const TInt KInputPortIndex = 0;
38 const TInt KOutputPortIndex = 1;
40 // ------------------------------------------------------------------------------------------
41 // CAudioDevice::CInput port class implementation
44 CAudioDevice::CInputPort::CInputPort(CAudioDevice& aParent)
45 : CActive(EPriorityNormal),
47 iSampleRate(KDefaultSampleRate),
48 iChannels(KDefaultNumberChannels),
49 iBufferSize(KBufferSize)
53 CAudioDevice::CInputPort::~CInputPort()
59 CAudioDevice::CInputPort* CAudioDevice::CInputPort::NewL(CAudioDevice& aParent)
61 CInputPort* self = new (ELeave) CInputPort(aParent);
62 CleanupStack::PushL(self);
64 CleanupStack::Pop(self);
68 void CAudioDevice::CInputPort::ConstructL()
70 CActiveScheduler::Add(this);
73 TInt CAudioDevice::CInputPort::MipConfigure(const TPuConfig& aConfig)
75 if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig))
77 const TTaskConfig* config = TPuTaskConfig::GetStructure(aConfig);
79 iSampleRate = config->iRate;
80 iChannels = (config->iStereoMode & ETaskMono)? 1 : 2;
81 iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse;
85 if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig2))
87 const TTaskConfig2* config = TPuTaskConfig2::GetStructure(aConfig);
89 iSampleRate = config->iRate;
90 iChannels = config->iNumberOfChannels;
91 iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse;
95 return KErrNotSupported;
98 TInt CAudioDevice::CInputPort::MipGetConfig(TPuConfig& /*aConfig*/)
100 return KErrNotSupported;
103 TInt CAudioDevice::CInputPort::MipTunnelRequest(const MMdfOutputPort& aOutputPortToBeConnectedTo,
104 TTunnelFlags& /*aTunnelFlags*/, TSupplierType& /*aSupplierType*/)
106 if ((iParent.State()!=EProcessingUnitLoaded) && (!iStopped))
109 return EInvalidState;
112 if (iPortConnectedTo)
114 // the port is already connected, return an error
115 return EPortAlreadyTunnelled;
117 iPortConnectedTo = const_cast<MMdfOutputPort*>(&aOutputPortToBeConnectedTo);
121 void CAudioDevice::CInputPort::MipWriteData(CMMFBuffer& aInputBuffer)
123 TInt err = iBuffers.Append(&aInputBuffer);
126 if (iParent.State() == EProcessingUnitExecuting && !IsActive())
129 TRequestStatus* status = &iStatus;
130 User::RequestComplete(status, KErrNone);
137 iObserver->MipoWriteDataComplete(this, &aInputBuffer, err);
142 void CAudioDevice::CInputPort::Execute()
144 if (!IsActive() && iBuffers.Count()>0)
147 TRequestStatus* status = &iStatus;
148 User::RequestComplete(status, KErrNone);
152 TBool CAudioDevice::CInputPort::MipIsTunnelled() const
154 if (iPortConnectedTo)
164 TInt CAudioDevice::CInputPort::MipIndex() const
166 return KInputPortIndex;
169 CMMFBuffer* CAudioDevice::CInputPort::MipCreateBuffer(TInt /*aBufferSize*/)
171 __ASSERT_ALWAYS(EFalse, User::Panic(KAudioDevicePanic, EInvalidUsage));
175 TInt CAudioDevice::CInputPort::MipUseBuffer(CMMFBuffer& /*aBuffer*/)
180 TInt CAudioDevice::CInputPort::MipFreeBuffer(CMMFBuffer* /*aBuffer*/)
185 void CAudioDevice::CInputPort::MipDisconnectTunnel()
189 void CAudioDevice::CInputPort::MipRestartTunnel()
193 TUint32 CAudioDevice::CInputPort::MipBufferSize() const
198 void CAudioDevice::CInputPort::Pause()
200 if (iParent.SoundDevice().Handle())
202 iParent.SoundDevice().PausePlayBuffer();
206 void CAudioDevice::CInputPort::Stop()
211 TInt CAudioDevice::CInputPort::MipCreateCustomInterface(TUid aUid)
213 if (aUid.iUid == KMmfPlaySettingsCustomInterface)
217 return KErrNotSupported;
220 TAny* CAudioDevice::CInputPort::MipCustomInterface(TUid aUid)
222 if (aUid.iUid == KMmfPlaySettingsCustomInterface)
224 return static_cast<MPlayCustomInterface*>(this);
229 void CAudioDevice::CInputPort::SetVolume(TUint aVolume)
234 TUint CAudioDevice::CInputPort::Volume()
239 TUint CAudioDevice::CInputPort::BytesPlayed()
244 void CAudioDevice::CInputPort::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
246 iRampDuration = aRampDuration;
249 TTimeIntervalMicroSeconds& CAudioDevice::CInputPort::VolumeRamp()
251 return iRampDuration;
254 void CAudioDevice::CInputPort::RunL()
256 if (iCurrentBuffer != NULL)
258 // If we've been signalled with a buffer, callback that we've completed the writing of the
262 iObserver->MipoWriteDataComplete(this, iCurrentBuffer, iStatus.Int());
263 if (iCurrentBuffer->LastBuffer())
265 iParent.Observer()->ExecuteComplete(&iParent, KErrUnderflow);
266 iParent.SoundDevice().Close();
269 iCurrentBuffer = NULL;
271 // only process the next buffer if there is no error
272 // error callbacks were handled in the previous block
273 if (iStatus == KErrNone)
275 if (iBuffers.Count()>0)
277 iCurrentBuffer = iBuffers[0];
280 if (CMMFBuffer::IsSupportedDataBuffer(iCurrentBuffer->Type()))
282 TDes8& aBufferDes = (static_cast<CMMFDataBuffer*>(iCurrentBuffer))->Data();
283 iStatus = KRequestPending;
284 iParent.SoundDevice().PlayData(iStatus, aBufferDes);
291 void CAudioDevice::CInputPort::DoCancel()
293 if (iParent.SoundDevice().Handle())
295 iParent.SoundDevice().CancelPlayData();
296 iParent.SoundDevice().FlushPlayBuffer();
300 // CAudioDevice::CInput port class implementation
301 CAudioDevice::COutputPort::COutputPort(CAudioDevice& aParent)
302 : CActive(EPriorityNormal),
304 iSampleRate(KDefaultSampleRate),
305 iChannels(KDefaultNumberChannels),
306 iBufferSize(KBufferSize)
310 TInt CAudioDevice::CInputPort::SampleRate()
315 TInt CAudioDevice::CInputPort::Channels()
320 void CAudioDevice::CInputPort::MipInitialize()
325 CAudioDevice::COutputPort* CAudioDevice::COutputPort::NewL(CAudioDevice& aParent)
327 COutputPort* self = new (ELeave) COutputPort(aParent);
328 CleanupStack::PushL(self);
330 CleanupStack::Pop(self);
334 void CAudioDevice::COutputPort::ConstructL()
336 CActiveScheduler::Add(this);
339 TInt CAudioDevice::COutputPort::MopConfigure(const TPuConfig& aConfig)
341 if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig))
343 const TTaskConfig* config = TPuTaskConfig::GetStructure(aConfig);
345 iSampleRate = config->iRate;
346 iChannels = (config->iStereoMode & ETaskMono)? 1 : 2;
347 iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse;
351 if (aConfig.Uid() == TUid::Uid(KUidTTaskConfig2))
353 const TTaskConfig2* config = TPuTaskConfig2::GetStructure(aConfig);
355 iSampleRate = config->iRate;
356 iChannels = config->iNumberOfChannels;
357 iInterleaved = (config->iStereoMode & ETaskInterleaved)?ETrue : EFalse;
360 return KErrNotSupported;
363 TInt CAudioDevice::COutputPort::MopGetConfig(TPuConfig& /*aConfig*/)
365 return KErrNotSupported;
368 void CAudioDevice::COutputPort::MopInitialize()
373 TInt CAudioDevice::COutputPort::MopTunnelRequest(const MMdfInputPort& /*aInputPortToBeConnectedTo*/,
374 TTunnelFlags& /*aTunnelFlags*/, TSupplierType& /*aSupplierType*/)
379 void CAudioDevice::COutputPort::MopReadData(CMMFBuffer& aOutputBuffer)
381 TInt err = iBuffers.Append(&aOutputBuffer);
384 if ((iParent.State() == EProcessingUnitExecuting || iParent.State() == EProcessingUnitPaused) && !IsActive())
387 TRequestStatus* status = &iStatus;
388 User::RequestComplete(status, KErrNone);
395 iObserver->MopoReadDataComplete(this, &aOutputBuffer, err);
400 TBool CAudioDevice::COutputPort::MopIsTunnelled() const
405 TInt CAudioDevice::COutputPort::MopIndex() const
407 return KOutputPortIndex;
410 CMMFBuffer* CAudioDevice::COutputPort::MopCreateBuffer(TInt /*aBufferSize*/)
415 TInt CAudioDevice::COutputPort::MopUseBuffer(CMMFBuffer& /*aBuffer*/)
420 TInt CAudioDevice::COutputPort::MopFreeBuffer(CMMFBuffer* /*aBuffer*/)
425 void CAudioDevice::COutputPort::Execute()
427 if (!IsActive() && iBuffers.Count()>0)
430 TRequestStatus* status = &iStatus;
431 User::RequestComplete(status, KErrNone);
435 void CAudioDevice::COutputPort::Pause()
437 if(iParent.SoundDevice().Handle())
439 iParent.SoundDevice().FlushRecordBuffer();
443 void CAudioDevice::COutputPort::Stop()
448 void CAudioDevice::COutputPort::MopDisconnectTunnel()
450 // Find the last buffer in the array and set it as the 'LastBuffer'
451 if(iBuffers.Count() > 0)
453 (iBuffers[iBuffers.Count() - 1])->SetLastBuffer(ETrue);
455 // Still have to send callback and cancel driver
456 iObserver->MopoDisconnectTunnelComplete(this, KErrNone);
457 iParent.SoundDevice().CancelRecordData();
460 void CAudioDevice::COutputPort::MopRestartTunnel()
464 TUint32 CAudioDevice::COutputPort::MopBufferSize() const
469 void CAudioDevice::CInputPort::MipSetObserver(const MMdfInputPortObserver& aObserver)
471 iObserver = const_cast<MMdfInputPortObserver*>(&aObserver);
474 void CAudioDevice::COutputPort::MopSetObserver(const MMdfOutputPortObserver& aObserver)
476 iObserver = const_cast<MMdfOutputPortObserver*>(&aObserver);
479 TInt CAudioDevice::COutputPort::MopCreateCustomInterface(TUid aUid)
481 if (aUid.iUid == KMmfRecordSettingsCustomInterface)
485 return KErrNotSupported;
488 TAny* CAudioDevice::COutputPort::MopCustomInterface(TUid aUid)
490 if (aUid.iUid == KMmfRecordSettingsCustomInterface)
492 return dynamic_cast<MRecordCustomInterface*>(this);
498 void CAudioDevice::COutputPort::RunL()
500 if (iCurrentBuffer != NULL)
502 // If we've been signalled with a buffer, callback that we've completed the writing of the
506 TInt length = iCurrentBuffer->BufferSize();
507 iBytesRecorded += length;
508 if (length<iBufferSize)
510 iCurrentBuffer->SetLastBuffer(ETrue);
511 iParent.SoundDevice().CancelRecordData(); // Required so that a resume of an encode functions correctly
514 iObserver->MopoReadDataComplete(this, iCurrentBuffer, iStatus.Int());
517 iCurrentBuffer = NULL;
520 if (iStatus == KErrNone)
522 if (iBuffers.Count()>0)
524 iCurrentBuffer = iBuffers[0];
527 if (CMMFBuffer::IsSupportedDataBuffer(iCurrentBuffer->Type()))
529 TDes8& aBufferDes = (static_cast<CMMFDataBuffer*>(iCurrentBuffer))->Data();
530 iStatus = KRequestPending;
531 iParent.SoundDevice().RecordData(iStatus, aBufferDes);
538 void CAudioDevice::COutputPort::DoCancel()
540 if (iParent.SoundDevice().Handle())
542 iParent.SoundDevice().CancelRecordData();
543 iParent.SoundDevice().FlushRecordBuffer();
547 TInt CAudioDevice::COutputPort::SampleRate()
552 TInt CAudioDevice::COutputPort::Channels()
557 CAudioDevice::COutputPort::~COutputPort()
563 // from MRecordCustomInterface
564 void CAudioDevice::COutputPort::SetGain(TUint aGain)
568 TUint CAudioDevice::COutputPort::Gain()
573 TUint CAudioDevice::COutputPort::BytesRecorded()
575 return iBytesRecorded;
578 // ------------------------------------------------------------------------------------------
579 // CAudioDevice Implementation
582 CAudioDevice::CAudioDevice()
586 CAudioDevice::~CAudioDevice()
590 iSoundDevice.Close();
593 void CAudioDevice::Execute()
595 __ASSERT_ALWAYS(iObserver, User::Panic(KAudioDevicePanic, EObserverNotSet));
597 if(!iSoundDevice.Handle())
599 err = iSoundDevice.Open();
602 RMdaDevSound::TCurrentSoundFormatBuf buf;
605 if(iState == EProcessingUnitPaused)
607 iSoundDevice.ResumePlaying();
611 // Set play format (for input port)
612 iSoundDevice.GetPlayFormat(buf);
613 buf().iRate = iInputPort->SampleRate();
614 buf().iChannels = iInputPort->Channels();
615 buf().iBufferSize = KBufferSize;
616 buf().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
617 err = iSoundDevice.SetPlayFormat(buf);
620 iState = EProcessingUnitExecuting;
623 // Set record format (for output format)
624 iSoundDevice.GetRecordFormat(buf);
625 buf().iRate = iOutputPort->SampleRate();
626 buf().iChannels = iOutputPort->Channels();
627 buf().iBufferSize = KBufferSize;
628 buf().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
629 iSoundDevice.SetRecordFormat(buf);
630 iInputPort->Execute();
631 iOutputPort->Execute();
635 iObserver->ExecuteComplete(this, err);
639 TInt CAudioDevice::Pause()
641 iState = EProcessingUnitPaused;
643 iOutputPort->Pause();
647 void CAudioDevice::Stop()
649 if(iState == EProcessingUnitExecuting || iState == EProcessingUnitPaused)
651 // Cancel and flush the device driver
654 iState = EProcessingUnitIdle;
656 // Close the sound device
657 iSoundDevice.Close();
661 CAudioDevice* CAudioDevice::NewL()
663 CAudioDevice* self = new (ELeave) CAudioDevice;
664 CleanupStack::PushL(self);
666 CleanupStack::Pop(self);
670 TInt CAudioDevice::Create(const MMdfProcessingUnitObserver& aObserver)
672 iObserver = const_cast<MMdfProcessingUnitObserver*>(&aObserver);
676 TInt CAudioDevice::Configure(const TPuConfig& /*aConfigurationSetup*/)
678 return KErrNotSupported;
681 TInt CAudioDevice::GetConfig(TPuConfig& /*aConfigurationSetup*/)
683 return KErrNotSupported;
686 TInt CAudioDevice::GetInputPorts(RPointerArray<MMdfInputPort>& aComponentInputPorts )
688 return aComponentInputPorts.Append(iInputPort);
691 TInt CAudioDevice::GetOutputPorts(RPointerArray<MMdfOutputPort>& aComponentOutputPorts )
693 return aComponentOutputPorts.Append(iOutputPort);
696 void CAudioDevice::ConstructL()
698 iInputPort = CInputPort::NewL(*this);
699 iOutputPort = COutputPort::NewL(*this);
700 iState = EProcessingUnitLoaded;
703 void CAudioDevice::Initialize()
705 __ASSERT_ALWAYS(iObserver, User::Panic(KAudioDevicePanic, EObserverNotSet));
707 iObserver->InitializeComplete(this, KErrNone);
708 iState = EProcessingUnitIdle;
711 MMdfProcessingUnitObserver* CAudioDevice::Observer()
716 TProcessingUnitState CAudioDevice::State()
721 RMdaDevSound& CAudioDevice::SoundDevice()
726 TAny* CAudioDevice::CustomInterface(TUid /*aUid*/)
731 TInt CAudioDevice::CreateCustomInterface(TUid /*aUid*/)
733 return KErrNotSupported;
736 // ------------------------------------------------------------------------------------------
737 // ECOM Implementation table entry
739 const TImplementationProxy ImplementationTable[] =
741 IMPLEMENTATION_PROXY_ENTRY(KUidPUAudioDevice, CAudioDevice::NewL),
744 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
746 aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
747 return ImplementationTable;