diff -r 000000000000 -r 09774dfdd46b qtinternetradio/ui/src/irplaycontroller.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtinternetradio/ui/src/irplaycontroller.cpp Mon Apr 19 14:01:53 2010 +0300 @@ -0,0 +1,698 @@ +/* +* 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 +#include +#include + +#include "irplaycontroller.h" +#include "irapplication.h" +#include "irqmediaplayer.h" +#include "irabstractviewmanager.h" +#include "irqisdsdatastructure.h" +#include "irlastplayedstationinfo.h" +#include "irqnetworkcontroller.h" +#include "irqsonghistoryengine.h" +#include "irqmetadata.h" +#include "irqsettings.h" +#include "irqfavoritesdb.h" +#include "irqstatisticsreporter.h" +// public functions + +/* + * Description : constructor + */ +IRPlayController::IRPlayController(IRApplication* aApplication) : + iApplication(aApplication), + iMediaPlayer(new IRQMediaPlayer()), + iStatisticsReporter(NULL), + iConnectedFrom(EIRQIsds), + iSessionStarted(false), + iGetServerResult(false), + iBufferingDialog(NULL), + iNowPlayingPreset(new IRQPreset()), + iMetaData(NULL), + iSongHistoryEngine(IRQSongHistoryEngine::openInstance()), + iPlayState(EStopped), + iResuming(false), + iTryingBitrate(0), + iUrlArray(0), + iRealBitrate(0), + iLastError(EIRQErrorNone), + iStopReason(EIRQUnknownTermination) +{ + connectSignalSlot(); + iStatisticsReporter = iApplication->getStatisticsReporter(); +} + +/* + * Description : destructor + */ +IRPlayController::~IRPlayController() +{ + iApplication = NULL; + iPlayState = EStopped; + + delete iBufferingDialog; + iBufferingDialog = NULL; + + stop(EIRQUserTerminated); + delete iMediaPlayer; + iMediaPlayer = NULL; + + delete iNowPlayingPreset; + iNowPlayingPreset = NULL; + + delete iUrlArray; + iUrlArray = NULL; + + iMetaData = NULL; + + if (iSongHistoryEngine) + { + iSongHistoryEngine->closeInstance(); + iSongHistoryEngine = NULL; + } +} + +/* + * Description : connect to a channel specified by aPreset. + * Parameters : aPreset : the preset of the channel + */ +void IRPlayController::connectToChannel(IRQPreset *aPreset, IRQConnectedFrom aConnectedFrom) +{ + iConnectedFrom = aConnectedFrom; + if (!aPreset) + { + return; + } + + if (iMediaPlayer) + { + // sort the URL by ascending order and get all available rates. + // iAvailableBitrate is cleared in getAvailableBitrates(). + aPreset->sortURLArray(); + aPreset->getAvailableBitrates(iAvailableBitrate); + if (iAvailableBitrate.count() == 0) + { + return; + } + + int selectedBitRate = 0; + IRQPreferredQuality preferredQuality = iApplication->getSettings()->getPreferredQuality(); + switch(preferredQuality) + { + case EIRQStandardQuality: + selectedBitRate = iAvailableBitrate.first(); + break; + case EIRQHighQuality: + selectedBitRate = iAvailableBitrate.last(); + break; + default: + selectedBitRate = iAvailableBitrate.first(); + break; + } + + // get URL to play + iTryingBitrate = selectedBitRate; + *iNowPlayingPreset = *aPreset; + delete iUrlArray; + iUrlArray = NULL; + iUrlArray = iNowPlayingPreset->getURLsForBitrate(selectedBitRate); + if (iUrlArray) + { + QString url = iUrlArray->at(0); +#ifdef __WINS__ + if (iLastPlayedChannelName != aPreset->name) + { + emit initializeLogo(); + } + url = tr("http://172.28.189.104:8000"); + iLastPlayedChannelName = aPreset->name; +#else + if (iLastPlayedUrl != iUrlArray->at(0)) + { + emit initializeLogo(); + } +#endif + iLastPlayedUrl = url; + iResuming = false; + doPlay(url); + } + } +} + +/* + * Description : RESUME playing after play is stopped. + * Use the last played url as station's url. + */ +void IRPlayController::resume() +{ + qDebug("IRPlayController::resume(), Entering"); + if (iMediaPlayer && (EStopped == iPlayState)) + { + iResuming = true; + + if (iLastPlayedUrl != "") + { + qDebug("IRPlayController::resume(), iLastPlayedUrl is not empty, doPlay()"); + doPlay(iLastPlayedUrl); + } + } + qDebug("IRPlayController::resume(), Exiting"); +} + +/* + * Description : stop playing + */ +void IRPlayController::stop(IRQTerminatedType aStopReason) +{ + qDebug("IRPlayController::stop, Entering, aStopReason=%d", aStopReason); + if (iMediaPlayer) + { + iMediaPlayer->disableStereoEffect(); + + iMediaPlayer->stop(); + + if (EPlaying == iPlayState) + { + iStopReason = aStopReason; + // playingStarted is emitted while iPlaying is set to true, + // so when stop() is called and iPlaying is true, playingStopped + // should be emitted. + qDebug("IRPlayController::stop, emit playingStopped()"); + emit playingStopped(); + } + iPlayState = EStopped; + } + endSession(aStopReason); + qDebug("IRPlayController::stop, Exiting"); +} + +/* + * Description : End Session + */ +void IRPlayController::endSession(IRQTerminatedType aStopReason) +{ + if(iStatisticsReporter && iSessionStarted) + { + if(!iGetServerResult) + { + iStatisticsReporter->logServerResult(iLastPlayedUrl,EIRQPlayerErrorConnectingFailed); + } + iStatisticsReporter->sessionEnded(aStopReason); + iSessionStarted = false; + } +} + +/* + * Description : get current volume setting from media player or + * central repository + * Return : current volume + */ +int IRPlayController::getVolume() const +{ + if (EPlaying == iPlayState) + { + return iMediaPlayer->getVolume(); + } + else + { + return iApplication->getSettings()->getVolumeSetting(); + } +} + +/* + * Description : set volume to media player and central repository + * Parameters : aVolume : volume value, between 0 and 100 + */ +void IRPlayController::setVolume(int aVolume) +{ + if (EPlaying == iPlayState) + { + iMediaPlayer->setVolume(aVolume); + } + iApplication->getSettings()->setVolumeSetting(aVolume); +} + +/* + * Description : enable stereo effect + */ +void IRPlayController::enableStereo() +{ + if (iMediaPlayer) + { + iMediaPlayer->enableStereoEffect(); + } +} + +/* + * Description : disable stereo effect + */ +void IRPlayController::disableStereo() +{ + if (iMediaPlayer) + { + iMediaPlayer->disableStereoEffect(); + } +} + +/* + * Description : return the flag of playing state + * Return : true : playing is ongoing + * false : playing is stopped + */ +bool IRPlayController::isPlaying() const +{ + return (EPlaying == iPlayState); +} + +/* + * Description : return the flag of stopped state + * Return : true : playing is stopped + * false : playing is ongoing + */ +bool IRPlayController::isStopped() const +{ + return (EStopped == iPlayState); +} + +/* + * Description : return the now playing preset + * Return : pointer to the now playing preset + */ +IRQPreset * IRPlayController::getNowPlayingPreset() const +{ + return iNowPlayingPreset; +} + +/* + * Description : return current metadata + * Return : pointer to current metadata + */ +IRQMetaData * IRPlayController::getMetaData() const +{ + return iMetaData; +} + +IRQTerminatedType IRPlayController::getStopReason() const +{ + return iStopReason; +} + +/* + * Description : show a buffering dialog to inform user the buffering stage. + * If the dialog is not created yet, create first. + */ +void IRPlayController::createBufferingDialog(const QObject *aReceiver, const char *aFunc) +{ + if (NULL == iBufferingDialog) + { + iBufferingDialog = new HbProgressDialog(HbProgressDialog::ProgressDialog); + iBufferingDialog->setMinimum(0); + iBufferingDialog->setMaximum(100); + iBufferingDialog->setModal(true); + } + + //disconnect everything connected to signal cancelled() + iBufferingDialog->disconnect(SIGNAL(cancelled())); + + connect(iBufferingDialog, SIGNAL(cancelled()), aReceiver, aFunc); + iBufferingDialog->setProgressValue(0); + iBufferingDialog->setText("0%"); + iBufferingDialog->show(); +} + +/* + * Description : close the buffering dialog + */ +void IRPlayController::closeBufferingDialog() +{ + if (iBufferingDialog) + { + iBufferingDialog->close(); + delete iBufferingDialog; + iBufferingDialog = NULL; + } +} + +// slot functions + +/* + * Description : data connection has been established. Signal is emitted by media player. + * + */ +void IRPlayController::connectionEstablished(int aBitrate) +{ + if(iStatisticsReporter && iSessionStarted) + { + iStatisticsReporter->logServerResult(iLastPlayedUrl,EIRQErrorNone); + iGetServerResult = true; + iStatisticsReporter->markSessionStart(); + } + + iMetaData = NULL; + iRealBitrate = aBitrate; + + // update bitrate for user defined channel + if (0 == iNowPlayingPreset->type) + { + if (iTryingBitrate != iRealBitrate) + { + iNowPlayingPreset->setUrlBitrate(0,iRealBitrate); + //when bitrate is available, it should be written to favorites db + iApplication->getFavoritesDB()->replaceUserDefinedPreset(*iNowPlayingPreset); + iTryingBitrate = iRealBitrate; + } + } +} + +/* + * Description : error occurred in media player. Signal is emitted by media player. + * Parameters : aError : error value + */ +void IRPlayController::errorOccured(IRQError aError) +{ + iLastError = aError; + + QTimer::singleShot(1, this, SLOT(handleError())); +} + +/* + * Description : handle the error async. + */ +void IRPlayController::handleError() +{ + qDebug("IRPlayController::handleError(), Entering, iLastError - %d", iLastError); + switch (iLastError) + { + case EIRQPlayerErrorServerFull: + case EIRQPlayerErrorTimeOut: + case EIRQPlayerErrorConnectingFailed: + if(iStatisticsReporter) + { + iStatisticsReporter->logServerResult(iLastPlayedUrl,iLastError); + iGetServerResult = true; + } + + // if there's NO other URL to try, show warning. + if (iNowPlayingPreset->getChannelURLCount() == 1) + { + endSession(EIRQNoConnectionToServer); + break; + } + + if (iResuming) + { + HbMessageBox note(tr("Connecting failed, try next URL"), HbMessageBox::MessageTypeInformation); + note.exec(); + connectToChannel(iNowPlayingPreset,iConnectedFrom); + iResuming = false; + return; + } + + // try next + if (true == playNextUrl()) + { + return; + } + else + { + endSession(EIRQNoConnectionToServer); + } + break; + + case EIRQPlayerErrorConnectionLost: + qDebug("IRPlayController::handleError, connection lost"); + stop(EIRQNoConnectionToServer); + break; + + case EIRQPlayerErrorGeneral: + case EIRQPlayerErrorAudioDeviceLost: + default: + stop(EIRQUnknownTermination); + break; + } + + closeBufferingDialog(); + + createNote(); + qDebug("IRPlayController::handleError(), Exiting"); +} + +/* + * Description : buffering process has updated, change the display of buffering dialog. + * If aProress is 100, buffering is complete, now playing view needs to + * be shown to user. + * Parameters : aProgress : progress value, between 0 and 100. + */ +void IRPlayController::updateProgress(int aProgress) +{ + /* we added this condition for sometimes, the function will be called + * when the state is playing. reference cr_9010 + */ + if( iBufferingDialog && EBuffering == iPlayState ) + { + iBufferingDialog->setProgressValue(aProgress); + iBufferingDialog->setText(QString("%1%").arg(aProgress)); + } + + if (100 == aProgress) + { + closeBufferingDialog(); + + //updateProgress(100) sometimes can be called more than one time, to improve performance, + //we only need to do the following work once. + if (EBuffering == iPlayState) + { + iApplication->getViewManager()->activateView(EIRView_PlayingView); + iPlayState = EPlaying; + + //update last played station + IRLastPlayedStationInfo *lastPlayedStationInfo = iApplication->getLastPlayedStationInfo(); + lastPlayedStationInfo->updateLastPlayedStation(iNowPlayingPreset,iConnectedFrom); + lastPlayedStationInfo->commitLastPlayedStation(); + + //increase the played times of current preset + iApplication->getFavoritesDB()->increasePlayedTimes(*iNowPlayingPreset); + + emit playingStarted(); + + // if the metadata is available, show it. + emit metaDataAvailable(iMetaData); + + // Save the station information to database + IRQMetaData tmpMetaData; + tmpMetaData.setBitrate(iRealBitrate); + tmpMetaData.setStreamUrl(iLastPlayedUrl); + iSongHistoryEngine->handleMetaDataReceived(tmpMetaData, *iNowPlayingPreset); + // open stereo according to settings + if (1 == iApplication->getSettings()->getStereoMode()) + { + iMediaPlayer->enableStereoEffect(); + } + } + } +} + +/* + * Description : get volume value from application setting. media player use the value + * to set volume. + * Parameters : aVolume : volume value + */ +void IRPlayController::fetchVolume(int &aVolume) +{ + aVolume = iApplication->getSettings()->getVolumeSetting(); +} + +/* + * Description : handle the receiption of metadata. Notify now playing view to update display + * Parameters : aIRmetaData : the metadata object + */ +void IRPlayController::handleMetaDataReceived(IRQMetaData& aIRmetaData) +{ + + + iMetaData = &aIRmetaData; + //TO DO: there maybe a potential bug when the user cancel the play, + if ((aIRmetaData.getSongName().trimmed() != "") + || (aIRmetaData.getArtistName().trimmed() != "")) + { + //when we are play the musicplayer and get the metadata from lower layer, we save the + //song's metadata into the db. After we save it to db, we emit the next signal to notify the UI + iSongHistoryEngine->handleSongMetaDataReceived(*iMetaData, + iNowPlayingPreset->musicStoreStatus); + } + + if (EPlaying == iPlayState) + { + // This signal will cause addBanner() work. Sometimes the metadata will come before + // the buffering is 100%, we need to avoid to show playing banner before 100% buffering. + emit metaDataAvailable(iMetaData); + } +} + +/* + * Description : during buffering stage, cancel playing request + */ +void IRPlayController::cancelBuffering() +{ + stop(EIRQUserTerminated); + if (!iResuming && EIRView_PlayingView == iApplication->getViewManager()->currentViewId()) + { + iApplication->getViewManager()->backToPreviousView(); + } +} + +// private functions + +/* + * Description : show a note to user to inform that error occured. + * + */ +void IRPlayController::createNote(const QString &aNote) +{ + HbMessageBox note(aNote, HbMessageBox::MessageTypeWarning); + note.setPrimaryAction(NULL); + note.exec(); +} + +/* + * Description : establish the signal&slot connection between media player and play controller + */ +void IRPlayController::connectSignalSlot() +{ + connect(iMediaPlayer, SIGNAL(connectionEstablished(int)), this, SLOT(connectionEstablished(int))); + connect(iMediaPlayer, SIGNAL(errorOccured(IRQError)), this, SLOT(errorOccured(IRQError))); + connect(iMediaPlayer, SIGNAL(percentageBuffered(int)), this, SLOT(updateProgress(int))); + connect(iMediaPlayer, SIGNAL(volumeExpected(int&)), this, SLOT(fetchVolume(int&))); + connect(iMediaPlayer, SIGNAL(metaDataReceived(IRQMetaData&)), + this, SLOT(handleMetaDataReceived(IRQMetaData&))); +} + +/* + * Description : try to play the next url in the preset. + * return value: true: it will play next URL; false, not. + */ +bool IRPlayController::playNextUrl() +{ + // remove the first url from iUrlArray + iUrlArray->removeFirst(); + + if (iUrlArray->isEmpty()) // try next bitrate + { + int index = iAvailableBitrate.indexOf(iTryingBitrate); + if (-1 != index) + { + bool tryingContinue = true; + IRQPreferredQuality preferredQuality = iApplication->getSettings()->getPreferredQuality(); + switch(preferredQuality) + { + case EIRQHighQuality: + if(index > 0) + { + iTryingBitrate = iAvailableBitrate.at(--index); + } + else + { + tryingContinue = false; + } + break; + + case EIRQStandardQuality: + default: + if(index < (iAvailableBitrate.count()-1)) + { + iTryingBitrate = iAvailableBitrate.at(++index); + } + else + { + tryingContinue = false; + } + break; + } + + if(tryingContinue) + { + HbMessageBox note(tr("Connecting failed, try next URL"), HbMessageBox::MessageTypeInformation); + note.exec(); + delete iUrlArray; + iUrlArray = iNowPlayingPreset->getURLsForBitrate(iTryingBitrate); + iLastPlayedUrl = iUrlArray->at(0); + doPlay(iLastPlayedUrl); + return true; + } + } + + } + else // try next url in iUrlArray + { + iLastPlayedUrl = iUrlArray->at(0); + doPlay(iLastPlayedUrl); + + HbMessageBox note(tr("Connecting failed, try next URL"), HbMessageBox::MessageTypeInformation); + note.exec(); + + return true; + } + + return false; +} + +/* + * Description : complete the play action + */ +void IRPlayController::doPlay(const QString& aUrl) +{ + // stop player, disable stereo effect, emit playstopped signal + stop(EIRQUserTerminated); + + //call getIAPId() every time before refering to it, because in ALR, the access point can + //be changed + unsigned long apId = 0; + iApplication->getNetworkController()->getIAPId(apId); + qDebug("IRPlayController::doPlay, access point : %d", apId); + iMediaPlayer->playStation(aUrl, apId); + iPlayState = EBuffering; + startSession(); + createBufferingDialog(this, SLOT(cancelBuffering())); +} + +/* + * Description : start a session + */ +void IRPlayController::startSession() +{ + iGetServerResult = false; + + int channelId = 0; + if(iNowPlayingPreset) + { + channelId = iNowPlayingPreset->presetId; + } + + if(iStatisticsReporter && !iSessionStarted) + { + iSessionStarted = iStatisticsReporter->sessionStarted(channelId,iConnectedFrom); + } +} + +#ifdef _DEBUG +int IRPlayController::bitrateTrying() const +{ + return iTryingBitrate; +} +#endif