summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGareth Stockwell <gareth.stockwell@sosco.com>2009-08-18 08:12:47 (GMT)
committerGareth Stockwell <gareth.stockwell@sosco.com>2009-08-18 08:15:29 (GMT)
commit008d464ea90a0a33f16bd6ce29563e7dd206b91f (patch)
tree7156f7124e8b520b1559e4cce1f0f2476cf075e6
parent427c415d876d57042a55e8b66730888512ac0ed1 (diff)
parent6b7603a0a2fed844b1264d8deb0ce78b110858c4 (diff)
downloadQt-008d464ea90a0a33f16bd6ce29563e7dd206b91f.zip
Qt-008d464ea90a0a33f16bd6ce29563e7dd206b91f.tar.gz
Qt-008d464ea90a0a33f16bd6ce29563e7dd206b91f.tar.bz2
Merged recognizer changes with abstraction for audio / video playback.
Audio playback now working to the same extent as prior to the abstraction, with one regression: the initial volume level in the UI is set to zero, although playback is audible. Some cleanup is required: - Functionality common to AudioPlayer and VideoPlayer (e.g. tick timer, changeState function) should be moved into AbstractPlayer. - Files may be opened by multiple instances of MediaObject at at time. For example, the musicplayer example app uses one instance to read file metadata, and one for the actual playback. In order to avoid KErrInUse errors from the file server, files must be opened with an EShare* flag and passed around by handle. At present this is done in a slightly hacky way (i.e. AbstractPlayer::setSource is renamed to setFileSource). - The pointer held by MediaObject::m_player must be checked for nullness in many of the public API calls. This could be made cleaner by implementing a stub derivation of AbstractPlayer, which returns sensible default values. Note that, if functionality such as tick timer handling is going to be pushed upwards from AudioPlayer / VideoPlayer, we should add an intermediate class to the hierarchy so that the overhead of constructing DummyPlayer objects is minimised. At present, media type (audio / video) is only recognised from file streams - this needs to be extended to include HTTP streaming aswell.
-rw-r--r--src/3rdparty/phonon/mmf/abstractplayer.h72
-rw-r--r--src/3rdparty/phonon/mmf/audiooutput.cpp2
-rw-r--r--src/3rdparty/phonon/mmf/audioplayer.cpp636
-rw-r--r--src/3rdparty/phonon/mmf/audioplayer.h179
-rw-r--r--src/3rdparty/phonon/mmf/backend.cpp2
-rw-r--r--src/3rdparty/phonon/mmf/mediaobject.cpp697
-rw-r--r--src/3rdparty/phonon/mmf/mediaobject.h99
-rw-r--r--src/3rdparty/phonon/mmf/utils.h2
-rw-r--r--src/3rdparty/phonon/mmf/videoplayer.cpp577
-rw-r--r--src/3rdparty/phonon/mmf/videoplayer.h153
-rw-r--r--src/3rdparty/phonon/phonon/factory.cpp6
-rw-r--r--src/plugins/phonon/mmf/mmf.pro33
12 files changed, 1886 insertions, 572 deletions
diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h
new file mode 100644
index 0000000..418b896
--- /dev/null
+++ b/src/3rdparty/phonon/mmf/abstractplayer.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MMF_ABSTRACTPLAYER_H
+#define PHONON_MMF_ABSTRACTPLAYER_H
+
+#include <QObject>
+#include <Phonon/phononnamespace.h>
+#include <Phonon/MediaSource.h>
+
+class RFile;
+
+namespace Phonon
+{
+ namespace MMF
+ {
+ class AudioOutput;
+
+ class AbstractPlayer : public QObject
+ {
+ public:
+ virtual void play() = 0;
+ virtual void pause() = 0;
+ virtual void stop() = 0;
+ virtual void seek(qint64 milliseconds) = 0;
+ virtual qint32 tickInterval() const = 0;
+ virtual void setTickInterval(qint32) = 0;
+ virtual bool hasVideo() const = 0;
+ virtual bool isSeekable() const = 0;
+ virtual qint64 currentTime() const = 0;
+ virtual Phonon::State state() const = 0;
+ virtual QString errorString() const = 0;
+ virtual Phonon::ErrorType errorType() const = 0;
+ virtual qint64 totalTime() const = 0;
+ virtual Phonon::MediaSource source() const = 0;
+
+ // This is a temporary hack to work around KErrInUse from MMF
+ // client utility OpenFileL calls
+ //virtual void setSource(const Phonon::MediaSource &) = 0;
+ virtual void setFileSource
+ (const Phonon::MediaSource&, RFile&) = 0;
+
+ virtual void setNextSource(const Phonon::MediaSource &) = 0;
+
+ virtual void setTransitionTime(qint32) = 0;
+ virtual qint32 transitionTime() const = 0;
+ virtual qint32 prefinishMark() const = 0;
+ virtual void setPrefinishMark(qint32) = 0;
+ virtual bool setVolume(qreal) = 0;
+ virtual qreal volume() const = 0;
+ virtual void setAudioOutput(AudioOutput *) = 0;
+ };
+ }
+}
+
+#endif
+
diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp
index 9c8cb6b..d8758fd 100644
--- a/src/3rdparty/phonon/mmf/audiooutput.cpp
+++ b/src/3rdparty/phonon/mmf/audiooutput.cpp
@@ -16,6 +16,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <e32debug.h>
+
#include "mediaobject.h"
#include "audiooutput.h"
#include "utils.h"
diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp
new file mode 100644
index 0000000..ce6a5f3
--- /dev/null
+++ b/src/3rdparty/phonon/mmf/audioplayer.cpp
@@ -0,0 +1,636 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <QUrl>
+#include <QTimer>
+#include <private/qcore_symbian_p.h>
+
+#include "audioplayer.h"
+#include "audiooutput.h"
+#include "utils.h"
+
+using namespace Phonon;
+using namespace Phonon::MMF;
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+const qint32 DefaultTickInterval = 20;
+const int NullMaxVolume = -1;
+
+
+//-----------------------------------------------------------------------------
+// Constructor / destructor
+//-----------------------------------------------------------------------------
+
+MMF::AudioPlayer::AudioPlayer() : m_player(NULL)
+ , m_audioOutput(NULL)
+ , m_error(NoError)
+ , m_state(GroundState)
+ , m_tickInterval(DefaultTickInterval)
+ , m_tickTimer(NULL)
+ , m_volume(0.0)
+ , m_maxVolume(NullMaxVolume)
+{
+ TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi);
+ TRACE_ENTRY_0();
+
+ Q_UNUSED(parent);
+
+ // TODO: should leaves be trapped in the constructor?
+ m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone);
+
+ m_tickTimer = new QTimer(this);
+ connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick()));
+
+ TRACE_EXIT_0();
+}
+
+MMF::AudioPlayer::~AudioPlayer()
+{
+ TRACE_CONTEXT(AudioPlayer::~AudioPlayer, EAudioApi);
+ TRACE_ENTRY_0();
+
+ delete m_tickTimer;
+ delete m_player;
+
+ TRACE_EXIT_0();
+}
+
+//-----------------------------------------------------------------------------
+// AudioPlayerInterface
+//-----------------------------------------------------------------------------
+
+void MMF::AudioPlayer::play()
+{
+ TRACE_CONTEXT(AudioPlayer::play, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ // Is this the correct error? Really we want 'NotReadyError'
+ m_error = NormalError;
+ changeState(ErrorState);
+ break;
+
+ case StoppedState:
+ case PausedState:
+ m_player->Play();
+ m_tickTimer->start(m_tickInterval);
+ changeState(PlayingState);
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+}
+
+void MMF::AudioPlayer::pause()
+{
+ TRACE_CONTEXT(AudioPlayer::pause, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case StoppedState:
+ case PausedState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ m_player->Pause();
+ m_tickTimer->stop();
+ changeState(PausedState);
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+}
+
+void MMF::AudioPlayer::stop()
+{
+ TRACE_CONTEXT(AudioPlayer::stop, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case StoppedState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ case PausedState:
+ m_player->Stop();
+ m_tickTimer->stop();
+ changeState(StoppedState);
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+}
+
+void MMF::AudioPlayer::seek(qint64 ms)
+{
+ TRACE_CONTEXT(AudioPlayer::seek, EAudioApi);
+ TRACE_ENTRY("state %d pos %Ld", m_state, ms);
+
+ m_player->SetPosition(TTimeIntervalMicroSeconds(ms));
+
+ TRACE_EXIT_0();
+}
+
+qint32 MMF::AudioPlayer::tickInterval() const
+{
+ TRACE_CONTEXT(AudioPlayer::tickInterval, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_RETURN("%d", m_tickInterval);
+}
+
+void MMF::AudioPlayer::setTickInterval(qint32 interval)
+{
+ TRACE_CONTEXT(AudioPlayer::setTickInterval, EAudioApi);
+ TRACE_ENTRY("state %d m_interval %d interval %d", m_state, m_tickInterval, interval);
+
+ m_tickInterval = interval;
+ m_tickTimer->setInterval(interval);
+
+ TRACE_EXIT_0();
+}
+
+bool MMF::AudioPlayer::hasVideo() const
+{
+ TRACE_CONTEXT(AudioPlayer::hasVideo, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: re-factor this class so that audio playback and video playback are
+ // delegated to separate classes, which internally hoat a
+ // CMdaAudioPlayerUtility / CVideoPlayerUtility instance as appropriate.
+
+ TRACE_RETURN("%d", false);
+}
+
+bool MMF::AudioPlayer::isSeekable() const
+{
+ TRACE_CONTEXT(AudioPlayer::isSeekable, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_RETURN("%d", true);
+}
+
+Phonon::State MMF::AudioPlayer::state() const
+{
+ TRACE_CONTEXT(AudioPlayer::state, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const Phonon::State result = phononState(m_state);
+
+ TRACE_RETURN("%d", result);
+}
+
+qint64 MMF::AudioPlayer::currentTime() const
+{
+ TRACE_CONTEXT(AudioPlayer::currentTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TTimeIntervalMicroSeconds us;
+ const TInt err = m_player->GetPosition(us);
+
+ qint64 result = -1;
+
+ if(KErrNone == err) {
+ result = toMilliSeconds(us);
+ }
+
+ TRACE_RETURN("%Ld", result);
+}
+
+QString MMF::AudioPlayer::errorString() const
+{
+ TRACE_CONTEXT(AudioPlayer::errorString, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_EXIT_0();
+ // TODO: put in proper error strings
+ QString result;
+ return result;
+}
+
+Phonon::ErrorType MMF::AudioPlayer::errorType() const
+{
+ TRACE_CONTEXT(AudioPlayer::errorType, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const Phonon::ErrorType result = (ErrorState == m_state)
+ ? m_error : NoError;
+
+ TRACE_RETURN("%d", result);
+}
+
+qint64 MMF::AudioPlayer::totalTime() const
+{
+ TRACE_CONTEXT(AudioPlayer::totalTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const qint64 result = toMilliSeconds(m_player->Duration());
+
+ TRACE_RETURN("%Ld", result);
+}
+
+MediaSource MMF::AudioPlayer::source() const
+{
+ TRACE_CONTEXT(AudioPlayer::source, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_EXIT_0();
+ return m_mediaSource;
+}
+
+void MMF::AudioPlayer::setFileSource(const MediaSource &source, RFile& file)
+{
+ TRACE_CONTEXT(AudioPlayer::setSource, EAudioApi);
+ TRACE_ENTRY("state %d source.type %d", m_state, source.type());
+
+ m_player->Close();
+ changeState(GroundState);
+
+ // TODO: is it correct to assign even if the media type is not supported in
+ // the switch statement below?
+ m_mediaSource = source;
+
+ TInt symbianErr = KErrNone;
+
+ switch(m_mediaSource.type())
+ {
+ case MediaSource::LocalFile:
+ {
+ // TODO: work out whose responsibility it is to ensure that paths
+ // are Symbian-style, i.e. have backslashes for path delimiters.
+ // Until then, use this utility function...
+ const QHBufC filename = Utils::symbianFilename(m_mediaSource.fileName());
+ //TRAP(symbianErr, m_player->OpenFileL(*filename));
+
+ // Open using shared filehandle
+ // This is a temporary hack to work around KErrInUse from MMF
+ // client utility OpenFileL calls
+ TRAP(symbianErr, m_player->OpenFileL(file));
+ break;
+ }
+
+ case MediaSource::Url:
+ {
+ const QHBufC filename(m_mediaSource.url().toString());
+ TRAP(symbianErr, m_player->OpenUrlL(*filename));
+ break;
+ }
+
+ case MediaSource::Invalid:
+ case MediaSource::Disc:
+ case MediaSource::Stream:
+ symbianErr = KErrNotSupported;
+ break;
+
+ case MediaSource::Empty:
+ TRACE_EXIT_0();
+ return;
+
+ // Protection against adding new media types and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidMediaTypePanic);
+ }
+
+ if(KErrNone == symbianErr)
+ {
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+ // There appears to be a bug in the CDrmPlayerUtility implementation (at least
+ // in S60 5.x) whereby the player does not check whether the loading observer
+ // pointer is null before dereferencing it. Therefore we must register for
+ // loading notification, even though we do nothing in the callback functions.
+ m_player->RegisterForAudioLoadingNotification(*this);
+#endif
+ changeState(LoadingState);
+ }
+ else
+ {
+ // TODO: do something with the value of symbianErr?
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+
+ TRACE_EXIT_0();
+}
+
+void MMF::AudioPlayer::setNextSource(const MediaSource &source)
+{
+ TRACE_CONTEXT(AudioPlayer::setNextSource, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: handle 'next source'
+
+ m_nextSource = source;
+ Q_UNUSED(source);
+
+ TRACE_EXIT_0();
+}
+
+qint32 MMF::AudioPlayer::prefinishMark() const
+{
+ TRACE_CONTEXT(AudioPlayer::prefinishMark, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: implement prefinish mark
+ const qint32 result = 0;
+ TRACE_RETURN("%d", result);
+}
+
+void MMF::AudioPlayer::setPrefinishMark(qint32 mark)
+{
+ TRACE_CONTEXT(AudioPlayer::setPrefinishMark, EAudioApi);
+ TRACE_ENTRY("state %d mark %d", m_state, mark);
+ Q_UNUSED(mark); // to silence warnings in release builds
+
+ // TODO: implement prefinish mark
+
+ TRACE_EXIT_0();
+}
+
+qint32 MMF::AudioPlayer::transitionTime() const
+{
+ TRACE_CONTEXT(AudioPlayer::transitionTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: implement transition time
+ const qint32 result = 0;
+ TRACE_RETURN("%d", result);
+}
+
+void MMF::AudioPlayer::setTransitionTime(qint32 time)
+{
+ TRACE_CONTEXT(AudioPlayer::setTransitionTime, EAudioApi);
+ TRACE_ENTRY("state %d time %d", m_state, time);
+ Q_UNUSED(time); // to silence warnings in release builds
+
+ // TODO: implement transition time
+
+ TRACE_EXIT_0();
+}
+
+
+//-----------------------------------------------------------------------------
+// Symbian multimedia client observer callbacks
+//-----------------------------------------------------------------------------
+
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+void MMF::AudioPlayer::MdapcInitComplete(TInt aError,
+ const TTimeIntervalMicroSeconds &)
+#else
+void MMF::AudioPlayer::MapcInitComplete(TInt aError,
+ const TTimeIntervalMicroSeconds &)
+#endif
+{
+ TRACE_CONTEXT(AudioPlayer::MapcInitComplete, EAudioInternal);
+ TRACE_ENTRY("state %d error %d", m_state, aError);
+
+ __ASSERT_ALWAYS(LoadingState == m_state, Utils::panic(InvalidStatePanic));
+
+ if(KErrNone == aError)
+ {
+ TInt volume = 0;
+ aError = m_player->GetVolume(volume);
+ if(KErrNone == aError)
+ {
+ m_maxVolume = m_player->MaxVolume();
+ m_volume = static_cast<qreal>(volume) / m_maxVolume;
+
+ if(m_audioOutput)
+ {
+ // Trigger AudioOutput signal
+ m_audioOutput->triggerVolumeChanged(m_volume);
+ }
+
+ emit totalTimeChanged();
+ changeState(StoppedState);
+ }
+ }
+ else
+ {
+ // TODO: set different error states according to value of aError?
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+
+ TRACE_EXIT_0();
+}
+
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+void MMF::AudioPlayer::MdapcPlayComplete(TInt aError)
+#else
+void MMF::AudioPlayer::MapcPlayComplete(TInt aError)
+#endif
+{
+ TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal);
+ TRACE_ENTRY("state %d error %d", m_state, aError);
+
+ m_tickTimer->stop();
+
+ if(KErrNone == aError)
+ {
+ changeState(StoppedState);
+ // TODO: move on to m_nextSource
+ }
+ else
+ {
+ // TODO: do something with aError?
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+
+/*
+ if(aError == KErrNone) {
+ if(m_nextSource.type() == MediaSource::Empty) {
+ emit finished();
+ } else {
+ setSource(m_nextSource);
+ m_nextSource = MediaSource();
+ }
+
+ changeState(StoppedState);
+ }
+ else {
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+*/
+
+ TRACE_EXIT_0();
+}
+
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+void MMF::AudioPlayer::MaloLoadingStarted()
+{
+
+}
+
+void MMF::AudioPlayer::MaloLoadingComplete()
+{
+
+}
+#endif // QT_PHONON_MMF_AUDIO_DRM
+
+
+//-----------------------------------------------------------------------------
+// Volume
+//-----------------------------------------------------------------------------
+
+qreal MMF::AudioPlayer::volume() const
+{
+ return m_volume;
+}
+
+bool MMF::AudioPlayer::setVolume(qreal volume)
+{
+ TRACE_CONTEXT(AudioPlayer::setVolume, EAudioInternal);
+ TRACE_ENTRY("state %d", m_state);
+
+ bool volumeChanged = false;
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case StoppedState:
+ case PausedState:
+ case PlayingState:
+ case BufferingState:
+ {
+ if(volume != m_volume)
+ {
+ const int err = m_player->SetVolume(volume * m_maxVolume);
+ if(KErrNone == err)
+ {
+ m_volume = volume;
+ volumeChanged = true;
+ }
+ else
+ {
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+ }
+ break;
+ }
+
+ // Protection against adding new states and forgetting to update this
+ // switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_RETURN("%d", volumeChanged);
+}
+
+void MMF::AudioPlayer::setAudioOutput(AudioOutput* audioOutput)
+{
+ m_audioOutput = audioOutput;
+}
+
+
+//-----------------------------------------------------------------------------
+// Private functions
+//-----------------------------------------------------------------------------
+
+qint64 MMF::AudioPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
+{
+ return in.Int64() / 1000;
+}
+
+Phonon::State MMF::AudioPlayer::phononState(PrivateState state)
+{
+ const Phonon::State phononState =
+ GroundState == state
+ ? Phonon::StoppedState
+ : static_cast<Phonon::State>(state);
+
+ return phononState;
+}
+
+void MMF::AudioPlayer::changeState(PrivateState newState)
+{
+ TRACE_CONTEXT(AudioPlayer::changeState, EAudioInternal);
+ TRACE_ENTRY("state %d newState %d", m_state, newState);
+
+ // TODO: add some invariants to check that the transition is valid
+
+ const Phonon::State currentPhononState = phononState(m_state);
+ const Phonon::State newPhononState = phononState(newState);
+ if(currentPhononState != newPhononState)
+ {
+ TRACE("emit stateChanged(%d, %d)", newPhononState, currentPhononState);
+ emit stateChanged(newPhononState, currentPhononState);
+ }
+
+ m_state = newState;
+
+ TRACE_EXIT_0();
+}
+
+void MMF::AudioPlayer::tick()
+{
+ TRACE_CONTEXT(AudioPlayer::tick, EAudioInternal);
+ TRACE_ENTRY("state %d", m_state);
+
+ emit tick(currentTime());
+
+ TRACE_EXIT_0();
+}
+
+
+
+
diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h
new file mode 100644
index 0000000..f573c94
--- /dev/null
+++ b/src/3rdparty/phonon/mmf/audioplayer.h
@@ -0,0 +1,179 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MMF_AUDIOPLAYER_H
+#define PHONON_MMF_AUDIOPLAYER_H
+
+#include "abstractplayer.h"
+
+class CDrmPlayerUtility;
+class TTimeIntervalMicroSeconds;
+class QTimer;
+
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+#include <drmaudiosampleplayer.h>
+typedef CDrmPlayerUtility CPlayerType;
+typedef MDrmAudioPlayerCallback MPlayerObserverType;
+#else
+#include <mdaaudiosampleplayer.h>
+typedef CMdaAudioPlayerUtility CPlayerType;
+typedef MMdaAudioPlayerCallback MPlayerObserverType;
+#endif
+
+namespace Phonon
+{
+ namespace MMF
+ {
+ class AudioOutput;
+
+ /**
+ *
+ * See
+ * <a href="http://wiki.forum.nokia.com/index.php/How_to_play_a_video_file_using_CVideoPlayerUtility">How to
+ * play a video file using CVideoPlayerUtility</a>
+ */
+ class AudioPlayer : public AbstractPlayer
+ , public MPlayerObserverType // typedef
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+ , public MAudioLoadingObserver
+#endif
+ {
+ Q_OBJECT
+
+ public:
+ AudioPlayer();
+ virtual ~AudioPlayer();
+
+ // AbstractPlayer
+ virtual void play();
+ virtual void pause();
+ virtual void stop();
+ virtual void seek(qint64 milliseconds);
+ virtual qint32 tickInterval() const;
+ virtual void setTickInterval(qint32 interval);
+ virtual bool hasVideo() const;
+ virtual bool isSeekable() const;
+ virtual qint64 currentTime() const;
+ virtual Phonon::State state() const;
+ virtual QString errorString() const;
+ virtual Phonon::ErrorType errorType() const;
+ virtual qint64 totalTime() const;
+ virtual MediaSource source() const;
+
+ // This is a temporary hack to work around KErrInUse from MMF
+ // client utility OpenFileL calls
+ //virtual void setSource(const Phonon::MediaSource &) = 0;
+ virtual void setFileSource
+ (const Phonon::MediaSource&, RFile&);
+
+ virtual void setNextSource(const MediaSource &source);
+ virtual qint32 prefinishMark() const;
+ virtual void setPrefinishMark(qint32);
+ virtual qint32 transitionTime() const;
+ virtual void setTransitionTime(qint32);
+
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+ // MDrmAudioPlayerCallback
+ virtual void MdapcInitComplete(TInt aError,
+ const TTimeIntervalMicroSeconds &aDuration);
+ virtual void MdapcPlayComplete(TInt aError);
+
+ // MAudioLoadingObserver
+ virtual void MaloLoadingStarted();
+ virtual void MaloLoadingComplete();
+#else
+ // MMdaAudioPlayerCallback
+ virtual void MapcInitComplete(TInt aError,
+ const TTimeIntervalMicroSeconds &aDuration);
+ virtual void MapcPlayComplete(TInt aError);
+#endif
+
+ qreal volume() const;
+ bool setVolume(qreal volume);
+
+ void setAudioOutput(AudioOutput* audioOutput);
+
+ Q_SIGNALS:
+ void totalTimeChanged();
+ void stateChanged(Phonon::State oldState,
+ Phonon::State newState);
+ void finished();
+ void tick(qint64 time);
+
+ private Q_SLOTS:
+ /**
+ * Receives signal from m_tickTimer
+ */
+ void tick();
+
+ private:
+ static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &);
+
+ /**
+ * Defined private state enumeration in order to add GroundState
+ */
+ enum PrivateState
+ {
+ LoadingState = Phonon::LoadingState,
+ StoppedState = Phonon::StoppedState,
+ PlayingState = Phonon::PlayingState,
+ BufferingState = Phonon::BufferingState,
+ PausedState = Phonon::PausedState,
+ ErrorState = Phonon::ErrorState,
+ GroundState
+ };
+
+ /**
+ * Converts PrivateState into the corresponding Phonon::State
+ */
+ static Phonon::State phononState(PrivateState state);
+
+ /**
+ * Changes state and emits stateChanged()
+ */
+ void changeState(PrivateState newState);
+
+ /**
+ * Using CPlayerType typedef in order to be able to easily switch between
+ * CMdaAudioPlayerUtility and CDrmPlayerUtility
+ */
+ CPlayerType* m_player;
+
+ AudioOutput* m_audioOutput;
+
+ ErrorType m_error;
+
+ /**
+ * Do not set this directly - call changeState() instead.
+ */
+ PrivateState m_state;
+
+ qint32 m_tickInterval;
+
+ QTimer* m_tickTimer;
+
+ MediaSource m_mediaSource;
+ MediaSource m_nextSource;
+
+ qreal m_volume;
+ int m_maxVolume;
+ };
+ }
+}
+
+#endif
diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp
index 3152603..8d7903e 100644
--- a/src/3rdparty/phonon/mmf/backend.cpp
+++ b/src/3rdparty/phonon/mmf/backend.cpp
@@ -33,7 +33,7 @@ Backend::Backend(QObject *parent)
setProperty("identifier", QLatin1String("phonon_mmf"));
setProperty("backendName", QLatin1String("MMF"));
- setProperty("backendComment", QLatin1String("Backend using Nokia's S60 Multimedia Framework Architecture (MMF)."));
+ setProperty("backendComment", QLatin1String("Backend using Symbian Multimedia Framework (MMF)"));
setProperty("backendVersion", QLatin1String("0.1"));
setProperty("backendWebsite", QLatin1String("http://www.qtsoftware.com/"));
}
diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp
index 6bf15e6..62dc903 100644
--- a/src/3rdparty/phonon/mmf/mediaobject.cpp
+++ b/src/3rdparty/phonon/mmf/mediaobject.cpp
@@ -16,37 +16,20 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <QUrl>
-#include <QTimer>
-#include <private/qcore_symbian_p.h>
-
+#include "audioplayer.h"
#include "mediaobject.h"
-#include "audiooutput.h"
#include "utils.h"
+#include "videoplayer.h"
+
using namespace Phonon;
using namespace Phonon::MMF;
//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
-const qint32 DefaultTickInterval = 20;
-const int NullMaxVolume = -1;
-
-
-//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::MediaObject::MediaObject(QObject *parent) : m_player(NULL)
- , m_audioOutput(NULL)
- , m_error(NoError)
- , m_state(GroundState)
- , m_tickInterval(DefaultTickInterval)
- , m_tickTimer(NULL)
- , m_volume(0.0)
- , m_maxVolume(NullMaxVolume)
+MMF::MediaObject::MediaObject(QObject *parent) : QObject::QObject(parent)
{
TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi);
TRACE_ENTRY_0();
@@ -56,9 +39,11 @@ MMF::MediaObject::MediaObject(QObject *parent) : m_player(NULL)
TInt err = m_recognizer.Connect();
err = m_fileServer.Connect();
// TODO: handle this error
-
- // TODO: should leaves be trapped in the constructor?
- m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone);
+
+ // This must be called in order to be able to share file handles with
+ // the recognizer server (see fileMediaType function).
+ err = m_fileServer.ShareProtected();
+ // TODO: handle this error
m_tickTimer = new QTimer(this);
connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick()));
@@ -72,8 +57,8 @@ MMF::MediaObject::~MediaObject()
TRACE_ENTRY_0();
delete m_tickTimer;
- delete m_player;
+ m_file.Close();
m_fileServer.Close();
m_recognizer.Close();
@@ -111,21 +96,20 @@ MMF::MediaObject::MediaType MMF::MediaObject::fileMediaType
{
MediaType result = MediaTypeUnknown;
- QHBufC fileNameSymbian = Utils::symbianFilename(m_mediaSource.fileName());
- RFile file;
- TInt err = file.Open(m_fileServer, *fileNameSymbian, EFileRead);
+ QHBufC fileNameSymbian = Utils::symbianFilename(fileName);
+
+ m_file.Close();
+ TInt err = m_file.Open(m_fileServer, *fileNameSymbian, EFileRead|EFileShareReadersOnly);
if(KErrNone == err)
{
TDataRecognitionResult recognizerResult;
- err = m_recognizer.RecognizeData(file, recognizerResult);
+ err = m_recognizer.RecognizeData(m_file, recognizerResult);
if(KErrNone == err)
{
const TPtrC mimeType = recognizerResult.iDataType.Des();
result = mimeTypeToMediaType(mimeType);
}
-
- file.Close();
}
return result;
}
@@ -137,442 +121,272 @@ MMF::MediaObject::MediaType MMF::MediaObject::fileMediaType
void MMF::MediaObject::play()
{
- TRACE_CONTEXT(MediaObject::play, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- switch(m_state)
- {
- case GroundState:
- case LoadingState:
- // Is this the correct error? Really we want 'NotReadyError'
- m_error = NormalError;
- changeState(ErrorState);
- break;
-
- case StoppedState:
- case PausedState:
- m_player->Play();
- m_tickTimer->start(m_tickInterval);
- changeState(PlayingState);
- break;
-
- case PlayingState:
- case BufferingState:
- case ErrorState:
- // Do nothing
- break;
-
- // Protection against adding new states and forgetting to update this switch
- default:
- TRACE_PANIC(InvalidStatePanic);
- }
-
- TRACE_EXIT("state %d", m_state);
+ if(!m_player.isNull())
+ {
+ m_player->play();
+ }
}
void MMF::MediaObject::pause()
{
- TRACE_CONTEXT(MediaObject::pause, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- switch(m_state)
- {
- case GroundState:
- case LoadingState:
- case StoppedState:
- case PausedState:
- case ErrorState:
- // Do nothing
- break;
-
- case PlayingState:
- case BufferingState:
- m_player->Pause();
- m_tickTimer->stop();
- changeState(PausedState);
- break;
-
- // Protection against adding new states and forgetting to update this switch
- default:
- TRACE_PANIC(InvalidStatePanic);
- }
-
- TRACE_EXIT("state %d", m_state);
+ if(!m_player.isNull())
+ {
+ m_player->pause();
+ }
}
void MMF::MediaObject::stop()
{
- TRACE_CONTEXT(MediaObject::stop, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- switch(m_state)
- {
- case GroundState:
- case LoadingState:
- case StoppedState:
- case ErrorState:
- // Do nothing
- break;
-
- case PlayingState:
- case BufferingState:
- case PausedState:
- m_player->Stop();
- m_tickTimer->stop();
- changeState(StoppedState);
- break;
-
- // Protection against adding new states and forgetting to update this switch
- default:
- TRACE_PANIC(InvalidStatePanic);
- }
-
- TRACE_EXIT("state %d", m_state);
+ if(!m_player.isNull())
+ {
+ m_player->stop();
+ }
}
void MMF::MediaObject::seek(qint64 ms)
{
- TRACE_CONTEXT(MediaObject::seek, EAudioApi);
- TRACE_ENTRY("state %d pos %Ld", m_state, ms);
-
- m_player->SetPosition(TTimeIntervalMicroSeconds(ms));
-
- TRACE_EXIT_0();
+ if(!m_player.isNull())
+ {
+ m_player->seek(ms);
+ }
}
qint32 MMF::MediaObject::tickInterval() const
{
- TRACE_CONTEXT(MediaObject::tickInterval, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- TRACE_RETURN("%d", m_tickInterval);
+ qint32 result = 0;
+ if(!m_player.isNull())
+ {
+ result = m_player->tickInterval();
+ }
+ return result;
}
void MMF::MediaObject::setTickInterval(qint32 interval)
{
- TRACE_CONTEXT(MediaObject::setTickInterval, EAudioApi);
- TRACE_ENTRY("state %d m_interval %d interval %d", m_state, m_tickInterval, interval);
-
- m_tickInterval = interval;
- m_tickTimer->setInterval(interval);
-
- TRACE_EXIT_0();
+ if(!m_player.isNull())
+ {
+ m_player->setTickInterval(interval);
+ }
}
bool MMF::MediaObject::hasVideo() const
{
- TRACE_CONTEXT(MediaObject::hasVideo, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- // TODO: re-factor this class so that audio playback and video playback are
- // delegated to separate classes, which internally hoat a
- // CMdaAudioPlayerUtility / CVideoPlayerUtility instance as appropriate.
-
- TRACE_RETURN("%d", false);
+ bool result = false;
+ if(!m_player.isNull())
+ {
+ result = m_player->hasVideo();
+ }
+ return result;
}
bool MMF::MediaObject::isSeekable() const
{
- TRACE_CONTEXT(MediaObject::isSeekable, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- TRACE_RETURN("%d", true);
+ bool result = false;
+ if(!m_player.isNull())
+ {
+ result = m_player->isSeekable();
+ }
+ return result;
}
Phonon::State MMF::MediaObject::state() const
{
- TRACE_CONTEXT(MediaObject::state, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- const Phonon::State result = phononState(m_state);
-
- TRACE_RETURN("%d", result);
+ Phonon::State result = Phonon::StoppedState;
+ if(!m_player.isNull())
+ {
+ result = m_player->state();
+ }
+ return result;
}
qint64 MMF::MediaObject::currentTime() const
{
- TRACE_CONTEXT(MediaObject::currentTime, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- TTimeIntervalMicroSeconds us;
- const TInt err = m_player->GetPosition(us);
-
- qint64 result = -1;
-
- if(KErrNone == err) {
- result = toMilliSeconds(us);
- }
-
- TRACE_RETURN("%Ld", result);
+ qint64 result = 0;
+ if(!m_player.isNull())
+ {
+ result = m_player->currentTime();
+ }
+ return result;
}
QString MMF::MediaObject::errorString() const
{
- TRACE_CONTEXT(MediaObject::errorString, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- TRACE_EXIT_0();
- // TODO: put in proper error strings
- QString result;
- return result;
+ QString result;
+ if(!m_player.isNull())
+ {
+ result = m_player->errorString();
+ }
+ return result;
}
Phonon::ErrorType MMF::MediaObject::errorType() const
{
- TRACE_CONTEXT(MediaObject::errorType, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- const Phonon::ErrorType result = (ErrorState == m_state)
- ? m_error : NoError;
-
- TRACE_RETURN("%d", result);
+ Phonon::ErrorType result = Phonon::NoError;
+ if(!m_player.isNull())
+ {
+ result = m_player->errorType();
+ }
+ return result;
}
qint64 MMF::MediaObject::totalTime() const
{
- TRACE_CONTEXT(MediaObject::totalTime, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- const qint64 result = toMilliSeconds(m_player->Duration());
-
- TRACE_RETURN("%Ld", result);
+ qint64 result = 0;
+ if(!m_player.isNull())
+ {
+ result = m_player->totalTime();
+ }
+ return result;
}
MediaSource MMF::MediaObject::source() const
{
- TRACE_CONTEXT(MediaObject::source, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- TRACE_EXIT_0();
- return m_mediaSource;
+ MediaSource result;
+ if(!m_player.isNull())
+ {
+ result = m_player->source();
+ }
+ return result;
}
void MMF::MediaObject::setSource(const MediaSource &source)
{
- TRACE_CONTEXT(MediaObject::setSource, EAudioApi);
- TRACE_ENTRY("state %d source.type %d", m_state, source.type());
-
- m_player->Close();
- changeState(GroundState);
-
- // TODO: is it correct to assign even if the media type is not supported in
- // the switch statement below?
- m_mediaSource = source;
-
- TInt symbianErr = KErrNone;
-
- switch(m_mediaSource.type())
+ loadPlayer(source);
+ if(!m_player.isNull())
{
- case MediaSource::LocalFile:
- {
- // TODO: work out whose responsibility it is to ensure that paths
- // are Symbian-style, i.e. have backslashes for path delimiters.
- // Until then, use this utility function...
- const QHBufC filename = Utils::symbianFilename(m_mediaSource.fileName());
- TRAP(symbianErr, m_player->OpenFileL(*filename));
- break;
- }
-
- case MediaSource::Url:
- {
- const QHBufC filename(m_mediaSource.url().toString());
- TRAP(symbianErr, m_player->OpenUrlL(*filename));
- break;
- }
-
- case MediaSource::Invalid:
- case MediaSource::Disc:
- case MediaSource::Stream:
- symbianErr = KErrNotSupported;
- break;
-
- case MediaSource::Empty:
- TRACE_EXIT_0();
- return;
-
- // Protection against adding new media types and forgetting to update this switch
- default:
- TRACE_PANIC(InvalidMediaTypePanic);
+ //m_player->setSource(source);
+
+ // This is a hack to work around KErrInUse from MMF client utility
+ // OpenFileL calls
+ m_player->setFileSource(source, m_file);
}
+}
- if(KErrNone == symbianErr)
- {
-#ifdef QT_PHONON_MMF_AUDIO_DRM
- // There appears to be a bug in the CDrmPlayerUtility implementation (at least
- // in S60 5.x) whereby the player does not check whether the loading observer
- // pointer is null before dereferencing it. Therefore we must register for
- // loading notification, even though we do nothing in the callback functions.
- m_player->RegisterForAudioLoadingNotification(*this);
-#endif
- changeState(LoadingState);
- }
- else
+void MMF::MediaObject::loadPlayer(const MediaSource &source)
+{
+ TRACE_CONTEXT(AudioPlayer::loadPlayer, EAudioApi);
+ //TRACE_ENTRY("state %d source.type %d", m_state, source.type());
+ // TODO: log state
+ TRACE_ENTRY("source.type %d", source.type());
+
+ // Destroy old player object
+ if(!m_player.isNull())
+ {
+ disconnect(m_player.data(), 0, this, 0);
+ m_player.reset(NULL);
+ }
+
+ MediaType mediaType = MediaTypeUnknown;
+
+ // Determine media type
+ switch(source.type())
+ {
+ case MediaSource::LocalFile:
+ mediaType = fileMediaType(source.fileName());
+ break;
+
+ case MediaSource::Url:
+ // TODO: support detection of media type from HTTP streams
+ TRACE_0("Network streaming not supported yet");
+
+ /*
+ * TODO: handle error
+ *
+ m_error = NormalError;
+ changeState(ErrorState);
+ break;
+ */
+
+ case MediaSource::Invalid:
+ case MediaSource::Disc:
+ case MediaSource::Stream:
+ TRACE_0("Unsupported media type");
+ /*
+ * TODO: handle error
+ *
+ m_error = NormalError;
+ changeState(ErrorState);
+ */
+ break;
+
+ case MediaSource::Empty:
+ TRACE_EXIT_0();
+ return;
+ }
+
+ switch(mediaType)
+ {
+ case MediaTypeUnknown:
+ TRACE_0("Media type could not be determined");
+ /*
+ * TODO: handle error
+ *
+ m_error = NormalError;
+ changeState(ErrorState);
+ */
+ break;
+
+ case MediaTypeAudio:
+ m_player.reset(new AudioPlayer());
+ break;
+
+ case MediaTypeVideo:
+ m_player.reset(new VideoPlayer());
+ break;
+ }
+
+ if(!m_player.isNull())
{
- // TODO: do something with the value of symbianErr?
- m_error = NormalError;
- changeState(ErrorState);
+ connect(m_player.data(), SIGNAL(totalTimeChanged()), SIGNAL(totalTimeChanged()));
+ connect(m_player.data(), SIGNAL(stateChanged(Phonon::State, Phonon::State)), SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished()));
+ connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64)));
}
-
- TRACE_EXIT_0();
}
void MMF::MediaObject::setNextSource(const MediaSource &source)
{
- TRACE_CONTEXT(MediaObject::setNextSource, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- // TODO: handle 'next source'
-
- m_nextSource = source;
- Q_UNUSED(source);
-
- TRACE_EXIT_0();
+ if(!m_player.isNull())
+ {
+ m_player->setNextSource(source);
+ }
}
qint32 MMF::MediaObject::prefinishMark() const
{
- TRACE_CONTEXT(MediaObject::prefinishMark, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- // TODO: implement prefinish mark
- const qint32 result = 0;
- TRACE_RETURN("%d", result);
+ qint32 result = 0;
+ if(!m_player.isNull())
+ {
+ result = m_player->prefinishMark();
+ }
+ return result;
}
void MMF::MediaObject::setPrefinishMark(qint32 mark)
{
- TRACE_CONTEXT(MediaObject::setPrefinishMark, EAudioApi);
- TRACE_ENTRY("state %d mark %d", m_state, mark);
- Q_UNUSED(mark); // to silence warnings in release builds
-
- // TODO: implement prefinish mark
-
- TRACE_EXIT_0();
+ if(!m_player.isNull())
+ {
+ m_player->setPrefinishMark(mark);
+ }
}
qint32 MMF::MediaObject::transitionTime() const
{
- TRACE_CONTEXT(MediaObject::transitionTime, EAudioApi);
- TRACE_ENTRY("state %d", m_state);
-
- // TODO: implement transition time
- const qint32 result = 0;
- TRACE_RETURN("%d", result);
+ qint32 result = 0;
+ if(!m_player.isNull())
+ {
+ result = m_player->transitionTime();
+ }
+ return result;
}
void MMF::MediaObject::setTransitionTime(qint32 time)
{
- TRACE_CONTEXT(MediaObject::setTransitionTime, EAudioApi);
- TRACE_ENTRY("state %d time %d", m_state, time);
- Q_UNUSED(time); // to silence warnings in release builds
-
- // TODO: implement transition time
-
- TRACE_EXIT_0();
-}
-
-
-//-----------------------------------------------------------------------------
-// Symbian multimedia client observer callbacks
-//-----------------------------------------------------------------------------
-
-#ifdef QT_PHONON_MMF_AUDIO_DRM
-void MMF::MediaObject::MdapcInitComplete(TInt aError,
- const TTimeIntervalMicroSeconds &)
-#else
-void MMF::MediaObject::MapcInitComplete(TInt aError,
- const TTimeIntervalMicroSeconds &)
-#endif
-{
- TRACE_CONTEXT(MediaObject::MapcInitComplete, EAudioInternal);
- TRACE_ENTRY("state %d error %d", m_state, aError);
-
- __ASSERT_ALWAYS(LoadingState == m_state, Utils::panic(InvalidStatePanic));
-
- if(KErrNone == aError)
- {
- TInt volume = 0;
- aError = m_player->GetVolume(volume);
- if(KErrNone == aError)
- {
- m_maxVolume = m_player->MaxVolume();
- m_volume = static_cast<qreal>(volume) / m_maxVolume;
-
- if(m_audioOutput)
- {
- // Trigger AudioOutput signal
- m_audioOutput->triggerVolumeChanged(m_volume);
- }
-
- emit totalTimeChanged();
- changeState(StoppedState);
- }
- }
- else
- {
- // TODO: set different error states according to value of aError?
- m_error = NormalError;
- changeState(ErrorState);
- }
-
- TRACE_EXIT_0();
-}
-
-#ifdef QT_PHONON_MMF_AUDIO_DRM
-void MMF::MediaObject::MdapcPlayComplete(TInt aError)
-#else
-void MMF::MediaObject::MapcPlayComplete(TInt aError)
-#endif
-{
- TRACE_CONTEXT(MediaObject::MapcPlayComplete, EAudioInternal);
- TRACE_ENTRY("state %d error %d", m_state, aError);
-
- m_tickTimer->stop();
-
- if(KErrNone == aError)
- {
- changeState(StoppedState);
- // TODO: move on to m_nextSource
- }
- else
- {
- // TODO: do something with aError?
- m_error = NormalError;
- changeState(ErrorState);
- }
-
-/*
- if(aError == KErrNone) {
- if(m_nextSource.type() == MediaSource::Empty) {
- emit finished();
- } else {
- setSource(m_nextSource);
- m_nextSource = MediaSource();
- }
-
- changeState(StoppedState);
- }
- else {
- m_error = NormalError;
- changeState(ErrorState);
- }
-*/
-
- TRACE_EXIT_0();
-}
-
-#ifdef QT_PHONON_MMF_AUDIO_DRM
-void MMF::MediaObject::MaloLoadingStarted()
-{
-
-}
-
-void MMF::MediaObject::MaloLoadingComplete()
-{
-
+ if(!m_player.isNull())
+ {
+ m_player->setTransitionTime(time);
+ }
}
-#endif // QT_PHONON_MMF_AUDIO_DRM
-
//-----------------------------------------------------------------------------
// Volume
@@ -580,110 +394,29 @@ void MMF::MediaObject::MaloLoadingComplete()
qreal MMF::MediaObject::volume() const
{
- return m_volume;
+ qreal result = 0.0;
+ if(!m_player.isNull())
+ {
+ m_player->volume();
+ }
+ return result;
}
bool MMF::MediaObject::setVolume(qreal volume)
{
- TRACE_CONTEXT(MediaObject::setVolume, EAudioInternal);
- TRACE_ENTRY("state %d", m_state);
-
- bool volumeChanged = false;
-
- switch(m_state)
- {
- case GroundState:
- case LoadingState:
- case ErrorState:
- // Do nothing
- break;
-
- case StoppedState:
- case PausedState:
- case PlayingState:
- case BufferingState:
- {
- if(volume != m_volume)
- {
- const int err = m_player->SetVolume(volume * m_maxVolume);
- if(KErrNone == err)
- {
- m_volume = volume;
- volumeChanged = true;
- }
- else
- {
- m_error = NormalError;
- changeState(ErrorState);
- }
- }
- break;
- }
-
- // Protection against adding new states and forgetting to update this
- // switch
- default:
- TRACE_PANIC(InvalidStatePanic);
- }
-
- TRACE_RETURN("%d", volumeChanged);
+ bool result = false;
+ if(!m_player.isNull())
+ {
+ result = m_player->setVolume(volume);
+ }
+ return result;
}
void MMF::MediaObject::setAudioOutput(AudioOutput* audioOutput)
{
- m_audioOutput = audioOutput;
-}
-
-
-//-----------------------------------------------------------------------------
-// Private functions
-//-----------------------------------------------------------------------------
-
-qint64 MMF::MediaObject::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
-{
- return in.Int64() / 1000;
-}
-
-Phonon::State MMF::MediaObject::phononState(PrivateState state)
-{
- const Phonon::State phononState =
- GroundState == state
- ? Phonon::StoppedState
- : static_cast<Phonon::State>(state);
-
- return phononState;
-}
-
-void MMF::MediaObject::changeState(PrivateState newState)
-{
- TRACE_CONTEXT(MediaObject::changeState, EAudioInternal);
- TRACE_ENTRY("state %d newState %d", m_state, newState);
-
- // TODO: add some invariants to check that the transition is valid
-
- const Phonon::State currentPhononState = phononState(m_state);
- const Phonon::State newPhononState = phononState(newState);
- if(currentPhononState != newPhononState)
- {
- TRACE("emit stateChanged(%d, %d)", newPhononState, currentPhononState);
- emit stateChanged(newPhononState, currentPhononState);
- }
-
- m_state = newState;
-
- TRACE_EXIT_0();
-}
-
-void MMF::MediaObject::tick()
-{
- TRACE_CONTEXT(MediaObject::tick, EAudioInternal);
- TRACE_ENTRY("state %d", m_state);
-
- emit tick(currentTime());
-
- TRACE_EXIT_0();
+ if(!m_player.isNull())
+ {
+ m_player->setAudioOutput(audioOutput);
+ }
}
-
-
-
diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h
index af9bae2..2eb70c3 100644
--- a/src/3rdparty/phonon/mmf/mediaobject.h
+++ b/src/3rdparty/phonon/mmf/mediaobject.h
@@ -19,26 +19,10 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#ifndef PHONON_MMF_MEDIAOBJECT_H
#define PHONON_MMF_MEDIAOBJECT_H
-/* We use the extra qualification include/ to avoid picking up the include
- * Phonon has. */
-#include <include/videoplayer.h>
-
#include <Phonon/MediaSource>
-#include <Phonon/mediaobjectinterface.h>
-
-class CDrmPlayerUtility;
-class TTimeIntervalMicroSeconds;
-class QTimer;
-
-#ifdef QT_PHONON_MMF_AUDIO_DRM
-#include <drmaudiosampleplayer.h>
-typedef CDrmPlayerUtility CPlayerType;
-typedef MDrmAudioPlayerCallback MPlayerObserverType;
-#else
-#include <mdaaudiosampleplayer.h>
-typedef CMdaAudioPlayerUtility CPlayerType;
-typedef MMdaAudioPlayerCallback MPlayerObserverType;
-#endif
+#include <Phonon/MediaObjectInterface>
+#include <QScopedPointer>
+#include <QTimer>
// For recognizer
#include <apgcli.h>
@@ -47,20 +31,13 @@ namespace Phonon
{
namespace MMF
{
+ class AbstractPlayer;
class AudioOutput;
/**
- *
- * See
- * <a href="http://wiki.forum.nokia.com/index.php/How_to_play_a_video_file_using_CVideoPlayerUtility">How to
- * play a video file using CVideoPlayerUtility</a>
*/
class MediaObject : public QObject
, public MediaObjectInterface
- , public MPlayerObserverType // typedef
-#ifdef QT_PHONON_MMF_AUDIO_DRM
- , public MAudioLoadingObserver
-#endif
{
Q_OBJECT
Q_INTERFACES(Phonon::MediaObjectInterface)
@@ -91,22 +68,6 @@ namespace Phonon
virtual qint32 transitionTime() const;
virtual void setTransitionTime(qint32);
-#ifdef QT_PHONON_MMF_AUDIO_DRM
- // MDrmAudioPlayerCallback
- virtual void MdapcInitComplete(TInt aError,
- const TTimeIntervalMicroSeconds &aDuration);
- virtual void MdapcPlayComplete(TInt aError);
-
- // MAudioLoadingObserver
- virtual void MaloLoadingStarted();
- virtual void MaloLoadingComplete();
-#else
- // MMdaAudioPlayerCallback
- virtual void MapcInitComplete(TInt aError,
- const TTimeIntervalMicroSeconds &aDuration);
- virtual void MapcPlayComplete(TInt aError);
-#endif
-
qreal volume() const;
bool setVolume(qreal volume);
@@ -119,15 +80,13 @@ namespace Phonon
void finished();
void tick(qint64 time);
- private Q_SLOTS:
- /**
- * Receives signal from m_tickTimer
- */
- void tick();
-
private:
static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &);
+// The following has been moved into the AbstractPlayer-derived classes
+// This needs to be cleaned up - at present, there is no way for this class
+// to enter an error state, unless it has already constructed m_player
+#if 0
/**
* Defined private state enumeration in order to add GroundState
*/
@@ -151,38 +110,34 @@ namespace Phonon
* Changes state and emits stateChanged()
*/
void changeState(PrivateState newState);
+
+ ErrorType m_error;
+ PrivateState m_state;
+#endif
- RApaLsSession m_recognizer;
- RFs m_fileServer;
- enum MediaType { MediaTypeUnknown, MediaTypeAudio, MediaTypeVideo };
- MediaType mimeTypeToMediaType(const TDesC& mimeType);
- MediaType fileMediaType(const QString& fileName);
- // TODO: urlMediaType function
-
- /**
- * Using CPlayerType typedef in order to be able to easily switch between
- * CMdaAudioPlayerUtility and CDrmPlayerUtility
- */
- CPlayerType* m_player;
-
+ RApaLsSession m_recognizer;
+ RFs m_fileServer;
+ enum MediaType { MediaTypeUnknown, MediaTypeAudio, MediaTypeVideo };
+ MediaType mimeTypeToMediaType(const TDesC& mimeType);
+ MediaType fileMediaType(const QString& fileName);
+ // TODO: urlMediaType function
+
+ // Storing the file handle here to work around KErrInUse error
+ // from MMF player utility OpenFileL functions
+ RFile m_file;
+
AudioOutput* m_audioOutput;
- ErrorType m_error;
-
- /**
- * Do not set this directly - call changeState() instead.
- */
- PrivateState m_state;
-
qint32 m_tickInterval;
QTimer* m_tickTimer;
- MediaSource m_mediaSource;
- MediaSource m_nextSource;
-
qreal m_volume;
int m_maxVolume;
+
+ void loadPlayer(const MediaSource &source);
+
+ QScopedPointer<AbstractPlayer> m_player;
};
}
}
diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h
index 4b967fc..72d5472 100644
--- a/src/3rdparty/phonon/mmf/utils.h
+++ b/src/3rdparty/phonon/mmf/utils.h
@@ -117,6 +117,7 @@ namespace Phonon
#define TRACE_EXIT(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "- Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); }
#define TRACE_RETURN(string, result) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "r Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, result); } return result;
#define TRACE_PANIC(code) { _TRACE_PRINT(_TRACE_TEXT(L ## "! Phonon::MMF::%s [0x%08x] panic %d"), _tc.iFunction, _tc.iAddr, code); } Utils::panic(code);
+ #define TRACE_0(string) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr); }
#define TRACE(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); }
#else
#define TRACE_CONTEXT(_fn, _cat)
@@ -126,6 +127,7 @@ namespace Phonon
#define TRACE_EXIT(string, args...)
#define TRACE_RETURN(string, result) return result;
#define TRACE_PANIC(code) Utils::panic(code);
+ #define TRACE_0(string)
#define TRACE(string, args...)
#endif
}
diff --git a/src/3rdparty/phonon/mmf/videoplayer.cpp b/src/3rdparty/phonon/mmf/videoplayer.cpp
new file mode 100644
index 0000000..a1cfc3c
--- /dev/null
+++ b/src/3rdparty/phonon/mmf/videoplayer.cpp
@@ -0,0 +1,577 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <QUrl>
+#include <QTimer>
+#include <private/qcore_symbian_p.h>
+
+#include "videoplayer.h"
+#include "audiooutput.h"
+#include "utils.h"
+
+using namespace Phonon;
+using namespace Phonon::MMF;
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+const qint32 DefaultTickInterval = 20;
+const int NullMaxVolume = -1;
+
+
+//-----------------------------------------------------------------------------
+// Constructor / destructor
+//-----------------------------------------------------------------------------
+
+MMF::VideoPlayer::VideoPlayer() : m_audioOutput(NULL)
+ , m_error(NoError)
+ , m_state(GroundState)
+ , m_tickInterval(DefaultTickInterval)
+ , m_tickTimer(NULL)
+ , m_volume(0.0)
+ , m_maxVolume(NullMaxVolume)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::VideoPlayer, EAudioApi);
+ TRACE_ENTRY_0();
+
+ Q_UNUSED(parent);
+
+ // TODO: should leaves be trapped in the constructor?
+ m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone);
+
+ m_tickTimer = new QTimer(this);
+ connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick()));
+
+ TRACE_EXIT_0();
+#endif
+}
+
+MMF::VideoPlayer::~VideoPlayer()
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::~VideoPlayer, EAudioApi);
+ TRACE_ENTRY_0();
+
+ delete m_tickTimer;
+ delete m_player;
+
+ TRACE_EXIT_0();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// VideoPlayerInterface
+//-----------------------------------------------------------------------------
+
+void MMF::VideoPlayer::play()
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::play, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ // Is this the correct error? Really we want 'NotReadyError'
+ m_error = NormalError;
+ changeState(ErrorState);
+ break;
+
+ case StoppedState:
+ case PausedState:
+ m_player->Play();
+ m_tickTimer->start(m_tickInterval);
+ changeState(PlayingState);
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+#endif
+}
+
+void MMF::VideoPlayer::pause()
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::pause, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case StoppedState:
+ case PausedState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ m_player->Pause();
+ m_tickTimer->stop();
+ changeState(PausedState);
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+#endif
+}
+
+void MMF::VideoPlayer::stop()
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::stop, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case StoppedState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case PlayingState:
+ case BufferingState:
+ case PausedState:
+ m_player->Stop();
+ m_tickTimer->stop();
+ changeState(StoppedState);
+ break;
+
+ // Protection against adding new states and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_EXIT("state %d", m_state);
+#endif
+}
+
+void MMF::VideoPlayer::seek(qint64 ms)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::seek, EAudioApi);
+ TRACE_ENTRY("state %d pos %Ld", m_state, ms);
+
+ m_player->SetPosition(TTimeIntervalMicroSeconds(ms));
+
+ TRACE_EXIT_0();
+#endif
+}
+
+qint32 MMF::VideoPlayer::tickInterval() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::tickInterval, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_RETURN("%d", m_tickInterval);
+#endif
+}
+
+void MMF::VideoPlayer::setTickInterval(qint32 interval)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setTickInterval, EAudioApi);
+ TRACE_ENTRY("state %d m_interval %d interval %d", m_state, m_tickInterval, interval);
+
+ m_tickInterval = interval;
+ m_tickTimer->setInterval(interval);
+
+ TRACE_EXIT_0();
+#endif
+}
+
+bool MMF::VideoPlayer::hasVideo() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::hasVideo, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: re-factor this class so that audio playback and video playback are
+ // delegated to separate classes, which internally hoat a
+ // CMdaVideoPlayerUtility / CVideoPlayerUtility instance as appropriate.
+
+ TRACE_RETURN("%d", false);
+#endif
+}
+
+bool MMF::VideoPlayer::isSeekable() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::isSeekable, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_RETURN("%d", true);
+#endif
+}
+
+Phonon::State MMF::VideoPlayer::state() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::state, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const Phonon::State result = phononState(m_state);
+
+ TRACE_RETURN("%d", result);
+#endif
+}
+
+qint64 MMF::VideoPlayer::currentTime() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::currentTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TTimeIntervalMicroSeconds us;
+ const TInt err = m_player->GetPosition(us);
+
+ qint64 result = -1;
+
+ if(KErrNone == err) {
+ result = toMilliSeconds(us);
+ }
+
+ TRACE_RETURN("%Ld", result);
+#endif
+}
+
+QString MMF::VideoPlayer::errorString() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::errorString, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_EXIT_0();
+ // TODO: put in proper error strings
+ QString result;
+ return result;
+#endif
+}
+
+Phonon::ErrorType MMF::VideoPlayer::errorType() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::errorType, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const Phonon::ErrorType result = (ErrorState == m_state)
+ ? m_error : NoError;
+
+ TRACE_RETURN("%d", result);
+#endif
+}
+
+qint64 MMF::VideoPlayer::totalTime() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::totalTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ const qint64 result = toMilliSeconds(m_player->Duration());
+
+ TRACE_RETURN("%Ld", result);
+#endif
+}
+
+MediaSource MMF::VideoPlayer::source() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::source, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ TRACE_EXIT_0();
+ return m_mediaSource;
+#endif
+}
+
+void MMF::VideoPlayer::setFileSource(const MediaSource &source, RFile&)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setSource, EAudioApi);
+ TRACE_ENTRY("state %d source.type %d", m_state, source.type());
+
+ m_player->Close();
+ changeState(GroundState);
+
+ // TODO: is it correct to assign even if the media type is not supported in
+ // the switch statement below?
+ m_mediaSource = source;
+
+ TInt symbianErr = KErrNone;
+
+ switch(m_mediaSource.type())
+ {
+ case MediaSource::LocalFile:
+ {
+ // TODO: work out whose responsibility it is to ensure that paths
+ // are Symbian-style, i.e. have backslashes for path delimiters.
+ // Until then, use this utility function...
+ const QHBufC filename = Utils::symbianFilename(m_mediaSource.fileName());
+ TRAP(symbianErr, m_player->OpenFileL(*filename));
+ break;
+ }
+
+ case MediaSource::Url:
+ {
+ const QHBufC filename(m_mediaSource.url().toString());
+ TRAP(symbianErr, m_player->OpenUrlL(*filename));
+ break;
+ }
+
+ case MediaSource::Invalid:
+ case MediaSource::Disc:
+ case MediaSource::Stream:
+ symbianErr = KErrNotSupported;
+ break;
+
+ case MediaSource::Empty:
+ TRACE_EXIT_0();
+ return;
+
+ // Protection against adding new media types and forgetting to update this switch
+ default:
+ TRACE_PANIC(InvalidMediaTypePanic);
+ }
+
+ if(KErrNone == symbianErr)
+ {
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+ // There appears to be a bug in the CDrmPlayerUtility implementation (at least
+ // in S60 5.x) whereby the player does not check whether the loading observer
+ // pointer is null before dereferencing it. Therefore we must register for
+ // loading notification, even though we do nothing in the callback functions.
+ m_player->RegisterForAudioLoadingNotification(*this);
+#endif
+ changeState(LoadingState);
+ }
+ else
+ {
+ // TODO: do something with the value of symbianErr?
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+
+ TRACE_EXIT_0();
+#endif
+}
+
+void MMF::VideoPlayer::setNextSource(const MediaSource &source)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setNextSource, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: handle 'next source'
+
+ m_nextSource = source;
+ Q_UNUSED(source);
+
+ TRACE_EXIT_0();
+#endif
+}
+
+qint32 MMF::VideoPlayer::prefinishMark() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::prefinishMark, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: implement prefinish mark
+ const qint32 result = 0;
+ TRACE_RETURN("%d", result);
+#endif
+}
+
+void MMF::VideoPlayer::setPrefinishMark(qint32 mark)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setPrefinishMark, EAudioApi);
+ TRACE_ENTRY("state %d mark %d", m_state, mark);
+ Q_UNUSED(mark); // to silence warnings in release builds
+
+ // TODO: implement prefinish mark
+
+ TRACE_EXIT_0();
+#endif
+}
+
+qint32 MMF::VideoPlayer::transitionTime() const
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::transitionTime, EAudioApi);
+ TRACE_ENTRY("state %d", m_state);
+
+ // TODO: implement transition time
+ const qint32 result = 0;
+ TRACE_RETURN("%d", result);
+#endif
+}
+
+void MMF::VideoPlayer::setTransitionTime(qint32 time)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setTransitionTime, EAudioApi);
+ TRACE_ENTRY("state %d time %d", m_state, time);
+ Q_UNUSED(time); // to silence warnings in release builds
+
+ // TODO: implement transition time
+
+ TRACE_EXIT_0();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Volume
+//-----------------------------------------------------------------------------
+
+qreal MMF::VideoPlayer::volume() const
+{
+ //return m_volume;
+}
+
+bool MMF::VideoPlayer::setVolume(qreal volume)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::setVolume, EAudioInternal);
+ TRACE_ENTRY("state %d", m_state);
+
+ bool volumeChanged = false;
+
+ switch(m_state)
+ {
+ case GroundState:
+ case LoadingState:
+ case ErrorState:
+ // Do nothing
+ break;
+
+ case StoppedState:
+ case PausedState:
+ case PlayingState:
+ case BufferingState:
+ {
+ if(volume != m_volume)
+ {
+ const int err = m_player->SetVolume(volume * m_maxVolume);
+ if(KErrNone == err)
+ {
+ m_volume = volume;
+ volumeChanged = true;
+ }
+ else
+ {
+ m_error = NormalError;
+ changeState(ErrorState);
+ }
+ }
+ break;
+ }
+
+ // Protection against adding new states and forgetting to update this
+ // switch
+ default:
+ TRACE_PANIC(InvalidStatePanic);
+ }
+
+ TRACE_RETURN("%d", volumeChanged);
+#endif
+}
+
+void MMF::VideoPlayer::setAudioOutput(AudioOutput* audioOutput)
+{
+ //m_audioOutput = audioOutput;
+}
+
+
+//-----------------------------------------------------------------------------
+// Private functions
+//-----------------------------------------------------------------------------
+
+qint64 MMF::VideoPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
+{
+ //return in.Int64() / 1000;
+}
+
+Phonon::State MMF::VideoPlayer::phononState(PrivateState state)
+{
+#if 0
+ const Phonon::State phononState =
+ GroundState == state
+ ? Phonon::StoppedState
+ : static_cast<Phonon::State>(state);
+
+ return phononState;
+#endif
+}
+
+void MMF::VideoPlayer::changeState(PrivateState newState)
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::changeState, EAudioInternal);
+ TRACE_ENTRY("state %d newState %d", m_state, newState);
+
+ // TODO: add some invariants to check that the transition is valid
+
+ const Phonon::State currentPhononState = phononState(m_state);
+ const Phonon::State newPhononState = phononState(newState);
+ if(currentPhononState != newPhononState)
+ {
+ TRACE("emit stateChanged(%d, %d)", newPhononState, currentPhononState);
+ emit stateChanged(newPhononState, currentPhononState);
+ }
+
+ m_state = newState;
+
+ TRACE_EXIT_0();
+#endif
+}
+
+void MMF::VideoPlayer::tick()
+{
+#if 0
+ TRACE_CONTEXT(VideoPlayer::tick, EAudioInternal);
+ TRACE_ENTRY("state %d", m_state);
+
+ emit tick(currentTime());
+
+ TRACE_EXIT_0();
+#endif
+}
+
diff --git a/src/3rdparty/phonon/mmf/videoplayer.h b/src/3rdparty/phonon/mmf/videoplayer.h
new file mode 100644
index 0000000..a880966
--- /dev/null
+++ b/src/3rdparty/phonon/mmf/videoplayer.h
@@ -0,0 +1,153 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MMF_VIDEOPLAYER_H
+#define PHONON_MMF_VIDEOPLAYER_H
+
+/* We use the extra qualification include/ to avoid picking up the include
+ * Phonon has. */
+#include <include/videoplayer.h>
+#include "abstractplayer.h"
+
+#include <Phonon/MediaSource>
+
+class CDrmPlayerUtility;
+class TTimeIntervalMicroSeconds;
+class QTimer;
+
+namespace Phonon
+{
+ namespace MMF
+ {
+ class AudioOutput;
+
+ /**
+ *
+ * See
+ * <a href="http://wiki.forum.nokia.com/index.php/How_to_play_a_video_file_using_CVideoPlayerUtility">How to
+ * play a video file using CVideoPlayerUtility</a>
+ */
+ class VideoPlayer : public AbstractPlayer
+ {
+ Q_OBJECT
+ public:
+ VideoPlayer();
+ virtual ~VideoPlayer();
+
+ // AbstractPlayer
+ virtual void play();
+ virtual void pause();
+ virtual void stop();
+ virtual void seek(qint64 milliseconds);
+ virtual qint32 tickInterval() const;
+ virtual void setTickInterval(qint32 interval);
+ virtual bool hasVideo() const;
+ virtual bool isSeekable() const;
+ virtual qint64 currentTime() const;
+ virtual Phonon::State state() const;
+ virtual QString errorString() const;
+ virtual Phonon::ErrorType errorType() const;
+ virtual qint64 totalTime() const;
+ virtual MediaSource source() const;
+
+ // This is a temporary hack to work around KErrInUse from MMF
+ // client utility OpenFileL calls
+ //virtual void setSource(const Phonon::MediaSource &);
+ virtual void setFileSource
+ (const Phonon::MediaSource&, RFile&);
+
+ virtual void setNextSource(const MediaSource &source);
+ virtual qint32 prefinishMark() const;
+ virtual void setPrefinishMark(qint32);
+ virtual qint32 transitionTime() const;
+ virtual void setTransitionTime(qint32);
+
+ qreal volume() const;
+ bool setVolume(qreal volume);
+
+ void setAudioOutput(AudioOutput* audioOutput);
+
+ Q_SIGNALS:
+ void totalTimeChanged();
+ void stateChanged(Phonon::State oldState,
+ Phonon::State newState);
+ void finished();
+ void tick(qint64 time);
+
+ private Q_SLOTS:
+ /**
+ * Receives signal from m_tickTimer
+ */
+ void tick();
+
+ private:
+ static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &);
+
+ /**
+ * Defined private state enumeration in order to add GroundState
+ */
+ enum PrivateState
+ {
+ LoadingState = Phonon::LoadingState,
+ StoppedState = Phonon::StoppedState,
+ PlayingState = Phonon::PlayingState,
+ BufferingState = Phonon::BufferingState,
+ PausedState = Phonon::PausedState,
+ ErrorState = Phonon::ErrorState,
+ GroundState
+ };
+
+ /**
+ * Converts PrivateState into the corresponding Phonon::State
+ */
+ static Phonon::State phononState(PrivateState state);
+
+ /**
+ * Changes state and emits stateChanged()
+ */
+ void changeState(PrivateState newState);
+
+ /**
+ * Using CPlayerType typedef in order to be able to easily switch between
+ * CMdaVideoPlayerUtility and CDrmPlayerUtility
+ */
+ // CPlayerType* m_player; TODO
+
+ AudioOutput* m_audioOutput;
+
+ ErrorType m_error;
+
+ /**
+ * Do not set this directly - call changeState() instead.
+ */
+ PrivateState m_state;
+
+ qint32 m_tickInterval;
+
+ QTimer* m_tickTimer;
+
+ MediaSource m_mediaSource;
+ MediaSource m_nextSource;
+
+ qreal m_volume;
+ int m_maxVolume;
+ };
+ }
+}
+
+#endif
diff --git a/src/3rdparty/phonon/phonon/factory.cpp b/src/3rdparty/phonon/phonon/factory.cpp
index f6e1a5b..5c3752a 100644
--- a/src/3rdparty/phonon/phonon/factory.cpp
+++ b/src/3rdparty/phonon/phonon/factory.cpp
@@ -142,6 +142,7 @@ bool FactoryPrivate::createBackend()
* sophisticated, so we make sure the Helix backend is attempted
* to be loaded first, and the MMF backend is used for backup. */
{
+
const int hxphonon = plugins.indexOf(QLatin1String("hxphonon"));
if (hxphonon != -1)
plugins.move(hxphonon, 0);
@@ -154,9 +155,8 @@ bool FactoryPrivate::createBackend()
}
#endif
- const QStringList files = dir.entryList(QDir::Files);
- for (int i = 0; i < files.count(); ++i) {
- QPluginLoader pluginLoader(libPath + files.at(i));
+ for (int i = 0; i < plugins.count(); ++i) {
+ QPluginLoader pluginLoader(libPath + plugins.at(i));
if (!pluginLoader.load()) {
pDebug() << Q_FUNC_INFO << " load failed:"
<< pluginLoader.errorString();
diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro
index 3c8a721..0f00832 100644
--- a/src/plugins/phonon/mmf/mmf.pro
+++ b/src/plugins/phonon/mmf/mmf.pro
@@ -21,20 +21,25 @@ phonon_mmf_audio_drm {
LIBS += -lmediaclientaudio.lib
}
-HEADERS += \
- $$PHONON_MMF_DIR/audiooutput.h \
- $$PHONON_MMF_DIR/backend.h \
- $$PHONON_MMF_DIR/mediaobject.h \
- $$PHONON_MMF_DIR/utils.h
-
-SOURCES += \
- $$PHONON_MMF_DIR/audiooutput.cpp \
- $$PHONON_MMF_DIR/backend.cpp \
- $$PHONON_MMF_DIR/mediaobject.cpp \
- $$PHONON_MMF_DIR/utils.cpp
-
-LIBS += -lefsrv # For file server
-LIBS += -lapgrfx.lib # For recognizer
+HEADERS += \
+ $$PHONON_MMF_DIR/abstractplayer.h \
+ $$PHONON_MMF_DIR/audiooutput.h \
+ $$PHONON_MMF_DIR/audioplayer.h \
+ $$PHONON_MMF_DIR/backend.h \
+ $$PHONON_MMF_DIR/mediaobject.h \
+ $$PHONON_MMF_DIR/utils.h \
+ $$PHONON_MMF_DIR/videoplayer.h
+
+SOURCES += \
+ $$PHONON_MMF_DIR/audiooutput.cpp \
+ $$PHONON_MMF_DIR/audioplayer.cpp \
+ $$PHONON_MMF_DIR/backend.cpp \
+ $$PHONON_MMF_DIR/mediaobject.cpp \
+ $$PHONON_MMF_DIR/utils.cpp \
+ $$PHONON_MMF_DIR/videoplayer.cpp
+
+LIBS += -lefsrv # For file server
+LIBS += -lapgrfx.lib -lapmime.lib # For recognizer
# This is needed for having the .qtplugin file properly created on Symbian.
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend