satui/satapp/src/satapptoneprovider.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:45:17 +0300
branchRCL_3
changeset 19 7d48bed6ce0c
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2010 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:
*
*/

// includes
#include <QTimer>
#include <QCoreApplication>
#include <QtDebug>
#include <hbmessagebox.h>//playtone note

#include "SatAppToneProvider.h"
#include "satappconstant.h"
#include "satappaction.h"

// ----------------------------------------------------------------------------
// SatAppToneProvider::SatAppToneProvider
// ----------------------------------------------------------------------------
//
SatAppToneProvider::SatAppToneProvider(QObject *parent) :
    QObject(parent)
{
    qDebug("SATAPP: SatAppToneProvider::SatAppToneProvider <>");
    mState = Idle;
    mWarningAndPlayTones = false;
    mVolume = 0;
    mPlayer = 0;
    mPlayToneError = ESatSuccess;
    mTimer = 0;
    mPermanentNote = 0;
    mAudioPlayer = 0;
    mCurrentAction = 0;
}

// ----------------------------------------------------------------------------
// SatAppToneProvider::~SatAppToneProvider
// ----------------------------------------------------------------------------
//
SatAppToneProvider::~SatAppToneProvider()
{
    qDebug("SATAPP: SatAppToneProvider::~SatAppToneProvider >");
    
    if (mCurrentAction) {
        stopPlayTone();
    }
    
    if (mPermanentNote) {
        qDebug("SatAppToneProvider::resetState delete mPermanentNote");
        delete mPermanentNote;
        mPermanentNote = 0;
    }
    
    if (mTimer) {
        qDebug("SatAppToneProvider::resetState delete timer");
        delete mTimer;
        mTimer = 0;
    }
    
    qDebug("SATAPP: SatAppToneProvider::~SatAppToneProvider <");
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::playTone
//-----------------------------------------------------------------------------
void SatAppToneProvider::playTone(SatAppAction& action)
{
    qDebug("SATAPP: SatAppToneProvider::playTone >");
    resetState();
    
    mCurrentAction = &action;
    int tone = action.value(KeyToneId).toInt();
    int duration = action.value(KeyDuration).toInt();
    QString text = action.value(KeyText).toString();
    QByteArray sequence;
    mState = recognizeTone(tone,sequence,duration);
    if (mState == PlayStandardTone)
    {
        playStandardTone(text,sequence,duration);
    }
    else if (mState == PlayUserSelectedTone)
    {
        playUserSelectedTone(text,tone,duration);
    }
    else
    {
        mCurrentAction->complete(ESatCmdDataNotUnderstood);
        mCurrentAction = 0;
    }
    qDebug("SATAPP: SatAppToneProvider::playTone <");
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::recognizeTone
// @param tone the tone code from server (see TSatTone in MSatUiObserver)
// @param sequence (out) standard tone play sequence
// @param duration (out) stanrard tone play duration (manipulated in some cases)
// @return suggested state for the tone provider (or Idle if tone is not recognised)
//-----------------------------------------------------------------------------
SatAppToneProvider::State SatAppToneProvider::recognizeTone(
    int tone,
    QByteArray& sequence,
    int& duration)
{
    qDebug("SATAPP: SatAppToneProvider::recognizeTone >");
    State ret = Idle;
    qDebug("SATAPP: SatAppToneProvider::recognizeTone tone: %d", tone);
    switch (tone)
    {
        case ESatGeneralBeep:
        case ESatPositiveTone:
        case ESatToneNotSet:
            {
            if (duration == 0) duration = KSatDur170ms; // 170ms
            sequence = charArrayToByteArray(KGeneralBeep, 
                                     sizeof(KGeneralBeep));
            ret = PlayStandardTone;
            break;
            }
        case ESatNegativeTone:
            {
            if (duration == 0) duration = KSatDur250ms; // 250ms
            sequence = charArrayToByteArray(KErrorTone, 
                                     sizeof(KErrorTone));
            ret = PlayStandardTone;
            break;
            }
        case ESatRadioPathNotAvailableCallDropped:
            {
            if (duration == 0) duration = KSatDur1200ms; // 1200ms
            sequence = charArrayToByteArray(KRadioPathNotAvailable, 
                                     sizeof(KRadioPathNotAvailable));
            ret = PlayStandardTone;
            break;
            }
        case ESatRadioPathAcknowledge:
            {
            if (duration == 0) duration = KSatDur200ms; // 200ms
            sequence = charArrayToByteArray(KRadioPathAck, 
                                     sizeof(KRadioPathAck));
            ret = PlayStandardTone;
            break;
            }
        case ESatDialTone:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqDial, 
                                     sizeof(KNetToneSeqDial));
            ret = PlayStandardTone;
            break;
            }
        case ESatCalledSubscriberBusy:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqNetBusy, 
                                     sizeof(KNetToneSeqNetBusy));
            ret = PlayStandardTone;
            break;
            }
        case ESatCongestion:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqNetCongestion, 
                                     sizeof(KNetToneSeqNetCongestion));
            ret = PlayStandardTone;
            break;
            }
        case ESatErrorSpecialInfo:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqNetSpecialInformation, 
                                     sizeof(KNetToneSeqNetSpecialInformation));
            ret = PlayStandardTone;
            break;
            }
        case ESatCallWaitingTone:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqNetCallWaiting, 
                                     sizeof(KNetToneSeqNetCallWaiting));
            ret = PlayStandardTone;
            break;
            }
        case ESatRingingTone:
            {
            if (duration == 0) break;
            sequence = charArrayToByteArray(KNetToneSeqRingGoing, 
                                     sizeof(KNetToneSeqRingGoing));
            ret = PlayStandardTone;
            break;
            }
        case ESatUserSelectedToneIncomingSpeech:
        case ESatUserSelectedToneIncomingSms:
            {
            ret = PlayUserSelectedTone;
            break;
            }
        default:
            break;
    }
    
    qDebug("SATAPP: SatAppToneProvider::recognizeTone state=%d <", ret);
    return ret;
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::charArrayToByteArray
//-----------------------------------------------------------------------------
QByteArray SatAppToneProvider::charArrayToByteArray(
    const char tone[], 
    int size)
{
    qDebug("SATAPP: SatAppToneProvider::charArrayToByteArray >");
    QByteArray seq;
    seq = QByteArray::fromRawData(tone, size);
    qDebug("SATAPP: SatAppToneProvider::charArrayToByteArray <");
    return seq;
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::playStandardTone
//-----------------------------------------------------------------------------
void SatAppToneProvider::playStandardTone(
    const QString& text,
    const QByteArray& sequence,
    int duration)
{
    qDebug("SATAPP: SatAppToneProvider::playStandardTone >");

    if (text.length() > 0) {
        mPermanentNote = new HbMessageBox(HbMessageBox::MessageTypeInformation);
        SAT_ASSERT(connect(mPermanentNote, SIGNAL(aboutToClose()),
                this, SLOT(stopPlayTone())));
        mPermanentNote->setText(text);
        mPermanentNote->setStandardButtons(HbMessageBox::Cancel);
        if (duration > 0 ) {
            mPermanentNote->setTimeout(duration);
        }
        mPermanentNote->setDismissPolicy(HbPopup::TapAnywhere);
        qDebug("SatAppToneProvider::playStandardTone show before");
        mPermanentNote->show();
        qDebug("SatAppToneProvider::playStandardTone show after");
    }

    TPtrC8 seq((unsigned char*)sequence.constData(), sequence.length());
    qDebug("SATAPP: SatAppToneProvider::playStandardTone TPtrC8 seq: %S", &seq);
    QT_TRAP_THROWING(SymbianPrepareAudioToneUtilityL(seq));

    if (duration > 0) {
        mTimer = new QTimer(this);
        SAT_ASSERT(connect(mTimer, SIGNAL(timeout()),
                this, SLOT(stopPlayTone())));
        mTimer->start(duration);
    }
    
    qDebug("SATAPP: SatAppToneProvider::playStandardTone <");
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::playUserSelectedTone
//-----------------------------------------------------------------------------
void SatAppToneProvider::playUserSelectedTone(
    const QString& text,
    int tone,
    int duration)
{
    qDebug("SatAppToneProvider::playUserSelectedTone >");

    // If several messages/calls arrive during a small amount of time and if the
    // message received or incoming call tone is already being played we do not 
    // restart it.
    if (mAudioPlayer) {
        qDebug( "SatAppToneProvider::\
            PlayUserSelectedToneL Error - already played" );
        mCurrentAction->complete(ESatFailure);
        mCurrentAction = 0;
        mState = Idle;
        return;
    }

    if (text.length() > 0) {
        mPermanentNote = new HbMessageBox(HbMessageBox::MessageTypeInformation);
        mPermanentNote->setText(text);
        mPermanentNote->setStandardButtons(HbMessageBox::Cancel);
        if (duration) {
            mPermanentNote->setTimeout(duration);
        }
        mPermanentNote->setDismissPolicy(HbPopup::TapAnywhere);
        qDebug("SatAppToneProvider::PlayUserSelectedToneL show before");
        mPermanentNote->show();
        qDebug("SatAppToneProvider::PlayUserSelectedToneL show after");
    }

    QT_TRAP_THROWING(SymbianPrepareAudioPlayerL(tone,duration));
    
    if (duration > 0) {
        qDebug( "SATAPP: SatAppToneProvider::PlayUserSelectedToneL\
            duration not 0" );
        mTimer = new QTimer(this);
        mTimer->start(duration);
        SAT_ASSERT(connect(mTimer, SIGNAL(timeout()), this, SLOT(stopPlayTone())));

        if (mPermanentNote) {
            SAT_ASSERT(connect(mPermanentNote, SIGNAL(aboutToClose()),
                    this, SLOT(stopPlayTone())));
        }
    }
    
    qDebug( "SatAppToneProvider::PlayUserSelectedToneL <" );
}


// ----------------------------------------------------------------------------
// SatAppToneProvider::clearScreen
// terminates all ongoing UI actions
// ----------------------------------------------------------------------------
//
void SatAppToneProvider::clearScreen()
{
    qDebug( "SatAppToneProvider::clearScreen >" );
    if (mCurrentAction) {
        stopPlayTone();
    }
    qDebug( "SatAppToneProvider::clearScreen <" );
}

// ----------------------------------------------------------------------------
// SatAppToneProvider::stopPlayTone
// Stops the music, frees blocked functions
// ----------------------------------------------------------------------------
//
void SatAppToneProvider::stopPlayTone()
{
    qDebug("SATAPP: SatAppToneProvider::stopPlayTone >");
    
    if (mPermanentNote) {
        qDebug("SatAppToneProvider::stopPlayTone close mPermanentNote");
        disconnect(mPermanentNote,SIGNAL(aboutToClose()),
                this, SLOT(stopPlayTone())); 
        mPermanentNote->close();
    }
    
    if (mTimer) {
        qDebug("SatAppToneProvider::stopPlayTone stop timer");
        disconnect(mTimer,SIGNAL(timeout()), this, SLOT(stopPlayTone()));
        if (mTimer->isActive()) {
            mTimer->stop();
        }
    }
    
    switch(mState) {
        case PlayStandardTone: {
            qDebug("SATAPP: SatAppToneProvider::stopPlayTone before play cancel");
            SymbianStopAudioToneUtility();

            //get warning and game tones setting from active profile
            QT_TRAP_THROWING(GetProfileParamsL());
            if( EFalse == mWarningAndPlayTones 
                && ESatSuccess == mPlayToneError ) {
                mPlayToneError = ESatSuccessToneNotPlayed;
            }
            break;
        }
        case PlayUserSelectedTone: {
            // Sample is played in forever loop for the duration.
            // After duration call back timers are destroyed       
            // If player exists, stop playing and delete player. MapcPlayComplete
            // is not called because CallBackTimer stops the playing.
            SymbianStopAudioPlayer();
            if( EFalse == mWarningAndPlayTones ) {
                mPlayToneError = ESatSuccessToneNotPlayed;
            }
            break;
        }
        default:
            break;
    }
    
    mState = Idle;
    if (mCurrentAction) {
        mCurrentAction->complete(mPlayToneError);
        mCurrentAction = 0;
    }
    
    qDebug("SATAPP: SatAppToneProvider::stopPlayTone <");
}

void SatAppToneProvider::resetState()
{
    qDebug("SATAPP: SatAppToneProvider::resetState >");
    if (mCurrentAction) {
        mCurrentAction->completeWithNoResponse();
        mCurrentAction = 0;
    }
    
    if (mPermanentNote) {
        qDebug("SatAppToneProvider::resetState delete mPermanentNote");
        delete mPermanentNote;
        mPermanentNote = 0;
    }
    
    if (mTimer) {
        qDebug("SatAppToneProvider::resetState delete timer");
        delete mTimer;
        mTimer = 0;
    }
    qDebug("SATAPP: SatAppToneProvider::resetState <");
}



// ****************************************************************************
// * ************************************************************************ *
// * *                          SYMBIAN PART                                * *
// * ************************************************************************ *
// ****************************************************************************


// includes
#include    <e32std.h> //TTimeIntervalMicroSeconds
#include    <MProfile.h>
#include    <MProfileEngine.h>
#include    <MProfileTones.h>
#include    <TProfileToneSettings.h>
#include    <AudioPreference.h> //KAudioPriorityLowLevel
#include    <mdaaudiotoneplayer.h> // for CMdaAudioToneUtility&CMdaAudioPlayerUtility
#include    <mda/common/resource.h> //KMdaRepeatForever

//constants

// Maximum length for sound file. 
const TInt KMaxSoundFileLength = 256;
// Used when dividing some values. Used only for preventing the use of magic 
// numbers
// Audio sample is repeated indefinitely.
const TInt KSoundPlayerRepeatForever = KMdaRepeatForever;

// The max volume value from settings.
// From TProfileToneSettings.h
const TInt KMaxVolumeFromProfile( 10 );

// ----------------------------------------------------------------------------
// SatAppToneProvider::SymbianPrepareAudioToneUtilityL
// creates and prepares CMdaAudioToneUtility
// ----------------------------------------------------------------------------
//
void SatAppToneProvider::SymbianPrepareAudioToneUtilityL(const TDesC8& sequence)
{
    qDebug( "SatAppToneProvider::SymbianPrepareAudioToneUtilityL >" );
    if (mPlayer) {
        delete mPlayer;
        mPlayer = 0;
    }
    mPlayer = CMdaAudioToneUtility::NewL(*this);
    TInt volume(mPlayer->MaxVolume());
    mPlayer->SetVolume(volume);
    mPlayer->PrepareToPlayDesSequence(sequence);
    qDebug( "SatAppToneProvider::SymbianPrepareAudioToneUtilityL <" );
}

// ----------------------------------------------------------------------------
// SatAppToneProvider::SymbianStopAudioToneUtility
// cancels and deletes CMdaAudioToneUtility
// ----------------------------------------------------------------------------
void SatAppToneProvider::SymbianStopAudioToneUtility()
{
    qDebug( "SatAppToneProvider::SymbianStopAudioToneUtility >" );
    if (mPlayer) {
        mPlayer->CancelPlay();
    }
    delete mPlayer;
    mPlayer = NULL;
    qDebug( "SatAppToneProvider::SymbianStopAudioToneUtility <" );
}

// ----------------------------------------------------------------------------
// SatAppToneProvider::SymbianPrepareAudioPlayerL
// cancels and deletes CMdaAudioToneUtility
// ----------------------------------------------------------------------------
void SatAppToneProvider::SymbianPrepareAudioPlayerL(
    int tone, int duration)
{
    qDebug( "SatAppToneProvider::SymbianPrepareAudioPlayerL >" );
    // This defines name for the current message alert or incoming call tone. 
    TBuf<KMaxSoundFileLength> soundFileName;
    GetProfileParamsL(tone, &soundFileName);

    // This defines the behaviour to be adopted by an
    // audio client if a higher priority client takes over the device.
    TInt mdaPriority( KAudioPrefIncomingCall );
    // This is used to resolve conflicts when more than one client tries to 
    // access the same sound output device simultaneously.
    TInt audioPriority( KAudioPriorityPhoneCall );

    qDebug( "SATAPP: SatAppToneProvider::PlayUserSelectedToneL\
        Volume is %d ", mVolume );

    // Creates the audio player.
    mAudioPlayer = CMdaAudioPlayerUtility::NewFilePlayerL( 
        soundFileName,
        *this,
        audioPriority,
        ( TMdaPriorityPreference ) mdaPriority );

    TTimeIntervalMicroSeconds no_silence(0);
    if (duration > 0)
    {
        // repeat forever in a loop
        mAudioPlayer->SetRepeats(KSoundPlayerRepeatForever, no_silence);
    }
    else
    {
        // play only once
        mAudioPlayer->SetRepeats(0, no_silence);
    }
    qDebug( "SatAppToneProvider::SymbianPrepareAudioPlayerL <" );

}

// ----------------------------------------------------------------------------
// SatAppToneProvider::SymbianStopAudioPlayer
// cancels and deletes CMdaAudioToneUtility
// ----------------------------------------------------------------------------
void SatAppToneProvider::SymbianStopAudioPlayer()
{
    qDebug( "SatAppToneProvider::SymbianStopAudioPlayer >" );
    if (mAudioPlayer) {
        qDebug( "SatAppToneProvider::SymbianStopAudioPlayer AudioPlayer stop" );
        mAudioPlayer->Stop();
    }
    delete mAudioPlayer;
    mAudioPlayer = 0;
    qDebug( "SatAppToneProvider::SymbianStopAudioPlayer <" );
}

// ---------------------------------------------------------
// SatAppCommandHandler::GetProfileParamsL
// Get and store settings from current profile 
// (other items were commented in a header).
// ---------------------------------------------------------
//
void SatAppToneProvider::GetProfileParamsL(
    int aTone /*= ESatToneNotSet*/,
    TDes* aToneName /*= NULL*/ )
{
    qDebug( "SatAppCommandHandler::GetProfileParamsL >" );
    MProfile* profile = NULL;
    MProfileEngine* engine = NULL;
    engine = CreateProfileEngineL();
    CleanupReleasePushL( *engine );

    profile = engine->ActiveProfileLC();

    const MProfileTones& tones = profile->ProfileTones();

    // Takes a current warning and gametones setting.
    const TProfileToneSettings& ts = tones.ToneSettings();
    mWarningAndPlayTones = ts.iWarningAndGameTones;
    mVolume = ts.iRingingVolume;
    
    qDebug( "SatAppCommandHandler::GetProfileParamsL \
        mVolume before mapping %d", mVolume );
    
    // Max volume from profile is KMaxVolumeFromProfile, Max volume from 
    // CMdaAudioToneUtility is different, maybe 10,000. So, 
    // rate = maxVolumeFromPlayer / KMaxVolumeFromProfile
    // User may never hear the TONE, because volume is too small.
    // iVolume times the rate make it can be heard.
    
    CMdaAudioToneUtility* toneUtl = CMdaAudioToneUtility::NewL( *this );
    TInt maxVolumeFromPlayer( toneUtl->MaxVolume() );
    mVolume *= maxVolumeFromPlayer / KMaxVolumeFromProfile;
    delete toneUtl;
    toneUtl = NULL;
    qDebug( "CSatUiViewAppUi::GetProfileParamsL \
        mVolume after mapping %d", mVolume );
    
    if ( ( ESatUserSelectedToneIncomingSms == aTone ) && ( aToneName ) )
        {
        qDebug("SatAppCommandHandler::GetProfileParamsL message tone");
        aToneName->Copy( tones.MessageAlertTone() );
    } else if( aToneName ) {
        qDebug("SatAppCommandHandler::GetProfileParamsL ring tone");
        aToneName->Copy( tones.RingingTone1() );
    }

    CleanupStack::PopAndDestroy(2); // engine, profile
    qDebug("SatAppCommandHandler::GetProfileParamsL <");
}

// ---------------------------------------------------------
// SatAppToneProvider::MatoPrepareComplete
// Preparation is complete -> Starts playing tone
// ---------------------------------------------------------
//
void SatAppToneProvider::MatoPrepareComplete(TInt aError)
{
    qDebug("SatAppToneProvider::MatoPrepareComplete \
        aError = %d >", aError);
    if (KErrNone == aError && mPlayer) {
        mPlayToneError = ESatSuccess;
        TTimeIntervalMicroSeconds zero(static_cast<TInt64>( 0 ));
        mPlayer->SetPriority(KAudioPriorityLowLevel,
               STATIC_CAST(TMdaPriorityPreference, KAudioPrefConfirmation));
        mPlayer->SetRepeats( KMdaAudioToneRepeatForever, zero );
        mPlayer->Play();
    } else {
        mPlayToneError = ESatFailure;
        stopPlayTone();
    }
    qDebug( "SatAppToneProvider::MatoPrepareComplete <" );
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::MatoPlayComplete
// Play complete -> Frees blocking function
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void SatAppToneProvider::MatoPlayComplete( TInt aError )
{
    qDebug("SatAppToneProvider::MatoPlayComplete >");
    if (KErrNone == aError && mPlayer) {
        qDebug("SatAppToneProvider::MatoPlayComplete play");
        mPlayer->Play();
    } else {
        qDebug( "SatAppToneProvider::MatoPlayComplete stop playing");
        // Stops playing if error.
        stopPlayTone();
    }
    qDebug("SatAppToneProvider::MatoPlayComplete error %d <", aError);
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::MapcInitComplete
// Initialisation complete -> starts playing the tone.
// ----------------------------------------------------------------------------
void SatAppToneProvider::MapcInitComplete( TInt aError, 
    const TTimeIntervalMicroSeconds& /*aDuration*/ )
{
    qDebug( "SatAppToneProvider::MapcInitComplete >" );
    // Audio player is initialised, so if there is no error, we can start 
    // playing the tone.
    if (KErrNone == aError && mAudioPlayer) {
        const TInt volume( Max(0, Min(mVolume, 
                           mAudioPlayer->MaxVolume())));
        qDebug("CSatUiViewAppUi::\
            MapcInitComplete SetVolume %d", volume );
        // Set volume according Settings. 
        mAudioPlayer->SetVolume( volume );
        mAudioPlayer->Play();
        qDebug( "SatAppToneProvider::MapcInitComplete Play" );
    } else {
        // Otherwise, we delete the initialised audio player.
        if ( mAudioPlayer ) {
            qDebug( "SatAppToneProvider::MapcInitComplete mAudioPlayer \
                          true" );
            delete mAudioPlayer;
            mAudioPlayer = 0;
        }

        // Remove also the note for play tone
        // If there was a duration for play tone, stop waiting
        stopPlayTone();

        qDebug( "SatAppToneProvider::MapcInitComplete Error %d", aError );
    }
    qDebug( "SatAppToneProvider::MapcInitComplete <" );
}

//-----------------------------------------------------------------------------
// SatAppToneProvider::MapcPlayComplete
// Deletes audio player after playing is completed.
// ----------------------------------------------------------------------------
void SatAppToneProvider::MapcPlayComplete( TInt /*aError*/ )
{
    qDebug( "SatAppToneProvider::MapcPlayComplete >" );

    // When playing is completed, deleting the audio player.
    if ( mAudioPlayer ) {
        qDebug("SatAppToneProvider::MapcPlayComplete delete mAudioPlayer");
        delete mAudioPlayer;
        mAudioPlayer = 0;
    }
    // Remove note after play has completed.
    stopPlayTone();
    qDebug( "SatAppToneProvider::MapcPlayComplete <" );
}


//End of file