mmfenh/advancedaudiocontroller/audiocontrollerpluginsvariant/AdvancedAudioController/Src/AdvancedAudioUtility.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 15 Mar 2010 12:42:35 +0200
branchRCL_3
changeset 8 e35735ece90c
parent 0 71ca22bcf22a
permissions -rw-r--r--
Revision: 201009 Kit: 201010

/*
* Copyright (c) 2006 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:  This class provides utility functions such as parsing of header
*				 information for VBR type clips.
*
*/


//  INCLUDES
#include "AdvancedAudioUtility.h"
#include "AdvancedAudioDecoder.h"
#include "DebugMacros.h"
#include <mmffile.h>
#include <mmfcontrollerframeworkbase.h>
#include <stdlib.h> // for abs
#include <mmfclip.h>

// CONSTANTS
const TUint64 KMaxScanDuration = 36000000000U;	// 10 hours
const TUint KSizeOfTagOffset = 6;


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::CAdvancedAudioUtility
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
EXPORT_C CAdvancedAudioUtility::CAdvancedAudioUtility()
	:	iPosArr(NULL),
    	iSamplingRate(0),
    	iBitRate(0),
    	iChannels(0),
    	iSamplesPerFrame(0),
    	iScanDuration(0),
    	iScanByteCount(0),
    	iScanInvByteCount(0),
    	iSavedLength(0),
    	iClipSize(0),
    	iHeaderOffset(0),
    	iSyncOffset(0),
    	iNumFrames(0),
    	iSumBitRate(0),
   	    iLenMetaData(0)

    {
    iObserver = NULL;
    iFrameTimeMs = 0;
    iReferenceBitRate = 0;
    iScannedOnce = EFalse;
    iDecoder = NULL;
    }

// Destructor
EXPORT_C CAdvancedAudioUtility::~CAdvancedAudioUtility()
    {
    }

	
// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ScanFramesL
// Scan source buffer, frame by frame to update the frame count, byte count and
// duration. Record controller still uses this, but not play controller.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::ScanFramesL(
	CMMFClip* aClip,
	CMMFDataBuffer* aBuf,
	TBool aScanThisBufferOnly,
    TInt /*aSourcePosition*/)
	{
    if (iScanDuration && !aScanThisBufferOnly)
        {
        // Already scanned once!
	    return aBuf->Data().Size();
        }

    iClipSize = aClip->Size();

    if (!aScanThisBufferOnly)
        {
        iHeaderOffset = this->SeekSync(aBuf, aBuf->Data().Size());
        }

    TInt readLen;
    TInt seekLen;
    const TUint8* seekPtr;

    TBool Done = EFalse;
    TInt SeekOffset = this->SeekSync(aBuf, aBuf->Data().Size());

	if (SeekOffset == aBuf->Data().Size())
		return SeekOffset;

    while (!Done)
        {
        readLen = aBuf->Data().Length();
        seekLen = readLen - SeekOffset;
        seekPtr = aBuf->Data().Ptr() + SeekOffset;

        TAudioFrameInfo frameInfo;
        while (seekLen >= this->FrameHeaderSize())
            {
            // Scan frame by frame until free format frame or EOB detected.
            TInt length = this->FrameInfo(seekPtr, seekLen, frameInfo);
            if (length > 0  &&  frameInfo.iBitRate > 0)
                {
                // record time position every time the frame length changes
                RecordTimeStampL(length);
                // update counters
                iScanByteCount += length;
                iScanDuration += (1000000*frameInfo.iFrameSamples) /
                                  frameInfo.iSamplingRateOut;
                iSamplingRate = frameInfo.iSamplingRate;
			    // Ignoring NO_DATA and SID Frames in bitrate calculation
                if (frameInfo.iBitRate != 400 && frameInfo.iBitRate != 2400)
                   	{
                		iSumBitRate += frameInfo.iBitRate;
                		iNumFrames++;
                		iBitRate = iSumBitRate/iNumFrames;
                	}
                iSamplesPerFrame = frameInfo.iFrameSamples;
                iChannels = frameInfo.iChannels;
                seekPtr += length;
                seekLen -= length;
                }
            else if (frameInfo.iBitRate < 0)
                {
                seekLen = readLen = 0;
                }
            else
                {
                iScanInvByteCount++;
                seekPtr++;
                seekLen--;
                iSavedLength = 0;
                }
            }

        // request more data, if eof or max scan duration has not been exceeded
        if ((readLen < this->FrameHeaderSize()) || (iScanDuration > KMaxScanDuration) || aScanThisBufferOnly)
            {
            Done = ETrue;
            }
        else
            {
            // request more data
            SeekOffset = 0;
            aClip->ReadBufferL(aBuf, iHeaderOffset+iScanByteCount+iScanInvByteCount);
            }
        }

	return aBuf->Data().Size();
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ScanHeaderL
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::ScanHeaderL(
	CMMFDataBuffer* aDataBuf)
	{
    // currently we are not handling how to search past the metadata
	ScanFramesL(aDataBuf, EFalse, 0);
	
	// reset iScanDuration because we didn't scan through the whole file,
    // and iScanDuration would not be the Total Duration of the source		
    iScanDuration = 0;
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ScanFramesL
// Scan source buffer, frame by frame to update the frame count, byte count and
// duration.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::ScanFramesL(
	CMMFDataBuffer* aBuf,
	TBool aScanThisBufferOnly,
    TInt /*aSourcePosition*/)
	{
    if (!aScanThisBufferOnly)
        {
        // Already scanned once!
        if (iScannedOnce)
            return aBuf->Data().Size();

        iHeaderOffset = this->SeekSync(aBuf, aBuf->Data().Size());
        }

    TInt readLen;
    TInt seekLen;
    const TUint8* seekPtr;

    TBool Done = EFalse;
    TInt SeekOffset = this->SeekSync(aBuf, aBuf->Data().Size());

    while (!Done)
        {
        readLen = aBuf->Data().Length();
        seekLen = readLen - SeekOffset;
        seekPtr = aBuf->Data().Ptr() + SeekOffset;
        TAudioFrameInfo frameInfo;
        while (seekLen >= this->FrameHeaderSize())
            {
            // Scan frame by frame until free format frame or EOB detected.
            TInt length = this->FrameInfo(seekPtr, seekLen, frameInfo);
            if (length > 0  &&  frameInfo.iBitRate > 0)
                {
                // record time position every time the frame length changes
                RecordTimeStampL(length);
                // update counters
                iScanByteCount += length;
                iScanDuration += (1000000*frameInfo.iFrameSamples)/frameInfo.iSamplingRateOut;
                iSamplingRate = frameInfo.iSamplingRate;
                
                if (iScanDuration)
                    iScannedOnce = ETrue;
                
                // Ignoring NO_DATA and SID Frames in bitrate calculation
                // this logic here is kinda dangerous, because ScanFramesL can be called
                // multiple time when SetPositionL is supported in Streaming/PDL, hence
                // the avg bitrate can be mess up the the repeat of the same frame
                if (frameInfo.iBitRate != 400 && frameInfo.iBitRate != 2400)
                   	{
            		iSumBitRate += frameInfo.iBitRate;
            		iNumFrames++;
            		iBitRate = iSumBitRate/iNumFrames;
                	}

                iSamplesPerFrame = frameInfo.iFrameSamples;
                iChannels = frameInfo.iChannels;
                seekPtr += length;
                seekLen -= length;
                }
            else if (frameInfo.iBitRate < 0)
                {
                seekLen = readLen = 0;
                }
            else
                {
                iScanInvByteCount++;
                seekPtr++;
                seekLen--;
                iSavedLength = 0;
                }
            }

         // request more data how? , if eof or max scan duration has not been exceeded
        if (aScanThisBufferOnly)
            {
            Done = ETrue;
            }
		}

	return aBuf->Data().Size();
    }

// -----------------------------------------------------------------------------
//  CAdvancedAudioUtility::FindFramePos
//  Finds the byte position of the frame at given time position.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::FindFramePos(
	const TInt64& aTimePos,
	CMMFClip* /*aClip*/)
    {
    TInt ret = KErrNotFound;

    // calculate frame duration
    TInt64 frmTime((iSamplesPerFrame*1000000) / iSamplingRate);

    // find the closest larger time stamp corresponding to time position
    TInt pos = 0;
    TTimePos timeStamp((aTimePos), 0, 0);
    TKeyArrayFix timeKey(_FOFF(TTimePos,iTimePos),ECmpTInt64);
    iPosArr->FindIsq(timeStamp, timeKey, pos);

    // calculate byte position based on the closest smaller time stamp
    if (iPosArr->Count() > 0)
        {
        // get the closest smaller
        if (pos > 0)
        	{
			pos--;
			}
        TTimePos& ts = iPosArr->At(pos);
        // offset from the closest smaller time stamp
        TInt64 dTime = aTimePos - ts.iTimePos;
        // time stamp position plus byte offset within this segment
        ret = ts.iBytePos + ((dTime / frmTime) * ts.iFrameLen);
        }

    // limit check
    if (ret < 0)
    	{
		ret = 0;
		}

    if ((ret > iClipSize) && (iClipSize != 0))
    	{
		ret = iClipSize;
		}

	DP3(_L("CAdvancedAudioUtility::FindFramePos high[%d], low[%d], ret[%d]"), I64HIGH(aTimePos), I64LOW(aTimePos), ret);

    return ret;
    }
// CAdvancedAudioUtility::FrameInfo
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::FrameInfo(
	const TUint8* /*aBuf*/,
	TInt /*aBufLen*/,
	TAudioFrameInfo& /*aInfo*/)
	{
	return 0;
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SampleRate
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::SampleRate()
    {
    return iSamplingRate;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::Channels
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::Channels()
    {
    return iChannels;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ChannelsOut
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::ChannelsOut()
    {
    return iChannelsOut;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ScanDuration
// -----------------------------------------------------------------------------
// get rid of this
EXPORT_C TInt64 CAdvancedAudioUtility::ScanDuration()
    {
    return iScanDuration;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::Duration
// -----------------------------------------------------------------------------
// default impl
EXPORT_C TInt64 CAdvancedAudioUtility::Duration()
    {
    DP0(_L("CAdvancedAudioUtility::Duration()"));
    
    TInt64 bitRate = BitRate(); // update bitrate
   	TInt64 size = iClipSize;
   	size -= (iSyncOffset+iHeaderOffset);
    if (size >= 0)
       	{
    	if (bitRate > 0)
    		{
    		iDurationUs = size*8000000/bitRate;
    		}
    	}
    DP3(_L("CAdvancedAudioUtility::Duration() iDuration(ms)[%d] bitRate[%d] size[%d]"), iDurationUs/1000, bitRate, iClipSize-iSyncOffset-iHeaderOffset);
    return iDurationUs;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::BitRate
// -----------------------------------------------------------------------------
// default impl - BitRate() would be called by user and updates reference
EXPORT_C TInt CAdvancedAudioUtility::BitRate()
    {
    if (iDecoder && !iBitRateFrozen)
        {
        TInt bitrate = iDecoder->BitRate();
        if (bitrate > 0)
        	{
            iBitRate = bitrate;
        	}
        }
    return iBitRate;
    }


// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::HeaderOffset
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::HeaderOffset()
    {
    return iHeaderOffset;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SyncOffset
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::SyncOffset()
    {
    return iSyncOffset;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SetCodecConfigData
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::SetCodecConfigData(
	RArray<TInt>& /*aCodecConfig*/)
    {
    }
    
// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SetObserver
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::SetObserver(MAdvancedAudioUtilityObserver& aObserver)
    {
    iObserver = &aObserver;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SetDecoder
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::SetDecoder(CAdvancedAudioDecoder& aDecoder)
    {
    iDecoder = &aDecoder;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::DeReferenceDecoder
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::DeReferenceDecoder()
    {
    iDecoder = NULL;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::FrameHeaderSize
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::FrameHeaderSize()
	{
	return 0;
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::GetDriveNumber
// -----------------------------------------------------------------------------
// is this needed?
EXPORT_C TDriveNumber CAdvancedAudioUtility::GetDriveNumber(
	const TDesC& aDriveName)
    {
    TDriveNumber driveNumber = EDriveC;

    if (!aDriveName.Length())
        {
        return driveNumber;
        }
    else
        {
        switch (aDriveName[0])
            {
            case 'a':
            case 'A':
                driveNumber = EDriveA;
                break;
            case 'b':
            case 'B':
                driveNumber = EDriveB;
                break;
            case 'c':
            case 'C':
                driveNumber = EDriveC;
                break;
            case 'd':
            case 'D':
                driveNumber = EDriveD;
                break;
            case 'e':
            case 'E':
                driveNumber = EDriveE;
                break;
            case 'f':
            case 'F':
                driveNumber = EDriveF;
                break;
            case 'g':
            case 'G':
                driveNumber = EDriveG;
                break;
            case 'h':
            case 'H':
                driveNumber = EDriveH;
                break;
            case 'i':
            case 'I':
                driveNumber = EDriveI;
                break;
            case 'j':
            case 'J':
                driveNumber = EDriveJ;
                break;
            case 'k':
            case 'K':
                driveNumber = EDriveK;
                break;
            case 'l':
            case 'L':
                driveNumber = EDriveL;
                break;
            case 'm':
            case 'M':
                driveNumber = EDriveM;
                break;
            case 'n':
            case 'N':
                driveNumber = EDriveN;
                break;
            case 'o':
            case 'O':
                driveNumber = EDriveO;
                break;
            case 'p':
            case 'P':
                driveNumber = EDriveP;
                break;
            case 'q':
            case 'Q':
                driveNumber = EDriveQ;
                break;
            case 'r':
            case 'R':
                driveNumber = EDriveR;
                break;
            case 's':
            case 'S':
                driveNumber = EDriveS;
                break;
            case 't':
            case 'T':
                driveNumber = EDriveT;
                break;
            case 'u':
            case 'U':
                driveNumber = EDriveU;
                break;
            case 'v':
            case 'V':
                driveNumber = EDriveV;
                break;
            case 'x':
            case 'X':
                driveNumber = EDriveX;
                break;
            case 'y':
            case 'Y':
                driveNumber = EDriveY;
                break;
            case 'z':
            case 'Z':
                driveNumber = EDriveZ;
                break;
            default:
                break;
            }
        }
        return driveNumber;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SetClipSizeL
// Set/Update the iClipSize varilable
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::SetClipSizeL(TUint aSize)
    {
    DP1(_L("CAdvancedAudioUtility::SetClipSizeL size[%d]"), aSize);
    if (aSize > (iSyncOffset+iHeaderOffset))
        {
        iClipSize = aSize;
        }
    else
    	{
        User::Leave(KErrArgument);
    	}
    }
    
// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::EnableBitRateChangedEventL
// Enable bitrate change callback
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::EnableBitRateChangedEventL(TInt aIntervalInMilliSeconds)
    {
    if (!iObserver)
        User::Leave(KErrNotReady);
    else if (aIntervalInMilliSeconds < -1)
        User::Leave(KErrArgument);
    
    if (iDecoder)
        {
        TInt err = KErrNone;

        if (aIntervalInMilliSeconds == -1)
            err = iDecoder->EnableDecodeIntervalEvent(EFalse);
        else
            err = iDecoder->EnableDecodeIntervalEvent(ETrue, aIntervalInMilliSeconds);

        // KErrNone means the decoder would callback on desire interval as it decodes
        // KErrNotSupported implys Utility would need to keep track of the interval
        // otherwise, leave on any other situation
        if (err == KErrNone)
            return;
        else if (err != KErrNotSupported)
            User::LeaveIfError(err);
        }
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SetSourceReference
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::SetSourceReference(TUint aTimeMs, TUint aPos)
	{
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->SetSourceReference(aTimeMs, aPos);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::FindFramePosFromTime
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::FindFramePosFromTime(TUint& aTimeMs, TUint& aPos)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->FindFramePosFromTime(aTimeMs, aPos);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}
    return stat;
    }

EXPORT_C TInt CAdvancedAudioUtility::FindFrameTimeFromPos(TUint& aTime, TUint& aPos)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->FindFrameTimeFromPos(aTime, aPos);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::LastFramePos
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::LastFramePos(TUint& aPos)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->LastFramePos(aPos);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::LastFrameTime
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::LastFrameTime(TUint& aTimeMs)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->LastFrameTime(aTimeMs);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}
    return stat;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::ResetTable
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::ResetTable()
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->ResetTable();
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::SeekToTimeMs
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::SeekToTimeMs(TUint aTimeMs)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->SeekToTimeMs(aTimeMs);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
    }

EXPORT_C TInt CAdvancedAudioUtility::SetPlayWindowEndTimeMs(TUint aTimeMs)
	{
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->SetPlayWindowEndTimeMs(aTimeMs);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::RecordTimeStampL
// Record time position every time the frame length changes or when the stamp
// array is empty. Positioning is accurate up to KMaxScanDuration. After that
// the last time stamp is used for estimating the position..
// -----------------------------------------------------------------------------
//
EXPORT_C void CAdvancedAudioUtility::RecordTimeStampL(
	TInt aFrameLength)
    {
    // record time position every time the frame length
    // changes or empty stamp array
    TInt pos = iScanInvByteCount + iScanByteCount;
    TInt count = iPosArr->Count();
    TTimePos lastEntry(0,0,0);
    
    if (count > 0)
    	lastEntry = (*iPosArr)[iPosArr->Count()-1];
    
    DP5(_L("CAdvancedAudioUtility::RecordTimeStampL Count[%d], iScanDuration[%d]millsec, BytePos[%d], aFrameLength[%d], lastEntry.iTimePos[%d]millsec"), count, I64LOW(iScanDuration/1000), pos, aFrameLength, I64LOW(lastEntry.iTimePos/1000));

	if (((pos > lastEntry.iBytePos) && aFrameLength != 0 && aFrameLength != iSavedLength) || (count == 0))
        {
        if (iScanDuration <= KMaxScanDuration)
            {
            DP0(_L("CAdvancedAudioUtility::RecordTimeStampL, AppendL new entry"));

            TTimePos timeStamp(I64LOW(iScanDuration), pos, aFrameLength);

            iPosArr->AppendL(timeStamp);
			iSavedLength = aFrameLength;
            }
        }
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::MetaDataLength
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CAdvancedAudioUtility::ID3HeaderLength(
	const CMMFDataBuffer* aBuf)
    {
	TInt lenMetaData;
	TUint offset = aBuf->Position();

	_LIT8 (KTagID3, "ID3");
	TPtrC8 searchBuf;

	// Set search buffer
	searchBuf.Set(aBuf->Data());

	const TUint8* ptr = aBuf->Data().Ptr();
	TInt len = aBuf->Data().Length();
	searchBuf.Set(ptr+offset, len-offset);

    TInt startTagPos = searchBuf.Find (KTagID3);
	if (startTagPos == KErrNotFound || startTagPos != 0)
		{
        lenMetaData = 0;
		}
	else
		{
        lenMetaData = searchBuf[KSizeOfTagOffset];
        lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+1] << 1)) >> 1;
		lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+2] << 1)) >> 1;
		lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+3] << 1)) >> 1;
		lenMetaData += 10;
		}

    return lenMetaData;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::CreateBufferOfSizeLC
// -----------------------------------------------------------------------------
//
EXPORT_C CMMFDataBuffer* CAdvancedAudioUtility::CreateBufferOfSizeLC(
	TUint aSize)
    {
    CMMFDataBuffer* buffer = CMMFDataBuffer::NewL(aSize);
    CleanupStack::PushL(buffer);
    buffer->Data().FillZ(aSize);
    buffer->SetRequestSizeL(aSize);
	buffer->Data().SetLength(0);
    return buffer;
    }

// -----------------------------------------------------------------------------
// CAdvancedAudioUtility::DecodeIntervalEvent
// -----------------------------------------------------------------------------
//	
EXPORT_C void CAdvancedAudioUtility::DecodeIntervalEvent()
    {
    if (iObserver)
        {
        BitRate(); // updates iBitRate
        TInt lim = iReferenceBitRate/10; // 10% tolerance
        if (abs(iReferenceBitRate - iBitRate) > lim)
            {
            iObserver->BitRateChanged();
            iReferenceBitRate = iBitRate;
            }
        }
    }
    
/*    
EXPORT_C TInt CAdvancedAudioUtility::IsSeeking(TBool& aIsSeeking)
    {
    TInt stat;
    if (iDecoder)
    	{
	    stat = iDecoder->IsSeeking(aIsSeeking);
    	}
    else
    	{
        stat = KErrNotSupported;
    	}	
    return stat;
    }
*/    
// -----------------------------------------------------------------------------
// CAdvancedAudioDecoder::SeekPositionReached
// -----------------------------------------------------------------------------
//	
EXPORT_C void CAdvancedAudioUtility::SeekPositionReached(TUint aTimeMs)
	{
	iObserver->SeekPositionReached(aTimeMs);
	}

// -----------------------------------------------------------------------------
// CAdvancedAudioDecoder::PlayWindowEndPositionReached
// -----------------------------------------------------------------------------
//	
EXPORT_C void CAdvancedAudioUtility::PlayWindowEndPositionReached()
	{
	iObserver->PlayWindowEndPositionReached();
	}

EXPORT_C TInt CAdvancedAudioUtility::GetOffsets(TInt& aOffsets)
	{
	aOffsets = iHeaderOffset + iSyncOffset;
	return KErrNone;
	}

// End of File