diff options
author | Gareth Stockwell <ext-gareth.stockwell@nokia.com> | 2009-12-04 11:49:12 (GMT) |
---|---|---|
committer | Jason McDonald <jason.mcdonald@nokia.com> | 2010-01-11 13:44:25 (GMT) |
commit | eb2d09cff261b6e2fdff7b45b0cd30151c71bc97 (patch) | |
tree | d64523cabdd9c11b35cf2c86d2d8b660bda9bc10 | |
parent | 9db0466448b83e99fafcd0b890eb39304b247af9 (diff) | |
download | Qt-eb2d09cff261b6e2fdff7b45b0cd30151c71bc97.zip Qt-eb2d09cff261b6e2fdff7b45b0cd30151c71bc97.tar.gz Qt-eb2d09cff261b6e2fdff7b45b0cd30151c71bc97.tar.bz2 |
Implemented node disconnection in Phonon MMF backend
Task-number: QTBUG-4663
Reviewed-by: Frans Englich
(cherry picked from commit 3f648dc075689e2ffedda2769cc76b4a56fb1073)
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 <http://www.gnu.org/licenses/>. #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<EffectParameter> ¶ms) : MediaNode::MediaNode(parent) - , m_params(params) + const QList<EffectParameter> ¶ms) + : MediaNode::MediaNode(parent) + , m_player(0) + , m_params(params) { } -bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target) -{ - MediaNode::disconnectMediaNode(target); - m_effect.reset(); - return true; -} - QList<EffectParameter> 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<AudioPlayer *>(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<AbstractMediaPlayer *>(mediaObject->abstractPlayer()); + + if (player) { + m_player = player; + + if (AudioPlayer *audioPlayer = qobject_cast<AudioPlayer *>(player)) { + connectAudioPlayer(audioPlayer->nativePlayer()); + } else { + VideoPlayer *videoPlayer = qobject_cast<VideoPlayer *>(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 <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_ABSTRACTEFFECT_H #define PHONON_MMF_ABSTRACTEFFECT_H -#include "mmf_medianode.h" - #include <QScopedPointer> #include <AudioEffectBase.h> #include <Phonon/EffectInterface> #include <Phonon/EffectParameter> + #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<CAudioEffect> m_effect; + private: + AbstractMediaPlayer * m_player; const QList<EffectParameter> m_params; QHash<int, QVariant> 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 <http://www.gnu.org/licenses/>. */ +#include <AudioEqualizerBase.h> #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<CAudioEqualizer *>(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<CAudioEqualizer *>(m_effect.data()); + // TODO: handle audio effect errors + TRAP_IGNORE(effect->SetBandLevelL(band, level)); } QList<EffectParameter> AudioEqualizer::createParams() @@ -57,7 +83,7 @@ QList<EffectParameter> AudioEqualizer::createParams() AudioPlayer dummyPlayer; CAudioEqualizer *eqPtr = 0; - QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.player());) + QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.nativePlayer())); QScopedPointer<CAudioEqualizer> 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 <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_AUDIOEQUALIZER_H #define PHONON_MMF_AUDIOEQUALIZER_H -#include <AudioEqualizerBase.h> #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<EffectParameter> createParams(); - QScopedPointer<CAudioEqualizer> 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<QByteArray, QVariant> 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 <drmaudiosampleplayer.h> -typedef CDrmPlayerUtility CPlayerType; -typedef MDrmAudioPlayerCallback MPlayerObserverType; +typedef MDrmAudioPlayerCallback NativePlayerObserver; #else #include <mdaaudiosampleplayer.h> -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<CPlayerType> m_player; + QScopedPointer<NativePlayer> 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<QObject *>) 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<MediaNode *>(source)); - Q_ASSERT(qobject_cast<MediaNode *>(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); - MediaNode *const mediaSource = static_cast<MediaNode *>(source); - MediaNode *const mediaTarget = static_cast<MediaNode *>(target); + MediaNode *const source = qobject_cast<MediaNode *>(sourceObject); + MediaNode *const target = qobject_cast<MediaNode *>(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<MediaNode *>(source)); - Q_ASSERT(qobject_cast<MediaNode *>(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); + + MediaNode *const source = qobject_cast<MediaNode *>(sourceObject); + MediaNode *const target = qobject_cast<MediaNode *>(targetObject); - const bool result = static_cast<MediaNode *>(source)->disconnectMediaNode(static_cast<MediaNode *>(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<QObject *>) 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 <http://www.gnu.org/licenses/>. */ +#include <BassBoostBase.h> #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 <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_BASSBOOST_H #define PHONON_MMF_BASSBOOST_H -#include <BassBoostBase.h> #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<CBassBoost> 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<TEffect> 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<MediaObject *>(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<const MediaObject *>(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<MediaNode *> unapplied; - MMF::MediaObject *mo = 0; + QList<MediaNode *> 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<MMF::MediaObject *>(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<MediaNode *>& 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<MediaObject *>(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<const MediaNode *> NodeList; + void visit(QList<MediaNode *>& 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<MediaNode *> 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<CVideoPlayerUtility> m_player; + QScopedPointer<NativePlayer> 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<VideoOutput> m_videoOutput; |