diff options
-rw-r--r-- | src/3rdparty/phonon/mmf/audiooutput.cpp | 50 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/audiooutput.h | 13 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/backend.cpp | 3 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/mediaobject.cpp | 523 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/mediaobject.h | 95 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/utils.cpp | 46 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/utils.h | 134 | ||||
-rw-r--r-- | src/plugins/phonon/mmf/mmf.pro | 30 | ||||
-rw-r--r-- | src/plugins/plugins.pro | 1 |
9 files changed, 765 insertions, 130 deletions
diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp index 9d1ff02..9c8cb6b 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.cpp +++ b/src/3rdparty/phonon/mmf/audiooutput.cpp @@ -16,39 +16,45 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ -#include <DrmAudioSamplePlayer.h> - #include "mediaobject.h" #include "audiooutput.h" +#include "utils.h" using namespace Phonon; using namespace Phonon::MMF; -MMF::AudioOutput::AudioOutput(Backend *, QObject *parent) : m_mediaObject(0) - , m_volume(0) - , m_maxVolume(-1) +MMF::AudioOutput::AudioOutput(Backend *, QObject *parent) : m_mediaObject(NULL) { setParent(parent); } qreal MMF::AudioOutput::volume() const { - return 0; + TRACE_CONTEXT(AudioOutput::volume, EAudioApi); + TRACE_ENTRY("m_mediaObject 0x%08x", m_mediaObject); + + const qreal result = m_mediaObject ? m_mediaObject->volume() : 0.0; + + TRACE_RETURN("%f", result); } -void MMF::AudioOutput::setVolume(qreal newVolume) +void MMF::AudioOutput::setVolume(qreal volume) { - if(!m_mediaObject) - return; + TRACE_CONTEXT(AudioOutput::setVolume, EAudioApi); + TRACE_ENTRY("volume %f", volume); - Q_ASSERT(m_mediaObject->m_player); + if(m_mediaObject and m_mediaObject->setVolume(volume)) + { + TRACE("emit volumeChanged(%f)", volume) + emit volumeChanged(volume); + } - if (newVolume == m_volume) - return; + TRACE_EXIT_0(); +} - m_volume = newVolume; - m_mediaObject->m_player->SetVolume(newVolume * m_maxVolume); - emit volumeChanged(m_volume); +void MMF::AudioOutput::triggerVolumeChanged(qreal volume) +{ + emit volumeChanged(volume); } int MMF::AudioOutput::outputDevice() const @@ -68,19 +74,7 @@ bool MMF::AudioOutput::setOutputDevice(const Phonon::AudioOutputDevice &) void MMF::AudioOutput::setMediaObject(MediaObject *mo) { - Q_ASSERT(m_mediaObject); + Q_ASSERT(!m_mediaObject); m_mediaObject = mo; - - Q_ASSERT(m_mediaObject->m_player); - m_maxVolume = m_mediaObject->m_player->MaxVolume(); - - TInt mmfVolume = 0; - const TInt errorCode = m_mediaObject->m_player->GetVolume(mmfVolume); - - if(errorCode == KErrNone) - return; - - m_volume = mmfVolume / m_maxVolume; - emit volumeChanged(m_volume); } diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h index 8c0de1f..5e4fef2 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.h +++ b/src/3rdparty/phonon/mmf/audiooutput.h @@ -55,7 +55,7 @@ namespace Phonon public: AudioOutput(Backend *backend, QObject *parent); virtual qreal volume() const; - virtual void setVolume(qreal); + virtual void setVolume(qreal volume); virtual int outputDevice() const; @@ -71,13 +71,18 @@ namespace Phonon void setMediaObject(MediaObject *mo); + /** + * Called by MediaObject to pass initial volume when clip has been + * successfully opened + */ + void triggerVolumeChanged(qreal volume); + Q_SIGNALS: - void volumeChanged(qreal newVolume); + void volumeChanged(qreal volume); + void audioDeviceFailed(); private: MediaObject * m_mediaObject; - qreal m_volume; - TInt m_maxVolume; }; } } diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp index 4324409..3152603 100644 --- a/src/3rdparty/phonon/mmf/backend.cpp +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -75,7 +75,7 @@ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescripti bool Backend::startConnectionChange(QSet<QObject *>) { - return false; + return true; } bool Backend::connectNodes(QObject *source, QObject *target) @@ -87,6 +87,7 @@ bool Backend::connectNodes(QObject *source, QObject *target) return false; ao->setMediaObject(mo); + mo->setAudioOutput(ao); return true; } diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 0763c42..8a4b76e 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -17,188 +17,473 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ #include <QUrl> +#include <QTimer> #include <private/qcore_symbian_p.h> #include "mediaobject.h" +#include "audiooutput.h" +#include "utils.h" using namespace Phonon; using namespace Phonon::MMF; -MMF::MediaObject::MediaObject(QObject *parent) : m_player(0) +//----------------------------------------------------------------------------- +// 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(StoppedState) + , m_state(GroundState) + , m_tickInterval(DefaultTickInterval) + , m_tickTimer(NULL) + , m_volume(0.0) + , m_maxVolume(NullMaxVolume) { + TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi); + TRACE_ENTRY_0(); + Q_UNUSED(parent); - m_player = CDrmPlayerUtility::NewL(*this, 0, EMdaPriorityPreferenceNone); - m_player->RegisterForAudioLoadingNotification(*this); + // 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::MediaObject::~MediaObject() { + TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi); + TRACE_ENTRY_0(); + + delete m_tickTimer; delete m_player; + + TRACE_EXIT_0(); } +//----------------------------------------------------------------------------- +// MediaObjectInterface +//----------------------------------------------------------------------------- + void MMF::MediaObject::play() { - transitTo(PlayingState); - m_player->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); } void MMF::MediaObject::pause() { - transitTo(PausedState); - m_player->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); } void MMF::MediaObject::stop() { - transitTo(StoppedState); - m_player->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); } -void MMF::MediaObject::seek(qint64 milliseconds) +void MMF::MediaObject::seek(qint64 ms) { - m_player->SetPosition(toMicroSeconds(milliseconds)); + TRACE_CONTEXT(MediaObject::seek, EAudioApi); + TRACE_ENTRY("state %d pos %Ld", m_state, ms); + + m_player->SetPosition(TTimeIntervalMicroSeconds(ms)); + + TRACE_EXIT_0(); } qint32 MMF::MediaObject::tickInterval() const { - return 0; + TRACE_CONTEXT(MediaObject::tickInterval, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + TRACE_RETURN("%d", m_tickInterval); } void MMF::MediaObject::setTickInterval(qint32 interval) { - Q_UNUSED(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(); } bool MMF::MediaObject::hasVideo() const { - return false; + 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 MMF::MediaObject::isSeekable() const { - return false; + TRACE_CONTEXT(MediaObject::isSeekable, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + TRACE_RETURN("%d", true); +} + +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); } qint64 MMF::MediaObject::currentTime() const { - TTimeIntervalMicroSeconds mss; - const TInt retcode = m_player->GetPosition(mss); + TRACE_CONTEXT(MediaObject::currentTime, EAudioApi); + TRACE_ENTRY("state %d", m_state); - if(retcode == KErrNone) - return toMilliSeconds(m_player->Duration()); - else { - // TODO Should we enter/emit error state? Tricky - // since we're in a const function. - return -1; + TTimeIntervalMicroSeconds us; + const TInt err = m_player->GetPosition(us); + + qint64 result = -1; + + if(KErrNone == err) { + result = toMilliSeconds(us); } + + TRACE_RETURN("%Ld", result); } QString MMF::MediaObject::errorString() const { - return QString(); + TRACE_CONTEXT(MediaObject::errorString, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + TRACE_EXIT_0(); + // TODO: put in proper error strings + QString result; + return result; } Phonon::ErrorType MMF::MediaObject::errorType() const { - return m_error; -} + TRACE_CONTEXT(MediaObject::errorType, EAudioApi); + TRACE_ENTRY("state %d", m_state); -qint64 MMF::MediaObject::toMilliSeconds(const TTimeIntervalMicroSeconds &in) -{ - return in.Int64() / 1000; -} + const Phonon::ErrorType result = (ErrorState == m_state) + ? m_error : NoError; -TTimeIntervalMicroSeconds MMF::MediaObject::toMicroSeconds(qint64 ms) -{ - return TTimeIntervalMicroSeconds(TInt64(ms)); + TRACE_RETURN("%d", result); } qint64 MMF::MediaObject::totalTime() const { - return toMilliSeconds(m_player->Duration()); + TRACE_CONTEXT(MediaObject::totalTime, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + const qint64 result = toMilliSeconds(m_player->Duration()); + + TRACE_RETURN("%Ld", result); } MediaSource MMF::MediaObject::source() const { + TRACE_CONTEXT(MediaObject::source, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + TRACE_EXIT_0(); return m_mediaSource; } void MMF::MediaObject::setSource(const MediaSource &source) { - stop(); + 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()) { case MediaSource::LocalFile: { - const QHBufC filename(source.fileName()); - m_player->OpenFileL(*filename); + // 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(source.url().toString()); - m_player->OpenUrlL(*filename); + const QHBufC filename(m_mediaSource.url().toString()); + TRAP(symbianErr, m_player->OpenUrlL(*filename)); break; } + case MediaSource::Invalid: - /* Fallthrough. */ case MediaSource::Disc: - /* Fallthrough. */ case MediaSource::Stream: - /* Fallthrough. */ + symbianErr = KErrNotSupported; + break; + case MediaSource::Empty: - { - transitTo(ErrorState); + 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); } - transitTo(LoadingState); + 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(); } qint32 MMF::MediaObject::prefinishMark() const { - return 0; + TRACE_CONTEXT(MediaObject::prefinishMark, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + // TODO: implement prefinish mark + const qint32 result = 0; + TRACE_RETURN("%d", result); } -void MMF::MediaObject::setPrefinishMark(qint32) +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(); } qint32 MMF::MediaObject::transitionTime() const { - return 0; + TRACE_CONTEXT(MediaObject::transitionTime, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + // TODO: implement transition time + const qint32 result = 0; + TRACE_RETURN("%d", result); } -void MMF::MediaObject::setTransitionTime(qint32) +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 { - if(aError == KErrNone) { + 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; - m_state = ErrorState; + changeState(ErrorState); } - emit totalTimeChanged(); - transitTo(StoppedState); + 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(); @@ -207,42 +492,140 @@ void MMF::MediaObject::MdapcPlayComplete(TInt aError) m_nextSource = MediaSource(); } - transitTo(StoppedState); + changeState(StoppedState); } else { m_error = NormalError; - transitTo(ErrorState); + changeState(ErrorState); } +*/ + + TRACE_EXIT_0(); } -void MMF::MediaObject::transitTo(Phonon::State newState) +#ifdef QT_PHONON_MMF_AUDIO_DRM +void MMF::MediaObject::MaloLoadingStarted() { - emit stateChanged(m_state, newState); - m_state = newState; + } -Phonon::State MMF::MediaObject::state() const +void MMF::MediaObject::MaloLoadingComplete() { - return m_state; + } +#endif // QT_PHONON_MMF_AUDIO_DRM -void MMF::MediaObject::MaloLoadingComplete() + +//----------------------------------------------------------------------------- +// Volume +//----------------------------------------------------------------------------- + +qreal MMF::MediaObject::volume() const { - transitTo(StoppedState); + return m_volume; } -void MMF::MediaObject::MaloLoadingStarted() +bool MMF::MediaObject::setVolume(qreal volume) { - transitTo(LoadingState); + 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); } -void MMF::MediaObject::MvloLoadingComplete() +void MMF::MediaObject::setAudioOutput(AudioOutput* audioOutput) { - transitTo(StoppedState); + m_audioOutput = audioOutput; } -void MMF::MediaObject::MvloLoadingStarted() + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +qint64 MMF::MediaObject::toMilliSeconds(const TTimeIntervalMicroSeconds &in) { - transitTo(LoadingState); + 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(); +} + + + + diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 0631e4a..f17580e 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -21,15 +21,24 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. /* We use the extra qualification include/ to avoid picking up the include * Phonon has. */ -#include <include/VideoPlayer.h> - -#include <DrmAudioSamplePlayer.h> +#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 namespace Phonon { @@ -45,10 +54,10 @@ namespace Phonon */ class MediaObject : public QObject , public MediaObjectInterface - , public MDrmAudioPlayerCallback - , public MAudioLoadingObserver - , public MVideoLoadingObserver - //, public MVideoPlayerUtilityObserver + , public MPlayerObserverType // typedef +#ifdef QT_PHONON_MMF_AUDIO_DRM + , public MAudioLoadingObserver +#endif { Q_OBJECT Q_INTERFACES(Phonon::MediaObjectInterface) @@ -79,45 +88,91 @@ 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 MaloLoadingComplete(); 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); - // MVideoLoadingObserver - virtual void MvloLoadingComplete(); - virtual void MvloLoadingStarted(); + 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: - friend class AudioOutput; - static inline qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); - static inline TTimeIntervalMicroSeconds toMicroSeconds(qint64 ms); + static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); /** - * Changes state() to \a newState, and emits stateChanged(). + * Defined private state enumeration in order to add GroundState */ - inline void transitTo(Phonon::State newState); + 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; - CDrmPlayerUtility * m_player; ErrorType m_error; /** - * Never update this state by assigning to it. Call transitTo(). + * Do not set this directly - call changeState() instead. */ - State m_state; + PrivateState m_state; + + qint32 m_tickInterval; + + QTimer* m_tickTimer; + MediaSource m_mediaSource; MediaSource m_nextSource; + + qreal m_volume; + int m_maxVolume; }; } } diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp new file mode 100644 index 0000000..aa87310 --- /dev/null +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -0,0 +1,46 @@ +/* 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 "utils.h" +#include <e32std.h> + +using namespace Phonon; +using namespace Phonon::MMF; + +_LIT(PanicCategory, "Phonon::MMF"); + +void MMF::Utils::panic(PanicCode code) + { + User::Panic(PanicCategory, code); + } + +QHBufC MMF::Utils::symbianFilename(const QString& qtFilename) +{ + _LIT(ForwardSlash, "/"); + _LIT(BackwardSlash, "\\"); + + QHBufC result(qtFilename); + TInt pos = result->Find(ForwardSlash); + while(pos != KErrNotFound) + { + result->Des().Replace(pos, 1, BackwardSlash); + pos = result->Find(ForwardSlash); + } + + return result; +} diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h new file mode 100644 index 0000000..4b967fc --- /dev/null +++ b/src/3rdparty/phonon/mmf/utils.h @@ -0,0 +1,134 @@ +/* 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_UTILS_H +#define PHONON_MMF_UTILS_H + +#include <private/qcore_symbian_p.h> + +namespace Phonon +{ + namespace MMF + { + /** + * Panic codes for fatal errors + */ + enum PanicCode + { + InvalidStatePanic, + InvalidMediaTypePanic + }; + + namespace Utils + { + /** + * Raise a fatal exception + */ + void panic(PanicCode code); + + /** + * Translate forward slashes to backslashes + * + * \note This function is a temporary measure, for use until the + * responsibility for constructing valid file paths is + * determined. + */ + QHBufC symbianFilename(const QString& qtFilename); + } + + /** + * Available trace categories; + */ + enum TTraceCategory + { + /** + * Functions which map directly to the public Phonon audio API + */ + EAudioApi = 0x00000001, + + /** + * Internal functions in the audio implementation + */ + EAudioInternal = 0x00000002 + }; + + /** + * Mask indicating which trace categories are enabled + * + * Note that, at the moment, this is a compiled static constant. For + * runtime control over enabled trace categories, this could be replaced + * by a per-thread singleton object which owns the trace mask, and which + * exposes an API allowing it to be modified. + */ + static const TUint KTraceMask = 0xffffffff; + + /** + * Data structure used by tracing macros + */ + class TTraceContext + { + public: + TTraceContext(const TText* aFunction, const TUint aAddr, + const TUint aCategory=0) + : iFunction(aFunction), + iAddr(aAddr), + iCategory(aCategory) + { } + + /** + * Check whether iCategory appears in the trace mask + */ + TBool Enabled() const + { + return (iCategory == 0) or (iCategory & KTraceMask); + } + + const TText* iFunction; // Name of function + const TUint iAddr; // 'this' pointer + const TUint iCategory; + }; + + // Macros used internally by the trace system + #define _TRACE_PRINT RDebug::Print + #define _TRACE_TEXT(x) (TPtrC((const TText *)(x))) + #define _TRACE_MODULE Phonon::MMF + + // Macros available for use by implementation code +#ifdef _DEBUG + #define TRACE_CONTEXT(_fn, _cat) const ::Phonon::MMF::TTraceContext _tc((TText*)L ## #_fn, (TUint)this, _cat); + #define TRACE_ENTRY_0() { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "+ Phonon::MMF::%s [0x%08x]"), _tc.iFunction, _tc.iAddr); } + #define TRACE_ENTRY(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "+ Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); } + #define TRACE_EXIT_0() { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "- Phonon::MMF::%s [0x%08x]"), _tc.iFunction, _tc.iAddr); } + #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(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) + #define TRACE_ENTRY_0() + #define TRACE_ENTRY(string, args...) + #define TRACE_EXIT_0() + #define TRACE_EXIT(string, args...) + #define TRACE_RETURN(string, result) return result; + #define TRACE_PANIC(code) Utils::panic(code); + #define TRACE(string, args...) +#endif + } +} + +#endif diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index 6d404f2..ee2d3f9 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -1,17 +1,37 @@ +# MMF Phonon backend + QT += phonon TARGET = phonon_mmf PHONON_MMF_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/mmf -LIBS += -lDrmAudioPlayUtility.lib + +# Uncomment the following line in order to use the CDrmPlayerUtility client +# API for audio playback, rather than CMdaAudioPlayerUtility. +#CONFIG += phonon_mmf_audio_drm + +phonon_mmf_audio_drm { + LIBS += -lDrmAudioPlayUtility.lib + + # In the internal 5th SDK, DrmAudioSamplePlayer.h is placed in this + # folder, as opposed to the public, where it is placed in + # epoc32/include. + INCLUDEPATH *= /epoc32/include/osextensions + + DEFINES += QT_PHONON_MMF_AUDIO_DRM +} else { + LIBS += -lmediaclientaudio.lib +} HEADERS += \ $$PHONON_MMF_DIR/audiooutput.h \ $$PHONON_MMF_DIR/backend.h \ - $$PHONON_MMF_DIR/mediaobject.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/mediaobject.cpp \ + $$PHONON_MMF_DIR/utils.cpp # This is needed for having the .qtplugin file properly created on Symbian. QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend @@ -21,10 +41,6 @@ INSTALLS += target include(../../qpluginbase.pri) -# In the internal 5th SDK, DrmAudioSamplePlayer.h is placed in this folder, as -# opposed to the public, where it is placed in epoc32/include. -INCLUDEPATH *= /epoc32/include/osextensions - # We need this to be able to resolve ambiguity for VideoPlayer.h. Phonon and # the SDK has the header. INCLUDEPATH *= /epoc32 diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index db2e534..004b816 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -8,6 +8,7 @@ unix:!symbian { } !embedded:SUBDIRS *= graphicssystems embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers +!win32:!embedded:!mac:!symbian:SUBDIRS *= inputmethods symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon contains(QT_CONFIG, multimedia): SUBDIRS *= audio |