From 3ed427637dd76da371174e14b0f7f2a15801fcac Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 11:39:44 +0000 Subject: Added error strings to Phonon MMF backend Note that changing Utils from a namespace into a class, and then using Q_DECLARE_TR_FUNCTIONS in the class declaration, was necessary in order to be able to call tr(...) from the implementation of Utils::symbianErrorToString. Task-number: QTBUG-4994 Reviewed-by: Oswald Buddenhagen --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 26 ++++--- src/3rdparty/phonon/mmf/abstractplayer.cpp | 12 ++- src/3rdparty/phonon/mmf/abstractplayer.h | 16 +++- src/3rdparty/phonon/mmf/audioplayer.cpp | 13 ++-- src/3rdparty/phonon/mmf/mediaobject.cpp | 12 +-- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 22 +++--- src/3rdparty/phonon/mmf/utils.cpp | 98 +++++++++++++++++++++++++ src/3rdparty/phonon/mmf/utils.h | 22 ++++-- 8 files changed, 170 insertions(+), 51 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 99e96cd..bc38513 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -70,7 +70,7 @@ void MMF::AbstractMediaPlayer::play() switch (privateState()) { case GroundState: - setError(NormalError); + setError(tr("Not ready to play")); break; case LoadingState: @@ -226,10 +226,13 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f m_source = source; TInt symbianErr = KErrNone; + QString errorMessage; switch (m_source.type()) { case MediaSource::LocalFile: { symbianErr = openFile(file); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); break; } @@ -238,11 +241,12 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f if (url.scheme() == QLatin1String("file")) { symbianErr = openFile(file); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening URL"); } else { - TRACE_0("Source type not supported"); - // TODO: support network URLs - symbianErr = KErrNotSupported; + TRACE_0("Error opening URL: protocol not supported"); + errorMessage = tr("Error opening URL: protocol not supported"); } break; @@ -251,8 +255,8 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f case MediaSource::Invalid: case MediaSource::Disc: case MediaSource::Stream: - TRACE_0("Source type not supported"); - symbianErr = KErrNotSupported; + TRACE_0("Error opening source: type not supported"); + errorMessage = tr("Error opening source: type not supported"); break; case MediaSource::Empty: @@ -265,11 +269,13 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f TRACE_PANIC(InvalidMediaTypePanic); } - if (KErrNone == symbianErr) { + if (errorMessage.isEmpty()) { changeState(LoadingState); } else { - TRACE("error %d", symbianErr) - setError(NormalError); + if (symbianErr) + setError(errorMessage, symbianErr); + else + setError(errorMessage); } TRACE_EXIT_0(); @@ -318,7 +324,7 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() const int err = setDeviceVolume(volume); if (KErrNone != err) { - setError(NormalError); + setError(tr("Setting volume failed"), err); } break; } diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp index caf4092..13ff5fb 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -113,19 +113,23 @@ void MMF::AbstractPlayer::videoOutputChanged() // Default behaviour is empty - overridden by VideoPlayer } -void MMF::AbstractPlayer::setError(Phonon::ErrorType error, - const QString &errorMessage) +void MMF::AbstractPlayer::setError(const QString &errorMessage) { TRACE_CONTEXT(AbstractPlayer::setError, EAudioInternal); - TRACE_ENTRY("state %d error %d", m_state, error); + TRACE_ENTRY("state %d", m_state); - m_error = error; + m_error = Phonon::NormalError; m_errorString = errorMessage; changeState(ErrorState); TRACE_EXIT_0(); } +void MMF::AbstractPlayer::setError(const QString &errorMessage, int symbianError) +{ + setError(errorMessage + ": " + Utils::symbianErrorToString(symbianError)); +} + Phonon::ErrorType MMF::AbstractPlayer::errorType() const { const Phonon::ErrorType result = (ErrorState == m_state) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 2e9cfa0..9af1362 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -87,10 +87,20 @@ public: void setVideoOutput(VideoOutput* videoOutput); /** - * Records error and changes state to ErrorState + * Records error message and changes state to ErrorState */ - void setError(Phonon::ErrorType error, - const QString &errorMessage = QString()); + void setError(const QString &errorMessage); + + /** + * Records error message and changes state to ErrorState + * + * Appends a human-readable version of symbianErrorCode to the error message, + * e.g. + * setError(NormalError, "Opening file failed", KErrPermissionDenied) + * results in the following error message: + * "Opening file failed: permission denied" + */ + void setError(const QString &errorMessage, int symbianErrorCode); Phonon::State state() const; diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 8fccfe6..72d6684 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -51,9 +51,8 @@ void MMF::AudioPlayer::construct() TRACE_ENTRY_0(); TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone))); - if (KErrNone != err) { - changeState(ErrorState); - } + if (KErrNone != err) + setError("Creation of audio player failed", err); TRACE_EXIT_0(); } @@ -151,7 +150,7 @@ qint64 MMF::AudioPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast(this)->setError(NormalError); + const_cast(this)->setError(tr("Getting position failed"), err); } return result; @@ -186,8 +185,7 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, updateMetaData(); changeState(StoppedState); } else { - // TODO: set different error states according to value of aError? - setError(NormalError); + setError(tr("Opening clip failed"), aError); } TRACE_EXIT_0(); @@ -208,8 +206,7 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) changeState(StoppedState); // TODO: move on to m_nextSource } else { - // TODO: do something with aError? - setError(NormalError); + setError(tr("Playback complete"), aError); } /* diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 21dcfe1..6158ca1 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -238,7 +238,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) const bool oldPlayerHasVideo = oldPlayer->hasVideo(); const bool oldPlayerSeekable = oldPlayer->isSeekable(); - Phonon::ErrorType error = NoError; QString errorMessage; // Determine media type @@ -255,7 +254,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) } else { errorMessage = QLatin1String("Network streaming not supported yet"); - error = NormalError; } } break; @@ -263,8 +261,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) case MediaSource::Invalid: case MediaSource::Disc: case MediaSource::Stream: - TRACE_0("Unsupported media type"); - error = NormalError; + errorMessage = tr("Error opening source: type not supported"); break; case MediaSource::Empty: @@ -287,8 +284,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) newPlayer = new DummyPlayer(); } - error = NormalError; - errorMessage = tr("Media type could not be determined"); + errorMessage = tr("Error opening source: media type could not be determined"); break; case MediaTypeAudio: @@ -326,9 +322,9 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) // We need to call setError() after doing the connects, otherwise the // error won't be received. - if (error != NoError) { + if (!errorMessage.isEmpty()) { Q_ASSERT(m_player); - m_player->setError(error, errorMessage); + m_player->setError(errorMessage); } TRACE_EXIT_0(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index b6f53ae..4619f54 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -93,7 +93,7 @@ void MMF::VideoPlayer::construct() m_dsaActive = true; if (KErrNone != err) - changeState(ErrorState); + setError("Creation of video player failed", err); TRACE_EXIT_0(); } @@ -129,7 +129,7 @@ void MMF::VideoPlayer::doPause() TRAPD(err, m_player->PauseL()); if (KErrNone != err) { TRACE("PauseL error %d", err); - setError(NormalError); + setError(tr("Pause failed"), err); } } @@ -158,7 +158,7 @@ void MMF::VideoPlayer::doSeek(qint64 ms) } else { TRACE("SetPositionL error %d", err); - setError(NormalError); + setError(tr("Seek failed"), err); } } @@ -200,7 +200,7 @@ qint64 MMF::VideoPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast(this)->setError(NormalError); + const_cast(this)->setError(tr("Getting position failed"), err); } return result; @@ -226,7 +226,7 @@ void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError) if (KErrNone == aError) m_player->Prepare(); else - setError(NormalError); + setError(tr("Opening clip failed"), aError); TRACE_EXIT_0(); } @@ -252,7 +252,7 @@ void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError) emit totalTimeChanged(totalTime()); changeState(StoppedState); } else { - setError(NormalError); + setError(tr("Buffering clip failed"), err); } TRACE_EXIT_0(); @@ -412,7 +412,7 @@ void MMF::VideoPlayer::startDirectScreenAccess() if(KErrNone == err) m_dsaActive = true; else - setError(NormalError); + setError(tr("Video display error"), err); } } @@ -424,7 +424,7 @@ bool MMF::VideoPlayer::stopDirectScreenAccess() if(KErrNone == err) m_dsaActive = false; else - setError(NormalError); + setError(tr("Video display error"), err); } return dsaWasActive; } @@ -600,7 +600,7 @@ void MMF::VideoPlayer::applyVideoWindowChange() TRAPD(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (1) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } if(KErrNone == err) { @@ -615,13 +615,13 @@ void MMF::VideoPlayer::applyVideoWindowChange() if (KErrNone != err) { TRACE("SetDisplayWindowL err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } else { m_dsaActive = true; TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (2) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } } } diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp index d728fcf..75fec9f 100644 --- a/src/3rdparty/phonon/mmf/utils.cpp +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -18,6 +18,7 @@ along with this library. If not, see . #include "utils.h" #include +#include QT_BEGIN_NAMESPACE @@ -69,6 +70,103 @@ MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType) return result; } +QString MMF::Utils::symbianErrorToString(int errorCode) +{ + /** + * Here we translate only the error codes which are likely to be + * meaningful to the user. For example, when an error occurs + * during opening of a media file, displaying "not found" or + * "permission denied" is informative. On the other hand, + * differentiating between KErrGeneral and KErrArgument at the UI + * level does not make sense. + */ + switch (errorCode) + { + // System-wide errors + case KErrNone: + return tr("no error"); + case KErrNotFound: + return tr("not found"); + case KErrNoMemory: + return tr("out of memory"); + case KErrNotSupported: + return tr("not supported"); + case KErrOverflow: + return tr("overflow"); + case KErrUnderflow: + return tr("underflow"); + case KErrAlreadyExists: + return tr("already exists"); + case KErrPathNotFound: + return tr("path not found"); + case KErrInUse: + return tr("in use"); + case KErrNotReady: + return tr("not ready"); + case KErrAccessDenied: + return tr("access denied"); + case KErrCouldNotConnect: + return tr("could not connect"); + case KErrDisconnected: + return tr("disconnected"); + case KErrPermissionDenied: + return tr("permission denied"); + + // Multimedia framework errors + case KErrMMNotEnoughBandwidth: + return tr("insufficient bandwidth"); + case KErrMMSocketServiceNotFound: + case KErrMMServerSocket: + return tr("network unavailable"); + case KErrMMNetworkRead: + case KErrMMNetworkWrite: + case KErrMMUDPReceive: + return tr("network communication error"); + case KErrMMServerNotSupported: + return tr("streaming not supported"); + case KErrMMServerAlert: + return tr("server alert"); + case KErrMMInvalidProtocol: + return tr("invalid protocol"); + case KErrMMInvalidURL: + return tr("invalid URL"); + case KErrMMMulticast: + return tr("multicast error"); + case KErrMMProxyServer: + case KErrMMProxyServerConnect: + return tr("proxy server error"); + case KErrMMProxyServerNotSupported: + return tr("proxy server not supported"); + case KErrMMAudioDevice: + return tr("audio output error"); + case KErrMMVideoDevice: + return tr("video output error"); + case KErrMMDecoder: + return tr("decoder error"); + case KErrMMPartialPlayback: + return tr("audio or video components could not be played"); + case KErrMMDRMNotAuthorized: + return tr("DRM error"); + + /* + // We don't use QoS settings + case KErrMMQosLowBandwidth: + case KErrMMQosUnsupportedTrafficClass: + case KErrMMQosPoorTrafficClass: + case KErrMMQosUnsupportedParameters: + case KErrMMQosPoorParameters: + case KErrMMQosNotSupported: + */ + + // Catch-all for errors other than those above + default: + { + QString errorString; + errorString.setNum(errorCode); + return tr("unknown error") + " (" + errorString + ")"; + } + } +} #ifndef QT_NO_DEBUG diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h index 7e363e8..60c03a5 100644 --- a/src/3rdparty/phonon/mmf/utils.h +++ b/src/3rdparty/phonon/mmf/utils.h @@ -21,7 +21,7 @@ along with this library. If not, see . #include #include // for RDebug - +#include // for Q_DECLARE_TR_FUNCTIONS #include #include "defs.h" @@ -41,32 +41,40 @@ enum PanicCode { InvalidBackendInterfaceClass = 3 }; -namespace Utils +class Utils { + Q_DECLARE_TR_FUNCTIONS(Utils) + +public: /** * Raise a fatal exception */ -void panic(PanicCode code); +static void panic(PanicCode code); /** * Determines whether the provided MIME type is an audio or video * type. If it is neither, the function returns MediaTypeUnknown. */ -MediaType mimeTypeToMediaType(const TDesC& mimeType); +static MediaType mimeTypeToMediaType(const TDesC& mimeType); + +/** + * Translates a Symbian error code into a user-readable string. + */ +static QString symbianErrorToString(int errorCode); #ifndef QT_NO_DEBUG /** * Retrieve color of specified pixel from the screen. */ -QColor getScreenPixel(const QPoint& pos); +static QColor getScreenPixel(const QPoint& pos); /** * Samples a small number of pixels from the screen, and dumps their * colors to the debug log. */ -void dumpScreenPixelSample(); +static void dumpScreenPixelSample(); #endif -} +}; /** * Available trace categories; -- cgit v0.12 From dfa9343cc1e634eebdb0f3a2cf931ada9829ae6b Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 14:35:43 +0000 Subject: Fixed bug which caused Phonon backend error messages to be suppressed When the mediaplayer receives a state change into the ErrorState, it calls pause() on the media object. Previously, this caused the backend to transition into PausedState. When the mediaplayer subsequently called errorString() to retrieve the error message, an empty string was returned because the backend was no longer in the ErrorState. Task-number: QTBUG-4994 Reviewed-by: trustme --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 11 ++++++----- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index bc38513..adade9c 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -104,21 +104,22 @@ void MMF::AbstractMediaPlayer::pause() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTickTimer(); switch (privateState()) { case GroundState: case LoadingState: case PausedState: + case StoppedState: // Do nothing break; - case StoppedState: case PlayingState: - case ErrorState: case BufferingState: - doPause(); - stopTickTimer(); changeState(PausedState); + // Fall through + case ErrorState: + doPause(); break; // Protection against adding new states and forgetting to update this switch @@ -135,6 +136,7 @@ void MMF::AbstractMediaPlayer::stop() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTickTimer(); switch (privateState()) { case GroundState: @@ -148,7 +150,6 @@ void MMF::AbstractMediaPlayer::stop() case BufferingState: case PausedState: doStop(); - stopTickTimer(); changeState(StoppedState); break; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 4619f54..eb6f690 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -127,7 +127,7 @@ void MMF::VideoPlayer::doPause() TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi); TRAPD(err, m_player->PauseL()); - if (KErrNone != err) { + if (KErrNone != err && state() != ErrorState) { TRACE("PauseL error %d", err); setError(tr("Pause failed"), err); } -- cgit v0.12 From db782f7ab22241d8161190b95c41af4d56c05b82 Mon Sep 17 00:00:00 2001 From: Frans Englich Date: Mon, 7 Dec 2009 15:09:33 +0100 Subject: Symbian: More i18n strings work. * Consistently capitalize error sentences * Simplify & fix code/documentation. Task-number: QTBUG-4994 Reviewed-by: TrustMe --- src/3rdparty/phonon/mmf/abstractplayer.h | 4 +- src/3rdparty/phonon/mmf/utils.cpp | 64 ++++++++++++++++---------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 9af1362..cd15baf 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -96,7 +96,9 @@ public: * * Appends a human-readable version of symbianErrorCode to the error message, * e.g. - * setError(NormalError, "Opening file failed", KErrPermissionDenied) + * @code + * setError("Opening file failed", KErrPermissionDenied) + * @endcode * results in the following error message: * "Opening file failed: permission denied" */ diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp index 75fec9f..2d17bd2 100644 --- a/src/3rdparty/phonon/mmf/utils.cpp +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -84,67 +84,67 @@ QString MMF::Utils::symbianErrorToString(int errorCode) { // System-wide errors case KErrNone: - return tr("no error"); + return tr("No error"); case KErrNotFound: - return tr("not found"); + return tr("Not found"); case KErrNoMemory: - return tr("out of memory"); + return tr("Out of memory"); case KErrNotSupported: - return tr("not supported"); + return tr("Not supported"); case KErrOverflow: - return tr("overflow"); + return tr("Overflow"); case KErrUnderflow: - return tr("underflow"); + return tr("Underflow"); case KErrAlreadyExists: - return tr("already exists"); + return tr("Already exists"); case KErrPathNotFound: - return tr("path not found"); + return tr("Path not found"); case KErrInUse: - return tr("in use"); + return tr("In use"); case KErrNotReady: - return tr("not ready"); + return tr("Not ready"); case KErrAccessDenied: - return tr("access denied"); + return tr("Access denied"); case KErrCouldNotConnect: - return tr("could not connect"); + return tr("Could not connect"); case KErrDisconnected: - return tr("disconnected"); + return tr("Disconnected"); case KErrPermissionDenied: - return tr("permission denied"); + return tr("Permission denied"); // Multimedia framework errors case KErrMMNotEnoughBandwidth: - return tr("insufficient bandwidth"); + return tr("Insufficient bandwidth"); case KErrMMSocketServiceNotFound: case KErrMMServerSocket: - return tr("network unavailable"); + return tr("Network unavailable"); case KErrMMNetworkRead: case KErrMMNetworkWrite: case KErrMMUDPReceive: - return tr("network communication error"); + return tr("Network communication error"); case KErrMMServerNotSupported: - return tr("streaming not supported"); + return tr("Streaming not supported"); case KErrMMServerAlert: - return tr("server alert"); + return tr("Server alert"); case KErrMMInvalidProtocol: - return tr("invalid protocol"); + return tr("Invalid protocol"); case KErrMMInvalidURL: - return tr("invalid URL"); + return tr("Invalid URL"); case KErrMMMulticast: - return tr("multicast error"); + return tr("Multicast error"); case KErrMMProxyServer: case KErrMMProxyServerConnect: - return tr("proxy server error"); + return tr("Proxy server error"); case KErrMMProxyServerNotSupported: - return tr("proxy server not supported"); + return tr("Proxy server not supported"); case KErrMMAudioDevice: - return tr("audio output error"); + return tr("Audio output error"); case KErrMMVideoDevice: - return tr("video output error"); + return tr("Video output error"); case KErrMMDecoder: - return tr("decoder error"); + return tr("Decoder error"); case KErrMMPartialPlayback: - return tr("audio or video components could not be played"); + return tr("Audio or video components could not be played"); case KErrMMDRMNotAuthorized: return tr("DRM error"); @@ -160,11 +160,9 @@ QString MMF::Utils::symbianErrorToString(int errorCode) // Catch-all for errors other than those above default: - { - QString errorString; - errorString.setNum(errorCode); - return tr("unknown error") + " (" + errorString + ")"; - } + { + return tr("Unknown error (%1)").arg(errorCode); + } } } -- cgit v0.12 From 99b10b64fd5f68c63e0c406558b507e429eea248 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:59:46 +0000 Subject: Removed stale TODO comments from Phonon MMF backend Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/mediaobject.h | 1 - src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 2 -- src/3rdparty/phonon/mmf/objectdump.cpp | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index ee94ea2..d6f4c7b 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -98,7 +98,6 @@ Q_SIGNALS: void aboutToFinish(); // TODO: emit prefinishMarkReached from MediaObject void prefinishMarkReached(qint32); - // TODO: emit metaDataChanged from MediaObject void metaDataChanged(const QMultiMap& metaData); void currentSourceChanged(const MediaSource& source); void stateChanged(Phonon::State oldState, diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index eb6f690..66bbe38 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -277,7 +277,6 @@ void MMF::VideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoFrameReady, EVideoApi); TRACE_ENTRY("state %d error %d", state(), aError); - // TODO Q_UNUSED(aFrame); Q_UNUSED(aError); // suppress warnings in release builds @@ -300,7 +299,6 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi); TRACE_ENTRY("state %d", state()); - // TODO Q_UNUSED(aEvent); TRACE_EXIT_0(); diff --git a/src/3rdparty/phonon/mmf/objectdump.cpp b/src/3rdparty/phonon/mmf/objectdump.cpp index 3d10be4..778cde9 100644 --- a/src/3rdparty/phonon/mmf/objectdump.cpp +++ b/src/3rdparty/phonon/mmf/objectdump.cpp @@ -390,7 +390,7 @@ void QVisitorPrivate::dumpNode // No annotations - just dump the object pointer const bool isNodeLine = true; QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild); - qDebug() << 0; // TODO + qDebug() << 0; } else { // Dump annotations -- cgit v0.12 From bbab8eabb91b95dcd946c94b5f0ac59413e7a929 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Thu, 3 Dec 2009 15:44:55 +0000 Subject: Phonon MMF: leaves during object construction throw exceptions Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/audioplayer.cpp | 6 +++--- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 72d6684..2ce10db 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -50,9 +50,9 @@ void MMF::AudioPlayer::construct() TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); TRACE_ENTRY_0(); - TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone))); - if (KErrNone != err) - setError("Creation of audio player failed", err); + CPlayerType *player = 0; + QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); + m_player.reset(player); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 66bbe38..0a1c78f 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -78,23 +78,21 @@ void MMF::VideoPlayer::construct() const TInt priority = 0; const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone; - TRAPD(err, - m_player.reset(CVideoPlayerUtility::NewL + CVideoPlayerUtility *player = 0; + QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL ( *this, priority, preference, m_wsSession, m_screenDevice, *m_window, m_videoRect, m_videoRect - )) + ) ); + m_player.reset(player); // CVideoPlayerUtility::NewL starts DSA m_dsaActive = true; - if (KErrNone != err) - setError("Creation of video player failed", err); - TRACE_EXIT_0(); } -- cgit v0.12 From 3117e3a6a9c1bf95fc30ebee4d8d11b646cb7125 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Thu, 5 Nov 2009 18:13:47 +0000 Subject: Added support for streaming playback to Phonon MMF backend Because the MIME type of the stream cannot always be deduced from the URL, we assume that it is a video stream. This is based on the assumption that the video controllers will be capable of parsing the container formats for audio-only, as well as video clips. Note that this assumption may not hold on all devices. Note that most implementations of the MMF client APIs do not support HTTP streaming (a.k.a. progressive download). The backend has therefore only been tested with RTSP streams - see the JIRA entry for further details. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 8 ++++---- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 1 + src/3rdparty/phonon/mmf/audioplayer.cpp | 11 +++++++++++ src/3rdparty/phonon/mmf/audioplayer.h | 1 + src/3rdparty/phonon/mmf/mediaobject.cpp | 5 ++++- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 6 ++++++ src/3rdparty/phonon/mmf/mmf_videoplayer.h | 1 + src/3rdparty/phonon/mmf/utils.h | 3 ++- 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index adade9c..260d8e6 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -243,12 +243,12 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f if (url.scheme() == QLatin1String("file")) { symbianErr = openFile(file); if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); + } else { + symbianErr = openUrl(url.toString()); + if (KErrNone != symbianErr) errorMessage = tr("Error opening URL"); } - else { - TRACE_0("Error opening URL: protocol not supported"); - errorMessage = tr("Error opening URL: protocol not supported"); - } break; } diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index cb6e437..0432b07 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -68,6 +68,7 @@ protected: virtual void doSeek(qint64 pos) = 0; virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(RFile& file) = 0; + virtual int openUrl(const QString& url) = 0; virtual void close() = 0; virtual void changeState(PrivateState newState); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 2ce10db..2d618b8 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -124,6 +124,17 @@ int MMF::AudioPlayer::openFile(RFile& file) return err; } +int MMF::AudioPlayer::openUrl(const QString& /*url*/) +{ + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + Utils::panic(AudioUtilityUrlNotSupported); + + // Silence warning + return 0; +} + void MMF::AudioPlayer::close() { m_player->Close(); diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index bc60076..4674afc 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -63,6 +63,7 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); virtual void close(); // MediaObjectInterface diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 6158ca1..ca3e837 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -253,7 +253,10 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) mediaType = fileMediaType(url.toLocalFile()); } else { - errorMessage = QLatin1String("Network streaming not supported yet"); + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + mediaType = MediaTypeVideo; } } break; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 0a1c78f..62bbdef 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -172,6 +172,12 @@ int MMF::VideoPlayer::openFile(RFile& file) return err; } +int MMF::VideoPlayer::openUrl(const QString& url) +{ + TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url))); + return err; +} + void MMF::VideoPlayer::close() { m_player->Close(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index abb1da8..7c42991 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -54,6 +54,7 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); virtual void close(); // MediaObjectInterface diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h index 60c03a5..56ccafc 100644 --- a/src/3rdparty/phonon/mmf/utils.h +++ b/src/3rdparty/phonon/mmf/utils.h @@ -38,7 +38,8 @@ namespace MMF enum PanicCode { InvalidStatePanic = 1, InvalidMediaTypePanic = 2, - InvalidBackendInterfaceClass = 3 + InvalidBackendInterfaceClass = 3, + AudioUtilityUrlNotSupported = 4 }; class Utils -- cgit v0.12 From bed33ac62d87073120d56ff75a3d2356c99c64ea Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 17:55:30 +0000 Subject: Implemented buffer status notifications in Phonon MMF backend When clips are buffering (either at the start of playback, or during playback, when buffer levels drop due to e.g. CPU, file system or network load), the backend receives notification from the MMF. While buffering is ongoing, the backend periodically queries the filling status and emits a signal. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 80 +++++++++++++++++++------ src/3rdparty/phonon/mmf/abstractmediaplayer.h | 23 ++++--- src/3rdparty/phonon/mmf/abstractplayer.h | 1 + src/3rdparty/phonon/mmf/audioplayer.cpp | 25 +++++++- src/3rdparty/phonon/mmf/audioplayer.h | 34 +++++------ src/3rdparty/phonon/mmf/mediaobject.cpp | 1 + src/3rdparty/phonon/mmf/mediaobject.h | 1 - src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 27 ++++++++- src/3rdparty/phonon/mmf/mmf_videoplayer.h | 32 ++++++---- 9 files changed, 162 insertions(+), 62 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 260d8e6..6e7f458 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -36,6 +36,7 @@ using namespace Phonon::MMF; //----------------------------------------------------------------------------- const int NullMaxVolume = -1; +const int BufferStatusTimerInterval = 100; // ms //----------------------------------------------------------------------------- @@ -44,19 +45,23 @@ const int NullMaxVolume = -1; MMF::AbstractMediaPlayer::AbstractMediaPlayer() : m_playPending(false) - , m_tickTimer(new QTimer(this)) + , m_positionTimer(new QTimer(this)) + , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) { - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); + connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); + connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); } MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : AbstractPlayer(player) , m_playPending(false) - , m_tickTimer(new QTimer(this)) + , m_positionTimer(new QTimer(this)) + , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) { - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); + connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); + connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); } //----------------------------------------------------------------------------- @@ -80,7 +85,7 @@ void MMF::AbstractMediaPlayer::play() case StoppedState: case PausedState: doPlay(); - startTickTimer(); + startPositionTimer(); changeState(PlayingState); break; @@ -104,7 +109,7 @@ void MMF::AbstractMediaPlayer::pause() TRACE_ENTRY("state %d", privateState()); m_playPending = false; - stopTickTimer(); + stopTimers(); switch (privateState()) { case GroundState: @@ -136,7 +141,7 @@ void MMF::AbstractMediaPlayer::stop() TRACE_ENTRY("state %d", privateState()); m_playPending = false; - stopTickTimer(); + stopTimers(); switch (privateState()) { case GroundState: @@ -174,14 +179,13 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) case PlayingState: case LoadingState: { - const bool tickTimerWasRunning = m_tickTimer->isActive(); - stopTickTimer(); + const bool positionTimerWasRunning = m_positionTimer->isActive(); + stopPositionTimer(); doSeek(ms); - if (tickTimerWasRunning) { - startTickTimer(); - } + if (positionTimerWasRunning) + startPositionTimer(); break; } case BufferingState: @@ -204,7 +208,7 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi); TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval); - m_tickTimer->setInterval(interval); + m_positionTimer->setInterval(interval); TRACE_EXIT_0(); } @@ -307,6 +311,35 @@ void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) TRACE_EXIT_0(); } +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::startPositionTimer() +{ + m_positionTimer->start(tickInterval()); +} + +void MMF::AbstractMediaPlayer::stopPositionTimer() +{ + m_positionTimer->stop(); +} + +void MMF::AbstractMediaPlayer::startBufferStatusTimer() +{ + m_bufferStatusTimer->start(BufferStatusTimerInterval); +} + +void MMF::AbstractMediaPlayer::stopBufferStatusTimer() +{ + m_bufferStatusTimer->stop(); +} + +void MMF::AbstractMediaPlayer::stopTimers() +{ + stopPositionTimer(); + stopBufferStatusTimer(); +} void MMF::AbstractMediaPlayer::doVolumeChanged() { @@ -342,14 +375,19 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() // Protected functions //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::startTickTimer() +void MMF::AbstractMediaPlayer::bufferingStarted() { - m_tickTimer->start(tickInterval()); + m_stateBeforeBuffering = privateState(); + changeState(BufferingState); + bufferStatusTick(); + startBufferStatusTimer(); } -void MMF::AbstractMediaPlayer::stopTickTimer() +void MMF::AbstractMediaPlayer::bufferingComplete() { - m_tickTimer->stop(); + stopBufferStatusTimer(); + emit MMF::AbstractPlayer::bufferStatus(100); + changeState(m_stateBeforeBuffering); } void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) @@ -367,12 +405,16 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds // Slots //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::tick() +void MMF::AbstractMediaPlayer::positionTick() { - // For the MWC compiler, we need to qualify the base class. emit MMF::AbstractPlayer::tick(currentTime()); } +void MMF::AbstractMediaPlayer::bufferStatusTick() +{ + emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); +} + void MMF::AbstractMediaPlayer::changeState(PrivateState newState) { TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal); diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 0432b07..7c11ec7 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -69,6 +69,7 @@ protected: virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(RFile& file) = 0; virtual int openUrl(const QString& url) = 0; + virtual int bufferStatus() const = 0; virtual void close() = 0; virtual void changeState(PrivateState newState); @@ -77,21 +78,22 @@ protected: virtual QPair metaDataEntry(int index) const = 0; protected: - bool tickTimerRunning() const; - void startTickTimer(); - void stopTickTimer(); + void bufferingStarted(); + void bufferingComplete(); void maxVolumeChanged(int maxVolume); - static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); private: + void startPositionTimer(); + void stopPositionTimer(); + void startBufferStatusTimer(); + void stopBufferStatusTimer(); + void stopTimers(); void doVolumeChanged(); private Q_SLOTS: - /** - * Receives signal from m_tickTimer - */ - void tick(); + void positionTick(); + void bufferStatusTick(); private: /** @@ -101,7 +103,10 @@ private: */ bool m_playPending; - QScopedPointer m_tickTimer; + QScopedPointer m_positionTimer; + + QScopedPointer m_bufferStatusTimer; + PrivateState m_stateBeforeBuffering; int m_mmfMaxVolume; diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index cd15baf..5aaae3c 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -110,6 +110,7 @@ Q_SIGNALS: void totalTimeChanged(qint64 length); void finished(); void tick(qint64 time); + void bufferStatus(int percentFilled); void stateChanged(Phonon::State oldState, Phonon::State newState); void metaDataChanged(const QMultiMap& metaData); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 2d618b8..0967a27 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -53,6 +53,7 @@ void MMF::AudioPlayer::construct() CPlayerType *player = 0; QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); m_player.reset(player); + m_player->RegisterForAudioLoadingNotification(*this); TRACE_EXIT_0(); } @@ -135,6 +136,13 @@ int MMF::AudioPlayer::openUrl(const QString& /*url*/) return 0; } +int MMF::AudioPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetAudioLoadingProgressL(result)); + return result; +} + void MMF::AudioPlayer::close() { m_player->Close(); @@ -211,8 +219,6 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - stopTickTimer(); - if (KErrNone == aError) { changeState(StoppedState); // TODO: move on to m_nextSource @@ -260,6 +266,21 @@ void MMF::AudioPlayer::MaloLoadingComplete() //----------------------------------------------------------------------------- +// MAudioLoadingObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::AudioPlayer::MaloLoadingStarted() +{ + bufferingStarted(); +} + +void MMF::AudioPlayer::MaloLoadingComplete() +{ + bufferingComplete(); +} + + +//----------------------------------------------------------------------------- // Private functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 4674afc..5c7cfc1 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -45,9 +45,7 @@ namespace MMF */ class AudioPlayer : public AbstractMediaPlayer , public MPlayerObserverType // typedef -#ifdef QT_PHONON_MMF_AUDIO_DRM , public MAudioLoadingObserver -#endif { Q_OBJECT @@ -64,6 +62,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -71,15 +70,24 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair metaDataEntry(int index) const; + + /** + * This class owns the pointer. + */ + CPlayerType *player() const; + +private: + void construct(); + +private: #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, @@ -87,17 +95,9 @@ public: virtual void MapcPlayComplete(TInt aError); #endif - /** - * This class owns the pointer. - */ - CPlayerType *player() const; - -private: - void construct(); - - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair metaDataEntry(int index) const; + // MAudioLoadingObserver + virtual void MaloLoadingStarted(); + virtual void MaloLoadingComplete(); private: /** diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index ca3e837..bf1f268 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -321,6 +321,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) 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))); + connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int))); connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap)), SIGNAL(metaDataChanged(QMultiMap))); // We need to call setError() after doing the connects, otherwise the diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index d6f4c7b..07baad0 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -92,7 +92,6 @@ Q_SIGNALS: void totalTimeChanged(qint64 length); void hasVideoChanged(bool hasVideo); void seekableChanged(bool seekable); - // TODO: emit bufferStatus from MediaObject void bufferStatus(int); // TODO: emit aboutToFinish from MediaObject void aboutToFinish(); diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 62bbdef..4a70d58 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -93,6 +93,8 @@ void MMF::VideoPlayer::construct() // CVideoPlayerUtility::NewL starts DSA m_dsaActive = true; + m_player->RegisterForVideoLoadingNotification(*this); + TRACE_EXIT_0(); } @@ -178,6 +180,13 @@ int MMF::VideoPlayer::openUrl(const QString& url) return err; } +int MMF::VideoPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result)); + return result; +} + void MMF::VideoPlayer::close() { m_player->Close(); @@ -292,7 +301,8 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) TRACE_ENTRY("state %d error %d", state(), aError); - Q_UNUSED(aError); // suppress warnings in release builds + // TODO: handle aError + Q_UNUSED(aError); changeState(StoppedState); TRACE_EXIT_0(); @@ -310,6 +320,21 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) //----------------------------------------------------------------------------- +// MVideoLoadingObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::MvloLoadingStarted() +{ + bufferingStarted(); +} + +void MMF::VideoPlayer::MvloLoadingComplete() +{ + bufferingComplete(); +} + + +//----------------------------------------------------------------------------- // Video window updates //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 7c42991..3ece19c 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -39,6 +39,7 @@ namespace MMF */ class VideoPlayer : public AbstractMediaPlayer , public MVideoPlayerUtilityObserver + , public MVideoLoadingObserver { Q_OBJECT @@ -55,6 +56,7 @@ public: virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -62,12 +64,12 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; - // MVideoPlayerUtilityObserver - virtual void MvpuoOpenComplete(TInt aError); - virtual void MvpuoPrepareComplete(TInt aError); - virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); - virtual void MvpuoPlayComplete(TInt aError); - virtual void MvpuoEvent(const TMMFEvent &aEvent); + // AbstractPlayer + virtual void videoOutputChanged(); + + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair metaDataEntry(int index) const; public Q_SLOTS: void videoWindowChanged(); @@ -81,12 +83,8 @@ private: void doPrepareCompleteL(TInt aError); - // AbstractPlayer - virtual void videoOutputChanged(); - void getVideoWindow(); void initVideoOutput(); - void updateVideoRect(); void applyPendingChanges(); @@ -95,9 +93,17 @@ private: void startDirectScreenAccess(); bool stopDirectScreenAccess(); - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair metaDataEntry(int index) const; +private: + // MVideoPlayerUtilityObserver + virtual void MvpuoOpenComplete(TInt aError); + virtual void MvpuoPrepareComplete(TInt aError); + virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); + virtual void MvpuoPlayComplete(TInt aError); + virtual void MvpuoEvent(const TMMFEvent &aEvent); + + // MVideoLoadingObserver + virtual void MvloLoadingStarted(); + virtual void MvloLoadingComplete(); private: QScopedPointer m_player; -- cgit v0.12 From 66b765734585971dd9d248059701fdecebbccd78 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 1 Dec 2009 18:51:45 +0000 Subject: Changed call sequence of seeking in Phonon MMF backend, for streaming Modified the sequence of calls made to the MMF APIs when seeking during ongoing playback. This fixes a bug found during early testing of streaming playback, whereby playback would not resume following the seeking operation. This was due to an interaction between the pause / seek / play operations, and the buffering callbacks received from the MMF, which caused the backend to enter an incorrect state. Task-number: QTBUG-4660 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 14 ++++++++++---- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 16 +--------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 6e7f458..83c534a 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -179,13 +179,20 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) case PlayingState: case LoadingState: { - const bool positionTimerWasRunning = m_positionTimer->isActive(); - stopPositionTimer(); + bool wasPlaying = false; + if (state() == PlayingState) { + stopPositionTimer(); + doPause(); + wasPlaying = true; + } doSeek(ms); - if (positionTimerWasRunning) + if(wasPlaying && state() != ErrorState) { + doPlay(); startPositionTimer(); + } + break; } case BufferingState: @@ -370,7 +377,6 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() } } - //----------------------------------------------------------------------------- // Protected functions //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 4a70d58..dab7505 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -142,24 +142,10 @@ void MMF::VideoPlayer::doSeek(qint64 ms) { TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi); - bool wasPlaying = false; - if (state() == PlayingState) { - // The call to SetPositionL does not have any effect if playback is - // ongoing, so we pause before seeking. - doPause(); - wasPlaying = true; - } - TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000))); - if (KErrNone == err) { - if (wasPlaying) - doPlay(); - } - else { - TRACE("SetPositionL error %d", err); + if(KErrNone != err) setError(tr("Seek failed"), err); - } } int MMF::VideoPlayer::setDeviceVolume(int mmfVolume) -- cgit v0.12 From 946dede337f0a43ccb394c10aa2045bc9ef59301 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:11:29 +0000 Subject: Mediaplayer: enqueue all entries from .ram file before starting playback This ensures that Phonon::MediaObject::setNextSource is called before the first clip finishes playback, and therefore that the next clip is played once the first finishes. Reviewed-by: Frans Englich --- demos/qmediaplayer/mediaplayer.cpp | 16 +++++++++++----- demos/qmediaplayer/mediaplayer.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp index 8f6848f..8471ebd 100644 --- a/demos/qmediaplayer/mediaplayer.cpp +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -673,6 +673,13 @@ void MediaPlayer::setFile(const QString &fileName) m_MediaObject.play(); } +void MediaPlayer::setLocation(const QString& location) +{ + setWindowTitle(location.right(location.length() - location.lastIndexOf('/') - 1)); + m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(location.toUtf8()))); + m_MediaObject.play(); +} + bool MediaPlayer::playPauseForDialog() { // If we're running on a small screen, we want to pause the video when @@ -850,9 +857,7 @@ void MediaPlayer::openUrl() bool ok = false; sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok); if (ok && !sourceURL.isEmpty()) { - setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1)); - m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8()))); - m_MediaObject.play(); + setLocation(sourceURL); settings.setValue("location", sourceURL); } } @@ -892,10 +897,11 @@ void MediaPlayer::openRamFile() } if (!list.isEmpty()) { - m_MediaObject.setCurrentSource(Phonon::MediaSource(list[0])); - m_MediaObject.play(); + m_MediaObject.clearQueue(); + setLocation(list[0].toString()); for (int i = 1; i < list.count(); i++) m_MediaObject.enqueue(Phonon::MediaSource(list[i])); + m_MediaObject.play(); } forwardButton->setEnabled(!m_MediaObject.queue().isEmpty()); diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h index 14ed4ac..fc1bd90 100644 --- a/demos/qmediaplayer/mediaplayer.h +++ b/demos/qmediaplayer/mediaplayer.h @@ -112,6 +112,7 @@ public: void dropEvent(QDropEvent *e); void handleDrop(QDropEvent *e); void setFile(const QString &text); + void setLocation(const QString &location); void initVideoWindow(); void initSettingsDialog(); -- cgit v0.12 From 89e1e7fcbcbe93d8096afe0f7c240fe706cc9069 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 16:20:00 +0000 Subject: Implemented support for playlist handling in Phonon MMF backend The main changes are: 1. MediaObject emits prefinishMark at the appropriate instant 2. MediaObject emits aboutToFinish at the appropriate instant 3. MediaObject switches to next source when playback completes Task-number: QTBUG-6214 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 84 ++++++++++++++----------- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 17 ++--- src/3rdparty/phonon/mmf/abstractplayer.cpp | 22 +++---- src/3rdparty/phonon/mmf/abstractplayer.h | 13 ++-- src/3rdparty/phonon/mmf/audioplayer.cpp | 41 +++--------- src/3rdparty/phonon/mmf/audioplayer.h | 5 +- src/3rdparty/phonon/mmf/dummyplayer.cpp | 19 +----- src/3rdparty/phonon/mmf/dummyplayer.h | 8 +-- src/3rdparty/phonon/mmf/mediaobject.cpp | 54 +++++++++------- src/3rdparty/phonon/mmf/mediaobject.h | 11 +++- src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 22 ++----- src/3rdparty/phonon/mmf/mmf_videoplayer.h | 3 +- 12 files changed, 129 insertions(+), 170 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 83c534a..18f96cc 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -20,6 +20,7 @@ along with this library. If not, see . #include "abstractmediaplayer.h" #include "defs.h" +#include "mediaobject.h" #include "utils.h" QT_BEGIN_NAMESPACE @@ -43,22 +44,16 @@ const int BufferStatusTimerInterval = 100; // ms // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractMediaPlayer::AbstractMediaPlayer() : - m_playPending(false) - , m_positionTimer(new QTimer(this)) - , m_bufferStatusTimer(new QTimer(this)) - , m_mmfMaxVolume(NullMaxVolume) -{ - connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); - connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); -} - -MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : - AbstractPlayer(player) +MMF::AbstractMediaPlayer::AbstractMediaPlayer + (MediaObject *parent, const AbstractPlayer *player) + : AbstractPlayer(player) + , m_parent(parent) , m_playPending(false) , m_positionTimer(new QTimer(this)) , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) + , m_prefinishMarkSent(false) + , m_aboutToFinishSent(false) { connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); @@ -220,12 +215,7 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) TRACE_EXIT_0(); } -MediaSource MMF::AbstractMediaPlayer::source() const -{ - return m_source; -} - -void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file) +void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file) { TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi); TRACE_ENTRY("state %d source.type %d", privateState(), source.type()); @@ -233,14 +223,10 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f close(); changeState(GroundState); - // TODO: is it correct to assign even if the media type is not supported in - // the switch statement below? - m_source = source; - TInt symbianErr = KErrNone; QString errorMessage; - switch (m_source.type()) { + switch (source.type()) { case MediaSource::LocalFile: { symbianErr = openFile(file); if (KErrNone != symbianErr) @@ -293,20 +279,6 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f TRACE_EXIT_0(); } -void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source) -{ - TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi); - TRACE_ENTRY("state %d", privateState()); - - // TODO: handle 'next source' - - m_nextSource = source; - Q_UNUSED(source); - - TRACE_EXIT_0(); -} - - void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) { TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); @@ -402,6 +374,23 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) doVolumeChanged(); } +void MMF::AbstractMediaPlayer::playbackComplete(int error) +{ + stopTimers(); + + if (KErrNone == error) { + changeState(StoppedState); + + // MediaObject::switchToNextSource deletes the current player, so we + // call it via delayed slot invokation to ensure that this object does + // not get deleted during execution of a member function. + QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); + } + else { + setError(tr("Playback complete"), error); + } +} + qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) { return in.Int64() / 1000; @@ -413,7 +402,26 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds void MMF::AbstractMediaPlayer::positionTick() { - emit MMF::AbstractPlayer::tick(currentTime()); + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && !m_prefinishMarkSent) { + if (remaining < (prefinishMark() + tickInterval()/2)) { + m_prefinishMarkSent = true; + emit prefinishMarkReached(remaining); + } + } + + if (!m_aboutToFinishSent) { + if (remaining < tickInterval()) { + m_aboutToFinishSent = true; + emit aboutToFinish(); + } + } + + // For the MWC compiler, we need to qualify the base class. + emit MMF::AbstractPlayer::tick(current); } void MMF::AbstractMediaPlayer::bufferStatusTick() diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 7c11ec7..24fa228 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -33,6 +33,7 @@ namespace Phonon namespace MMF { class AudioOutput; +class MediaObject; /** * Interface via which MMF client APIs for both audio and video can be @@ -43,19 +44,17 @@ class AbstractMediaPlayer : public AbstractPlayer Q_OBJECT protected: - AbstractMediaPlayer(); - explicit AbstractMediaPlayer(const AbstractPlayer& player); + AbstractMediaPlayer(MediaObject *parent, const AbstractPlayer *player); public: + virtual void open(const Phonon::MediaSource&, RFile&); + // MediaObjectInterface virtual void play(); virtual void pause(); virtual void stop(); virtual void seek(qint64 milliseconds); virtual bool isSeekable() const; - virtual MediaSource source() const; - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); virtual void volumeChanged(qreal volume); protected: @@ -81,6 +80,8 @@ protected: void bufferingStarted(); void bufferingComplete(); void maxVolumeChanged(int maxVolume); + void playbackComplete(int error); + static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); private: @@ -96,6 +97,8 @@ private Q_SLOTS: void bufferStatusTick(); private: + MediaObject *const m_parent; + /** * This flag is set to true if play is called when the object is * in a Loading state. Once loading is complete, playback will @@ -110,8 +113,8 @@ private: int m_mmfMaxVolume; - MediaSource m_source; - MediaSource m_nextSource; + bool m_prefinishMarkSent; + bool m_aboutToFinishSent; QMultiMap m_metaData; diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp index 13ff5fb..53973eb 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -33,7 +33,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractPlayer::AbstractPlayer() +MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer *player) : m_videoOutput(0) , m_volume(InitialVolume) , m_state(GroundState) @@ -42,19 +42,13 @@ MMF::AbstractPlayer::AbstractPlayer() , m_transitionTime(0) , m_prefinishMark(0) { - -} - -MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer& player) - : m_videoOutput(player.m_videoOutput) - , m_volume(player.m_volume) - , m_state(GroundState) - , m_error(NoError) - , m_tickInterval(player.tickInterval()) - , m_transitionTime(player.transitionTime()) - , m_prefinishMark(player.prefinishMark()) -{ - + if(player) { + m_videoOutput = player->m_videoOutput; + m_volume = player->m_volume; + m_tickInterval = player->m_tickInterval; + m_transitionTime = player->m_transitionTime; + m_prefinishMark = player->m_prefinishMark; + } } //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 5aaae3c..40ad7f8 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -53,8 +53,9 @@ class AbstractPlayer : public QObject Q_OBJECT public: - AbstractPlayer(); - explicit AbstractPlayer(const AbstractPlayer& player); + AbstractPlayer(const AbstractPlayer *player); + + virtual void open(const Phonon::MediaSource&, RFile&) = 0; // MediaObjectInterface (implemented) qint32 tickInterval() const; @@ -75,12 +76,6 @@ public: virtual Phonon::ErrorType errorType() const; virtual QString errorString() const; 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 volumeChanged(qreal volume); @@ -114,6 +109,8 @@ Q_SIGNALS: void stateChanged(Phonon::State oldState, Phonon::State newState); void metaDataChanged(const QMultiMap& metaData); + void aboutToFinish(); + void prefinishMarkReached(qint32 remaining); protected: /** diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 0967a27..77488f4 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -34,13 +34,9 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AudioPlayer::AudioPlayer() -{ - construct(); -} - -MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::AudioPlayer::AudioPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) + , m_totalTime(0) { construct(); } @@ -177,7 +173,7 @@ qint64 MMF::AudioPlayer::currentTime() const qint64 MMF::AudioPlayer::totalTime() const { - return toMilliSeconds(m_player->Duration()); + return m_totalTime; } @@ -200,7 +196,8 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, if (KErrNone == aError) { maxVolumeChanged(m_player->MaxVolume()); - emit totalTimeChanged(totalTime()); + m_totalTime = toMilliSeconds(m_player->Duration()); + emit totalTimeChanged(m_totalTime); updateMetaData(); changeState(StoppedState); } else { @@ -219,29 +216,9 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - if (KErrNone == aError) { - changeState(StoppedState); - // TODO: move on to m_nextSource - } else { - setError(tr("Playback complete"), aError); - } - - /* - 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); - } - */ + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 5c7cfc1..4c4bcd0 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -50,8 +50,7 @@ class AudioPlayer : public AbstractMediaPlayer Q_OBJECT public: - AudioPlayer(); - explicit AudioPlayer(const AbstractPlayer& player); + AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~AudioPlayer(); // AbstractMediaPlayer @@ -105,6 +104,8 @@ private: * CMdaAudioPlayerUtility and CDrmPlayerUtility */ QScopedPointer m_player; + + qint64 m_totalTime; }; } } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp index e6f3855..6970088 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.cpp +++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp @@ -31,12 +31,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::DummyPlayer::DummyPlayer() -{ - -} - -MMF::DummyPlayer::DummyPlayer(const AbstractPlayer& player) +MMF::DummyPlayer::DummyPlayer(const AbstractPlayer *player) : AbstractPlayer(player) { @@ -97,17 +92,7 @@ qint64 MMF::DummyPlayer::totalTime() const return 0; } -MediaSource MMF::DummyPlayer::source() const -{ - return MediaSource(); -} - -void MMF::DummyPlayer::setFileSource(const Phonon::MediaSource &, RFile &) -{ - -} - -void MMF::DummyPlayer::setNextSource(const MediaSource &) +void MMF::DummyPlayer::open(const Phonon::MediaSource &, RFile &) { } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h index c6270c9..6841b5d 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.h +++ b/src/3rdparty/phonon/mmf/dummyplayer.h @@ -42,8 +42,7 @@ class AudioOutput; class DummyPlayer : public AbstractPlayer { public: - DummyPlayer(); - DummyPlayer(const AbstractPlayer& player); + DummyPlayer(const AbstractPlayer *player = 0); // MediaObjectInterface virtual void play(); @@ -56,12 +55,9 @@ public: virtual Phonon::State state() const; virtual Phonon::ErrorType errorType() const; virtual qint64 totalTime() const; - virtual MediaSource source() const; - // virtual void setSource(const MediaSource &); - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); // AbstractPlayer + virtual void open(const Phonon::MediaSource&, RFile&); virtual void doSetTickInterval(qint32 interval); }; } diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index bf1f268..a9a012f 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -45,6 +45,7 @@ using namespace Phonon::MMF; MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent) , m_recognizerOpened(false) + , m_nextSourceSet(false) { m_player.reset(new DummyPlayer()); @@ -211,18 +212,20 @@ qint64 MMF::MediaObject::totalTime() const MediaSource MMF::MediaObject::source() const { - return m_player->source(); + return m_source; } void MMF::MediaObject::setSource(const MediaSource &source) { - createPlayer(source); - - // This is a hack to work around KErrInUse from MMF client utility - // OpenFileL calls - m_player->setFileSource(source, m_file); + switchToSource(source); +} - emit currentSourceChanged(source); +void MMF::MediaObject::switchToSource(const MediaSource &source) +{ + createPlayer(source); + m_source = source; + m_player->open(m_source, m_file); + emit currentSourceChanged(m_source); } void MMF::MediaObject::createPlayer(const MediaSource &source) @@ -281,29 +284,16 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) switch (mediaType) { case MediaTypeUnknown: TRACE_0("Media type could not be determined"); - if (oldPlayer) { - newPlayer = new DummyPlayer(*oldPlayer); - } else { - newPlayer = new DummyPlayer(); - } - + newPlayer = new DummyPlayer(oldPlayer); errorMessage = tr("Error opening source: media type could not be determined"); break; case MediaTypeAudio: - if (oldPlayer) { - newPlayer = new AudioPlayer(*oldPlayer); - } else { - newPlayer = new AudioPlayer(); - } + newPlayer = new AudioPlayer(this, oldPlayer); break; case MediaTypeVideo: - if (oldPlayer) { - newPlayer = new VideoPlayer(*oldPlayer); - } else { - newPlayer = new VideoPlayer(); - } + newPlayer = new VideoPlayer(this, oldPlayer); break; } @@ -323,6 +313,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int))); connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap)), SIGNAL(metaDataChanged(QMultiMap))); + connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish())); + connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(tick(qint32))); // We need to call setError() after doing the connects, otherwise the // error won't be received. @@ -336,7 +328,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) void MMF::MediaObject::setNextSource(const MediaSource &source) { - m_player->setNextSource(source); + m_nextSource = source; + m_nextSourceSet = true; } qint32 MMF::MediaObject::prefinishMark() const @@ -385,5 +378,18 @@ bool MMF::MediaObject::activateOnMediaObject(MediaObject *) return true; } +//----------------------------------------------------------------------------- +// Playlist support +//----------------------------------------------------------------------------- + +void MMF::MediaObject::switchToNextSource() +{ + if (m_nextSourceSet) { + m_nextSourceSet = false; + switchToSource(m_nextSource); + play(); + } +} + QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 07baad0..7c39598 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -87,16 +87,16 @@ public: public Q_SLOTS: void volumeChanged(qreal volume); + void switchToNextSource(); Q_SIGNALS: void totalTimeChanged(qint64 length); void hasVideoChanged(bool hasVideo); void seekableChanged(bool seekable); void bufferStatus(int); - // TODO: emit aboutToFinish from MediaObject void aboutToFinish(); - // TODO: emit prefinishMarkReached from MediaObject - void prefinishMarkReached(qint32); + void prefinishMarkReached(qint32 remaining); + // TODO: emit metaDataChanged from MediaObject void metaDataChanged(const QMultiMap& metaData); void currentSourceChanged(const MediaSource& source); void stateChanged(Phonon::State oldState, @@ -105,6 +105,7 @@ Q_SIGNALS: void tick(qint64 time); private: + void switchToSource(const MediaSource &source); void createPlayer(const MediaSource &source); bool openRecognizer(); @@ -121,6 +122,10 @@ private: RApaLsSession m_recognizer; RFs m_fileServer; + MediaSource m_source; + MediaSource m_nextSource; + bool m_nextSourceSet; + // Storing the file handle here to work around KErrInUse error // from MMF player utility OpenFileL functions RFile m_file; diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index dab7505..877dfb3 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -44,20 +44,8 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::VideoPlayer::VideoPlayer() - : m_wsSession(CCoeEnv::Static()->WsSession()) - , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) - , m_window(0) - , m_totalTime(0) - , m_pendingChanges(false) - , m_dsaActive(false) - , m_dsaWasActive(false) -{ - construct(); -} - -MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::VideoPlayer::VideoPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) , m_wsSession(CCoeEnv::Static()->WsSession()) , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) , m_window(0) @@ -287,9 +275,9 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) TRACE_ENTRY("state %d error %d", state(), aError); - // TODO: handle aError - Q_UNUSED(aError); - changeState(StoppedState); + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); TRACE_EXIT_0(); } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 3ece19c..6200e39 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -44,8 +44,7 @@ class VideoPlayer : public AbstractMediaPlayer Q_OBJECT public: - VideoPlayer(); - explicit VideoPlayer(const AbstractPlayer& player); + VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~VideoPlayer(); // AbstractPlayer -- cgit v0.12 From fe5b275bfab1605da3ee95b6eb1d976aecb0a8a8 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 8 Dec 2009 10:31:26 +0000 Subject: Re-emit prefinishMarkReached and aboutToFinish if rewound back past mark. Task-number: QTBUG-6214 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 25 +++++++++++++++++++++++-- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 2 ++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 18f96cc..344413d 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -182,6 +182,7 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) } doSeek(ms); + resetMarksIfRewound(); if(wasPlaying && state() != ErrorState) { doPlay(); @@ -402,6 +403,14 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds void MMF::AbstractMediaPlayer::positionTick() { + emitMarksIfReached(); + + const qint64 current = currentTime(); + emit MMF::AbstractPlayer::tick(current); +} + +void MMF::AbstractMediaPlayer::emitMarksIfReached() +{ const qint64 current = currentTime(); const qint64 total = totalTime(); const qint64 remaining = total - current; @@ -419,9 +428,21 @@ void MMF::AbstractMediaPlayer::positionTick() emit aboutToFinish(); } } +} - // For the MWC compiler, we need to qualify the base class. - emit MMF::AbstractPlayer::tick(current); +void MMF::AbstractMediaPlayer::resetMarksIfRewound() +{ + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && m_prefinishMarkSent) + if (remaining >= (prefinishMark() + tickInterval()/2)) + m_prefinishMarkSent = false; + + if (m_aboutToFinishSent) + if (remaining >= tickInterval()) + m_aboutToFinishSent = false; } void MMF::AbstractMediaPlayer::bufferStatusTick() diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 24fa228..abd6bff 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -91,6 +91,8 @@ private: void stopBufferStatusTimer(); void stopTimers(); void doVolumeChanged(); + void emitMarksIfReached(); + void resetMarksIfRewound(); private Q_SLOTS: void positionTick(); -- cgit v0.12 From 8e21fc62fe40c8e393007516958c216ad8dbd629 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Wed, 2 Dec 2009 17:03:48 +0000 Subject: Removed dead code from Phonon MMF backend The following source types are handled in MediaObject::createPlayer Invalid, Disc, Stream, Empty The code removed in this patch is therefore never executed. Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 344413d..544762a 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -251,19 +251,9 @@ void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file) break; } - case MediaSource::Invalid: - case MediaSource::Disc: - case MediaSource::Stream: - TRACE_0("Error opening source: type not supported"); - errorMessage = tr("Error opening source: type not supported"); - break; - - case MediaSource::Empty: - TRACE_0("Empty source - doing nothing"); - TRACE_EXIT_0(); - return; + // Other source types are handled in MediaObject::createPlayer - // Protection against adding new media types and forgetting to update this switch + // Protection against adding new media types and forgetting to update this switch default: TRACE_PANIC(InvalidMediaTypePanic); } -- cgit v0.12 From 3f648dc075689e2ffedda2769cc76b4a56fb1073 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 4 Dec 2009 11:49:12 +0000 Subject: Implemented node disconnection in Phonon MMF backend Task-number: QTBUG-4663 Reviewed-by: Frans Englich --- src/3rdparty/phonon/mmf/abstractaudioeffect.cpp | 58 ++++++--- src/3rdparty/phonon/mmf/abstractaudioeffect.h | 27 +++-- src/3rdparty/phonon/mmf/audioequalizer.cpp | 38 +++++- src/3rdparty/phonon/mmf/audioequalizer.h | 13 +- src/3rdparty/phonon/mmf/audiooutput.cpp | 13 +- src/3rdparty/phonon/mmf/audiooutput.h | 4 +- src/3rdparty/phonon/mmf/audioplayer.cpp | 15 ++- src/3rdparty/phonon/mmf/audioplayer.h | 21 ++-- src/3rdparty/phonon/mmf/backend.cpp | 29 +++-- src/3rdparty/phonon/mmf/bassboost.cpp | 22 +++- src/3rdparty/phonon/mmf/bassboost.h | 12 +- src/3rdparty/phonon/mmf/effectfactory.cpp | 2 +- src/3rdparty/phonon/mmf/mediaobject.cpp | 25 +++- src/3rdparty/phonon/mmf/mediaobject.h | 6 +- src/3rdparty/phonon/mmf/mmf_medianode.cpp | 153 ++++++++++++++---------- src/3rdparty/phonon/mmf/mmf_medianode.h | 76 ++++++------ src/3rdparty/phonon/mmf/mmf_videoplayer.cpp | 5 + src/3rdparty/phonon/mmf/mmf_videoplayer.h | 5 +- src/3rdparty/phonon/mmf/videowidget.cpp | 14 ++- src/3rdparty/phonon/mmf/videowidget.h | 4 +- 20 files changed, 348 insertions(+), 194 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp index a559249..8c73027 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp @@ -19,6 +19,8 @@ along with this library. If not, see . #include "mediaobject.h" #include "abstractaudioeffect.h" +#include "audioplayer.h" +#include "mmf_videoplayer.h" QT_BEGIN_NAMESPACE @@ -34,18 +36,13 @@ using namespace Phonon::MMF; */ AbstractAudioEffect::AbstractAudioEffect(QObject *parent, - const QList ¶ms) : MediaNode::MediaNode(parent) - , m_params(params) + const QList ¶ms) + : MediaNode::MediaNode(parent) + , m_player(0) + , m_params(params) { } -bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target) -{ - MediaNode::disconnectMediaNode(target); - m_effect.reset(); - return true; -} - QList AbstractAudioEffect::parameters() const { return m_params; @@ -61,21 +58,44 @@ QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam return val; } -bool AbstractAudioEffect::activateOnMediaObject(MediaObject *mo) -{ - AudioPlayer *const ap = qobject_cast(mo->abstractPlayer()); - - if (ap) - return activateOn(ap->player()); - else - return true; -} - void AbstractAudioEffect::setParameterValue(const EffectParameter ¶m, const QVariant &newValue) { m_values.insert(param.id(), newValue); parameterChanged(param.id(), newValue); + // TODO: handle audio effect errors + TRAP_IGNORE(m_effect->ApplyL()); +} + +void AbstractAudioEffect::connectMediaObject(MediaObject *mediaObject) +{ + Q_ASSERT_X(!m_player, Q_FUNC_INFO, "Player already connected"); + Q_ASSERT_X(!m_effect.data(), Q_FUNC_INFO, "Effect already created"); + + AbstractMediaPlayer *const player = + qobject_cast(mediaObject->abstractPlayer()); + + if (player) { + m_player = player; + + if (AudioPlayer *audioPlayer = qobject_cast(player)) { + connectAudioPlayer(audioPlayer->nativePlayer()); + } else { + VideoPlayer *videoPlayer = qobject_cast(player); + Q_ASSERT_X(videoPlayer, Q_FUNC_INFO, "Player type not recognised"); + connectVideoPlayer(videoPlayer->nativePlayer()); + } + + applyParameters(); + // TODO: handle audio effect errors + TRAP_IGNORE(m_effect->EnableL()); + } +} + +void AbstractAudioEffect::disconnectMediaObject(MediaObject * /*mediaObject*/) +{ + m_player = 0; + m_effect.reset(); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h index 01542c9..10578af 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.h +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h @@ -19,15 +19,16 @@ along with this library. If not, see . #ifndef PHONON_MMF_ABSTRACTEFFECT_H #define PHONON_MMF_ABSTRACTEFFECT_H -#include "mmf_medianode.h" - #include #include #include #include + #include "audioplayer.h" +#include "mmf_medianode.h" +#include "mmf_videoplayer.h" QT_BEGIN_NAMESPACE @@ -35,6 +36,7 @@ namespace Phonon { namespace MMF { +class AbstractMediaPlayer; /** * @short Base class for all effects for MMF. @@ -66,8 +68,6 @@ public: virtual void setParameterValue(const EffectParameter &, const QVariant &newValue); - virtual bool disconnectMediaNode(MediaNode *target); - enum Type { EffectAudioEqualizer = 1, @@ -81,21 +81,26 @@ public: }; protected: - virtual bool activateOn(CPlayerType *player) = 0; + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player) = 0; + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player) = 0; + virtual void applyParameters() = 0; + virtual void parameterChanged(const int id, const QVariant &value) = 0; - /** - * Part of the implementation of AbstractAudioEffect. Forwards the call to - * activateOn(), essentially. - */ - virtual bool activateOnMediaObject(MediaObject *mo); - +protected: QScopedPointer m_effect; + private: + AbstractMediaPlayer * m_player; const QList m_params; QHash m_values; }; + } } diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp index 7cc9bc7..51f1c32 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.cpp +++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include "audioequalizer.h" QT_BEGIN_NAMESPACE @@ -34,18 +35,43 @@ AudioEqualizer::AudioEqualizer(QObject *parent) : AbstractAudioEffect::AbstractA void AudioEqualizer::parameterChanged(const int pid, const QVariant &value) { - // There is no way to return an error from this function, so we just - // have to trap and ignore exceptions. - TRAP_IGNORE(static_cast(m_effect.data())->SetBandLevelL(pid, value.toInt())); + if (m_effect.data()) { + const int band = pid; + const int level = value.toInt(); + setBandLevel(band, level); + } } -bool AudioEqualizer::activateOn(CPlayerType *player) +void AudioEqualizer::connectAudioPlayer(AudioPlayer::NativePlayer *player) { CAudioEqualizer *ptr = 0; QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); m_effect.reset(ptr); +} - return true; +void AudioEqualizer::connectVideoPlayer(VideoPlayer::NativePlayer *player) +{ + CAudioEqualizer *ptr = 0; + QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); + m_effect.reset(ptr); +} + +void AudioEqualizer::applyParameters() +{ + Q_ASSERT_X(m_effect.data(), Q_FUNC_INFO, "Effect not created"); + EffectParameter param; + foreach (param, parameters()) { + const int band = param.id(); + const int level = parameterValue(param).toInt(); + setBandLevel(band, level); + } +} + +void AudioEqualizer::setBandLevel(int band, int level) +{ + CAudioEqualizer *const effect = static_cast(m_effect.data()); + // TODO: handle audio effect errors + TRAP_IGNORE(effect->SetBandLevelL(band, level)); } QList AudioEqualizer::createParams() @@ -57,7 +83,7 @@ QList AudioEqualizer::createParams() AudioPlayer dummyPlayer; CAudioEqualizer *eqPtr = 0; - QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.player());) + QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.nativePlayer())); QScopedPointer e(eqPtr); TInt32 dbMin; diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h index d4c8165..9910ea4 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.h +++ b/src/3rdparty/phonon/mmf/audioequalizer.h @@ -19,7 +19,6 @@ along with this library. If not, see . #ifndef PHONON_MMF_AUDIOEQUALIZER_H #define PHONON_MMF_AUDIOEQUALIZER_H -#include #include "abstractaudioeffect.h" QT_BEGIN_NAMESPACE @@ -43,14 +42,18 @@ public: AudioEqualizer(QObject *parent); protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // AbstractAudioEffect + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); + virtual void applyParameters(); + virtual void parameterChanged(const int id, const QVariant &value); - virtual bool activateOn(CPlayerType *player); +private: + void setBandLevel(int band, int level); private: static QList createParams(); - QScopedPointer m_bassBoost; + }; } } diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp index d6e0c13..c6be20b 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.cpp +++ b/src/3rdparty/phonon/mmf/audiooutput.cpp @@ -81,13 +81,18 @@ bool MMF::AudioOutput::setOutputDevice(int index) return true; } -bool MMF::AudioOutput::activateOnMediaObject(MediaObject *mo) +void MMF::AudioOutput::connectMediaObject(MediaObject *mediaObject) { // Ensure that the MediaObject has the correct initial volume - mo->volumeChanged(m_volume); + mediaObject->volumeChanged(m_volume); // Connect MediaObject to receive future volume changes - connect(this, SIGNAL(volumeChanged(qreal)), mo, SLOT(volumeChanged(qreal))); - return true; + connect(this, SIGNAL(volumeChanged(qreal)), mediaObject, SLOT(volumeChanged(qreal))); +} + +void MMF::AudioOutput::disconnectMediaObject(MediaObject *mediaObject) +{ + // Disconnect all signal-slot connections + disconnect(this, 0, mediaObject, 0); } QHash MMF::AudioOutput::audioOutputDescription(int index) diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h index 1e1e134..67aaa38 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.h +++ b/src/3rdparty/phonon/mmf/audiooutput.h @@ -74,7 +74,9 @@ public: }; protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); Q_SIGNALS: void volumeChanged(qreal volume); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 77488f4..ee07229 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -46,8 +46,8 @@ void MMF::AudioPlayer::construct() TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); TRACE_ENTRY_0(); - CPlayerType *player = 0; - QT_TRAP_THROWING(player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); + NativePlayer *player = 0; + QT_TRAP_THROWING(player = NativePlayer::NewL(*this, 0, EMdaPriorityPreferenceNone)); m_player.reset(player); m_player->RegisterForAudioLoadingNotification(*this); @@ -62,6 +62,11 @@ MMF::AudioPlayer::~AudioPlayer() TRACE_EXIT_0(); } +MMF::AudioPlayer::NativePlayer *MMF::AudioPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- @@ -223,12 +228,6 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_EXIT_0(); } -CPlayerType *MMF::AudioPlayer::player() const -{ - return m_player.data(); -} - - #ifdef QT_PHONON_MMF_AUDIO_DRM void MMF::AudioPlayer::MaloLoadingStarted() { diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index 4c4bcd0..0eb8bb7 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -26,12 +26,10 @@ class TTimeIntervalMicroSeconds; #ifdef QT_PHONON_MMF_AUDIO_DRM #include -typedef CDrmPlayerUtility CPlayerType; -typedef MDrmAudioPlayerCallback MPlayerObserverType; +typedef MDrmAudioPlayerCallback NativePlayerObserver; #else #include -typedef CMdaAudioPlayerUtility CPlayerType; -typedef MMdaAudioPlayerCallback MPlayerObserverType; +typedef MMdaAudioPlayerCallback NativePlayerObserver; #endif QT_BEGIN_NAMESPACE @@ -44,7 +42,7 @@ namespace MMF * @short Wrapper over MMF audio client utility */ class AudioPlayer : public AbstractMediaPlayer - , public MPlayerObserverType // typedef + , public NativePlayerObserver , public MAudioLoadingObserver { Q_OBJECT @@ -53,6 +51,14 @@ public: AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~AudioPlayer(); +#ifdef QT_PHONON_MMF_AUDIO_DRM +typedef CDrmPlayerUtility NativePlayer; +#else +typedef CMdaAudioPlayerUtility NativePlayer; +#endif + + NativePlayer *nativePlayer() const; + // AbstractMediaPlayer virtual void doPlay(); virtual void doPause(); @@ -76,7 +82,7 @@ public: /** * This class owns the pointer. */ - CPlayerType *player() const; + NativePlayer *player() const; private: void construct(); @@ -103,9 +109,10 @@ private: * Using CPlayerType typedef in order to be able to easily switch between * CMdaAudioPlayerUtility and CDrmPlayerUtility */ - QScopedPointer m_player; + QScopedPointer m_player; qint64 m_totalTime; + }; } } diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp index 7e3a67f..0c07f66 100644 --- a/src/3rdparty/phonon/mmf/backend.cpp +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -139,29 +139,32 @@ bool Backend::startConnectionChange(QSet) return true; } -bool Backend::connectNodes(QObject *source, QObject *target) +bool Backend::connectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::connectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast(source)); - Q_ASSERT(qobject_cast(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); - MediaNode *const mediaSource = static_cast(source); - MediaNode *const mediaTarget = static_cast(target); + MediaNode *const source = qobject_cast(sourceObject); + MediaNode *const target = qobject_cast(targetObject); - return mediaSource->connectMediaNode(mediaTarget); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); + + return source->connectOutput(target); } -bool Backend::disconnectNodes(QObject *source, QObject *target) +bool Backend::disconnectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::disconnectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast(source)); - Q_ASSERT(qobject_cast(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); + + MediaNode *const source = qobject_cast(sourceObject); + MediaNode *const target = qobject_cast(targetObject); - const bool result = static_cast(source)->disconnectMediaNode(static_cast(target)); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); - TRACE_RETURN("%d", result); + return source->disconnectOutput(target); } bool Backend::endConnectionChange(QSet) diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp index e34f9e7..36069fb 100644 --- a/src/3rdparty/phonon/mmf/bassboost.cpp +++ b/src/3rdparty/phonon/mmf/bassboost.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include "bassboost.h" QT_BEGIN_NAMESPACE @@ -35,13 +36,26 @@ BassBoost::BassBoost(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect void BassBoost::parameterChanged(const int, const QVariant &) { - // We should never be called, because we have no parameters. + Q_ASSERT_X(false, Q_FUNC_INFO, "BassBoost has not parameters"); } -bool BassBoost::activateOn(CPlayerType *player) +void BassBoost::connectAudioPlayer(AudioPlayer::NativePlayer *player) { - m_effect.reset(CBassBoost::NewL(*player, true)); - return true; + CBassBoost *ptr = 0; + QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player)); + m_effect.reset(ptr); +} + +void BassBoost::connectVideoPlayer(VideoPlayer::NativePlayer *player) +{ + CBassBoost *ptr = 0; + QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player)); + m_effect.reset(ptr); +} + +void BassBoost::applyParameters() +{ + // No parameters to apply } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h index c16393a..1b893db 100644 --- a/src/3rdparty/phonon/mmf/bassboost.h +++ b/src/3rdparty/phonon/mmf/bassboost.h @@ -19,7 +19,6 @@ along with this library. If not, see . #ifndef PHONON_MMF_BASSBOOST_H #define PHONON_MMF_BASSBOOST_H -#include #include "abstractaudioeffect.h" QT_BEGIN_NAMESPACE @@ -41,13 +40,12 @@ public: BassBoost(QObject *parent); protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // AbstractAudioEffect + virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player); + virtual void connectVideoPlayer(VideoPlayer::NativePlayer *player); + virtual void applyParameters(); + virtual void parameterChanged(const int id, const QVariant &value); - virtual bool activateOn(CPlayerType *player); - -private: - QScopedPointer m_bassBoost; }; } } diff --git a/src/3rdparty/phonon/mmf/effectfactory.cpp b/src/3rdparty/phonon/mmf/effectfactory.cpp index e9c5e27..cc94367 100644 --- a/src/3rdparty/phonon/mmf/effectfactory.cpp +++ b/src/3rdparty/phonon/mmf/effectfactory.cpp @@ -113,7 +113,7 @@ bool isEffectSupported() AudioPlayer audioPlayer; QScopedPointer eff; - TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player()))); + TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.nativePlayer()))); return errorCode != KErrNone; } diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index a9a012f..4653fee 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -358,6 +358,25 @@ void MMF::MediaObject::volumeChanged(qreal volume) } //----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Connection of MediaObject to MediaObject"); +} + +void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Disconnection of MediaObject from MediaObject"); +} + + +//----------------------------------------------------------------------------- // Video output //----------------------------------------------------------------------------- @@ -372,12 +391,6 @@ AbstractPlayer *MMF::MediaObject::abstractPlayer() const return m_player.data(); } -bool MMF::MediaObject::activateOnMediaObject(MediaObject *) -{ - // Guess what, we do nothing. - return true; -} - //----------------------------------------------------------------------------- // Playlist support //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 7c39598..668b953 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -75,6 +75,10 @@ public: virtual qint32 transitionTime() const; virtual void setTransitionTime(qint32); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + /** * This class owns the AbstractPlayer, and will delete it upon * destruction. @@ -83,8 +87,6 @@ public: void setVideoOutput(VideoOutput* videoOutput); - virtual bool activateOnMediaObject(MediaObject *); - public Q_SLOTS: void volumeChanged(qreal volume); void switchToNextSource(); diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.cpp b/src/3rdparty/phonon/mmf/mmf_medianode.cpp index 253c5e7..ca413d9 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp +++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp @@ -29,92 +29,123 @@ using namespace Phonon::MMF; \internal */ -MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent) - , m_source(0) - , m_target(0) - , m_isApplied(false) +MMF::MediaNode::MediaNode(QObject *parent) + : QObject(parent) + , m_mediaObject(qobject_cast(this)) + , m_input(0) { -} - -bool MMF::MediaNode::connectMediaNode(MediaNode *target) -{ - m_target = target; - m_target->setSource(this); - return applyNodesOnMediaObject(target); } -bool MMF::MediaNode::disconnectMediaNode(MediaNode *target) +MMF::MediaNode::~MediaNode() { - Q_UNUSED(target); - m_target = 0; - m_isApplied = false; - return true; + // Phonon framework ensures nodes are disconnected before being destroyed. + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, + "Media node not disconnected before destruction"); } -void MMF::MediaNode::setSource(MediaNode *source) +bool MMF::MediaNode::connectOutput(MediaNode *output) { - m_source = source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool connected = false; + + // Check that this connection will not result in a graph which + // containing more than one MediaObject + const bool mediaObjectMisMatch = + m_mediaObject + && output->m_mediaObject + && m_mediaObject != output->m_mediaObject; + + const bool canConnect = + !output->isMediaObject() + && !output->m_input + && !m_outputs.contains(output); + + if (canConnect && !mediaObjectMisMatch) { + output->m_input = this; + m_outputs += output; + updateMediaObject(); + connected = true; + } + + return connected; } -MMF::MediaNode *MMF::MediaNode::source() const +bool MMF::MediaNode::disconnectOutput(MediaNode *output) { - return m_source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool disconnected = false; + + if (m_outputs.contains(output) && this == output->m_input) { + output->m_input = 0; + const bool removed = m_outputs.removeOne(output); + Q_ASSERT_X(removed, Q_FUNC_INFO, "Output removal failed"); + + Q_ASSERT_X(!m_outputs.contains(output), Q_FUNC_INFO, + "Output list contains duplicate entries"); + + // Perform traversal across each of the two graphs separately + updateMediaObject(); + output->updateMediaObject(); + + disconnected = true; + } + + return disconnected; } -MMF::MediaNode *MMF::MediaNode::target() const +bool MMF::MediaNode::isMediaObject() const { - return m_target; + return (qobject_cast(this) != 0); } -bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *) +void MMF::MediaNode::updateMediaObject() { - // Algorithmically, this can be expressed in a more efficient way by - // exercising available assumptions, but it complicates code for input - // data(length of the graph) which typically is very small. - - // First, we go to the very beginning of the graph. - MMF::MediaNode *current = this; - do { - MediaNode *const candidate = current->source(); - if (candidate) - current = candidate; - else - break; - } - while (current); - - // Now we do two things, while walking to the other end: - // 1. Find the MediaObject, if present - // 2. Collect a list of all unapplied MediaNodes - - QList unapplied; - MMF::MediaObject *mo = 0; + QList nodes; + MediaObject *mediaObject = 0; - do { - if (!current->m_isApplied) - unapplied.append(current); + // Traverse the graph, collecting a list of nodes, and locating + // the MediaObject node, if present + visit(nodes, mediaObject); - if (!mo) - mo = qobject_cast(current); + MediaNode *node = 0; + foreach(node, nodes) + node->setMediaObject(mediaObject); +} - current = current->target(); +void MMF::MediaNode::setMediaObject(MediaObject *mediaObject) +{ + if(!isMediaObject() && m_mediaObject != mediaObject) { + if (!mediaObject) + disconnectMediaObject(m_mediaObject); + else { + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, "MediaObject already set"); + connectMediaObject(mediaObject); + } + m_mediaObject = mediaObject; } - while (current); +} - // Now, lets activate all the objects, if we found the MediaObject. +void MMF::MediaNode::visit(QList& visited, MediaObject*& mediaObject) +{ + if (isMediaObject()) { + // There can never be more than one MediaObject per graph, due to the + // mediaObjectMisMatch test in connectOutput(). + Q_ASSERT_X(!mediaObject, Q_FUNC_INFO, "MediaObject already found"); + mediaObject = static_cast(this); + } - if (mo) { - for (int i = 0; i < unapplied.count(); ++i) { - MediaNode *const at = unapplied.at(i); + visited += this; - // We don't want to apply MediaObject on itself. - if (at != mo) - at->activateOnMediaObject(mo); - } - } + if (m_input && !visited.contains(m_input)) + m_input->visit(visited, mediaObject); - return true; + MediaNode *output = 0; + foreach (output, m_outputs) + if (!visited.contains(output)) + output->visit(visited, mediaObject); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.h b/src/3rdparty/phonon/mmf/mmf_medianode.h index 4616ff1..0ed21c4 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.h +++ b/src/3rdparty/phonon/mmf/mmf_medianode.h @@ -43,54 +43,62 @@ class MediaObject; /** * @short Base class for all nodes in the MMF backend. * - * MediaNode is the base class for all nodes in the chain for MMF. Currently - * they are: + * MediaNode is the base class for all nodes created by the MMF + * backend. * - * - MediaObject: a source of media - * - AbstractEffect: supplying audio effects - * - AudioOutput: pretty much a dummy interface, but is also MediaNode in order - * to simplify connection/disconnection. + * These nodes may be one of the following types: * - * MediaNode provides spectatability into the chain, and also allows the - * connection code to be written in a polymorphic manner, instead of putting it - * all in the Backend class. Due to that MMF has no concept of chaining, the - * order of the nodes in the graph has no meaning. + * - MediaObject + * This represents the source of media data. It encapsulates the + * appropriate MMF client API for playing audio or video. + * - AudioOutput + * This represents the audio output device. Since the MMF client API + * does not expose the output device directly, this backend node + * simply forwards volume control commands to the MediaObject. + * - VideoWidget + * A native widget on which video will be rendered. + * - An audio effect, derived form AbstractAudioEffect + * + * Because the MMF API does not support the concept of a media filter graph, + * this class must ensure the following: + * + * - Each media graph contains at most one MediaObject instance. + * - Every non-MediaObject node holds a reference to the MediaObject. This + * allows commands to be sent through the graph to the encapsulated MMF client + * API. */ class MediaNode : public QObject { Q_OBJECT public: MediaNode(QObject *parent); + ~MediaNode(); + + bool connectOutput(MediaNode *output); + bool disconnectOutput(MediaNode *output); + + virtual void connectMediaObject(MediaObject *mediaObject) = 0; + virtual void disconnectMediaObject(MediaObject *mediaObject) = 0; - virtual bool connectMediaNode(MediaNode *target); - virtual bool disconnectMediaNode(MediaNode *target); - void setSource(MediaNode *source); +private: + bool isMediaObject() const; - MediaNode *source() const; - MediaNode *target() const; + void updateMediaObject(); + void setMediaObject(MediaObject *mediaObject); -protected: - /** - * When connectMediaNode() is called and a MediaObject is part of - * the its graph, this function will be called for each MediaNode in the - * graph for which it hasn't been called yet. - * - * The caller guarantees that @p mo is always non-null. - */ - virtual bool activateOnMediaObject(MediaObject *mo) = 0; + typedef QList NodeList; + void visit(QList& visited, MediaObject*& mediaObject); private: - /** - * Finds a MediaObject anywhere in the graph @p target is apart of, and - * calls activateOnMediaObject() for all MediaNodes in the graph for which - * it hasn't been applied to already. - */ - bool applyNodesOnMediaObject(MediaNode *target); - - MediaNode * m_source; - MediaNode * m_target; - bool m_isApplied; + MediaObject * m_mediaObject; + + // All nodes except MediaObject may have an input + MediaNode * m_input; + + // Only MediaObject can have more than one output + QList m_outputs; }; + } } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index 877dfb3..127edb4 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -97,6 +97,11 @@ MMF::VideoPlayer::~VideoPlayer() TRACE_EXIT_0(); } +CVideoPlayerUtility* MMF::VideoPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index 6200e39..0253ab9 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -47,6 +47,9 @@ public: VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~VideoPlayer(); + typedef CVideoPlayerUtility NativePlayer; + NativePlayer *nativePlayer() const; + // AbstractPlayer virtual void doPlay(); virtual void doPause(); @@ -105,7 +108,7 @@ private: virtual void MvloLoadingComplete(); private: - QScopedPointer m_player; + QScopedPointer m_player; // Not owned RWsSession& m_wsSession; diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp index bd22307..bc9acfd 100644 --- a/src/3rdparty/phonon/mmf/videowidget.cpp +++ b/src/3rdparty/phonon/mmf/videowidget.cpp @@ -157,10 +157,18 @@ QWidget* MMF::VideoWidget::widget() return m_videoOutput.data(); } -bool MMF::VideoWidget::activateOnMediaObject(MediaObject *mo) +//----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::VideoWidget::connectMediaObject(MediaObject *mediaObject) +{ + mediaObject->setVideoOutput(m_videoOutput.data()); +} + +void MMF::VideoWidget::disconnectMediaObject(MediaObject *mediaObject) { - mo->setVideoOutput(m_videoOutput.data()); - return true; + mediaObject->setVideoOutput(0); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h index 2f0978b..a876748 100644 --- a/src/3rdparty/phonon/mmf/videowidget.h +++ b/src/3rdparty/phonon/mmf/videowidget.h @@ -61,7 +61,9 @@ public: virtual QWidget *widget(); protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); private: QScopedPointer m_videoOutput; -- cgit v0.12 From 60d27f4b9fd2dbed204260334b817ce41788cb3e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 13:42:05 +0200 Subject: Added UIDs and icons to some webkit examples Reviewed-by: TrustMe --- examples/webkit/domtraversal/domtraversal.pro | 5 +++++ examples/webkit/fancybrowser/fancybrowser.pro | 5 ++++- examples/webkit/googlechat/googlechat.pro | 5 ++++- examples/webkit/simpleselector/simpleselector.pro | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/webkit/domtraversal/domtraversal.pro b/examples/webkit/domtraversal/domtraversal.pro index 49400de..ba5f2d8 100644 --- a/examples/webkit/domtraversal/domtraversal.pro +++ b/examples/webkit/domtraversal/domtraversal.pro @@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal INSTALLS += target sources + +symbian { + TARGET.UID3 = 0xA000D7CB + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/fancybrowser/fancybrowser.pro b/examples/webkit/fancybrowser/fancybrowser.pro index e496241..3786d9c 100644 --- a/examples/webkit/fancybrowser/fancybrowser.pro +++ b/examples/webkit/fancybrowser/fancybrowser.pro @@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/fancybrowser INSTALLS += target sources -symbian:TARGET.UID3 = 0xA000CF6C +symbian { + TARGET.UID3 = 0xA000CF6C + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/googlechat/googlechat.pro b/examples/webkit/googlechat/googlechat.pro index 8e4f9a6..3d32c1b 100644 --- a/examples/webkit/googlechat/googlechat.pro +++ b/examples/webkit/googlechat/googlechat.pro @@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$FORMS *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/googlechat INSTALLS += target sources -symbian:TARGET.UID3 = 0xA000CF6E +symbian { + TARGET.UID3 = 0xA000CF6E + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} diff --git a/examples/webkit/simpleselector/simpleselector.pro b/examples/webkit/simpleselector/simpleselector.pro index 3f3037f..acd0ae7 100644 --- a/examples/webkit/simpleselector/simpleselector.pro +++ b/examples/webkit/simpleselector/simpleselector.pro @@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector INSTALLS += target sources + +symbian { + TARGET.UID3 = 0xA000D7CC + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) +} -- cgit v0.12 From e2f2765b52508515874edea7015c01eb95ff89be Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 15:10:07 +0200 Subject: Separated "make run" and "make runonphone" targets Reviewed-by: axis --- doc/src/platforms/symbian-introduction.qdoc | 28 ++++++++++++++++++++++------ qmake/generators/symbian/symmake.cpp | 7 +------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/doc/src/platforms/symbian-introduction.qdoc b/doc/src/platforms/symbian-introduction.qdoc index 477e629..4d06bbc 100644 --- a/doc/src/platforms/symbian-introduction.qdoc +++ b/doc/src/platforms/symbian-introduction.qdoc @@ -124,12 +124,8 @@ \row \o \c release-gcce \o Build release binaries for hardware using GCCE. \row \o \c debug-armv5 \o Build debug binaries for hardware using RVCT. \row \o \c release-armv5 \o Build release binaries for hardware using RVCT. - \row \o \c run \o Run the application. Environment variable - \c QT_SIS_TARGET (see below) can be used to specify which - build target is run. By default it is the last build target. - Note that running the application on real device - using this command requires \c TRK application to be running - on the device. + \row \o \c run \o Run the application on the emulator. + \row \o \c runonphone \o Run the application on a device. \row \o \c sis \o Create signed \c .sis file for project. \endtable @@ -199,4 +195,24 @@ with the \c QT_SIS_OPTIONS=-i, like this: \snippet doc/src/snippets/code/doc_src_symbian-introduction.qdoc 5 + + \section1 Running applications from command line + + The application can be launched on the emulator using \c{make run} command. + + The application can be launched on a device using \c{make runonphone} command. + When this command is invoked, a \c .sis file is first created as if \c{make sis} + command was invoked (see above for details). + \bold{Note:} Running the application on a device using this command requires + \c TRK application to be running on the device. + + Additional environment variables that can be utilized with these commands are: + \table + \row \o \c QT_RUN_OPTIONS \o Any command line parameters you wish to pass + to your application. + \row \o \c QT_RUN_ON_PHONE_OPTIONS \o Options for runonphone application. + Execute \c runonphone from command line for + more information about available options. + \c{make runonphone} only. + \endtable */ diff --git a/qmake/generators/symbian/symmake.cpp b/qmake/generators/symbian/symmake.cpp index b2709d1..81f2d15 100644 --- a/qmake/generators/symbian/symmake.cpp +++ b/qmake/generators/symbian/symmake.cpp @@ -1857,16 +1857,11 @@ void SymbianMakefileGenerator::generateExecutionTargets(QTextStream& t, const QS // create execution targets if (targetType == TypeExe) { if (platforms.contains("winscw")) { - t << "ifeq (\"DEBUG-winscw\", \"$(QT_SIS_TARGET)\")" << endl; t << "run:" << endl; t << "\t-call " << epocRoot() << "epoc32/release/winscw/udeb/" << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; - t << "else" << endl; } - t << "run: sis" << endl; + t << "runonphone: sis" << endl; t << "\trunonphone $(QT_RUN_ON_PHONE_OPTIONS) --sis " << fixedTarget << "_$(QT_SIS_TARGET).sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; - if (platforms.contains("winscw")) { - t << "endif" << endl; - } t << endl; } } -- cgit v0.12 From 784374ac949ecf2fdc6895908e1e4dfe938931b8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 7 Jan 2010 17:25:13 +0200 Subject: Deploy sqlite3.sis instead of sqlite3.dll in Symbian Task-number: QTBUG-4879 Reviewed-by: Shane Kearns --- src/s60installs/s60installs.pro | 7 +++---- src/s60installs/sqlite3.sis | Bin 0 -> 286192 bytes 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 src/s60installs/sqlite3.sis diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index e024396..eb35419 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -35,10 +35,8 @@ symbian: { qtlibraries.pkg_postrules += qts60plugindeployment sqlitedeployment = \ - "; Deploy sqlite onto phone that does not have it (this should be replaced with embedded sis file when available)" \ - "IF NOT package(0x2002533b) " \ - "\"$${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/sqlite3.dll\" - \"c:\\sys\\bin\\sqlite3.dll\"" \ - "ENDIF" + "; Deploy sqlite onto phone that does not have it already" \ + "@\"sqlite3.sis\", (0x2002af5f)" qtlibraries.pkg_postrules += sqlitedeployment qtlibraries.path = c:/sys/bin @@ -61,6 +59,7 @@ symbian: { contains(CONFIG, stl) { qtlibraries.pkg_prerules += "(0x2000F866), 1, 0, 0, {\"Standard C++ Library Common\"}" } + qtlibraries.pkg_prerules += "(0x2002af5f), 0, 5, 0, {\"sqlite3\"}" !contains(QT_CONFIG, no-jpeg): imageformats_plugins.sources += qjpeg.dll !contains(QT_CONFIG, no-gif): imageformats_plugins.sources += qgif.dll diff --git a/src/s60installs/sqlite3.sis b/src/s60installs/sqlite3.sis new file mode 100644 index 0000000..1785365 Binary files /dev/null and b/src/s60installs/sqlite3.sis differ -- cgit v0.12 From 4378b168ad289e1acbde9580b750ce04b51260c3 Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Fri, 8 Jan 2010 09:54:48 +0200 Subject: Fix for QTBUG-5870 QGraphicsProxyWidget does not show children on Symbian. QS60PaintEngine returned wrong device in QPaintEngine::paintDevice(). Task-number: QTBUG-5870 Reviewed-by: Jason Barron --- src/gui/painting/qpaintengine_s60.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp index 6f4f398..c5840f1 100644 --- a/src/gui/painting/qpaintengine_s60.cpp +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -47,18 +47,25 @@ QT_BEGIN_NAMESPACE class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate { public: - QS60PaintEnginePrivate(QS60PaintEngine *engine) { Q_UNUSED(engine); } + QS60PaintEnginePrivate() {} }; QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data) - : QRasterPaintEngine(*(new QS60PaintEnginePrivate(this)), device), pixmapData(data) + : QRasterPaintEngine(*(new QS60PaintEnginePrivate), device), pixmapData(data) { } bool QS60PaintEngine::begin(QPaintDevice *device) { + Q_D(QS60PaintEngine); + pixmapData->beginDataAccess(); - return QRasterPaintEngine::begin(device); + bool ret = QRasterPaintEngine::begin(device); + // Make sure QPaintEngine::paintDevice() returns the proper device. + // QRasterPaintEngine changes pdev to QImage in case of RasterClass QPixmapData + // which is incorrect in Symbian. + d->pdev = device; + return ret; } bool QS60PaintEngine::end() -- cgit v0.12 From 1f8fa41e78b4174ab64953dd80a1d562b0afc5aa Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 8 Jan 2010 12:30:43 +0200 Subject: Added mention of Symbian binary packages to INSTALL file Task-number: QTBUG-6162 Reviewed-by: TrustMe --- dist/README | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/README b/dist/README index e7dfb19..73c8be1 100644 --- a/dist/README +++ b/dist/README @@ -26,6 +26,10 @@ For Mac OS X Cocoa, the binary package requires Mac OS X 10.5 (Leopard) or later and GCC 4.0.1 to develop applications. Its applications will run on Mac OS X 10.5 and above. +If you want to install the precompiled binary package for Symbian, +follow these instructions: +http://qt.nokia.com/doc/%SHORTVERSION%/install-symbian-installer.html + DEMOS AND EXAMPLES -- cgit v0.12 From 32419380bdd11e7db401fd37a840e0ec4f5b6845 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 7 Jan 2010 17:46:16 +0000 Subject: Enable building with MSVC2008 Removed the alternate implementation of the registry reading, although the new API is simpler, the old XP method is not deprecated. Added an extra library that is needed according to API documentation, but is omittable on MinGW. Also gave a better error message when serial port detection fails. Reviewed-by: Miikka Heikkinen --- tools/runonphone/main.cpp | 4 ++++ tools/runonphone/runonphone.pro | 3 ++- tools/runonphone/serenum_win.cpp | 11 +---------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index e2f6758..6081e67 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -155,6 +155,10 @@ int main(int argc, char *argv[]) serialPortName = id.portName; } } + if(serialPortName.isEmpty()) { + errstream << "No phone found, ensure USB cable is connected or specify manually with -p" << endl; + return 1; + } } QScopedPointer launcher; diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro index d243121..cf0c055 100644 --- a/tools/runonphone/runonphone.pro +++ b/tools/runonphone/runonphone.pro @@ -15,5 +15,6 @@ HEADERS += trksignalhandler.h \ windows { SOURCES += serenum_win.cpp LIBS += -lsetupapi \ - -luuid + -luuid \ + -ladvapi32 } diff --git a/tools/runonphone/serenum_win.cpp b/tools/runonphone/serenum_win.cpp index ec11c3c..23e3862 100644 --- a/tools/runonphone/serenum_win.cpp +++ b/tools/runonphone/serenum_win.cpp @@ -77,8 +77,7 @@ QList enumerateSerialPorts() } HKEY key = SetupDiOpenDevRegKey(infoset, &info, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); if(key != INVALID_HANDLE_VALUE) { -#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 - //RegGetValue not supported on XP, SHRegGetValue not supported by mingw :( + //RegGetValue not supported on XP, SHRegGetValue not supported by mingw, so use the old method of enumerating all the values for (DWORD dwi=0;;dwi++) { DWORD vsize = valueName.size(); if (ERROR_SUCCESS == RegEnumValue(key, dwi, (WCHAR*)(valueName.data()), &vsize, 0, 0, 0, &size)) { @@ -93,14 +92,6 @@ QList enumerateSerialPorts() break; } } -#else - if (ERROR_SUCCESS == SHRegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, 0, &size)) { - QByteArray ba(size, 0); - if (ERROR_SUCCESS == RegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, (BYTE*)(ba.data()), &size)) { - portName = QString((const QChar*)(ba.constData()), ba.size() / 2 - 1); - } - } -#endif RegCloseKey(key); } SerialPortId id; -- cgit v0.12