summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/phonon/mmf/abstractmediaplayer.cpp')
-rw-r--r--src/3rdparty/phonon/mmf/abstractmediaplayer.cpp226
1 files changed, 150 insertions, 76 deletions
diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
index 99e96cd..544762a 100644
--- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
+++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
@@ -20,6 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "abstractmediaplayer.h"
#include "defs.h"
+#include "mediaobject.h"
#include "utils.h"
QT_BEGIN_NAMESPACE
@@ -36,27 +37,26 @@ using namespace Phonon::MMF;
//-----------------------------------------------------------------------------
const int NullMaxVolume = -1;
+const int BufferStatusTimerInterval = 100; // ms
//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::AbstractMediaPlayer::AbstractMediaPlayer() :
- m_playPending(false)
- , m_tickTimer(new QTimer(this))
- , m_mmfMaxVolume(NullMaxVolume)
-{
- connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
-}
-
-MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) :
- AbstractPlayer(player)
+MMF::AbstractMediaPlayer::AbstractMediaPlayer
+ (MediaObject *parent, const AbstractPlayer *player)
+ : AbstractPlayer(player)
+ , m_parent(parent)
, m_playPending(false)
- , m_tickTimer(new QTimer(this))
+ , m_positionTimer(new QTimer(this))
+ , m_bufferStatusTimer(new QTimer(this))
, m_mmfMaxVolume(NullMaxVolume)
+ , m_prefinishMarkSent(false)
+ , m_aboutToFinishSent(false)
{
- connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
+ connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick()));
+ connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick()));
}
//-----------------------------------------------------------------------------
@@ -70,7 +70,7 @@ void MMF::AbstractMediaPlayer::play()
switch (privateState()) {
case GroundState:
- setError(NormalError);
+ setError(tr("Not ready to play"));
break;
case LoadingState:
@@ -80,7 +80,7 @@ void MMF::AbstractMediaPlayer::play()
case StoppedState:
case PausedState:
doPlay();
- startTickTimer();
+ startPositionTimer();
changeState(PlayingState);
break;
@@ -104,21 +104,22 @@ void MMF::AbstractMediaPlayer::pause()
TRACE_ENTRY("state %d", privateState());
m_playPending = false;
+ stopTimers();
switch (privateState()) {
case GroundState:
case LoadingState:
case PausedState:
+ case StoppedState:
// Do nothing
break;
- case StoppedState:
case PlayingState:
- case ErrorState:
case BufferingState:
- doPause();
- stopTickTimer();
changeState(PausedState);
+ // Fall through
+ case ErrorState:
+ doPause();
break;
// Protection against adding new states and forgetting to update this switch
@@ -135,6 +136,7 @@ void MMF::AbstractMediaPlayer::stop()
TRACE_ENTRY("state %d", privateState());
m_playPending = false;
+ stopTimers();
switch (privateState()) {
case GroundState:
@@ -148,7 +150,6 @@ void MMF::AbstractMediaPlayer::stop()
case BufferingState:
case PausedState:
doStop();
- stopTickTimer();
changeState(StoppedState);
break;
@@ -173,14 +174,21 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms)
case PlayingState:
case LoadingState:
{
- const bool tickTimerWasRunning = m_tickTimer->isActive();
- stopTickTimer();
+ bool wasPlaying = false;
+ if (state() == PlayingState) {
+ stopPositionTimer();
+ doPause();
+ wasPlaying = true;
+ }
doSeek(ms);
+ resetMarksIfRewound();
- if (tickTimerWasRunning) {
- startTickTimer();
+ if(wasPlaying && state() != ErrorState) {
+ doPlay();
+ startPositionTimer();
}
+
break;
}
case BufferingState:
@@ -203,17 +211,12 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);
- m_tickTimer->setInterval(interval);
+ m_positionTimer->setInterval(interval);
TRACE_EXIT_0();
}
-MediaSource MMF::AbstractMediaPlayer::source() const
-{
- return m_source;
-}
-
-void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file)
+void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file)
{
TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
TRACE_ENTRY("state %d source.type %d", privateState(), source.type());
@@ -221,15 +224,14 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f
close();
changeState(GroundState);
- // TODO: is it correct to assign even if the media type is not supported in
- // the switch statement below?
- m_source = source;
-
TInt symbianErr = KErrNone;
+ QString errorMessage;
- switch (m_source.type()) {
+ switch (source.type()) {
case MediaSource::LocalFile: {
symbianErr = openFile(file);
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening file");
break;
}
@@ -238,68 +240,76 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f
if (url.scheme() == QLatin1String("file")) {
symbianErr = openFile(file);
- }
- else {
- TRACE_0("Source type not supported");
- // TODO: support network URLs
- symbianErr = KErrNotSupported;
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening file");
+ } else {
+ symbianErr = openUrl(url.toString());
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening URL");
}
break;
}
- case MediaSource::Invalid:
- case MediaSource::Disc:
- case MediaSource::Stream:
- TRACE_0("Source type not supported");
- symbianErr = KErrNotSupported;
- break;
-
- case MediaSource::Empty:
- TRACE_0("Empty source - doing nothing");
- TRACE_EXIT_0();
- return;
+ // Other source types are handled in MediaObject::createPlayer
- // Protection against adding new media types and forgetting to update this switch
+ // Protection against adding new media types and forgetting to update this switch
default:
TRACE_PANIC(InvalidMediaTypePanic);
}
- if (KErrNone == symbianErr) {
+ if (errorMessage.isEmpty()) {
changeState(LoadingState);
} else {
- TRACE("error %d", symbianErr)
- setError(NormalError);
+ if (symbianErr)
+ setError(errorMessage, symbianErr);
+ else
+ setError(errorMessage);
}
TRACE_EXIT_0();
}
-void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source)
+void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
{
- TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi);
+ TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
TRACE_ENTRY("state %d", privateState());
- // TODO: handle 'next source'
-
- m_nextSource = source;
- Q_UNUSED(source);
+ AbstractPlayer::volumeChanged(volume);
+ doVolumeChanged();
TRACE_EXIT_0();
}
+//-----------------------------------------------------------------------------
+// Private functions
+//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
+void MMF::AbstractMediaPlayer::startPositionTimer()
{
- TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
- TRACE_ENTRY("state %d", privateState());
+ m_positionTimer->start(tickInterval());
+}
- AbstractPlayer::volumeChanged(volume);
- doVolumeChanged();
+void MMF::AbstractMediaPlayer::stopPositionTimer()
+{
+ m_positionTimer->stop();
+}
- TRACE_EXIT_0();
+void MMF::AbstractMediaPlayer::startBufferStatusTimer()
+{
+ m_bufferStatusTimer->start(BufferStatusTimerInterval);
}
+void MMF::AbstractMediaPlayer::stopBufferStatusTimer()
+{
+ m_bufferStatusTimer->stop();
+}
+
+void MMF::AbstractMediaPlayer::stopTimers()
+{
+ stopPositionTimer();
+ stopBufferStatusTimer();
+}
void MMF::AbstractMediaPlayer::doVolumeChanged()
{
@@ -318,7 +328,7 @@ void MMF::AbstractMediaPlayer::doVolumeChanged()
const int err = setDeviceVolume(volume);
if (KErrNone != err) {
- setError(NormalError);
+ setError(tr("Setting volume failed"), err);
}
break;
}
@@ -330,19 +340,23 @@ void MMF::AbstractMediaPlayer::doVolumeChanged()
}
}
-
//-----------------------------------------------------------------------------
// Protected functions
//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::startTickTimer()
+void MMF::AbstractMediaPlayer::bufferingStarted()
{
- m_tickTimer->start(tickInterval());
+ m_stateBeforeBuffering = privateState();
+ changeState(BufferingState);
+ bufferStatusTick();
+ startBufferStatusTimer();
}
-void MMF::AbstractMediaPlayer::stopTickTimer()
+void MMF::AbstractMediaPlayer::bufferingComplete()
{
- m_tickTimer->stop();
+ stopBufferStatusTimer();
+ emit MMF::AbstractPlayer::bufferStatus(100);
+ changeState(m_stateBeforeBuffering);
}
void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
@@ -351,6 +365,23 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
doVolumeChanged();
}
+void MMF::AbstractMediaPlayer::playbackComplete(int error)
+{
+ stopTimers();
+
+ if (KErrNone == error) {
+ changeState(StoppedState);
+
+ // MediaObject::switchToNextSource deletes the current player, so we
+ // call it via delayed slot invokation to ensure that this object does
+ // not get deleted during execution of a member function.
+ QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection);
+ }
+ else {
+ setError(tr("Playback complete"), error);
+ }
+}
+
qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
{
return in.Int64() / 1000;
@@ -360,10 +391,53 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds
// Slots
//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::tick()
+void MMF::AbstractMediaPlayer::positionTick()
+{
+ emitMarksIfReached();
+
+ const qint64 current = currentTime();
+ emit MMF::AbstractPlayer::tick(current);
+}
+
+void MMF::AbstractMediaPlayer::emitMarksIfReached()
+{
+ const qint64 current = currentTime();
+ const qint64 total = totalTime();
+ const qint64 remaining = total - current;
+
+ if (prefinishMark() && !m_prefinishMarkSent) {
+ if (remaining < (prefinishMark() + tickInterval()/2)) {
+ m_prefinishMarkSent = true;
+ emit prefinishMarkReached(remaining);
+ }
+ }
+
+ if (!m_aboutToFinishSent) {
+ if (remaining < tickInterval()) {
+ m_aboutToFinishSent = true;
+ emit aboutToFinish();
+ }
+ }
+}
+
+void MMF::AbstractMediaPlayer::resetMarksIfRewound()
+{
+ const qint64 current = currentTime();
+ const qint64 total = totalTime();
+ const qint64 remaining = total - current;
+
+ if (prefinishMark() && m_prefinishMarkSent)
+ if (remaining >= (prefinishMark() + tickInterval()/2))
+ m_prefinishMarkSent = false;
+
+ if (m_aboutToFinishSent)
+ if (remaining >= tickInterval())
+ m_aboutToFinishSent = false;
+}
+
+void MMF::AbstractMediaPlayer::bufferStatusTick()
{
- // For the MWC compiler, we need to qualify the base class.
- emit MMF::AbstractPlayer::tick(currentTime());
+ emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
}
void MMF::AbstractMediaPlayer::changeState(PrivateState newState)