--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/voipaudioservices/JitterBufferUtility/src/JitterBuffer.cpp Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,423 @@
+/*
+* Copyright (c) 2008 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: JitterBuffer component capable to audioframe buffering.
+*
+*/
+
+
+// INCLUDE FILES
+#include <e32base.h>
+#include <mmcccodecinformation.h> //FourCC codes
+#include "debugtracemacros.h"
+#include "InternalDef.h"
+#include "JitterBufferObserver.h"
+#include "JitterBufferImpl.h"
+#include "JitterBuffer.h"
+
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::CVoIPJitterBuffer
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CVoIPJitterBuffer::CVoIPJitterBuffer(MJitterBufferObserver* aObserver) :
+ CActive(EPriorityNormal)
+ {
+ iObserver = aObserver;
+ iState = EJBufStopped;
+ iTmCurrentEmptyBuffer = TTime(0);
+ iTmPreviousEmptyBuffer = TTime(0);
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPDownlinkThread::NewL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CVoIPJitterBuffer* CVoIPJitterBuffer::NewL(
+ MJitterBufferObserver* aObserver)
+ {
+ CVoIPJitterBuffer* self = new (ELeave) CVoIPJitterBuffer(aObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::ConstructL
+// Symbian two-phase constructor
+// -----------------------------------------------------------------------------
+//
+void CVoIPJitterBuffer::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ iTimer.CreateLocal();
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::~CVoIPJitterBuffer
+// Destructor deallocate memory.
+// -----------------------------------------------------------------------------
+//
+CVoIPJitterBuffer::~CVoIPJitterBuffer()
+ {
+ TRACE_PRN_FN_ENT;
+
+ if (IsActive())
+ {
+ Cancel();
+ }
+
+ delete iJitterBufferImpl;
+ iTimer.Close();
+
+ TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::SetupL
+// Setup Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::SetupL(const TFourCC aCodec,
+ const TVoIPJBConfig& aJBConfig)
+ {
+ TRACE_PRN_FN_ENT;
+
+ iCodec = aCodec;
+
+ if (!iJitterBufferImpl)
+ {
+ iJitterBufferImpl = CVoIPJitterBufferImpl::NewL(iObserver);
+ }
+
+ if (iJitterBufferImpl)
+ {
+ iJitterBufferImpl->SetupL(aCodec, aJBConfig);
+ iSampleInterval =
+ aJBConfig.iSampleInterval * KJBMillisecondsToMicroseconds;
+
+ // Cannot use with G711 as it asks buffers in uncontrolled manner
+ // TODO: change the logic so that it inspects what happens in long
+ // run and if it fails, send error and pause itself.
+ if (iCodec != KMccFourCCIdG711)
+ {
+ // Not too strict with delaying, threshold cannot be bigger than
+ // frame time
+ iEmptyBufferDelayThreshold = iSampleInterval / KJBEmptyBufferDelay;
+ }
+
+ TRACE_PRN_N1(_L("JB-> DelayThreshold [%d]"),iEmptyBufferDelayThreshold);
+ }
+
+ TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::ResetBuffer
+// Reset Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::ResetBuffer(TBool aPlayTone)
+ {
+ TRACE_PRN_FN_ENT;
+
+ if (iJitterBufferImpl)
+ {
+ iJitterBufferImpl->ResetBuffer(aPlayTone);
+ }
+
+ TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::DelayDownL
+// Delay Down
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::DelayDown()
+ {
+ if (iJitterBufferImpl)
+ {
+ TRAPD(err, iJitterBufferImpl->DelayDownL());
+ if (err != KErrNone)
+ {
+ TRACE_PRN_IF_ERR(err);
+ iObserver->EventJB(MJitterBufferObserver::EGeneralError, err);
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::DelayUpL
+// Delay Up
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::DelayUp()
+ {
+ if (iJitterBufferImpl)
+ {
+ TRAPD(err, iJitterBufferImpl->DelayUpL());
+ if (err != KErrNone)
+ {
+ TRACE_PRN_IF_ERR(err);
+ iObserver->EventJB(MJitterBufferObserver::EGeneralError, err);
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::Play
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::Play()
+ {
+ TRACE_PRN_FN_ENT;
+
+ iState = EJBufPlaying;
+ iRequestSize = 0;
+
+ TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::Pause
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::Pause()
+ {
+ iState = EJBufPaused;
+ ResetBuffer();
+ Cancel();
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::Stop
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVoIPJitterBuffer::Stop()
+ {
+ iState = EJBufStopped;
+ ResetBuffer();
+ Cancel();
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::FillBufferL
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CVoIPJitterBuffer::FillBuffer(CMMFBuffer* aBuffer)
+ {
+// TRACE_PRN_FN_ENT;
+
+ TInt err = KErrNone;
+
+ if (iJitterBufferImpl && iJitterBufferImpl->BufferLength())
+ {
+ TRACE_PRN_N(_L("CVoIPJitterBuffer::FillBufferL NORMAL"));
+
+ TUint32 emptyBufferDelay = 0;
+
+ if (iCodec != KMccFourCCIdG729)
+ {
+ // This can cause JB overflow on G729 (it does in the loopback)
+ DetermineEmptyBufferDelay();
+ }
+
+ iPlayBuffer = aBuffer;
+ iJitterBufferImpl->GetDataFrame(iPlayBuffer);
+ TransitionState(EEmptyData, emptyBufferDelay);
+ }
+ else
+ {
+ err = KErrNotReady;
+ TRACE_PRN_IF_ERR(err);
+ iObserver->EventJB(MJitterBufferObserver::EGeneralError, err);
+ }
+
+// TRACE_PRN_FN_EXT;
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::EmptyBuffer
+// Buffer with data comes in and is passed to JB queue.
+//
+// It was callback based; now DNL-THR->BufferFilled will call it directly
+// upon data receiving. The supplier is now the DNL thread.
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CVoIPJitterBuffer::EmptyBuffer(CMMFBuffer* aBuffer)
+ {
+// TRACE_PRN_FN_ENT;
+ TInt err = KErrNotReady;
+
+ if (iJitterBufferImpl && (iState == EJBufPlaying))
+ {
+ if (iJitterBufferImpl->BufferLength() == 0)
+ {
+ return err;
+ }
+
+// TRACE_PRN_N1(_L("JB-> BUF Size: [%d]"), aBuffer->BufferSize());
+// TRACE_PRN_N1(_L("JB-> REQ Size: [%d]"), aBuffer->RequestSize());
+
+ // Adaptation control will be done based on played frames
+ err = iJitterBufferImpl->AddDataFrame(aBuffer);
+ }
+
+ iObserver->EventJB(MJitterBufferObserver::EBufferConsumed);
+
+ TRACE_PRN_IF_ERR(err);
+// TRACE_PRN_FN_EXT;
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::PlayBuffer
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPJitterBuffer::PlayBuffer()
+ {
+// TRACE_PRN_FN_ENT;
+
+ // iDataSink has valid data - send for playback
+ iObserver->EventJB(MJitterBufferObserver::EBufferReadyToPlay);
+
+ // Go to wait state
+// TransitionState(EWait);
+
+// TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::DoCancel
+// From CActive
+// -----------------------------------------------------------------------------
+//
+void CVoIPJitterBuffer::DoCancel()
+ {
+ iTimer.Cancel();
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::RunL
+// From CActive
+// -----------------------------------------------------------------------------
+//
+void CVoIPJitterBuffer::RunL()
+ {
+ TRACE_PRN_FN_ENT;
+
+ switch (iState)
+ {
+ case EJBufStopped:
+ break;
+ case EJBufPaused:
+ break;
+ case EJBufPlaying:
+ {
+ switch (iTransitionState)
+ {
+ case EWait:
+ TRACE_PRN_N(_L("CVoIPJitterBuffer::RunL EWait"));
+ break;
+ case EEmptyData:
+ TRACE_PRN_N(_L("CVoIPJitterBuffer::RunL EEmptyData"));
+ PlayBuffer();
+ break;
+ default:
+ User::Leave(KErrArgument);
+ break;
+ }
+ break;
+ }
+ default:
+ User::Leave(KErrArgument);
+ break;
+ }
+
+ TRACE_PRN_FN_EXT;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::RunError
+//
+// -----------------------------------------------------------------------------
+//
+TInt CVoIPJitterBuffer::RunError(TInt aError)
+ {
+ iObserver->EventJB(MJitterBufferObserver::EGeneralError, aError);
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::TransitionState
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPJitterBuffer::TransitionState(TJBTransitionState aTransitionState,
+ TUint32 aStateChangeDelay)
+ {
+ TRequestStatus* stat = &iStatus;
+
+ iTransitionState = aTransitionState;
+ Cancel();
+
+ if (aStateChangeDelay)
+ {
+ iTimer.After(iStatus, TTimeIntervalMicroSeconds32(aStateChangeDelay));
+ }
+ else
+ {
+ User::RequestComplete(stat, KErrNone);
+ }
+
+ SetActive();
+ }
+
+// -----------------------------------------------------------------------------
+// CVoIPJitterBuffer::DetermineEmptyBufferDelay
+// -----------------------------------------------------------------------------
+//
+TUint32 CVoIPJitterBuffer::DetermineEmptyBufferDelay()
+ {
+ TUint32 emptyBufferDelay(0);
+ iTmCurrentEmptyBuffer.HomeTime();
+
+ if (iTmPreviousEmptyBuffer.Int64())
+ {
+ TTimeIntervalMicroSeconds difference =
+ iTmCurrentEmptyBuffer.MicroSecondsFrom(iTmPreviousEmptyBuffer);
+
+ if (difference.Int64() < iEmptyBufferDelayThreshold)
+ {
+ emptyBufferDelay = iSampleInterval - difference.Int64();
+ }
+ }
+
+ iTmPreviousEmptyBuffer = iTmCurrentEmptyBuffer;
+ return emptyBufferDelay;
+ }
+
+
+// End of File