Update contrib.
3 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
4 // All rights reserved.
5 // This component and the accompanying materials are made available
6 // under the terms of "Eclipse Public License v1.0"
7 // which accompanies this distribution, and is available
8 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
10 // Initial Contributors:
11 // Nokia Corporation - initial contribution.
21 #include <a3f/a3fbase.h>
22 #include <a3f/audioprocessingunittypeuids.h>
23 #include <a3f/a3ffourcclookup.h>
25 #include "audiostream.h"
27 // PHYSICAL COMPONENTS
28 #include "audiocodec.h"
29 #include "audiostream.h"
30 #include "buffersource.h"
31 #include "buffersink.h"
32 #include "audiodevicesource.h"
33 #include "audiodevicesink.h"
34 #include "audiogaincontrol.h"
35 #include "maudiostreamadaptationobserver.h"
37 #include <a3f/maudiodatasupplier.h>
38 #include <a3f/maudiodataconsumer.h>
40 #include "minputport.h"
41 #include "moutputport.h"
42 #include "audiocontext.h"
44 #include <ecom/implementationproxy.h>
48 const TInt KSampleRate8000Hz = 8000;
50 // Map the interface implementation UIDs to implementation factory functions
51 const TImplementationProxy ImplementationTable[] =
53 IMPLEMENTATION_PROXY_ENTRY(0x10283461, CAudioStream::NewL),
57 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
59 aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
60 return ImplementationTable;
63 // ---------------------------------------------------------------------------
65 // ---------------------------------------------------------------------------
67 CAudioStream::CAudioStream()
68 : iCurrentStreamState(EUninitialized),
69 iDesiredStreamState(EUninitialized)
72 DP_CONTEXT(CAudioStream::CAudioStream *CD1*, CtxDevSound, DPLOCAL);
74 // Some init config values
75 iSampleRateConfig = KSampleRate8000Hz;
76 iModeConfig = KA3FModeMono;
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 CAudioStream* CAudioStream::NewL()
87 DP_STATIC_CONTEXT(CAudioStream::NewL *CD0*, CtxDevSound, DPLOCAL);
89 CAudioStream* self = new(ELeave)CAudioStream();
90 CleanupStack::PushL(self);
92 CleanupStack::Pop(self);
93 DP0_RET(self, "0x%x");
96 // ---------------------------------------------------------------------------
97 // Second phase constructor
98 // ---------------------------------------------------------------------------
100 void CAudioStream::ConstructL()
102 DP_CONTEXT(CAudioStream::ConstructL *CD1*, CtxDevSound, DPLOCAL);
107 // ---------------------------------------------------------------------------
109 // ---------------------------------------------------------------------------
111 CAudioStream::~CAudioStream()
113 DP_CONTEXT(CAudioStream::~CAudioStream *CD1*, CtxDevSound, DPLOCAL);
116 iAudioStreamObservers.Close();
117 iAudioCodecObservers.Close();
119 DeletePhysicalComponents();
120 REComSession::FinalClose();
124 // ---------------------------------------------------------------------------
125 // CAudioStream::RegisterAudioStreamObserver
126 // ---------------------------------------------------------------------------
128 TInt CAudioStream::RegisterAudioStreamObserver(MAudioStreamAdaptationObserver& aObserver)
130 DP_CONTEXT(CAudioStream::RegisterAudioStreamObserver *CD1*, CtxDevSound, DPLOCAL);
132 TInt err = iAudioStreamObservers.Find(&aObserver);
133 if(err == KErrNotFound)
135 err = iAudioStreamObservers.Append(&aObserver);
139 err = KErrAlreadyExists;
144 // ---------------------------------------------------------------------------
145 // CAudioStream::UnregisterAudioStreamObserver
146 // ---------------------------------------------------------------------------
148 void CAudioStream::UnregisterAudioStreamObserver(MAudioStreamAdaptationObserver& aObserver)
150 DP_CONTEXT(CAudioStream::UnregisterAudioStreamObserver *CD1*, CtxDevSound, DPLOCAL);
152 TInt idxOrErr = iAudioStreamObservers.Find(&aObserver);
153 if( idxOrErr != KErrNotFound )
155 iAudioStreamObservers.Remove(idxOrErr);
161 // ---------------------------------------------------------------------------
162 // CAudioStream::SetFourCC
163 // ---------------------------------------------------------------------------
165 void CAudioStream::SetFourCC(const CFourCCConvertor& aFourCCConvertor)
167 DP_CONTEXT(CAudioStream::SetFourCC *CD1*, CtxDevSound, DPLOCAL);
169 CFourCCConvertor& ref = const_cast<CFourCCConvertor&>(aFourCCConvertor);
170 iFourCCConvertor = static_cast<CFourCCConvertor*>(static_cast<TAny*>(&ref));
175 // ---------------------------------------------------------------------------
176 // CAudioStream::UnregisterAudioStreamObserver
177 // ---------------------------------------------------------------------------
179 void CAudioStream::UnregisterAllAudioStreamObserver()
181 DP_CONTEXT(CAudioStream::UnregisterAudioStreamObserver *CD1*, CtxDevSound, DPLOCAL);
184 iAudioStreamObservers.Reset();
190 // ---------------------------------------------------------------------------
191 // MMRC extension mechanism
192 // ---------------------------------------------------------------------------
193 TAny* CAudioStream::GetComponent(TUid aType)
196 MLogicalChain* clientDesiredChain = NULL;
197 CAudioContext* context = static_cast<CAudioContext*>(iAudioContext);
200 clientDesiredChain = context->GetLogicalChain(0);
202 if (clientDesiredChain)
204 ptr = clientDesiredChain->GetComponent(aType);
209 // ---------------------------------------------------------------------------
210 // CAudioStream::Message
211 // ---------------------------------------------------------------------------
212 TInt CAudioStream::Message(MLogicalChain& aCurrentChain, MLogicalChain& aDesiredChain, MAudioContext& aContext, TInt aFlags)
214 DP_CONTEXT(CAudioStream::Message *CD0*, CtxDevSound, DPLOCAL);
218 iCurrentChain = &aCurrentChain;
219 iDesiredChain = &aDesiredChain;
221 TUint messageType = aDesiredChain.MessageType();
223 iAudioContext = &aContext;
225 CAudioContext* audioContext = static_cast<CAudioContext*> (iAudioContext);
226 // TO NOTIFY DIRECTLY CONTEXT
227 MMultimediaResourceControlObserver* mmrcObserver = static_cast<MMultimediaResourceControlObserver*>(audioContext);
229 // Register stream observer
230 if (messageType & ERegisterStreamObserver != 0)
232 // Use MMRC extension mechanism
233 TAny* ptr = GetComponent(KUidAudioStreamAdaptationObserver);
234 MAudioStreamAdaptationObserver* observer = static_cast<MAudioStreamAdaptationObserver*>(ptr);
237 err = RegisterAudioStreamObserver(*observer);
241 // Register codec observer
242 if (messageType & ERegisterCodecObserver != 0)
244 // Use MMRC extension mechanism
245 TAny* ptr = GetComponent(KUidAudioCodecObserver);
246 MAudioCodecObserver* observer = static_cast<MAudioCodecObserver*>(ptr);
249 err = RegisterAudioCodecObserver(*observer);
253 // Component creation
254 TUint bit = messageType & EComponentCreation;
255 if( (err == KErrNone) && (bit != 0) )
257 CAudioContext* context = static_cast<CAudioContext*>(iAudioContext);
258 MLogicalChain* clientDesiredChain = context->GetLogicalChain(0);
259 err = CreatePhysicalComponents(*clientDesiredChain);
264 clientDesiredChain->SetAdaptationStream(*this);
265 clientDesiredChain->SetStreamBufferControl(*this);
269 // Component alteration
270 // Changes that must be applied before stream state transition
271 TBool configCodec = EFalse;
272 bit = messageType & EComponentAlterationCodec;
273 if( (err == KErrNone) && (bit != 0) )
278 TUid desiredCodecFormat = iDesiredChain->CodecFormat();
279 err = iCodec->SetFormat( desiredCodecFormat );
284 //if samplerate or mode has changed, update value and trigger callbacks at appropriate point
285 if ((iDesiredChain->GetSampleRate() > 0) && (iDesiredChain->GetSampleRate() != iSampleRateConfig))
287 iSampleRateConfig = iDesiredChain->GetSampleRate();
290 if ((iDesiredChain->GetMode() != KNullUid) && (iDesiredChain->GetMode() != iModeConfig))
292 iModeConfig = iDesiredChain->GetMode();
299 bit = messageType & EComponentAlterationGain;
300 if( (err == KErrNone) && (bit != 0) )
303 // Note that ramp operation and gain now are applied separately because current tone arquitecture
304 // need the volume ramp to be set before start the tonehwdevice
305 TTimeIntervalMicroSeconds currentRampTimeValue = 0;
306 TUid currentRampTimeOperation(KNullUid);
307 TTimeIntervalMicroSeconds desiredRampTimeValue = 0;
308 TUid desiredRampTimeOperation(KNullUid);
309 iCurrentChain->GetVolumeRampParameters(currentRampTimeOperation, currentRampTimeValue);
310 iDesiredChain->GetVolumeRampParameters(desiredRampTimeOperation, desiredRampTimeValue);
312 if(currentRampTimeOperation != desiredRampTimeOperation ||
313 currentRampTimeValue.Int64() != desiredRampTimeValue.Int64() )
317 err = iGainControl->ConfigureRamp(desiredRampTimeOperation, desiredRampTimeValue);
322 //Configuration request
324 TBool invokeStateEventCallback = EFalse;
325 iDesiredStreamState = iDesiredChain->StreamState();
326 if( (err == KErrNone) && (iCurrentStreamState != iDesiredStreamState) )
328 err = ChangeState(iCurrentStreamState, iDesiredStreamState);
331 iCurrentStreamState = iDesiredStreamState;
333 invokeStateEventCallback = ETrue;
336 // Component alteration
337 // Changes that must be applied after stream state transition
338 TBool gainUpdated = EFalse;
339 bit = messageType & EComponentAlterationGain;
340 if( (err == KErrNone) && (bit != 0) )
342 TAny* ptr = GetComponent(KUidAudioGainControl);
343 MAudioGainControl* gaincontrol = static_cast<MAudioGainControl*>(ptr);
344 if (iGainControl && gaincontrol)
346 RArray<TAudioChannelGain> channels;
347 TInt err = gaincontrol->GetGain(channels);
348 if (channels.Count() != 0 )
350 err = iGainControl->SetGain(channels);
357 TBool invokeCodecCallbacks = EFalse;
358 bit = messageType & EComponentAlterationCodec;
359 if ( (err == KErrNone) && (bit != 0) && configCodec && (iCurrentStreamState == EInitialized) )
361 //codec loading actually configures sample rate and mode
363 err = iCodec->Load(iSampleRateConfig, iModeConfig);
364 iIsCodecConfig = (err == KErrNone);
365 invokeCodecCallbacks = ETrue;
366 if ( err != KErrNone )
368 //get back to previous values in case of error
369 iSampleRateConfig = iCurrentChain->GetSampleRate();
370 iModeConfig = iCurrentChain->GetMode();
374 // Component destruction
375 bit = messageType & EComponentDestruction;
376 if( (err == KErrNone) && (bit != 0) )
378 DeletePhysicalComponents();
381 TUint isStopping = aFlags & KServerStopping;
382 TUint preemptionRequest = aFlags & KPreemptionRequest;
384 // HERE WE CAN GUARANTEE THAT THE REQUEST IS SUCCESFUL
387 if(!preemptionRequest)
389 mmrcObserver->ReceiveResourceUpdate(&aDesiredChain, KErrNone);
393 mmrcObserver->ReceivePreemptionUpdate(&aDesiredChain, err);
396 // Processing unit callbacks
398 // Note that due to error checking before applying any change
399 // this callback always returned the error obtained by calling SetGain
405 iGainControl->IssueGainChangedCallBack(err);
410 if(invokeStateEventCallback)
412 invokeStateEventCallback = EFalse;
413 for ( TUint idx(0); idx < iAudioStreamObservers.Count(); idx++ )
417 iAudioStreamObservers[idx]->StateEvent(err, iCurrentStreamState);
421 if( invokeCodecCallbacks && (iCurrentStreamState == EInitialized) )
423 TInt count = iAudioCodecObservers.Count();
424 for ( TInt idx = 0; idx < count; idx++ )
426 //TODO replace this functionality with the new mmrc
427 iAudioCodecObservers[idx]->SampleRateSet(err);
428 iAudioCodecObservers[idx]->ModeSet(err);
432 // Now has no effect on context
433 // But it's needed to let the MMRC know about the operation being completed
434 // and in such way let it to know that
435 for ( TUint idx(0); idx < iAudioStreamObservers.Count(); idx++ )
439 iAudioStreamObservers[idx]->PhysicalAdaptationEvent(EOperationComplete, err);
443 // Don't need to send last callback sync
449 // ---------------------------------------------------------------------------
450 // CAudioStream::DeletePhysicalComponents
451 // ---------------------------------------------------------------------------
452 void CAudioStream::DeletePhysicalComponents()
454 DP_CONTEXT(CAudioStream::DeletePhysicalComponents *CD0*, CtxDevSound, DPLOCAL);
458 delete iBufferSource;
459 iBufferSource = NULL;
470 iIsCodecConfig = EFalse;
479 delete iDeviceSource;
480 iDeviceSource = NULL;
491 // ---------------------------------------------------------------------------
492 // CAudioStream::CreatePhysicalComponents
493 // ---------------------------------------------------------------------------
494 TInt CAudioStream::CreatePhysicalComponents(MLogicalChain& aDesiredChain)
496 DP_CONTEXT(CAudioStream::CreatePhysicalComponents *CD0*, CtxDevSound, DPLOCAL);
500 TInt units = aDesiredChain.AudioProcessingUnitsCount();
504 for (index=0; index < units ; index++)
506 typeId = aDesiredChain.AudioProcessingUnitUid(index);
508 // By the moment all components
511 if (typeId == KUidAudioDecoder || typeId == KUidAudioEncoder )
515 TRAP(err, iCodec = CAudioCodec::NewL(typeId, *iFourCCConvertor ));
516 iIsCodecConfig = EFalse;
517 iCodec->RegisterAudioCodecObserver(*this);
518 TAny* ptr = GetComponent(KUidAudioCodecAdaptationObserver);
519 MAudioCodecAdaptationObserver* observer = static_cast<MAudioCodecAdaptationObserver*>(ptr);
522 iCodec->RegisterAudioCodecObserver(*observer);
524 // For HW custom interface
525 aDesiredChain.SetCustomInterfaceProvider(*iCodec);
529 iGainControl->SetHelper(*iCodec);
531 // This mechanism is temporary and must be replaced
532 // with the Extension mechanism when the MMRC server
533 aDesiredChain.SetStreamPositionControl(*iCodec);
535 else if (typeId == KUidMmfBufferSource)
539 TRAP(err,iBufferSource = CBufferSource::NewL());
540 // This mechanism is temporary and must be replaced
541 // with the Extension mechanism when the MMRC server
542 aDesiredChain.SetAdaptationSource(*iBufferSource);
544 TAny* ptr = aDesiredChain.GetComponent(KUidMmfBufferSource);
545 MMMFAudioDataSupplier* supplier = static_cast<MMMFAudioDataSupplier*>(ptr);
548 iBufferSource->SetDataSupplier(*supplier);
553 else if (typeId == KUidMmfBufferSink)
557 TRAP(err, iBufferSink = CBufferSink::NewL());
558 // This mechanism is temporary and must be replaced
559 // with the Extension mechanism when the MMRC server
560 aDesiredChain.SetAdaptationSink(*iBufferSink);
563 else if (typeId == KUidAudioGainControl)
567 // This mechanism is temporary and must be replaced
568 // with the Extension mechanism when the MMRC server
569 TRAP(err, iGainControl = CAudioGainControl::NewL());
570 aDesiredChain.SetAdaptationGainControl(*iGainControl);
573 else if (typeId == KUidAudioDeviceSink)
577 TRAP(err, iDeviceSink = CAudioDeviceSink::NewL());
580 else if (typeId == KUidAudioDeviceSource)
584 TRAP(err, iDeviceSource = CAudioDeviceSource::NewL());
589 err = KErrNotSupported;
593 // Notify the observers
594 for ( TUint idx(0); idx < iAudioStreamObservers.Count(); idx++ )
596 iAudioStreamObservers[idx]->AddProcessingUnitComplete(typeId, err);
602 // ---------------------------------------------------------------------------
603 // CAudioStream::CreateDataPath
604 // ---------------------------------------------------------------------------
605 TInt CAudioStream::CreateDataPath()
607 DP_CONTEXT(CAudioStream::CreateDataPath *CD1*, CtxDevSound, DPLOCAL);
609 TInt err(KErrNotReady);
611 if(iBufferSource && iCodec) // && iSink && iGain)
614 if(KErrNone == iBufferSource->GetOutputPort(iOutputport) && KErrNone == iCodec->GetInputPort(iInputport))
616 iOutputport->SetInput(iInputport);
617 iInputport->SetOutput(iOutputport);
621 else if(iBufferSink && iCodec) // && iSink && iGain)
624 if(KErrNone == iCodec->GetOutputPort(iOutputport) && KErrNone == iBufferSink->GetInputPort(iInputport))
626 iOutputport->SetInput(iInputport);
627 iInputport->SetOutput(iOutputport);
634 // ---------------------------------------------------------------------------
635 // CAudioStream::DemolishDataPath
636 // ---------------------------------------------------------------------------
638 TInt CAudioStream::DemolishDataPath()
640 DP_CONTEXT(CAudioStream::DemolishDataPath *CD1*, CtxDevSound, DPLOCAL);
642 iOutputport->RemoveInput(iInputport);
643 iInputport->RemoveOutput(iOutputport);
644 DP0_RET(KErrNone, "%d");
647 // ---------------------------------------------------------------------------
648 // CAudioStream::ChangeState
649 // ---------------------------------------------------------------------------
650 TInt CAudioStream::ChangeState(TAudioState aPreviousState, TAudioState aDesiredState)
652 DP_CONTEXT(CAudioStream::ChangeState *CD1*, CtxDevSound, DPLOCAL);
655 iCurrentStreamState = aPreviousState;
656 iDesiredStreamState = aDesiredState;
658 // Ensure that there is no dereference of a NULL pointer
659 ASSERT(iDesiredStreamState < EInitialized || iDesiredStreamState > EActive || iCodec);
661 switch (iDesiredStreamState)
665 if (iCurrentStreamState == EUninitialized) //Initialize
667 err = CreateDataPath();
670 err = iCodec->Initialize();
673 else if( iCurrentStreamState == EIdle ) //codec unload (actually, unconfig)
675 iIsCodecConfig = EFalse;
679 // This A3F adaptation allows going from Active/Primed directly to initialised
680 // otherwise reference MMRC would need to handle those transitions separately
681 else if(iCurrentStreamState == EActive || iCurrentStreamState == EPrimed)
684 err = iCodec->Stop();
686 iIsCodecConfig = EFalse;
691 iCurrentStreamState = EInitialized;
697 if ( (iCurrentStreamState == EInitialized) && !iIsCodecConfig )
699 //codec loading actually configures sample rate and mode
700 err = iCodec->Load(iSampleRateConfig, iModeConfig);
701 iIsCodecConfig = (err == KErrNone);
703 else if (iCurrentStreamState == EActive)
705 err = iCodec->Stop();
707 else if (iCurrentStreamState == EPrimed)
709 err = iCodec->Stop();
715 iCurrentStreamState = EIdle;
721 if (iCurrentStreamState == EIdle)
723 DP0(DLINFO,"============== Stream is going from EIdle -> PRIMED");
724 DP0(DLINFO,"Nothing to be done");
726 else if (iCurrentStreamState == EActive)
728 DP0(DLINFO,"============== Stream is going from EActive -> PRIMED");
729 err = iCodec->Pause();
733 iCurrentStreamState = EPrimed;
739 if (iCurrentStreamState == EPrimed) //Activate from Primed
741 // Reusing AudioCodec::Start for resuming
742 DP0(DLINFO,"============== Stream is going from EPrimed -> ACTIVE");
743 err = iCodec->Start();
745 else if(iCurrentStreamState == EIdle) //Activate from Idle
747 DP0(DLINFO,"============== Stream is going from EIdle -> ACTIVATE");
748 err = iCodec->Start();
753 iCurrentStreamState = EActive;
759 err = DemolishDataPath();
762 iCurrentStreamState = EUninitialized;
768 err = DemolishDataPath();
771 iCurrentStreamState = EDead;
776 err = KErrNotSupported;
777 DP1(DLINFO,"CAudioStream::ChangeState Unknown state! %d", iDesiredStreamState);
783 TInt CAudioStream::FlushBuffers()
785 DP_CONTEXT(CAudioStream::FlushBuffers *CD1*, CtxDevSound, DPLOCAL);
790 MOutputPort* outPort= static_cast<MOutputPort*>(iCodec);
793 outPort->FlushBuffer(this);
804 void CAudioStream::FlushComplete(TInt aError)
806 DP_CONTEXT(CAudioStream::FlushComplete *CD1*, CtxDevSound, DPLOCAL);
808 TUint count = iAudioStreamObservers.Count();
809 for ( TUint i(0); i < count; i++ )
811 iAudioStreamObservers[i]->FlushComplete(aError);
816 void CAudioStream::AllBuffersProcessed()
818 DP_CONTEXT(CAudioStream::AllBuffersProcessed *CD1*, CtxDevSound, DPLOCAL);
820 TUint count = iAudioStreamObservers.Count();
821 for ( TUint i(0); i < count; i++ )
823 iAudioStreamObservers[i]->ProcessingFinished();
828 void CAudioStream::ProcessingUnitError(TInt /*aError*/)
830 DP_CONTEXT(CAudioStream::ProcessingUnitError *CD1*, CtxDevSound, DPLOCAL);
835 // ---------------------------------------------------------------------------
836 // CAudioStream::RegisterAudioCodecObserver
837 // ---------------------------------------------------------------------------
838 TInt CAudioStream::RegisterAudioCodecObserver(MAudioCodecObserver& aObserver)
840 DP_CONTEXT(CAudioStream::RegisterAudioCodecObserver *CD1*, CtxDevSound, DPLOCAL);
842 TInt err = iAudioCodecObservers.Find(&aObserver);
843 if(err == KErrNotFound)
845 err = iAudioCodecObservers.Append(&aObserver);
849 err = KErrAlreadyExists;
854 // ---------------------------------------------------------------------------
855 // CAudioStream::UnregisterAudioCodecObserver
856 // ---------------------------------------------------------------------------
857 void CAudioStream::UnregisterAudioCodecObserver(MAudioCodecObserver& aObserver)
859 DP_CONTEXT(CAudioStream::UnregisterAudioCodecObserver *CD1*, CtxDevSound, DPLOCAL);
861 TInt idxOrErr = iAudioCodecObservers.Find(&aObserver);
862 if( idxOrErr != KErrNotFound )
864 iAudioCodecObservers.Remove(idxOrErr);
869 void CAudioStream::GetSupportedAModesComplete(TInt /*aError*/)
871 DP_CONTEXT(CAudioStream::GetSupportedAModesComplete *CD1*, CtxDevSound, DPLOCAL);
876 void CAudioStream::GetSupportedARatesComplete(TInt /*aError*/)
878 DP_CONTEXT(CAudioStream::GetSupportedARatesComplete *CD1*, CtxDevSound, DPLOCAL);
883 // ---------------------------------------------------------------------------
884 // CAudioStream::GetSupportedSampleRates
885 // ---------------------------------------------------------------------------
886 TInt CAudioStream::GetSupportedSampleRates(RArray<TInt>& aSupportedRates)
888 TInt err = (KErrNotReady);
889 err = iCodec->SupportedRates(aSupportedRates);
893 // ---------------------------------------------------------------------------
894 // CAudioStream::GetSupportedModes
895 // ---------------------------------------------------------------------------
896 TInt CAudioStream::GetSupportedModes(RArray<TUid>& aSupportedModes)
898 TInt err = (KErrNotReady);
899 err = iCodec->SupportedModes(aSupportedModes);