qtinternetradio/irqmediaplayer/src/irqmmfadapter.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:01:53 +0300
changeset 0 09774dfdd46b
child 5 0930554dc389
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* Copyright (c) 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 <mmf/common/mmferrors.h>
#include <NokiaAudioPreference.h>
#include <coedef.h>
#include <QStringList>
#include <hxmetadatakeys.h>
#include "irqmetadata.h"
#include "irqenums.h"
#include "irqmmfadapter.h"

//Constants
const TUid KUidController        = { 0x101F8514 }; // Helix Video controller UID
const TInt KConnectingTime       = 30*1000000;     // 30 seconds
const TInt KVolumeMinPercentage  = 0;              // Minimum volume percentage
const TInt KVolumeMaxPercentage  = 100;            // Maximum volume percentage
const TInt KLoadingCompletePercentage = 100;       // Loading Complete percentage

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::IRQMMFAdapter
//  Constructor
//  Initialize viriants
// ---------------------------------------------------------------------------
//
IRQMMFAdapter::IRQMMFAdapter() :
    iVideoPlayer(NULL)
    ,iQMetaData(NULL)
    ,iPrepareTimer(NULL)
{
    iPlayState = EStopped;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::~IRQMMFAdapter
//  Destructor
//  Clean up resources
// ---------------------------------------------------------------------------
//
IRQMMFAdapter::~IRQMMFAdapter()
{
    destroyPlayer();

    delete iQMetaData;
    iQMetaData = NULL;

    if (iPrepareTimer)
    {
        if (iPrepareTimer->IsActive())
        {
            iPrepareTimer->Cancel();
        }
        delete iPrepareTimer;
        iPrepareTimer = NULL;
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::playStation
//  IRQPlayerAdapterInterface method
//  Play url via specific access point id
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::playStation(const QString &aUrl, int aApId)
{
    TRAPD(error, playL(aUrl, aApId));
    if (NULL == iQMetaData)
    {
        emit errorOccured(EIRQErrorOutOfMemory);
    }

    if (KErrNone != error)
    {
        emit errorOccured(EIRQPlayerErrorGeneral);
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::playL
//  Play url via specific access point id
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::playL(const QString &aUrl, int aApId)
{
    // Save stream Url
    if (NULL == iQMetaData)
    {
        iQMetaData = new (ELeave) IRQMetaData();
    }
    else
    {
        // Clear MetaData
        iQMetaData->clear();
    }
    iQMetaData->setStreamUrl(aUrl);

    // Transfer url from QString to TDesC
    TPtrC stationUrl(reinterpret_cast<const TUint16*>(aUrl.utf16()));

    // Create player if it doesn't exist
    if (NULL == iVideoPlayer)
    {
        createPlayerL();
    }

    // If the status is not stopped, clean up last playback resources
    stop();

    // Open url
    iVideoPlayer->OpenUrlL(stationUrl, aApId, KNullDesC8, KUidController);
    iPlayState = EOpenning;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::stop
//  IRQPlayerAdapterInterface method
//  Stop playback, call Close() to clean up allocated resources
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::stop()
{
    if (iVideoPlayer && EStopped != iPlayState)
    {
        if (iPrepareTimer)
        {
            if (iPrepareTimer->IsActive())
            {
                iPrepareTimer->Cancel();
            }
        }

        iVideoPlayer->Stop();
        iVideoPlayer->Close();
        iPlayState = EStopped;
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::setVolume
//  IRQPlayerAdapterInterface method
//  Set volume to player
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::setVolume(int aVolume)
{
    if (iVideoPlayer && iPlayState > EOpenning)
    {
        // aVolume is a percentage
        if (aVolume < KVolumeMinPercentage)
        {
            aVolume = KVolumeMinPercentage;
        }
        else if (aVolume > KVolumeMaxPercentage)
        {
            aVolume = KVolumeMaxPercentage;
        }
        int volume = aVolume*iVideoPlayer->MaxVolume()/KVolumeMaxPercentage;

        TRAPD(error, iVideoPlayer->SetVolumeL(volume));
        if (KErrNone != error)
        {
            emit errorOccured(EIRQPlayerErrorGeneral);
        }
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::getVolume
//  IRQPlayerAdapterInterface method
//  Get current volume value from player
// ---------------------------------------------------------------------------
//
int IRQMMFAdapter::getVolume()
{
    int volume = KVolumeMinPercentage;

    if (iVideoPlayer && iPlayState > EOpenning)
    {
        // Return a percentage
        volume = iVideoPlayer->Volume()*KVolumeMaxPercentage/iVideoPlayer->MaxVolume();
    }
    return volume;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::getPlayerInstance
//  IRQPlayerAdapterInterface method
//  Get audio player instance
// ---------------------------------------------------------------------------
//
void* IRQMMFAdapter::getPlayerInstance()
{
    return (void*)iVideoPlayer;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvpuoOpenComplete
//  Callback function, MVideoPlayerUtilityObserver method
//  Called after calling CVideoPlayerUtility::OpenUrlL()
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvpuoOpenComplete(TInt aError)
{
    if (KErrNone == aError)
    {
        if (NULL == iPrepareTimer)
        {
            TRAPD(error, iPrepareTimer = CPeriodic::NewL(CPeriodic::EPriorityStandard));
            if (KErrNone != error)
            {
                emit errorOccured(EIRQErrorOutOfMemory);
                return;
             }
        }

        // Prepare to playback
        iVideoPlayer->Prepare();
        iPlayState = EConnecting;

        // Start a timer to check preparation status
        if (iPrepareTimer->IsActive())
        {
            // Cancel the previous request if pending
            iPrepareTimer->Cancel();
        }
        TTimeIntervalMicroSeconds32 interval(KConnectingTime);
        iPrepareTimer->Start(interval,interval,
                             TCallBack(IRQMMFAdapter::isPrepareCompleted,this));
    }
    else
    {
        emit errorOccured(EIRQPlayerErrorConnectingFailed);
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvpuoPrepareComplete
//  Callback function, MVideoPlayerUtilityObserver method
//  Called after calling CVideoPlayerUtility::Prepare. Since some audio types
//  are not explicitly(hxmmffourccmap.cpp), they are not retrieved here.
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvpuoPrepareComplete(TInt aError)
{
    // Cancel the previous request if pending
    if (iPrepareTimer->IsActive())
    {
        iPrepareTimer->Cancel();
    }

    if (KErrNone == aError)
    {
        // Get volume from preset
        int volumeval = KVolumeMaxPercentage/2;
        emit volumeExpected(volumeval);
        setVolume(volumeval);

        // Save bit rate
        int bitrate = 0;
        TRAPD(error, bitrate = iVideoPlayer->AudioBitRateL());
        if (KErrNone == error)
        {
            iQMetaData->setBitrate(bitrate/1000);
        }

        // Send signal ConnectionEstablished
        emit connectionEstablished(iQMetaData->getBitrate());

        // Set specific event to get meta data from player
        setMetadataEventConfig();

        // Start playback
        iVideoPlayer->Play();
        iPlayState = EBuffering;
    }
    else if (KErrServerBusy == aError)
    {
        emit errorOccured(EIRQPlayerErrorServerFull);
    }
    else
    {
        emit errorOccured(EIRQPlayerErrorConnectingFailed);
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvpuoPlayComplete
//  Callback function, MVideoPlayerUtilityObserver method
//  Notification that video playback has completed. This is not called if play
//  back is explicitly stopped by calling Stop. Moreover, radio station stream
//  has no end. So it should be NEVER called.
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvpuoPlayComplete(TInt aError)
{
    if (KErrNone != aError)
    {
        emit errorOccured(EIRQPlayerErrorGeneral);
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvpuoEvent
//  Callback function, MVideoPlayerUtilityObserver method
//  Handle events from player.
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvpuoEvent(TMMFEvent const & aEvent)
{
    if (KMMFEventCategoryVideoPlayerGeneralError == aEvent.iEventType)
    {
        switch (aEvent.iErrorCode)
        {
            case KErrHardwareNotAvailable:
            case KErrMMAudioDevice:
                // Higher priority application has taken over the
                // audio device. --> Do stop.
                emit errorOccured(EIRQPlayerErrorAudioDeviceLost);
                break;
            case KErrDisconnected:
                emit errorOccured(EIRQPlayerErrorConnectionLost);
                break;
            case KErrTimedOut:    
                emit errorOccured(EIRQPlayerErrorTimeOut);
                break;
            case KErrServerBusy:    
                emit errorOccured(EIRQPlayerErrorServerFull);
                break;                                            
            default:
                emit errorOccured(EIRQPlayerErrorGeneral);			
                break;
        }
    }
    else if (KMMFRefreshMetaData == aEvent.iEventType)
    {
        // Get refreshed meta data
        TRAPD(error, getRefreshedMetaDataL(aEvent.iErrorCode));
        if (KErrNone != error)
        {
            emit errorOccured(EIRQPlayerErrorGeneral);
        }
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvpuoFrameReady
//  Callback function, MVideoPlayerUtilityObserver method
//  For video stream only, never called
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvpuoFrameReady(CFbsBitmap& aFrame,TInt aError)
{
    Q_UNUSED(aFrame);
    Q_UNUSED(aError);
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvloLoadingStarted
//  Callback function, MVideoLoadingObserver method
//  Start buffering after CVideoPlayerUtility::Play() is called
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvloLoadingStarted()
{
    // Get buffering progress and send it to application
    int percentageComplete = 0;

    TRAPD(error, iVideoPlayer->GetVideoLoadingProgressL(percentageComplete));

    if (KErrNone == error)
    {
        // Send signal to UpdateProgress
        emit percentageBuffered(percentageComplete);
    }
    else
    {
        emit errorOccured(EIRQPlayerErrorGeneral);
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::MvloLoadingComplete
//  Callback function, MVideoLoadingObserver method
//  Send 100% buffering status out
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::MvloLoadingComplete()
{
    iPlayState = EPlaying;

    // Send signal to update progress, 100%
    emit percentageBuffered(KLoadingCompletePercentage);
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::getRefreshedMetaData
//  Get refreshed meta data according to the index
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::getRefreshedMetaDataL(TInt index)
{
    if (iQMetaData)
    {
        CMMFMetaDataEntry* pMetadataEntry = iVideoPlayer->MetaDataEntryL(index);

        QString entryName = QString::fromUtf16(pMetadataEntry->Name().Ptr(),
                                               pMetadataEntry->Name().Length());

        // If the meta data is the same as last, we don't need to report it.
        if (iLastArtistSongName == entryName)
        {
            return;
        }
        else
        {
            iLastArtistSongName = entryName;
        }

        // Artist, song name
        if (entryName == HXAuthor)
        {
            QString songArtist = QString::fromUtf16(pMetadataEntry->Value().Ptr(),
                                                    pMetadataEntry->Value().Length());
            iQMetaData->setArtistSongName(songArtist);

            // Send signal HandleMetaDataReceived
            emit metaDataReceived(*iQMetaData);
        }
    }
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::createPlayer
//  Create player instance
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::createPlayerL()
{
    // Create player instance
    iVideoPlayer = CVideoPlayerUtility2::NewL(*this,KAudioPriorityAudioPlaybackStreaming ,
                                             (TMdaPriorityPreference)KAudioPrefRealOneStreaming);
    // Register loading notification
    iVideoPlayer->RegisterForVideoLoadingNotification(*this);
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::destroyPlayer
//  Destroy player
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::destroyPlayer()
{
    delete iVideoPlayer;
    iVideoPlayer = NULL;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::SetMetadataEventConfig
//  Enable meta data event
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::setMetadataEventConfig()
{
    TMMFMessageDestinationPckg  destinationPckg(KUidInterfaceMMFControllerMetadataEventMsg);
    TPckgBuf<TBool>             metadataEventPckg(EMMFEnableMetadataEvent);

    //  Enable meta data event.
    iVideoPlayer->CustomCommandSync(destinationPckg,
                                    EMMFSetMetadataEventConfig,
                                    metadataEventPckg,
                                    KNullDesC8);
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::isPrepareCompleted
//  Static function for periodic call
// ---------------------------------------------------------------------------
//
TInt IRQMMFAdapter::isPrepareCompleted(TAny* aPtr)
{
    IRQMMFAdapter* self = static_cast<IRQMMFAdapter*>(aPtr);
    if (self)
    {
        self->checkPrepare();
    }
    return KErrNone;
}

// ---------------------------------------------------------------------------
//  IRQMMFAdapter::checkPrepare
//  Check if the preparation is complete
// ---------------------------------------------------------------------------
//
void IRQMMFAdapter::checkPrepare()
{
    if (iPrepareTimer->IsActive())
    {
        // Cancel the previous request if pending
        iPrepareTimer->Cancel();
    }

    if (EConnecting == iPlayState)
    {
        emit errorOccured(EIRQPlayerErrorConnectingFailed);
        stop();
    }
}