--- /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 <hbprogressdialog.h>
+#include <hbmessagebox.h>
+#include <QTimer>
+
+#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