diff options
64 files changed, 6818 insertions, 83 deletions
diff --git a/demos/embedded/fluidlauncher/config_s60/config.xml b/demos/embedded/fluidlauncher/config_s60/config.xml index 192a2e3..acd14cb 100644 --- a/demos/embedded/fluidlauncher/config_s60/config.xml +++ b/demos/embedded/fluidlauncher/config_s60/config.xml @@ -20,6 +20,7 @@ <example filename="weatherinfo" name="Weather Info" image="screenshots/weatherinfo.png"/> <example filename="flickable" name="Kinetic Scrolling" image="screenshots/flickable.png"/> <example filename="digiflip" name="Flipping Clock" image="screenshots/digiflip.png"/> + <example filename="qmediaplayer" name="Media Player" image="screenshots/mediaplayer.png"/> </demos> <slideshow timeout="60000" interval="10000"> <imagedir dir="slides"/> diff --git a/demos/embedded/fluidlauncher/fluidlauncher.pro b/demos/embedded/fluidlauncher/fluidlauncher.pro index 3ed4f31..62791f1 100644 --- a/demos/embedded/fluidlauncher/fluidlauncher.pro +++ b/demos/embedded/fluidlauncher/fluidlauncher.pro @@ -96,6 +96,11 @@ symbian { $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/lightmaps_reg.rsc \ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/flightinfo_reg.rsc + contains(QT_CONFIG, phonon) { + reg_resource.sources += $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/qmediaplayer_reg.rsc + } + + reg_resource.path = $$REG_RESOURCE_IMPORT_DIR resource.sources = \ @@ -136,6 +141,11 @@ symbian { reg_resource.sources += $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/anomaly_reg.rsc resource.sources += $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/anomaly.rsc } + + contains(QT_CONFIG, phonon) { + resource.sources += $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/qmediaplayer.rsc + } + contains(QT_CONFIG, script) { executables.sources += context2d.exe reg_resource.sources += $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/context2d_reg.rsc diff --git a/demos/mediaplayer/mediaplayer.cpp b/demos/mediaplayer/mediaplayer.cpp index 8dd0609..30e3a5b 100644 --- a/demos/mediaplayer/mediaplayer.cpp +++ b/demos/mediaplayer/mediaplayer.cpp @@ -152,6 +152,9 @@ MediaPlayer::MediaPlayer(const QString &filePath) : m_AudioOutput(Phonon::VideoCategory), m_videoWidget(new MediaVideoWidget(this)) { + m_videoWindow.setObjectName("videoWindow"); + m_videoWidget->setObjectName("videoWidget"); + setWindowTitle(tr("Media Player")); setContextMenuPolicy(Qt::CustomContextMenu); m_videoWidget->setContextMenuPolicy(Qt::CustomContextMenu); @@ -159,6 +162,7 @@ MediaPlayer::MediaPlayer(const QString &filePath) : QSize buttonSize(34, 28); QPushButton *openButton = new QPushButton(this); + openButton->setObjectName("openButton"); openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); QPalette bpal; @@ -169,20 +173,25 @@ MediaPlayer::MediaPlayer(const QString &filePath) : openButton->setPalette(bpal); rewindButton = new QPushButton(this); + rewindButton->setObjectName("rewindButton"); rewindButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); forwardButton = new QPushButton(this); + forwardButton->setObjectName("forwardButton"); forwardButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); forwardButton->setEnabled(false); playButton = new QPushButton(this); + playButton->setObjectName("playButton"); playIcon = style()->standardIcon(QStyle::SP_MediaPlay); pauseIcon = style()->standardIcon(QStyle::SP_MediaPause); playButton->setIcon(playIcon); slider = new Phonon::SeekSlider(this); + slider->setObjectName("slider"); slider->setMediaObject(&m_MediaObject); volume = new Phonon::VolumeSlider(&m_AudioOutput); + volume->setObjectName("volume"); QVBoxLayout *vLayout = new QVBoxLayout(this); vLayout->setContentsMargins(8, 8, 8, 8); @@ -190,6 +199,7 @@ MediaPlayer::MediaPlayer(const QString &filePath) : QHBoxLayout *layout = new QHBoxLayout(); info = new QLabel(this); + info->setObjectName("info"); info->setMinimumHeight(70); info->setAcceptDrops(false); info->setMargin(2); @@ -227,8 +237,11 @@ MediaPlayer::MediaPlayer(const QString &filePath) : buttonPanelLayout->addLayout(layout); timeLabel = new QLabel(this); + timeLabel->setObjectName("timeLabel"); progressLabel = new QLabel(this); + progressLabel->setObjectName("progressLabel"); QWidget *sliderPanel = new QWidget(this); + sliderPanel->setObjectName("sliderPanel"); QHBoxLayout *sliderLayout = new QHBoxLayout(); sliderLayout->addWidget(slider); sliderLayout->addWidget(timeLabel); @@ -251,6 +264,7 @@ MediaPlayer::MediaPlayer(const QString &filePath) : // forwardButton->setStyle(flatButtonStyle); #endif QWidget *buttonPanelWidget = new QWidget(this); + buttonPanelWidget->setObjectName("buttonPanelWidget"); buttonPanelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); buttonPanelWidget->setLayout(buttonPanelLayout); vLayout->addWidget(buttonPanelWidget); diff --git a/demos/mediaplayer/mediaplayer.pro b/demos/mediaplayer/mediaplayer.pro index 49a652e..8f9ec82 100644 --- a/demos/mediaplayer/mediaplayer.pro +++ b/demos/mediaplayer/mediaplayer.pro @@ -3,7 +3,7 @@ ###################################################################### TEMPLATE = app -TARGET = +TARGET = qmediaplayer DEPENDPATH += . build src ui QT += phonon diff --git a/demos/qtdemo/xml/examples.xml b/demos/qtdemo/xml/examples.xml index b545e1d..3f0cd25 100644 --- a/demos/qtdemo/xml/examples.xml +++ b/demos/qtdemo/xml/examples.xml @@ -16,7 +16,7 @@ <example filename="embeddeddialogs" name="Embedded Dialogs" /> <example filename="interview" name="Interview" /> <example filename="browser" name="Browser" /> - <example filename="mediaplayer" name="Media Player" /> + <example filename="qmediaplayer" name="Media Player" /> <example filename="boxes" name="Boxes" /> <example filename="sub-attaq" name="Sub-attaq" /> </demos> diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index d455463..5be66f8 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -411,6 +411,24 @@ For information about mixing exceptions with symbian leaves, see \l{Exception Safety with Symbian} + + \section1 Multimedia and Phonon Support + + Qt provides a backend for Qt's multimedia module, Phonon, which supports + video and sound playback through Symbian's Multimedia Framework, MMF. + + In this release the support is experimental. Video playback may have + flickering issues, and support for effects and playback queueing is + incomplete. + + The audio and video formats that Phonon supports depends on what support + the platform provides for MMF. The emulator is known to have limited + codec support. + + In addition, there exists a backend for the Helix framework. However, due + to it not shipping with Qt, its availability depends on the Symbian + platform in use. If available, it is loaded instead of the MMF plugin. + */ /*! diff --git a/src/3rdparty/phonon/mmf/TODO.txt b/src/3rdparty/phonon/mmf/TODO.txt new file mode 100644 index 0000000..47abddc --- /dev/null +++ b/src/3rdparty/phonon/mmf/TODO.txt @@ -0,0 +1,41 @@ +TODO list for MMF Phonon backend +-------------------------------- + +The following items are in rough order of priority. + + +* Review the latest changes for making video visible on target. In particular, the temporary hack in qmediaplayer (setting the Qt::WA_TranslucentBackground attribute on the top-level widget, so that the CFbsBitmap used as the window surface is created with a display mode of EColor16MA) needs to be replaced with a change in QtGui. Some possiblilities are as follows: +1. Change the QS60WindowSurface constructor so that *all* window surfaces are 16MA. This has some drawbacks: + - It causes application backgrounds to be transparent, because CFbsBitmap data (including the alpha channel) gets zero-initialized. This may require the alpha values in the bitmap to be set to 255. + - Blitting of RGB32 and ABGR Qt pixmaps to a 16MA surface is slower than blitting to 16MU. This could be alleviated by modifying the software blitting routines. +2. Add a function in QS60WindowSurface, e.g. setAlphaValue(const QRegion& region, int value), allowing the client to set alpha values in the bitmap. Assuming that WSERV will transfer these values, when blitting a 16MU source, this would allow the video to be visible, and avoid the performance penalties of option (1). We would then call this from VideoOutput::paintEvent. + +* On-target testing +1. Ensure that Phonon front- and back-end libraries are included in the SIS file. +2. Add musicplayer.exe and mediaplayer.exe to the FluidLauncher +3. Ensure that both apps can be launched, and that we can somehow get trace output from the MMF backend onto the PC for analysis. + +* Trace for on-target testing +Do we need to connect up the TRACE_* macros to another logging output (e.g. file / Flogger / UTrace etc)? + +* Implement audio effects + +* Support for network streaming playback +The main question here is how best to implement the MIME type detection for streams. The OpenUrlL functions only take a URL, whereas the corresponding OpenFileL functions have overloads for filenames and for open RFile handles. This is because files support random access whereas streams do not. A naieve approach to MIME type detection for streams is as follows; is there a more efficient approach? + 1. Open network connection + 2. Download header + 3. Detect MIME type and create AbstractMediaPlayer instance + 4. Close network connection + 5. Pass URL to MMF client utility, which will then re-open the stream +An alternative approach is to always create a VideoPlayer when passed an RTSP URL, and then modify VideoPlayer::hasVideo to check CVideoPlayerUtility::VideoMimeTypeL before returning. This way, we would always use CVideoPlayerUtility for RTSP streaming, whether the source is audio or video. Well-behaved client apps, however, should check MediaObject::hasVideo before creating the UI - and therefore the VideoWidget would only be connected if the source is actually a video stream. + +* Performance analysis +Compare video frame rate obtained using default S60 media player and Qt demo apps + +* Implement MMF::Backend::disconnectNodes +This should probably be left for now, particularly until audio effects have been implemented. This is because the node connection mechanism may need to be refactored slightly once we start building up longer graphs (e.g. MediaObject -> Effect -> Effect -> AudioOutput). + +* Before merging, ensure the UID3 is properly allocated, see the .pro file. + +* Metadata is not implemented. + diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp new file mode 100644 index 0000000..b3155a6 --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp @@ -0,0 +1,74 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "mediaobject.h" + +#include "abstractaudioeffect.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +AbstractAudioEffect::AbstractAudioEffect(QObject *parent, + const QList<EffectParameter> ¶ms) : MediaNode::MediaNode(parent) + , m_params(params) +{ +} + +bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target) +{ + MediaNode::disconnectMediaNode(target); + m_effect.reset(); + return true; +} + +QList<EffectParameter> AbstractAudioEffect::parameters() const +{ + return m_params; +} + +QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam) const +{ + const QVariant &val = m_values.value(queriedParam.id()); + + if (val.isNull()) + return queriedParam.defaultValue(); + else + 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); +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h new file mode 100644 index 0000000..01542c9 --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h @@ -0,0 +1,105 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_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" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ + +/** + * @short Base class for all effects for MMF. + * + * Adhering to Phonon with MMF is cumbersome because of a number of reasons: + * + * - MMF has no concept of effect chaining. Simply, an effect is a applied + * to PlayerUtility, that's it. This means that the order of effects is + * undefined. + * - We apply an effect to a PlayerUtility, and MediaObject has that one. + * However, effects might be created before MediaObject, but nevertheless + * needs to work. We solve this by that we are aware of the whole connection + * chain, and whenever a connection happens, we walk the chain, find effects + * that aren't applied, and apply it if we have a media object. + * - There are plenty of corner cases which we don't handle and where behavior + * are undefined. For instance, graphs with more than one MediaObject. + */ +class AbstractAudioEffect : public MediaNode + , public EffectInterface +{ + Q_OBJECT + Q_INTERFACES(Phonon::EffectInterface) +public: + AbstractAudioEffect(QObject *parent, + const QList<EffectParameter> ¶ms); + + virtual QList<EffectParameter> parameters() const; + virtual QVariant parameterValue(const EffectParameter ¶m) const; + virtual void setParameterValue(const EffectParameter &, + const QVariant &newValue); + + virtual bool disconnectMediaNode(MediaNode *target); + + enum Type + { + EffectAudioEqualizer = 1, + EffectBassBoost, + EffectDistanceAttenuation, + EffectEnvironmentalReverb, + EffectListenerOrientation, + EffectLoudness, + EffectSourceOrientation, + EffectStereoWidening + }; + +protected: + virtual bool activateOn(CPlayerType *player) = 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); + + QScopedPointer<CAudioEffect> m_effect; +private: + const QList<EffectParameter> m_params; + QHash<int, QVariant> m_values; +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp new file mode 100644 index 0000000..2f2146b --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -0,0 +1,465 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "abstractmediaplayer.h" +#include "defs.h" +#include "utils.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +const int NullMaxVolume = -1; + + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::AbstractMediaPlayer::AbstractMediaPlayer() : + m_state(GroundState) + , m_error(NoError) + , m_playPending(false) + , m_tickTimer(new QTimer(this)) + , m_volume(InitialVolume) + , m_mmfMaxVolume(NullMaxVolume) +{ + connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); +} + +MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : + AbstractPlayer(player) + , m_state(GroundState) + , m_error(NoError) + , m_playPending(false) + , m_tickTimer(new QTimer(this)) + , m_volume(InitialVolume) + , m_mmfMaxVolume(NullMaxVolume) +{ + connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); +} + +MMF::AbstractMediaPlayer::~AbstractMediaPlayer() +{ + +} + + +//----------------------------------------------------------------------------- +// MediaObjectInterface +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::play() +{ + TRACE_CONTEXT(AbstractMediaPlayer::play, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + switch (m_state) { + case GroundState: + // Is this the correct error? Really we want 'NotReadyError' + m_error = NormalError; + changeState(ErrorState); + break; + + case LoadingState: + m_playPending = true; + break; + + case StoppedState: + case PausedState: + doPlay(); + startTickTimer(); + changeState(PlayingState); + break; + + case PlayingState: + case BufferingState: + case ErrorState: + // Do nothing + break; + + // Protection against adding new states and forgetting to update this switch + default: + TRACE_PANIC(InvalidStatePanic); + } + + TRACE_EXIT("state %d", m_state); +} + +void MMF::AbstractMediaPlayer::pause() +{ + TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + m_playPending = false; + + switch (m_state) { + case GroundState: + case LoadingState: + case StoppedState: + case PausedState: + case ErrorState: + // Do nothing + break; + + case PlayingState: + case BufferingState: + doPause(); + stopTickTimer(); + changeState(PausedState); + break; + + // Protection against adding new states and forgetting to update this switch + default: + TRACE_PANIC(InvalidStatePanic); + } + + TRACE_EXIT("state %d", m_state); +} + +void MMF::AbstractMediaPlayer::stop() +{ + TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + m_playPending = false; + + switch (m_state) { + case GroundState: + case LoadingState: + case StoppedState: + case ErrorState: + // Do nothing + break; + + case PlayingState: + case BufferingState: + case PausedState: + doStop(); + stopTickTimer(); + changeState(StoppedState); + break; + + // Protection against adding new states and forgetting to update this switch + default: + TRACE_PANIC(InvalidStatePanic); + } + + TRACE_EXIT("state %d", m_state); +} + +void MMF::AbstractMediaPlayer::seek(qint64 ms) +{ + TRACE_CONTEXT(AbstractMediaPlayer::seek, EAudioApi); + TRACE_ENTRY("state %d pos %Ld", state(), ms); + + switch (m_state) { + // Fallthrough all these + case GroundState: + case StoppedState: + case PausedState: + case PlayingState: + case LoadingState: + { + const bool tickTimerWasRunning = m_tickTimer->isActive(); + stopTickTimer(); + + doSeek(ms); + + if (tickTimerWasRunning) { + startTickTimer(); + } + break; + } + case BufferingState: + // Fallthrough + case ErrorState: + // Do nothing + break; + } + + TRACE_EXIT_0(); +} + +bool MMF::AbstractMediaPlayer::isSeekable() const +{ + return true; +} + +void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) +{ + TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi); + TRACE_ENTRY("state %d m_interval %d interval %d", m_state, tickInterval(), interval); + + m_tickTimer->setInterval(interval); + + TRACE_EXIT_0(); +} + +Phonon::ErrorType MMF::AbstractMediaPlayer::errorType() const +{ + const Phonon::ErrorType result = (ErrorState == m_state) + ? m_error : NoError; + return result; +} + +QString MMF::AbstractMediaPlayer::errorString() const +{ + // TODO: put in proper error strings + QString result; + return result; +} + +Phonon::State MMF::AbstractMediaPlayer::state() const +{ + return phononState(m_state); +} + +MediaSource MMF::AbstractMediaPlayer::source() const +{ + return m_source; +} + +void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file) +{ + TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi); + TRACE_ENTRY("state %d source.type %d", m_state, source.type()); + + 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; + + switch (m_source.type()) { + case MediaSource::LocalFile: { + // TODO: work out whose responsibility it is to ensure that paths + // are Symbian-style, i.e. have backslashes for path delimiters. + // Until then, use this utility function... + //const QHBufC filename = Utils::symbianFilename(m_source.fileName()); + //TRAP(symbianErr, m_player->OpenFileL(*filename)); + + // Open using shared filehandle + // This is a temporary hack to work around KErrInUse from MMF + // client utility OpenFileL calls + //TRAP(symbianErr, m_player->OpenFileL(file)); + + symbianErr = openFile(file); + break; + } + + case MediaSource::Url: { + TRACE_0("Source type not supported"); + // TODO: support opening URLs + symbianErr = KErrNotSupported; + break; + } + + case MediaSource::Invalid: + case MediaSource::Disc: + case MediaSource::Stream: + TRACE_0("Source type not supported"); + symbianErr = KErrNotSupported; + break; + + case MediaSource::Empty: + TRACE_0("Empty source - doing nothing"); + TRACE_EXIT_0(); + return; + + // Protection against adding new media types and forgetting to update this switch + default: + TRACE_PANIC(InvalidMediaTypePanic); + } + + if (KErrNone == symbianErr) { + changeState(LoadingState); + } else { + TRACE("error %d", symbianErr) + + // TODO: do something with the value of symbianErr? + m_error = NormalError; + changeState(ErrorState); + } + + TRACE_EXIT_0(); +} + +void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source) +{ + TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi); + TRACE_ENTRY("state %d", m_state); + + // TODO: handle 'next source' + + m_nextSource = source; + Q_UNUSED(source); + + TRACE_EXIT_0(); +} + + +//----------------------------------------------------------------------------- +// VolumeObserver +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) +{ + TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); + TRACE_ENTRY("state %d", m_state); + + m_volume = volume; + doVolumeChanged(); + + TRACE_EXIT_0(); +} + + +void MMF::AbstractMediaPlayer::doVolumeChanged() +{ + switch (m_state) { + case GroundState: + case LoadingState: + case ErrorState: + // Do nothing + break; + + case StoppedState: + case PausedState: + case PlayingState: + case BufferingState: { + const int err = setDeviceVolume(m_volume * m_mmfMaxVolume); + + if (KErrNone != err) { + m_error = NormalError; + changeState(ErrorState); + } + break; + } + + // Protection against adding new states and forgetting to update this + // switch + default: + Utils::panic(InvalidStatePanic); + } +} + + +//----------------------------------------------------------------------------- +// Protected functions +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::startTickTimer() +{ + m_tickTimer->start(tickInterval()); +} + +void MMF::AbstractMediaPlayer::stopTickTimer() +{ + m_tickTimer->stop(); +} + +void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) +{ + m_mmfMaxVolume = mmfMaxVolume; + doVolumeChanged(); +} + +Phonon::State MMF::AbstractMediaPlayer::phononState() const +{ + return phononState(m_state); +} + +Phonon::State MMF::AbstractMediaPlayer::phononState(PrivateState state) +{ + const Phonon::State phononState = + GroundState == state + ? Phonon::LoadingState + : static_cast<Phonon::State>(state); + + return phononState; +} + +void MMF::AbstractMediaPlayer::changeState(PrivateState newState) +{ + TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal); + TRACE_ENTRY("state %d newState %d", m_state, newState); + + // TODO: add some invariants to check that the transition is valid + + const Phonon::State oldPhononState = phononState(m_state); + const Phonon::State newPhononState = phononState(newState); + if (oldPhononState != newPhononState) { + TRACE("emit stateChanged(%d, %d)", newPhononState, oldPhononState); + emit stateChanged(newPhononState, oldPhononState); + } + + m_state = newState; + + // Check whether play() was called while clip was being loaded. If so, + // playback should be started now + if ( + LoadingState == oldPhononState + and StoppedState == newPhononState + and m_playPending + ) { + TRACE_0("play was called while loading; starting playback now"); + m_playPending = false; + play(); + } + + TRACE_EXIT_0(); +} + +void MMF::AbstractMediaPlayer::setError(Phonon::ErrorType error) +{ + TRACE_CONTEXT(AbstractMediaPlayer::setError, EAudioInternal); + TRACE_ENTRY("state %d error %d", m_state, error); + + m_error = error; + changeState(ErrorState); + + TRACE_EXIT_0(); +} + +qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) +{ + return in.Int64() / 1000; +} + + +//----------------------------------------------------------------------------- +// Slots +//----------------------------------------------------------------------------- + +void MMF::AbstractMediaPlayer::tick() +{ + // For the MWC compiler, we need to qualify the base class. + emit MMF::AbstractPlayer::tick(currentTime()); +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h new file mode 100644 index 0000000..e69f325 --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -0,0 +1,155 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_ABSTRACTMEDIAPLAYER_H +#define PHONON_MMF_ABSTRACTMEDIAPLAYER_H + +#include <QTimer> +#include <QScopedPointer> +#include <e32std.h> +#include "abstractplayer.h" + +class RFile; + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class AudioOutput; + +/** + * Interface via which MMF client APIs for both audio and video can be + * accessed. + */ +class AbstractMediaPlayer : public AbstractPlayer +{ + Q_OBJECT + +protected: + AbstractMediaPlayer(); + explicit AbstractMediaPlayer(const AbstractPlayer& player); + ~AbstractMediaPlayer(); + +public: + // MediaObjectInterface + virtual void play(); + virtual void pause(); + virtual void stop(); + virtual void seek(qint64 milliseconds); + virtual bool isSeekable() const; + virtual Phonon::ErrorType errorType() const; + virtual QString errorString() const; + virtual Phonon::State state() const; + virtual MediaSource source() const; + virtual void setFileSource(const Phonon::MediaSource&, RFile&); + virtual void setNextSource(const MediaSource &source); + + // VolumeObserver + virtual void volumeChanged(qreal volume); + +protected: + // AbstractPlayer + virtual void doSetTickInterval(qint32 interval); + + virtual void doPlay() = 0; + virtual void doPause() = 0; + virtual void doStop() = 0; + virtual void doSeek(qint64 pos) = 0; + virtual int setDeviceVolume(int mmfVolume) = 0; + virtual int openFile(RFile& file) = 0; + virtual void close() = 0; + +protected: + bool tickTimerRunning() const; + void startTickTimer(); + void stopTickTimer(); + void maxVolumeChanged(int maxVolume); + + /** + * Defined private state enumeration in order to add GroundState + */ + enum PrivateState { + LoadingState = Phonon::LoadingState, + StoppedState = Phonon::StoppedState, + PlayingState = Phonon::PlayingState, + BufferingState = Phonon::BufferingState, + PausedState = Phonon::PausedState, + ErrorState = Phonon::ErrorState, + GroundState + }; + + /** + * Converts PrivateState into the corresponding Phonon::State + */ + Phonon::State phononState() const; + + /** + * Converts PrivateState into the corresponding Phonon::State + */ + static Phonon::State phononState(PrivateState state); + + /** + * Changes state and emits stateChanged() + */ + void changeState(PrivateState newState); + + /** + * Records error and changes state to ErrorState + */ + void setError(Phonon::ErrorType error); + + static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); + +private: + void doVolumeChanged(); + +private Q_SLOTS: + /** + * Receives signal from m_tickTimer + */ + void tick(); + +private: + PrivateState m_state; + Phonon::ErrorType m_error; + + /** + * This flag is set to true if play is called when the object is + * in a Loading state. Once loading is complete, playback will + * be started. + */ + bool m_playPending; + + QScopedPointer<QTimer> m_tickTimer; + + qreal m_volume; + int m_mmfMaxVolume; + + MediaSource m_source; + MediaSource m_nextSource; + +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp new file mode 100644 index 0000000..c6f0f6b --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -0,0 +1,103 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "abstractplayer.h" +#include "defs.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::AbstractPlayer::AbstractPlayer() + : m_videoOutput(NULL) + , m_tickInterval(DefaultTickInterval) + , m_transitionTime(0) + , m_prefinishMark(0) +{ + +} + +MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer& player) + : m_videoOutput(player.m_videoOutput) + , m_tickInterval(player.tickInterval()) + , m_transitionTime(player.transitionTime()) + , m_prefinishMark(player.prefinishMark()) +{ + +} + +//----------------------------------------------------------------------------- +// MediaObjectInterface +//----------------------------------------------------------------------------- + +qint32 MMF::AbstractPlayer::tickInterval() const +{ + return m_tickInterval; +} + +void MMF::AbstractPlayer::setTickInterval(qint32 interval) +{ + m_tickInterval = interval; + doSetTickInterval(interval); +} + +qint32 MMF::AbstractPlayer::prefinishMark() const +{ + return m_prefinishMark; +} + +void MMF::AbstractPlayer::setPrefinishMark(qint32 mark) +{ + m_prefinishMark = mark; +} + +qint32 MMF::AbstractPlayer::transitionTime() const +{ + return m_transitionTime; +} + +void MMF::AbstractPlayer::setTransitionTime(qint32 time) +{ + m_transitionTime = time; +} + + +//----------------------------------------------------------------------------- +// Video output +//----------------------------------------------------------------------------- + +void MMF::AbstractPlayer::setVideoOutput(VideoOutput* videoOutput) +{ + m_videoOutput = videoOutput; + videoOutputChanged(); +} + +void MMF::AbstractPlayer::videoOutputChanged() +{ + // Default behaviour is empty - overridden by VideoPlayer +} + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h new file mode 100644 index 0000000..72d0a3b --- /dev/null +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -0,0 +1,121 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_ABSTRACTPLAYER_H +#define PHONON_MMF_ABSTRACTPLAYER_H + +#include <Phonon/phononnamespace.h> +#include <Phonon/MediaSource.h> + +#include <QObject> + +#include "volumeobserver.h" + +#include "videooutput.h" + +class RFile; + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class VideoOutput; + +/** + * @short Interface which abstracts from MediaObject the current + * media type + * + * This may be: + * - Nothing, in which case this interface is implemented by + * DummyPlayer + * - Audio, in which case the implementation is AudioPlayer + * - Video, in which case the implementation is VideoPlayer + */ +class AbstractPlayer : public QObject + , public VolumeObserver +{ + // Required although this class has no signals or slots + // Without this, qobject_cast will fail + Q_OBJECT + +public: + AbstractPlayer(); + explicit AbstractPlayer(const AbstractPlayer& player); + + // MediaObjectInterface (implemented) + qint32 tickInterval() const; + void setTickInterval(qint32); + void setTransitionTime(qint32); + qint32 transitionTime() const; + void setPrefinishMark(qint32); + qint32 prefinishMark() const; + + // MediaObjectInterface (abstract) + virtual void play() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + virtual void seek(qint64 milliseconds) = 0; + virtual bool hasVideo() const = 0; + virtual bool isSeekable() const = 0; + virtual qint64 currentTime() const = 0; + virtual Phonon::State state() const = 0; + virtual QString errorString() const = 0; + virtual Phonon::ErrorType errorType() const = 0; + virtual qint64 totalTime() const = 0; + virtual Phonon::MediaSource source() const = 0; + // This is a temporary hack to work around KErrInUse from MMF + // client utility OpenFileL calls + //virtual void setSource(const Phonon::MediaSource &) = 0; + virtual void setFileSource(const Phonon::MediaSource&, RFile&) = 0; + virtual void setNextSource(const Phonon::MediaSource &) = 0; + + void setVideoOutput(VideoOutput* videoOutput); + +Q_SIGNALS: + void totalTimeChanged(qint64 length); + void finished(); + void tick(qint64 time); + void stateChanged(Phonon::State oldState, + Phonon::State newState); + + +protected: + virtual void videoOutputChanged(); + +private: + virtual void doSetTickInterval(qint32 interval) = 0; + +protected: + // Not owned + VideoOutput* m_videoOutput; + +private: + qint32 m_tickInterval; + qint32 m_transitionTime; + qint32 m_prefinishMark; + +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp new file mode 100644 index 0000000..78c6ff7 --- /dev/null +++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp @@ -0,0 +1,85 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "audioequalizer.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +AudioEqualizer::AudioEqualizer(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect(parent, createParams()) +{ +} + +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(eq()->SetBandLevelL(pid, value.toInt())); +} + +bool AudioEqualizer::activateOn(CPlayerType *player) +{ + m_effect.reset(CAudioEqualizer::NewL(*player)); + return true; +} + +CAudioEqualizer *AudioEqualizer::eq() const +{ + return static_cast<CAudioEqualizer *>(m_effect.data()); +} + +QList<EffectParameter> AudioEqualizer::createParams() +{ + QList<EffectParameter> retval; + + // We temporarily create an AudioPlayer, and run the effect on it, so + // we can extract the readonly data we need. + AudioPlayer dummyPlayer; + activateOn(dummyPlayer.player()); + + TInt32 dbMin; + TInt32 dbMax; + eq()->DbLevelLimits(dbMin, dbMax); + + const int bandCount = eq()->NumberOfBands(); + + for (int i = 0; i < bandCount; ++i) { + const qint32 hz = eq()->CenterFrequency(i); + + const qint32 defVol = eq()->BandLevel(i); + + retval.append(EffectParameter(i, + tr("Frequency band, %1 Hz").arg(hz), + EffectParameter::LogarithmicHint, + QVariant(qint32(defVol)), + QVariant(qint32(dbMin)), + QVariant(qint32(dbMax)), + QVariantList(), + QString())); + } + + m_effect.reset(); + + return retval; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h new file mode 100644 index 0000000..6415411 --- /dev/null +++ b/src/3rdparty/phonon/mmf/audioequalizer.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_AUDIOEQUALIZER_H +#define PHONON_MMF_AUDIOEQUALIZER_H + +#include <AudioEqualizerBase.h> +#include "abstractaudioeffect.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short A classic equalizer. + * + * The equalizer has a number of bands, and each band has a frequency, and a + * volume. With Phonon's API, this is modeled such that each band is one + * Phonon::EffectParameter, where Phonon::EffectParameter::id() is the band + * number, and the setting is the volume level. + */ +class AudioEqualizer : public AbstractAudioEffect +{ + Q_OBJECT +public: + AudioEqualizer(QObject *parent); + +protected: + virtual void parameterChanged(const int id, + const QVariant &value); + + virtual bool activateOn(CPlayerType *player); + +private: + inline CAudioEqualizer *eq() const; + QList<EffectParameter> createParams(); + QScopedPointer<CAudioEqualizer> m_bassBoost; +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp new file mode 100644 index 0000000..20130ad --- /dev/null +++ b/src/3rdparty/phonon/mmf/audiooutput.cpp @@ -0,0 +1,101 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <e32debug.h> + +#include "audiooutput.h" +#include "defs.h" +#include "mediaobject.h" +#include "utils.h" +#include "volumeobserver.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::AudioOutput::AudioOutput(Backend *, QObject *parent) : MediaNode(parent) + , m_volume(InitialVolume) + , m_observer(NULL) +{ + +} + + +//----------------------------------------------------------------------------- +// Public API +//----------------------------------------------------------------------------- + +qreal MMF::AudioOutput::volume() const +{ + return m_volume; +} + +void MMF::AudioOutput::setVolume(qreal volume) +{ + TRACE_CONTEXT(AudioOutput::setVolume, EAudioApi); + TRACE_ENTRY("observer 0x%08x volume %f", m_observer, volume); + + if (volume != m_volume) { + if (m_observer) { + m_observer->volumeChanged(volume); + } + + m_volume = volume; + TRACE("emit volumeChanged(%f)", volume) + emit volumeChanged(volume); + } + + TRACE_EXIT_0(); +} + +int MMF::AudioOutput::outputDevice() const +{ + return 0; +} + +bool MMF::AudioOutput::setOutputDevice(int) +{ + return true; +} + +bool MMF::AudioOutput::setOutputDevice(const Phonon::AudioOutputDevice &) +{ + return true; +} + +void MMF::AudioOutput::setVolumeObserver(VolumeObserver* observer) +{ + m_observer = observer; + if (m_observer) { + m_observer->volumeChanged(m_volume); + } +} + +bool MMF::AudioOutput::activateOnMediaObject(MediaObject *mo) +{ + setVolumeObserver(mo); + return true; +} + +QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h new file mode 100644 index 0000000..0a962a9 --- /dev/null +++ b/src/3rdparty/phonon/mmf/audiooutput.h @@ -0,0 +1,93 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_AUDIOOUTPUT_H +#define PHONON_MMF_AUDIOOUTPUT_H + +#include "mmf_medianode.h" +#include <phonon/audiooutputinterface.h> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class Backend; +class VolumeObserver; + +/** + * @short AudioOutputInterface implementation for MMF. + * + * Forwards volume commands to the VolumeObserver instance, + * which is provided by the backend when MediaNode objects are + * connected. + * + * \section volume Volume + * + * Phonon's concept on volume is from 0.0 to 1.0, and from 1< it does + * voltage multiplication. CDrmPlayerUtility goes from 1 to + * CDrmPlayerUtility::MaxVolume(). We apply some basic math to convert + * between the two. + * + * @author Frans Englich<frans.englich@nokia.com> + */ +class AudioOutput : public MediaNode + , public AudioOutputInterface +{ + Q_OBJECT + Q_INTERFACES(Phonon::AudioOutputInterface) + +public: + AudioOutput(Backend *backend, QObject *parent); + virtual qreal volume() const; + virtual void setVolume(qreal volume); + + virtual int outputDevice() const; + + /** + * Has no effect. + */ + virtual bool setOutputDevice(int); + + /** + * Has no effect. + */ + virtual bool setOutputDevice(const Phonon::AudioOutputDevice &); + +protected: + virtual bool activateOnMediaObject(MediaObject *mo); + +Q_SIGNALS: + void volumeChanged(qreal volume); + void audioDeviceFailed(); + +private: + void setVolumeObserver(VolumeObserver* observer); + + qreal m_volume; + + // Not owned + VolumeObserver* m_observer; +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp new file mode 100644 index 0000000..17294a7 --- /dev/null +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -0,0 +1,249 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QUrl> + +#include "audioplayer.h" +#include "utils.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::AudioPlayer::AudioPlayer() : m_player(NULL) +{ + construct(); +} + +MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player) + : AbstractMediaPlayer(player) + , m_player(NULL) +{ + construct(); +} + +void MMF::AudioPlayer::construct() +{ + TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); + TRACE_ENTRY_0(); + + // TODO: is this the correct way to handle errors which occur when + // creating a Symbian object in the constructor of a Qt object? + TRAPD(err, m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)); + if (KErrNone != err) { + changeState(ErrorState); + } + + TRACE_EXIT_0(); +} + +MMF::AudioPlayer::~AudioPlayer() +{ + TRACE_CONTEXT(AudioPlayer::~AudioPlayer, EAudioApi); + TRACE_ENTRY_0(); + + delete m_player; + + TRACE_EXIT_0(); +} + +//----------------------------------------------------------------------------- +// Public API +//----------------------------------------------------------------------------- + +void MMF::AudioPlayer::doPlay() +{ + m_player->Play(); +} + +void MMF::AudioPlayer::doPause() +{ + m_player->Pause(); +} + +void MMF::AudioPlayer::doStop() +{ + m_player->Stop(); +} + +void MMF::AudioPlayer::doSeek(qint64 ms) +{ + m_player->SetPosition(TTimeIntervalMicroSeconds(ms * 1000)); +} + +int MMF::AudioPlayer::setDeviceVolume(int mmfVolume) +{ + /* In SDK 3.1, this function is void. */ +#if !defined(__SERIES60_31__) + return m_player->SetVolume(mmfVolume); +#else + m_player->SetVolume(mmfVolume); + return KErrNone; +#endif +} + +int MMF::AudioPlayer::openFile(RFile& file) +{ + TRAPD(err, m_player->OpenFileL(file)); + +#ifdef QT_PHONON_MMF_AUDIO_DRM + if (KErrNone == err) { + // There appears to be a bug in the CDrmPlayerUtility implementation (at least + // in S60 5.x) whereby the player does not check whether the loading observer + // pointer is null before dereferencing it. Therefore we must register for + // loading notification, even though we do nothing in the callback functions. + m_player->RegisterForAudioLoadingNotification(*this); + } +#endif + + return err; +} + +void MMF::AudioPlayer::close() +{ + m_player->Close(); +} + +bool MMF::AudioPlayer::hasVideo() const +{ + return false; +} + +qint64 MMF::AudioPlayer::currentTime() const +{ + TRACE_CONTEXT(AudioPlayer::currentTime, EAudioApi); + + TTimeIntervalMicroSeconds us; + const TInt err = m_player->GetPosition(us); + + qint64 result = 0; + + if (KErrNone == err) { + result = toMilliSeconds(us); + } else { + TRACE("GetPosition err %d", err); + + // If we don't cast away constness here, we simply have to ignore + // the error. + const_cast<AudioPlayer*>(this)->setError(NormalError); + } + + return result; +} + +qint64 MMF::AudioPlayer::totalTime() const +{ + return toMilliSeconds(m_player->Duration()); +} + + +//----------------------------------------------------------------------------- +// Symbian multimedia client observer callbacks +//----------------------------------------------------------------------------- + +#ifdef QT_PHONON_MMF_AUDIO_DRM +void MMF::AudioPlayer::MdapcInitComplete(TInt aError, + const TTimeIntervalMicroSeconds &) +#else +void MMF::AudioPlayer::MapcInitComplete(TInt aError, + const TTimeIntervalMicroSeconds &) +#endif +{ + TRACE_CONTEXT(AudioPlayer::MapcInitComplete, EAudioInternal); + TRACE_ENTRY("state %d error %d", state(), aError); + + __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + + if (KErrNone == aError) { + maxVolumeChanged(m_player->MaxVolume()); + + emit totalTimeChanged(totalTime()); + changeState(StoppedState); + } else { + // TODO: set different error states according to value of aError? + setError(NormalError); + } + + TRACE_EXIT_0(); +} + +#ifdef QT_PHONON_MMF_AUDIO_DRM +void MMF::AudioPlayer::MdapcPlayComplete(TInt aError) +#else +void MMF::AudioPlayer::MapcPlayComplete(TInt aError) +#endif +{ + TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); + TRACE_ENTRY("state %d error %d", state(), aError); + + stopTickTimer(); + + if (KErrNone == aError) { + changeState(StoppedState); + // TODO: move on to m_nextSource + } else { + // TODO: do something with aError? + setError(NormalError); + } + + /* + if(aError == KErrNone) { + if(m_nextSource.type() == MediaSource::Empty) { + emit finished(); + } else { + setSource(m_nextSource); + m_nextSource = MediaSource(); + } + + changeState(StoppedState); + } + else { + m_error = NormalError; + changeState(ErrorState); + } + */ + + TRACE_EXIT_0(); +} + +CPlayerType *MMF::AudioPlayer::player() const +{ + return m_player; +} + + +#ifdef QT_PHONON_MMF_AUDIO_DRM +void MMF::AudioPlayer::MaloLoadingStarted() +{ + +} + +void MMF::AudioPlayer::MaloLoadingComplete() +{ + +} +#endif // QT_PHONON_MMF_AUDIO_DRM + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h new file mode 100644 index 0000000..f16de1d --- /dev/null +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -0,0 +1,106 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_AUDIOPLAYER_H +#define PHONON_MMF_AUDIOPLAYER_H + +#include "abstractmediaplayer.h" + +class CDrmPlayerUtility; +class TTimeIntervalMicroSeconds; + +#ifdef QT_PHONON_MMF_AUDIO_DRM +#include <drmaudiosampleplayer.h> +typedef CDrmPlayerUtility CPlayerType; +typedef MDrmAudioPlayerCallback MPlayerObserverType; +#else +#include <mdaaudiosampleplayer.h> +typedef CMdaAudioPlayerUtility CPlayerType; +typedef MMdaAudioPlayerCallback MPlayerObserverType; +#endif + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short Wrapper over MMF audio client utility + */ +class AudioPlayer : public AbstractMediaPlayer + , public MPlayerObserverType // typedef +#ifdef QT_PHONON_MMF_AUDIO_DRM + , public MAudioLoadingObserver +#endif +{ + Q_OBJECT + +public: + AudioPlayer(); + explicit AudioPlayer(const AbstractPlayer& player); + virtual ~AudioPlayer(); + + // AbstractMediaPlayer + virtual void doPlay(); + virtual void doPause(); + virtual void doStop(); + virtual void doSeek(qint64 milliseconds); + virtual int setDeviceVolume(int mmfVolume); + virtual int openFile(RFile& file); + virtual void close(); + + // MediaObjectInterface + virtual bool hasVideo() const; + virtual qint64 currentTime() const; + virtual qint64 totalTime() const; + +#ifdef QT_PHONON_MMF_AUDIO_DRM + // MDrmAudioPlayerCallback + virtual void MdapcInitComplete(TInt aError, + const TTimeIntervalMicroSeconds &aDuration); + virtual void MdapcPlayComplete(TInt aError); + + // MAudioLoadingObserver + virtual void MaloLoadingStarted(); + virtual void MaloLoadingComplete(); +#else + // MMdaAudioPlayerCallback + virtual void MapcInitComplete(TInt aError, + const TTimeIntervalMicroSeconds &aDuration); + virtual void MapcPlayComplete(TInt aError); +#endif + + CPlayerType *player() const; + +private: + void construct(); + +private: + /** + * Using CPlayerType typedef in order to be able to easily switch between + * CMdaAudioPlayerUtility and CDrmPlayerUtility + */ + CPlayerType* m_player; +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp new file mode 100644 index 0000000..fe1b1a7 --- /dev/null +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -0,0 +1,194 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QStringList> +#include <QtPlugin> + +#include <apgcli.h> // for RApaLsSession +#include <apmrec.h> // for CDataTypeArray +#include <apmstd.h> // for TDataType + +#include "abstractaudioeffect.h" +#include "audiooutput.h" +#include "audioplayer.h" +#include "backend.h" +#include "effectfactory.h" +#include "mediaobject.h" +#include "utils.h" +#include "videowidget.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +Backend::Backend(QObject *parent) : QObject(parent) +{ + TRACE_CONTEXT(Backend::Backend, EBackend); + TRACE_ENTRY_0(); + + setProperty("identifier", QLatin1String("phonon_mmf")); + setProperty("backendName", QLatin1String("MMF")); + setProperty("backendComment", QLatin1String("Backend using Symbian Multimedia Framework (MMF)")); + setProperty("backendVersion", QLatin1String("0.1")); + setProperty("backendWebsite", QLatin1String("http://www.qtsoftware.com/")); + + TRACE_EXIT_0(); +} + +QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args) +{ + TRACE_CONTEXT(Backend::createObject, EBackend); + TRACE_ENTRY("class %d", c); + + QObject* result = NULL; + + switch (c) { + case AudioOutputClass: + result = new AudioOutput(this, parent); + break; + + case MediaObjectClass: + result = new MediaObject(parent); + break; + + case VolumeFaderEffectClass: + case VisualizationClass: + case VideoDataOutputClass: + case EffectClass: + { + Q_ASSERT(args.count() == 1); + Q_ASSERT(args.first().type() == QVariant::Int); + const AbstractAudioEffect::Type effect = AbstractAudioEffect::Type(args.first().toInt()); + + return EffectFactory::createAudioEffect(effect, parent); + } + case VideoWidgetClass: + result = new VideoWidget(qobject_cast<QWidget *>(parent)); + break; + + default: + TRACE_PANIC(InvalidBackendInterfaceClass); + } + + TRACE_RETURN("0x%08x", result); +} + +QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const +{ + TRACE_CONTEXT(Backend::objectDescriptionIndexes, EAudioApi); + TRACE_ENTRY_0(); + QList<int> retval; + + switch(type) + { + case EffectType: + retval.append(EffectFactory::effectIndexes()); + default: + ; + } + + TRACE_EXIT_0(); + return retval; +} + +QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const +{ + TRACE_CONTEXT(Backend::connectNodes, EBackend); + + if (type == EffectType) + return EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type(index)); + else + return QHash<QByteArray, QVariant>(); +} + +bool Backend::startConnectionChange(QSet<QObject *>) +{ + return true; +} + +bool Backend::connectNodes(QObject *source, QObject *target) +{ + 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)); + + MediaNode *const mediaSource = static_cast<MediaNode *>(source); + MediaNode *const mediaTarget = static_cast<MediaNode *>(target); + + return mediaSource->connectMediaNode(mediaTarget); +} + +bool Backend::disconnectNodes(QObject *source, QObject *target) +{ + 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)); + + const bool result = static_cast<MediaNode *>(source)->disconnectMediaNode(static_cast<MediaNode *>(target)); + + TRACE_RETURN("%d", result); +} + +bool Backend::endConnectionChange(QSet<QObject *>) +{ + return true; +} + +void getAvailableMimeTypesL(QStringList& result) +{ + RApaLsSession apaSession; + User::LeaveIfError(apaSession.Connect()); + CleanupClosePushL(apaSession); + + static const TInt DataTypeArrayGranularity = 8; + CDataTypeArray* array = new(ELeave) CDataTypeArray(DataTypeArrayGranularity); + CleanupStack::PushL(array); + + apaSession.GetSupportedDataTypesL(*array); + + for (TInt i = 0; i < array->Count(); ++i) { + const TPtrC mimeType = array->At(i).Des(); + const MediaType mediaType = Utils::mimeTypeToMediaType(mimeType); + if (MediaTypeAudio == mediaType or MediaTypeVideo == mediaType) { + result.append(qt_TDesC2QString(mimeType)); + } + } + + CleanupStack::PopAndDestroy(2); // apaSession, array +} + +QStringList Backend::availableMimeTypes() const +{ + QStringList result; + + // There is no way to return an error from this function, so we just + // have to trap and ignore exceptions... + TRAP_IGNORE(getAvailableMimeTypesL(result)); + + result.sort(); + + return result; +} + +Q_EXPORT_PLUGIN2(phonon_mmf, Phonon::MMF::Backend); + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/backend.h b/src/3rdparty/phonon/mmf/backend.h new file mode 100644 index 0000000..1886ae6 --- /dev/null +++ b/src/3rdparty/phonon/mmf/backend.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_BACKEND_H +#define PHONON_MMF_BACKEND_H + +#include <Phonon/MediaSource> +#include <Phonon/BackendInterface> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class Backend : public QObject + , public BackendInterface +{ + Q_OBJECT + Q_INTERFACES(Phonon::BackendInterface) +public: + Backend(QObject *parent = 0); + + virtual QObject *createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args); + virtual QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const; + virtual QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const; + virtual bool startConnectionChange(QSet<QObject *>); + virtual bool connectNodes(QObject *, QObject *); + virtual bool disconnectNodes(QObject *, QObject *); + virtual bool endConnectionChange(QSet<QObject *>); + virtual QStringList availableMimeTypes() const; + +Q_SIGNALS: + void objectDescriptionChanged(ObjectDescriptionType); +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp new file mode 100644 index 0000000..fc88d03 --- /dev/null +++ b/src/3rdparty/phonon/mmf/bassboost.cpp @@ -0,0 +1,44 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "bassboost.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +BassBoost::BassBoost(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect(parent, + QList<EffectParameter>()) +{ +} + +void BassBoost::parameterChanged(const int, + const QVariant &) +{ + // We should never be called, because we have no parameters. +} + +bool BassBoost::activateOn(CPlayerType *player) +{ + m_effect.reset(CBassBoost::NewL(*player, true)); + return true; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h new file mode 100644 index 0000000..c16393a --- /dev/null +++ b/src/3rdparty/phonon/mmf/bassboost.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_BASSBOOST_H +#define PHONON_MMF_BASSBOOST_H + +#include <BassBoostBase.h> +#include "abstractaudioeffect.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short An "bass boost" effect. + * + * The documentation does not say what "bass boost" is, neither has it anykind + * of setting. It's an on or off thing. + */ +class BassBoost : public AbstractAudioEffect +{ + Q_OBJECT +public: + BassBoost(QObject *parent); + +protected: + virtual void parameterChanged(const int id, + const QVariant &value); + + virtual bool activateOn(CPlayerType *player); + +private: + QScopedPointer<CBassBoost> m_bassBoost; +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/defs.h b/src/3rdparty/phonon/mmf/defs.h new file mode 100644 index 0000000..1a93aa9 --- /dev/null +++ b/src/3rdparty/phonon/mmf/defs.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_DEFS_H +#define PHONON_MMF_DEFS_H + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +static const qint32 DefaultTickInterval = 10; +static const qreal InitialVolume = 0.5; + +enum MediaType { + MediaTypeUnknown, + MediaTypeAudio, + MediaTypeVideo +}; +} +} + +QT_END_NAMESPACE + +#endif // PHONON_MMF_DEFS_H diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp new file mode 100644 index 0000000..dc55af7 --- /dev/null +++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp @@ -0,0 +1,138 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "dummyplayer.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::DummyPlayer::DummyPlayer() +{ + +} + +MMF::DummyPlayer::DummyPlayer(const AbstractPlayer& player) + : AbstractPlayer(player) +{ + +} + + +//----------------------------------------------------------------------------- +// MediaObjectInterface +//----------------------------------------------------------------------------- + +void MMF::DummyPlayer::play() +{ + +} + +void MMF::DummyPlayer::pause() +{ + +} + +void MMF::DummyPlayer::stop() +{ + +} + +void MMF::DummyPlayer::seek(qint64) +{ + +} + +bool MMF::DummyPlayer::hasVideo() const +{ + return false; +} + +bool MMF::DummyPlayer::isSeekable() const +{ + return false; +} + +Phonon::State MMF::DummyPlayer::state() const +{ + return Phonon::LoadingState; +} + +qint64 MMF::DummyPlayer::currentTime() const +{ + return 0; +} + +QString MMF::DummyPlayer::errorString() const +{ + return QString(); +} + +Phonon::ErrorType MMF::DummyPlayer::errorType() const +{ + return Phonon::NoError; +} + +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 &) +{ + +} + + +//----------------------------------------------------------------------------- +// VolumeObserver +//----------------------------------------------------------------------------- + +void MMF::DummyPlayer::volumeChanged(qreal) +{ + +} + + +//----------------------------------------------------------------------------- +// AbstractPlayer +//----------------------------------------------------------------------------- + +void MMF::DummyPlayer::doSetTickInterval(qint32) +{ + +} + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h new file mode 100644 index 0000000..b2725df --- /dev/null +++ b/src/3rdparty/phonon/mmf/dummyplayer.h @@ -0,0 +1,77 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_DUMMYPLAYER_H +#define PHONON_MMF_DUMMYPLAYER_H + +#include "abstractplayer.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class AudioOutput; + +/** + * @short Stub implementation of AbstractPlayer. + * + * The functions of this class are: + * - Allow MediaObject to call a subset of the MediaObjectInterface + * API, before SetSource has been called. + * - Cache any parameters which are set in this state (e.g. + * prefinish mark), so that they can be copied into the 'real' + * AbstractPlayer implementation once a source has been loaded. + */ +class DummyPlayer : public AbstractPlayer +{ +public: + DummyPlayer(); + DummyPlayer(const AbstractPlayer& player); + + // MediaObjectInterface + virtual void play(); + virtual void pause(); + virtual void stop(); + virtual void seek(qint64 milliseconds); + virtual bool hasVideo() const; + virtual bool isSeekable() const; + virtual qint64 currentTime() const; + virtual Phonon::State state() const; + virtual QString errorString() const; + virtual Phonon::ErrorType errorType() const; + virtual qint64 totalTime() const; + virtual MediaSource source() const; + // virtual void setSource(const MediaSource &); + virtual void setFileSource(const Phonon::MediaSource&, RFile&); + virtual void setNextSource(const MediaSource &source); + + // VolumeObserver + virtual void volumeChanged(qreal volume); + + // AbstractPlayer + virtual void doSetTickInterval(qint32 interval); + +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/effectfactory.cpp b/src/3rdparty/phonon/mmf/effectfactory.cpp new file mode 100644 index 0000000..4acaaa4 --- /dev/null +++ b/src/3rdparty/phonon/mmf/effectfactory.cpp @@ -0,0 +1,150 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QObject> + +#include <AudioEqualizerBase.h> +#include <BassBoostBase.h> +#include <DistanceAttenuationBase.h> +#include <DopplerBase.h> +#include <EnvironmentalReverbBase.h> +#include <ListenerOrientationBase.h> +#include <LocationBase.h> +#include <LoudnessBase.h> +#include <SourceOrientationBase.h> +#include <StereoWideningBase.h> + +#include "audioequalizer.h" +#include "bassboost.h" + +#include "effectfactory.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +QHash<QByteArray, QVariant> EffectFactory::constructEffectDescription(const QString &name, + const QString &description) +{ + QHash<QByteArray, QVariant> retval; + + retval.insert("name", name); + retval.insert("description", description); + retval.insert("available", true); + + return retval; +} + + +QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type type) +{ + switch (type) + { + case AbstractAudioEffect::EffectAudioEqualizer: + return constructEffectDescription(QObject::tr("audio equalizer"), "Audio equalizer."); + case AbstractAudioEffect::EffectBassBoost: + return constructEffectDescription(QObject::tr("Bass boost"), "Bass boost."); + case AbstractAudioEffect::EffectDistanceAttenuation: + return constructEffectDescription(QObject::tr("Distance Attenuation"), "Distance Attenuation."); + case AbstractAudioEffect::EffectEnvironmentalReverb: + return constructEffectDescription(QObject::tr("Environmental Reverb"), "Environmental Reverb."); + case AbstractAudioEffect::EffectListenerOrientation: + return constructEffectDescription(QObject::tr("Environmental Reverb"), "Environmental Reverb."); + case AbstractAudioEffect::EffectLoudness: + return constructEffectDescription(QObject::tr("Loudness"), "Loudness."); + case AbstractAudioEffect::EffectSourceOrientation: + return constructEffectDescription(QObject::tr("Source Orientation"), "Source Orientation."); + case AbstractAudioEffect::EffectStereoWidening: + return constructEffectDescription(QObject::tr("Stereo Widening"), "Stereo Widening."); + } + + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect type."); + return QHash<QByteArray, QVariant>(); +} + +AbstractAudioEffect *EffectFactory::createAudioEffect(AbstractAudioEffect::Type type, + QObject *parent) +{ + Q_ASSERT(parent); + + switch (type) + { + case AbstractAudioEffect::EffectBassBoost: + return new BassBoost(parent); + case AbstractAudioEffect::EffectAudioEqualizer: + return new AudioEqualizer(parent); + case AbstractAudioEffect::EffectDistanceAttenuation: + case AbstractAudioEffect::EffectEnvironmentalReverb: + case AbstractAudioEffect::EffectListenerOrientation: + case AbstractAudioEffect::EffectLoudness: + case AbstractAudioEffect::EffectSourceOrientation: + case AbstractAudioEffect::EffectStereoWidening: + ; + } + + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect."); + return 0; +} + +template<typename TEffect> +bool isEffectSupported() +{ + AudioPlayer audioPlayer; + + QScopedPointer<TEffect> eff; + TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player()))); + + return errorCode != KErrNone; +} + +QList<int> EffectFactory::effectIndexes() +{ + QList<int> retval; + + if (isEffectSupported<CAudioEqualizer>()) + retval.append(AbstractAudioEffect::EffectAudioEqualizer); + + if (isEffectSupported<CBassBoost>()) + retval.append(AbstractAudioEffect::EffectBassBoost); + + /* We haven't implemented these yet. + if (isEffectSupported<CDistanceAttenuation>()) + retval.append(AbstractAudioEffect::EffectDistanceAttenuation); + + if (isEffectSupported<CEnvironmentalReverb>()) + retval.append(AbstractAudioEffect::EffectEnvironmentalReverb); + + if (isEffectSupported<CLoudness>()) + retval.append(AbstractAudioEffect::EffectLoudness); + + if (isEffectSupported<CListenerOrientation>()) + retval.append(AbstractAudioEffect::EffectListenerOrientation); + + if (isEffectSupported<CSourceOrientation>()) + retval.append(AbstractAudioEffect::EffectSourceOrientation); + + if (isEffectSupported<CStereoWidening>()) + retval.append(AbstractAudioEffect::EffectStereoWidening); + */ + + return retval; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/effectfactory.h b/src/3rdparty/phonon/mmf/effectfactory.h new file mode 100644 index 0000000..e83ad15 --- /dev/null +++ b/src/3rdparty/phonon/mmf/effectfactory.h @@ -0,0 +1,76 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_EFFECTFACTORY_H +#define PHONON_MMF_EFFECTFACTORY_H + +#include "abstractaudioeffect.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ + +/** + * @short Contains utility functions related to effects. + */ +class EffectFactory +{ +public: + /** + * @short Creates an audio effect of type @p type. + */ + static AbstractAudioEffect *createAudioEffect(AbstractAudioEffect::Type type, + QObject *parent); + + /** + * @short Return the properties for effect @p type. + * + * This handles the effects for + * BackendInterface::objectDescriptionProperties(). + */ + static QHash<QByteArray, QVariant> audioEffectDescriptions(AbstractAudioEffect::Type type); + + /** + * @short Returns the indexes for the supported effects. + * + * This handles the effects for + * BackendInterface::objectDescriptionIndexes(). + */ + static QList<int> effectIndexes(); + +private: + static inline QHash<QByteArray, QVariant> constructEffectDescription(const QString &name, + const QString &description); + + /** + * This class is not supposed to be instantiated, so disable + * the default constructor. + */ + inline EffectFactory(); + Q_DISABLE_COPY(EffectFactory) +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp new file mode 100644 index 0000000..de0de59 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -0,0 +1,384 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "audiooutput.h" +#include "audioplayer.h" +#include "defs.h" +#include "dummyplayer.h" +#include "utils.h" +#include "utils.h" +#include "mmf_videoplayer.h" +#include "videowidget.h" + +#include "mediaobject.h" + +#include <QDir> + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent) + , m_recognizerOpened(false) +{ + m_player.reset(new DummyPlayer()); + + TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi); + TRACE_ENTRY_0(); + + Q_UNUSED(parent); + + TRACE_EXIT_0(); +} + +MMF::MediaObject::~MediaObject() +{ + TRACE_CONTEXT(MediaObject::~MediaObject, EAudioApi); + TRACE_ENTRY_0(); + + m_file.Close(); + m_fileServer.Close(); + m_recognizer.Close(); + + TRACE_EXIT_0(); +} + + +//----------------------------------------------------------------------------- +// Recognizer +//----------------------------------------------------------------------------- + +bool MMF::MediaObject::openRecognizer() +{ + TRACE_CONTEXT(MediaObject::openRecognizer, EAudioInternal); + + if (!m_recognizerOpened) { + TInt err = m_recognizer.Connect(); + if (KErrNone != err) { + TRACE("RApaLsSession::Connect error %d", err); + return false; + } + + err = m_fileServer.Connect(); + if (KErrNone != err) { + TRACE("RFs::Connect error %d", err); + return false; + } + + // This must be called in order to be able to share file handles with + // the recognizer server (see fileMediaType function). + err = m_fileServer.ShareProtected(); + if (KErrNone != err) { + TRACE("RFs::ShareProtected error %d", err); + return false; + } + + m_recognizerOpened = true; + } + + return true; +} + +MMF::MediaType MMF::MediaObject::fileMediaType +(const QString& fileName) +{ + TRACE_CONTEXT(MediaObject::fileMediaType, EAudioInternal); + + MediaType result = MediaTypeUnknown; + + if (openRecognizer()) { + + const QHBufC fileNameSymbian(QDir::toNativeSeparators(fileName)); + + m_file.Close(); + TInt err = m_file.Open(m_fileServer, *fileNameSymbian, EFileRead | EFileShareReadersOnly); + + if (KErrNone == err) { + TDataRecognitionResult recognizerResult; + err = m_recognizer.RecognizeData(m_file, recognizerResult); + if (KErrNone == err) { + const TPtrC mimeType = recognizerResult.iDataType.Des(); + result = Utils::mimeTypeToMediaType(mimeType); + } else { + TRACE("RApaLsSession::RecognizeData filename %S error %d", fileNameSymbian.data(), err); + } + } else { + TRACE("RFile::Open filename %S error %d", fileNameSymbian.data(), err); + } + } + + return result; +} + + +//----------------------------------------------------------------------------- +// MediaObjectInterface +//----------------------------------------------------------------------------- + +void MMF::MediaObject::play() +{ + m_player->play(); +} + +void MMF::MediaObject::pause() +{ + m_player->pause(); +} + +void MMF::MediaObject::stop() +{ + m_player->stop(); +} + +void MMF::MediaObject::seek(qint64 ms) +{ + m_player->seek(ms); + + if (state() == PausedState or state() == PlayingState) { + emit tick(currentTime()); + } +} + +qint32 MMF::MediaObject::tickInterval() const +{ + return m_player->tickInterval(); +} + +void MMF::MediaObject::setTickInterval(qint32 interval) +{ + m_player->setTickInterval(interval); +} + +bool MMF::MediaObject::hasVideo() const +{ + return m_player->hasVideo(); +} + +bool MMF::MediaObject::isSeekable() const +{ + return m_player->isSeekable(); +} + +Phonon::State MMF::MediaObject::state() const +{ + return m_player->state(); +} + +qint64 MMF::MediaObject::currentTime() const +{ + return m_player->currentTime(); +} + +QString MMF::MediaObject::errorString() const +{ + return m_player->errorString(); +} + +Phonon::ErrorType MMF::MediaObject::errorType() const +{ + return m_player->errorType(); +} + +qint64 MMF::MediaObject::totalTime() const +{ + return m_player->totalTime(); +} + +MediaSource MMF::MediaObject::source() const +{ + return m_player->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); + + emit currentSourceChanged(source); +} + +void MMF::MediaObject::createPlayer(const MediaSource &source) +{ + TRACE_CONTEXT(MediaObject::createPlayer, EAudioApi); + TRACE_ENTRY("state %d source.type %d", state(), source.type()); + TRACE_ENTRY("source.type %d", source.type()); + + MediaType mediaType = MediaTypeUnknown; + + AbstractPlayer* oldPlayer = m_player.data(); + + const bool oldPlayerHasVideo = oldPlayer->hasVideo(); + const bool oldPlayerSeekable = oldPlayer->isSeekable(); + + // Determine media type + switch (source.type()) { + case MediaSource::LocalFile: + mediaType = fileMediaType(source.fileName()); + break; + + case MediaSource::Url: + // TODO: support detection of media type from HTTP streams + TRACE_0("Network streaming not supported yet"); + /* + * TODO: handle error + * + m_error = NormalError; + changeState(ErrorState); + */ + break; + + case MediaSource::Invalid: + case MediaSource::Disc: + case MediaSource::Stream: + TRACE_0("Unsupported media type"); + /* + * TODO: handle error + * + m_error = NormalError; + changeState(ErrorState); + */ + break; + + case MediaSource::Empty: + TRACE_0("Empty media source"); + break; + } + + AbstractPlayer* newPlayer = NULL; + + // Construct newPlayer using oldPlayer (if not NULL) in order to copy + // parameters (volume, prefinishMark, transitionTime) which may have + // been set on oldPlayer. + + switch (mediaType) { + case MediaTypeUnknown: + TRACE_0("Media type could not be determined"); + if (oldPlayer) { + newPlayer = new DummyPlayer(*oldPlayer); + } else { + newPlayer = new DummyPlayer(); + } + /* + * TODO: handle error? + * + m_error = NormalError; + changeState(ErrorState); + */ + break; + + case MediaTypeAudio: + if (oldPlayer) { + newPlayer = new AudioPlayer(*oldPlayer); + } else { + newPlayer = new AudioPlayer(); + } + break; + + case MediaTypeVideo: + if (oldPlayer) { + newPlayer = new VideoPlayer(*oldPlayer); + } else { + newPlayer = new VideoPlayer(); + } + break; + } + + m_player.reset(newPlayer); + + if (oldPlayerHasVideo != hasVideo()) { + emit hasVideoChanged(hasVideo()); + } + + if (oldPlayerSeekable != isSeekable()) { + emit seekableChanged(isSeekable()); + } + + connect(m_player.data(), SIGNAL(totalTimeChanged(qint64)), SIGNAL(totalTimeChanged(qint64))); + connect(m_player.data(), SIGNAL(stateChanged(Phonon::State, Phonon::State)), SIGNAL(stateChanged(Phonon::State, Phonon::State))); + connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished())); + connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); + + TRACE_EXIT_0(); +} + +void MMF::MediaObject::setNextSource(const MediaSource &source) +{ + m_player->setNextSource(source); +} + +qint32 MMF::MediaObject::prefinishMark() const +{ + return m_player->prefinishMark(); +} + +void MMF::MediaObject::setPrefinishMark(qint32 mark) +{ + m_player->setPrefinishMark(mark); +} + +qint32 MMF::MediaObject::transitionTime() const +{ + return m_player->transitionTime(); +} + +void MMF::MediaObject::setTransitionTime(qint32 time) +{ + m_player->setTransitionTime(time); +} + + +//----------------------------------------------------------------------------- +// VolumeObserver +//----------------------------------------------------------------------------- + +void MMF::MediaObject::volumeChanged(qreal volume) +{ + m_player->volumeChanged(volume); +} + +//----------------------------------------------------------------------------- +// Video output +//----------------------------------------------------------------------------- + +void MMF::MediaObject::setVideoOutput(VideoOutput* videoOutput) +{ + m_player->setVideoOutput(videoOutput); +} + + +AbstractPlayer *MMF::MediaObject::abstractPlayer() const +{ + return m_player.data(); +} + +bool MMF::MediaObject::activateOnMediaObject(MediaObject *) +{ + // Guess what, we do nothing. + return true; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h new file mode 100644 index 0000000..409918d --- /dev/null +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -0,0 +1,140 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_MEDIAOBJECT_H +#define PHONON_MMF_MEDIAOBJECT_H + +#include <Phonon/MediaSource> +#include <Phonon/MediaObjectInterface> +#include <QScopedPointer> +#include <QTimer> + +// For recognizer +#include <apgcli.h> + +#include "abstractplayer.h" +#include "mmf_medianode.h" +#include "defs.h" +#include "volumeobserver.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class AbstractPlayer; +class VideoOutput; + +/** + * @short Facade class which wraps MMF client utility instance + */ +class MediaObject : public MediaNode + , public MediaObjectInterface + , public VolumeObserver +{ + Q_OBJECT + Q_INTERFACES(Phonon::MediaObjectInterface) + +public: + MediaObject(QObject *parent); + virtual ~MediaObject(); + + // MediaObjectInterface + virtual void play(); + virtual void pause(); + virtual void stop(); + virtual void seek(qint64 milliseconds); + virtual qint32 tickInterval() const; + virtual void setTickInterval(qint32 interval); + virtual bool hasVideo() const; + virtual bool isSeekable() const; + virtual qint64 currentTime() const; + virtual Phonon::State state() const; + virtual QString errorString() const; + virtual Phonon::ErrorType errorType() const; + virtual qint64 totalTime() const; + virtual MediaSource source() const; + virtual void setSource(const MediaSource &); + virtual void setNextSource(const MediaSource &source); + virtual qint32 prefinishMark() const; + virtual void setPrefinishMark(qint32); + virtual qint32 transitionTime() const; + virtual void setTransitionTime(qint32); + + // VolumeObserver + void volumeChanged(qreal volume); + + /** + * This class owns the AbstractPlayer, and will delete it upon + * destruction. + */ + AbstractPlayer *abstractPlayer() const; + + void setVideoOutput(VideoOutput* videoOutput); + + virtual bool activateOnMediaObject(MediaObject *); + +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(); + // TODO: emit prefinishMarkReached from MediaObject + void prefinishMarkReached(qint32); + // TODO: emit metaDataChanged from MediaObject + void metaDataChanged(const QMultiMap<QString, QString>& metaData); + void currentSourceChanged(const MediaSource& source); + void stateChanged(Phonon::State oldState, + Phonon::State newState); + void finished(); + void tick(qint64 time); + +private: + void createPlayer(const MediaSource &source); + bool openRecognizer(); + + // Audio / video media type recognition + MediaType fileMediaType(const QString& fileName); + // TODO: urlMediaType function + + static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); + +private: + + // Audio / video media type recognition + bool m_recognizerOpened; + RApaLsSession m_recognizer; + RFs m_fileServer; + + // Storing the file handle here to work around KErrInUse error + // from MMF player utility OpenFileL functions + RFile m_file; + + QScopedPointer<AbstractPlayer> m_player; + +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.cpp b/src/3rdparty/phonon/mmf/mmf_medianode.cpp new file mode 100644 index 0000000..a9eee58 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp @@ -0,0 +1,117 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "mediaobject.h" + +#include "mmf_medianode.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent) + , m_source(0) + , m_target(0) + , m_isApplied(false) +{ +} + +bool MMF::MediaNode::connectMediaNode(MediaNode *target) +{ + m_target = target; + m_target->setSource(this); + + return applyNodesOnMediaObject(target); +} + +bool MMF::MediaNode::disconnectMediaNode(MediaNode *target) +{ + Q_UNUSED(target); + m_target = 0; + m_isApplied = false; + return false; +} + +void MMF::MediaNode::setSource(MediaNode *source) +{ + m_source = source; +} + +MMF::MediaNode *MMF::MediaNode::source() const +{ + return m_source; +} + +MMF::MediaNode *MMF::MediaNode::target() const +{ + return m_target; +} + +bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *) +{ + // 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; + + do { + if (!current->m_isApplied) + unapplied.append(current); + + if (!mo) + mo = qobject_cast<MMF::MediaObject *>(current); + + current = current->target(); + } + while (current); + + // Now, lets activate all the objects, if we found the MediaObject. + + if (mo) { + for (int i = 0; i < unapplied.count(); ++i) { + MediaNode *const at = unapplied.at(i); + + // We don't want to apply MediaObject on itself. + if (at != mo) + at->activateOnMediaObject(mo); + } + } + + return true; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.h b/src/3rdparty/phonon/mmf/mmf_medianode.h new file mode 100644 index 0000000..4616ff1 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmf_medianode.h @@ -0,0 +1,100 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_MEDIANODE_H +#define PHONON_MMF_MEDIANODE_H + +#include <QObject> +#include <Phonon/EffectInterface> +#include "audioplayer.h" + +QT_BEGIN_NAMESPACE + +/** + * @file mmf_medianode.h mmf_medianode.cpp + * + * This file starts with mmf_ in order to avoid clash with Phonon's + * medianode.h. The GStreamer backend has a file named medianode.h, but it + * isn't compiled with ABLD build system, which have problems with separating + * user and system include paths. + */ + +namespace Phonon +{ +namespace MMF +{ +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: + * + * - 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. + * + * 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. + */ +class MediaNode : public QObject +{ + Q_OBJECT +public: + MediaNode(QObject *parent); + + virtual bool connectMediaNode(MediaNode *target); + virtual bool disconnectMediaNode(MediaNode *target); + void setSource(MediaNode *source); + + MediaNode *source() const; + MediaNode *target() const; + +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; + +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; +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp new file mode 100644 index 0000000..0c47ece --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -0,0 +1,436 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QUrl> +#include <QTimer> +#include <QWidget> + +#include <coemain.h> // For CCoeEnv +#include <coecntrl.h> + +#include "mmf_videoplayer.h" +#include "utils.h" + +#ifdef _DEBUG +#include "objectdump.h" +#endif + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::VideoPlayer::VideoPlayer() + : m_wsSession(NULL) + , m_screenDevice(NULL) + , m_window(NULL) + , m_totalTime(0) + , m_mmfOutputChangePending(false) +{ + construct(); +} + +MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player) + : AbstractMediaPlayer(player) + , m_wsSession(NULL) + , m_screenDevice(NULL) + , m_window(NULL) + , m_totalTime(0) + , m_mmfOutputChangePending(false) +{ + construct(); +} + +void MMF::VideoPlayer::construct() +{ + TRACE_CONTEXT(VideoPlayer::VideoPlayer, EVideoApi); + TRACE_ENTRY_0(); + + if (!m_videoOutput) { + m_dummyVideoOutput.reset(new VideoOutput(NULL)); + } + + videoOutput().setObserver(this); + + const TInt priority = 0; + const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone; + + getNativeWindowSystemHandles(); + + // TODO: is this the correct way to handle errors which occur when + // creating a Symbian object in the constructor of a Qt object? + + // TODO: check whether videoOutput is visible? If not, then the + // corresponding window will not be active, meaning that the + // clipping region will be set to empty and the video will not be + // visible. If this is the case, we should set m_mmfOutputChangePending + // and respond to future showEvents from the videoOutput widget. + + TRAPD(err, + m_player.reset(CVideoPlayerUtility::NewL + ( + *this, + priority, preference, + *m_wsSession, *m_screenDevice, + *m_window, + m_windowRect, m_clipRect + )) + ); + + if (KErrNone != err) { + changeState(ErrorState); + } + + TRACE_EXIT_0(); +} + +MMF::VideoPlayer::~VideoPlayer() +{ + TRACE_CONTEXT(VideoPlayer::~VideoPlayer, EVideoApi); + TRACE_ENTRY_0(); + + TRACE_EXIT_0(); +} + +//----------------------------------------------------------------------------- +// Public API +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::doPlay() +{ + TRACE_CONTEXT(VideoPlayer::doPlay, EVideoApi); + + // See comment in updateMmfOutput + if(m_mmfOutputChangePending) { + TRACE_0("MMF output change pending - pushing now"); + updateMmfOutput(); + } + + m_player->Play(); +} + +void MMF::VideoPlayer::doPause() +{ + TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi); + + TRAPD(err, m_player->PauseL()); + if (KErrNone != err) { + TRACE("PauseL error %d", err); + setError(NormalError); + } +} + +void MMF::VideoPlayer::doStop() +{ + m_player->Stop(); +} + +void MMF::VideoPlayer::doSeek(qint64 ms) +{ + TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi); + + TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000))); + + if (KErrNone != err) { + TRACE("SetPositionL error %d", err); + setError(NormalError); + } +} + +int MMF::VideoPlayer::setDeviceVolume(int mmfVolume) +{ + TRAPD(err, m_player->SetVolumeL(mmfVolume)); + return err; +} + +int MMF::VideoPlayer::openFile(RFile& file) +{ + TRAPD(err, m_player->OpenFileL(file)); + return err; +} + +void MMF::VideoPlayer::close() +{ + m_player->Close(); +} + +bool MMF::VideoPlayer::hasVideo() const +{ + return true; +} + +qint64 MMF::VideoPlayer::currentTime() const +{ + TRACE_CONTEXT(VideoPlayer::currentTime, EVideoApi); + + TTimeIntervalMicroSeconds us; + TRAPD(err, us = m_player->PositionL()) + + qint64 result = 0; + + if (KErrNone == err) { + result = toMilliSeconds(us); + } else { + TRACE("PositionL error %d", err); + + // If we don't cast away constness here, we simply have to ignore + // the error. + const_cast<VideoPlayer*>(this)->setError(NormalError); + } + + return result; +} + +qint64 MMF::VideoPlayer::totalTime() const +{ + return m_totalTime; +} + + +//----------------------------------------------------------------------------- +// MVideoPlayerUtilityObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError) +{ + TRACE_CONTEXT(VideoPlayer::MvpuoOpenComplete, EVideoApi); + TRACE_ENTRY("state %d error %d", state(), aError); + + __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + + if (KErrNone == aError) + m_player->Prepare(); + else + setError(NormalError); + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError) +{ + TRACE_CONTEXT(VideoPlayer::MvpuoPrepareComplete, EVideoApi); + TRACE_ENTRY("state %d error %d", state(), aError); + + __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + + TRAPD(err, doPrepareCompleteL(aError)); + + if (KErrNone == err) { + maxVolumeChanged(m_player->MaxVolume()); + + videoOutput().setFrameSize(m_frameSize); + + // See comment in updateMmfOutput + if(m_mmfOutputChangePending) { + TRACE_0("MMF output change pending - pushing now"); + updateMmfOutput(); + } + + emit totalTimeChanged(totalTime()); + changeState(StoppedState); + } else { + setError(NormalError); + } + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::doPrepareCompleteL(TInt aError) +{ + User::LeaveIfError(aError); + + // Get frame size + TSize size; + m_player->VideoFrameSizeL(size); + m_frameSize = QSize(size.iWidth, size.iHeight); + + // Get duration + m_totalTime = toMilliSeconds(m_player->DurationL()); +} + + +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 + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) +{ + TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) + TRACE_ENTRY("state %d error %d", state(), aError); + + // TODO + Q_UNUSED(aError); // suppress warnings in release builds + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) +{ + TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi); + TRACE_ENTRY("state %d", state()); + + // TODO + Q_UNUSED(aEvent); + + TRACE_EXIT_0(); +} + + +//----------------------------------------------------------------------------- +// VideoOutputObserver +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::videoOutputRegionChanged() +{ + TRACE_CONTEXT(VideoPlayer::videoOutputRegionChanged, EVideoInternal); + TRACE_ENTRY("state %d", state()); + + getNativeWindowSystemHandles(); + + // See comment in updateMmfOutput + if(state() == LoadingState) + m_mmfOutputChangePending = true; + else + updateMmfOutput(); + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::updateMmfOutput() +{ + TRACE_CONTEXT(VideoPlayer::updateMmfOutput, EVideoInternal); + TRACE_ENTRY_0(); + + // Calling SetDisplayWindowL is a no-op unless the MMF controller has + // been loaded, so we shouldn't do it. Instead, the + // m_mmfOutputChangePending flag is used to record the fact that we + // need to call SetDisplayWindowL, and this is checked in + // MvpuoPrepareComplete, at which point the MMF controller has been + // loaded. + + // TODO: check whether videoOutput is visible? If not, then the + // corresponding window will not be active, meaning that the + // clipping region will be set to empty and the video will not be + // visible. If this is the case, we should set m_mmfOutputChangePending + // and respond to future showEvents from the videoOutput widget. + + getNativeWindowSystemHandles(); + + TRAPD(err, + m_player->SetDisplayWindowL + ( + *m_wsSession, *m_screenDevice, + *m_window, + m_windowRect, m_clipRect + ) + ); + + if (KErrNone != err) { + TRACE("SetDisplayWindowL error %d", err); + setError(NormalError); + } + + m_mmfOutputChangePending = false; + + TRACE_EXIT_0(); +} + + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +VideoOutput& MMF::VideoPlayer::videoOutput() +{ + TRACE_CONTEXT(VideoPlayer::videoOutput, EVideoInternal); + TRACE("videoOutput 0x%08x dummy 0x%08x", m_videoOutput, m_dummyVideoOutput.data()); + + return m_videoOutput ? *m_videoOutput : *m_dummyVideoOutput; +} + +void MMF::VideoPlayer::videoOutputChanged() +{ + TRACE_CONTEXT(VideoPlayer::videoOutputChanged, EVideoInternal); + TRACE_ENTRY_0(); + + // Lazily construct a dummy output if needed here + if (!m_videoOutput and m_dummyVideoOutput.isNull()) { + m_dummyVideoOutput.reset(new VideoOutput(NULL)); + } + + videoOutput().setObserver(this); + + videoOutput().setFrameSize(m_frameSize); + + videoOutputRegionChanged(); + + TRACE_EXIT_0(); +} + +void MMF::VideoPlayer::getNativeWindowSystemHandles() +{ + TRACE_CONTEXT(VideoPlayer::getNativeWindowSystemHandles, EVideoInternal); + TRACE_ENTRY_0(); + + VideoOutput& output = videoOutput(); + CCoeControl* const control = output.winId(); + + CCoeEnv* const coeEnv = control->ControlEnv(); + m_wsSession = &(coeEnv->WsSession()); + m_screenDevice = coeEnv->ScreenDevice(); + m_window = control->DrawableWindow(); + +#ifdef _DEBUG + QScopedPointer<ObjectDump::QDumper> dumper(new ObjectDump::QDumper); + dumper->setPrefix("Phonon::MMF"); // to aid searchability of logs + ObjectDump::addDefaultAnnotators(*dumper); + TRACE_0("Dumping VideoOutput:"); + dumper->dumpObject(output); +#endif + + m_windowRect = TRect( + control->DrawableWindow()->AbsPosition(), + control->DrawableWindow()->Size()); + + m_clipRect = m_windowRect; + + TRACE("windowRect %d %d - %d %d", + m_windowRect.iTl.iX, m_windowRect.iTl.iY, + m_windowRect.iBr.iX, m_windowRect.iBr.iY); + TRACE("clipRect %d %d - %d %d", + m_clipRect.iTl.iX, m_clipRect.iTl.iY, + m_clipRect.iBr.iX, m_clipRect.iBr.iY); + + TRACE_EXIT_0(); +} + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h new file mode 100644 index 0000000..2878d6a --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -0,0 +1,111 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_VIDEOPLAYER_H +#define PHONON_MMF_VIDEOPLAYER_H + +#include <include/videoplayer.h> + +#include "abstractmediaplayer.h" +#include "videooutput.h" +#include "videooutputobserver.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short Wrapper over MMF video client utility + * + * See + * <a href="http://wiki.forum.nokia.com/index.php/How_to_play_a_video_file_using_CVideoPlayerUtility">How to + * play a video file using CVideoPlayerUtility</a> + */ +class VideoPlayer : public AbstractMediaPlayer + , public MVideoPlayerUtilityObserver + , public VideoOutputObserver +{ + Q_OBJECT + +public: + VideoPlayer(); + explicit VideoPlayer(const AbstractPlayer& player); + virtual ~VideoPlayer(); + + // AbstractPlayer + virtual void doPlay(); + virtual void doPause(); + virtual void doStop(); + virtual void doSeek(qint64 milliseconds); + virtual int setDeviceVolume(int mmfVolume); + virtual int openFile(RFile& file); + virtual void close(); + + // MediaObjectInterface + virtual bool hasVideo() const; + 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); + + // VideoOutputObserver + virtual void videoOutputRegionChanged(); + +private: + void construct(); + VideoOutput& videoOutput(); + + void doPrepareCompleteL(TInt aError); + + // AbstractPlayer + virtual void videoOutputChanged(); + + void getNativeWindowSystemHandles(); + void updateMmfOutput(); + +private: + QScopedPointer<CVideoPlayerUtility> m_player; + QScopedPointer<VideoOutput> m_dummyVideoOutput; + + // Not owned + RWsSession* m_wsSession; + CWsScreenDevice* m_screenDevice; + RWindowBase* m_window; + TRect m_windowRect; + TRect m_clipRect; + + QSize m_frameSize; + qint64 m_totalTime; + + bool m_mmfOutputChangePending; + +}; + +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.cpp b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.cpp new file mode 100644 index 0000000..50c6bf8 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.cpp @@ -0,0 +1,527 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QByteArray> +#include <QDebug> +#include <QHash> +#include <QTextStream> +#include <QWidget> + +#include "objectdump.h" +#include "objecttree.h" + +QT_BEGIN_NAMESPACE + +namespace ObjectDump +{ + +//----------------------------------------------------------------------------- +// QObjectAnnotator +//----------------------------------------------------------------------------- + +QAnnotator::~QAnnotator() +{ + +} + + +//----------------------------------------------------------------------------- +// Annotators +//----------------------------------------------------------------------------- + +QList<QByteArray> QAnnotatorBasic::annotation(const QObject& object) +{ + QList<QByteArray> result; + + QByteArray array; + QTextStream stream(&array); + + stream << '[' << &object << ']'; + stream << ' '; + stream << object.metaObject()->className(); + + if(object.objectName() != "") + stream << " \"" << object.objectName() << '"'; + + if(object.isWidgetType()) + stream << " isWidget"; + + stream.flush(); + result.append(array); + return result; +} + +QList<QByteArray> QAnnotatorWidget::annotation(const QObject& object) +{ + QList<QByteArray> result; + + const QWidget* widget = qobject_cast<const QWidget*>(&object); + if(widget) { + + QByteArray array; + QTextStream stream(&array); + + stream << "widget: "; + + if(widget->isVisible()) + stream << "visible "; + else + stream << "invisible "; + + stream << widget->x() << ',' << widget->y() << ' '; + stream << widget->size().width() << 'x'<< widget->size().height() << ' '; + + stream << "hint " << widget->sizeHint().width() << 'x' << widget->sizeHint().height(); + + stream.flush(); + result.append(array); + } + + return result; +} + + +//----------------------------------------------------------------------------- +// Base class for QDumperPrivate, QVisitorPrivate +//----------------------------------------------------------------------------- + +class QDumperBase +{ +public: + QDumperBase(); + ~QDumperBase(); + + void setPrefix(const QString& prefix); + void addAnnotator(QAnnotator* annotator); + +protected: + QByteArray m_prefix; + QList<QAnnotator*> m_annotators; + +}; + +QDumperBase::QDumperBase() +{ + +} + +QDumperBase::~QDumperBase() +{ + QAnnotator* annotator; + foreach(annotator, m_annotators) + delete annotator; +} + +void QDumperBase::setPrefix(const QString& prefix) +{ + m_prefix = prefix.count() + ? (prefix + " ").toAscii() + : prefix.toAscii(); +} + +void QDumperBase::addAnnotator(QAnnotator* annotator) +{ + // Protect against an exception occurring during QList::append + QScopedPointer<QAnnotator> holder(annotator); + m_annotators.append(annotator); + holder.take(); +} + + +//----------------------------------------------------------------------------- +// QDumper +//----------------------------------------------------------------------------- + +class QDumperPrivate : public QDumperBase +{ +public: + QDumperPrivate(); + ~QDumperPrivate(); + + void dumpObject(const QObject& object); + +}; + + +QDumperPrivate::QDumperPrivate() +{ + +} + +QDumperPrivate::~QDumperPrivate() +{ + +} + +void QDumperPrivate::dumpObject(const QObject& object) +{ + QAnnotator* annotator; + foreach(annotator, m_annotators) { + + const QList<QByteArray> annotations = annotator->annotation(object); + QByteArray annotation; + foreach(annotation, annotations) { + QByteArray buffer(m_prefix); + buffer.append(annotation); + qDebug() << buffer.constData(); + } + } +} + + +QDumper::QDumper() + : d_ptr(new QDumperPrivate) +{ + +} + +QDumper::~QDumper() +{ + +} + +void QDumper::setPrefix(const QString& prefix) +{ + d_func()->setPrefix(prefix); +} + +void QDumper::addAnnotator(QAnnotator* annotator) +{ + d_func()->addAnnotator(annotator); +} + +void QDumper::dumpObject(const QObject& object) +{ + d_func()->dumpObject(object); +} + + +//----------------------------------------------------------------------------- +// QVisitor +//----------------------------------------------------------------------------- + +class QVisitorPrivate : public QDumperBase +{ +public: + QVisitorPrivate(); + ~QVisitorPrivate(); + + void setIndent(unsigned indent); + + void visitNode(const QObject& object); + void visitComplete(); + +private: + class Node + { + public: + Node(); + ~Node(); + + QList<QByteArray> m_annotation; + QList<Node*> m_children; + + typedef QList<Node*>::const_iterator child_iterator; + }; + +private: + Node* findNode(const QObject* object) const; + QByteArray branchBuffer(const QList<bool>& branches, bool isNodeLine, bool isLastChild) const; + void dumpRecursive(const Node& node, QList<bool> branches, bool isLastChild); + void dumpNode(const Node& node, const QList<bool>& branches, bool isLastChild); + +private: + unsigned m_indent; + + QScopedPointer<Node> m_root; + + // Hash table used to associate internal nodes with QObjects + typedef QHash<const QObject*, Node*> Hash; + Hash m_hash; +}; + +static const unsigned DefaultIndent = 2; + +QVisitorPrivate::QVisitorPrivate() + : m_indent(DefaultIndent) +{ + +} + +QVisitorPrivate::~QVisitorPrivate() +{ + +} + +void QVisitorPrivate::setIndent(unsigned indent) +{ + m_indent = indent; +} + +// Builds up a mirror of the object tree, rooted in m_root, with each node +// storing annotations generated by +void QVisitorPrivate::visitNode(const QObject& object) +{ + QObject* const objectParent = object.parent(); + Node* const nodeParent = objectParent ? findNode(objectParent) : NULL; + + // Create a new node and store in scoped pointer for exception safety + Node* node = new Node; + QScopedPointer<Node> nodePtr(node); + + // Associate node with QObject + m_hash.insert(&object, node); + + // Insert node into internal tree + if(nodeParent) + { + nodeParent->m_children.append(nodePtr.take()); + } + else + { + Q_ASSERT(m_root.isNull()); + m_root.reset(nodePtr.take()); + } + + // Generate and store annotations + QAnnotator* annotator; + foreach(annotator, m_annotators) + node->m_annotation.append( annotator->annotation(object) ); +} + +void QVisitorPrivate::visitComplete() +{ + QList<bool> branches; + static const bool isLastChild = true; + dumpRecursive(*m_root, branches, isLastChild); + m_root.reset(NULL); +} + +QVisitorPrivate::Node* QVisitorPrivate::findNode(const QObject* object) const +{ + Hash::const_iterator i = m_hash.find(object); + return (m_hash.end() == i) ? NULL : *i; +} + +QByteArray QVisitorPrivate::branchBuffer + (const QList<bool>& branches, bool isNodeLine, bool isLastChild) const +{ + const int depth = branches.count(); + + const QByteArray indent(m_indent, ' '); + const QByteArray horiz(m_indent, '-'); + + QByteArray buffer; + QTextStream stream(&buffer); + + for (int i=0; i<depth-1; ++i) { + if(branches[i]) + stream << '|'; + else + stream << ' '; + stream << indent; + } + + if(depth) { + if(isNodeLine) + stream << '+' << horiz; + else { + if(!isLastChild) + stream << '|'; + else + stream << ' '; + stream << indent; + } + } + + stream.flush(); + buffer.push_front(m_prefix); + + return buffer; +} + +void QVisitorPrivate::dumpRecursive + (const Node& node, QList<bool> branches, bool isLastChild) +{ + dumpNode(node, branches, isLastChild); + + // Recurse down tree + const Node::child_iterator begin = node.m_children.begin(); + const Node::child_iterator end = node.m_children.end(); + for(Node::child_iterator i = begin; end != i; ++i) { + + isLastChild = (end == i + 1); + + if(begin == i) + branches.push_back(!isLastChild); + else + branches.back() = !isLastChild; + + static const bool isNodeLine = false; + const QByteArray buffer = branchBuffer(branches, isNodeLine, false); + qDebug() << buffer.constData(); + + dumpRecursive(**i, branches, isLastChild); + } +} + +void QVisitorPrivate::dumpNode + (const Node& node, const QList<bool>& branches, bool isLastChild) +{ + const QList<QByteArray>::const_iterator + begin = node.m_annotation.begin(), end = node.m_annotation.end(); + + if(begin == end) { + // No annotations - just dump the object pointer + const bool isNodeLine = true; + QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild); + qDebug() << NULL; // TODO + } + else { + // Dump annotations + for(QList<QByteArray>::const_iterator i = begin; end != i; ++i) { + const bool isNodeLine = (begin == i); + QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild); + buffer.append(*i); + qDebug() << buffer.constData(); + } + } +} + + +// QVisitorPrivate::Node + +QVisitorPrivate::Node::Node() +{ + +} + +QVisitorPrivate::Node::~Node() +{ + Node* child; + foreach(child, m_children) + delete child; +} + + +// QVisitor + +QVisitor::QVisitor() + : d_ptr(new QVisitorPrivate) +{ + +} + +QVisitor::~QVisitor() +{ + +} + +void QVisitor::setPrefix(const QString& prefix) +{ + d_func()->setPrefix(prefix); +} + +void QVisitor::setIndent(unsigned indent) +{ + d_func()->setIndent(indent); +} + +void QVisitor::addAnnotator(QAnnotator* annotator) +{ + d_func()->addAnnotator(annotator); +} + +void QVisitor::visitPrepare() +{ + // Do nothing +} + +void QVisitor::visitNode(const QObject& object) +{ + d_func()->visitNode(object); +} + +void QVisitor::visitComplete() +{ + d_func()->visitComplete(); +} + + +//----------------------------------------------------------------------------- +// Utility functions +//----------------------------------------------------------------------------- + +void addDefaultAnnotators_sys(QDumper& visitor); +void addDefaultAnnotators_sys(QVisitor& visitor); + +void addDefaultAnnotators(QDumper& dumper) +{ + dumper.addAnnotator(new QAnnotatorBasic); + dumper.addAnnotator(new QAnnotatorWidget); + + // Add platform-specific annotators + addDefaultAnnotators_sys(dumper); +} + +void addDefaultAnnotators(QVisitor& visitor) +{ + visitor.addAnnotator(new QAnnotatorBasic); + visitor.addAnnotator(new QAnnotatorWidget); + + // Add platform-specific annotators + addDefaultAnnotators_sys(visitor); +} + +void dumpTreeFromRoot(const QObject& root, QVisitor& visitor) +{ + // Set up iteration range + ObjectTree::DepthFirstConstIterator begin(root), end; + + // Invoke generic visitor algorithm + ObjectTree::visit(begin, end, visitor); +} + +void dumpTreeFromLeaf(const QObject& leaf, QVisitor& visitor) +{ + // Walk up to root + const QObject* root = &leaf; + while(root->parent()) + { + root = root->parent(); + } + + dumpTreeFromRoot(*root, visitor); +} + +void dumpAncestors(const QObject& leaf, QVisitor& visitor) +{ + // Set up iteration range + ObjectTree::AncestorConstIterator begin(leaf), end; + + // Invoke generic visitor algorithm + ObjectTree::visit(begin, end, visitor); +} + + +} // namespace ObjectDump + +QT_END_NAMESPACE + + + diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.h b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.h new file mode 100644 index 0000000..cbd9bea --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump.h @@ -0,0 +1,166 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef OBJECTDUMP_H +#define OBJECTDUMP_H + +#include "objectdump_global.h" + +#include <QObject> +#include <QList> +#include <QByteArray> +#include <QScopedPointer> + +QT_BEGIN_NAMESPACE + +namespace ObjectDump +{ + +/** + * Abstract base for annotator classes invoked by QVisitor. + */ +class OBJECTDUMP_EXPORT QAnnotator : public QObject +{ + Q_OBJECT +public: + virtual ~QAnnotator(); + virtual QList<QByteArray> annotation(const QObject& object) = 0; +}; + +/** + * Annotator which replicates QObject::dumpObjectTree functionality. + */ +class OBJECTDUMP_EXPORT QAnnotatorBasic : public QAnnotator +{ + Q_OBJECT +public: + QList<QByteArray> annotation(const QObject& object); +}; + +/** + * Annotator which returns widget information. + */ +class OBJECTDUMP_EXPORT QAnnotatorWidget : public QAnnotator +{ + Q_OBJECT +public: + QList<QByteArray> annotation(const QObject& object); +}; + + +class QDumperPrivate; + +/** + * Class used to dump information about individual QObjects. + */ +class OBJECTDUMP_EXPORT QDumper : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDumper) + +public: + QDumper(); + ~QDumper(); + + /** + * Specify a prefix, to be printed on each line of output. + */ + void setPrefix(const QString& prefix); + + /** + * Takes ownership of annotator. + */ + void addAnnotator(QAnnotator* annotator); + + /** + * Invoke each annotator on the object and write to debug output. + */ + void dumpObject(const QObject& object); + +private: + QScopedPointer<QDumperPrivate> d_ptr; + +}; + + +class QVisitorPrivate; + +/** + * Visitor class which dumps information about nodes in the object tree. + */ +class OBJECTDUMP_EXPORT QVisitor : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QVisitor) + +public: + QVisitor(); + ~QVisitor(); + + /** + * Specify a prefix, to be printed on each line of output. + */ + void setPrefix(const QString& prefix); + + /** + * Set number of spaces by which each level of the tree is indented. + */ + void setIndent(unsigned indent); + + /** + * Called by the visitor algorithm before starting the visit. + */ + void visitPrepare(); + + /** + * Called by the visitor algorithm as each node is visited. + */ + void visitNode(const QObject& object); + + /** + * Called by the visitor algorithm when the visit is complete. + */ + void visitComplete(); + + /** + * Takes ownership of annotator. + */ + void addAnnotator(QAnnotator* annotator); + +private: + QScopedPointer<QVisitorPrivate> d_ptr; + +}; + + +//----------------------------------------------------------------------------- +// Utility functions +//----------------------------------------------------------------------------- + +void OBJECTDUMP_EXPORT addDefaultAnnotators(QDumper& dumper); +void OBJECTDUMP_EXPORT addDefaultAnnotators(QVisitor& visitor); + +void OBJECTDUMP_EXPORT dumpTreeFromRoot(const QObject& root, QVisitor& visitor); +void OBJECTDUMP_EXPORT dumpTreeFromLeaf(const QObject& leaf, QVisitor& visitor); +void OBJECTDUMP_EXPORT dumpAncestors(const QObject& leaf, QVisitor& visitor); + +} // namespace ObjectDump + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_global.h b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_global.h new file mode 100644 index 0000000..b8987e0 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_global.h @@ -0,0 +1,30 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef OBJECTDUMP_GLOBAL_H +#define OBJECTDUMP_GLOBAL_H + +#include <QtCore/QtGlobal> + +#if defined(OBJECTDUMP_LIBRARY) +# define OBJECTDUMP_EXPORT +#else +# define OBJECTDUMP_EXPORT +#endif + +#endif diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_stub.cpp b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_stub.cpp new file mode 100644 index 0000000..6207dac --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_stub.cpp @@ -0,0 +1,40 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "objectdump.h" + +QT_BEGIN_NAMESPACE + +namespace ObjectDump +{ + +void addDefaultAnnotators_sys(QDumper& /*dumper*/) +{ + +} + +void addDefaultAnnotators_sys(QVisitor& /*visitor*/) +{ + +} + +} // namespace ObjectDump + +QT_END_NAMESPACE + + diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.cpp b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.cpp new file mode 100644 index 0000000..f8adcd5 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.cpp @@ -0,0 +1,135 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QTextStream> +#include <QWidget> +#include <coecntrl.h> +#include "objectdump_symbian.h" + +QT_BEGIN_NAMESPACE + +namespace ObjectDump +{ +namespace Symbian +{ + +QList<QByteArray> QAnnotatorControl::annotation(const QObject& object) +{ + QList<QByteArray> result; + + const QWidget* widget = qobject_cast<const QWidget*>(&object); + if(widget) { + + const CCoeControl* control = widget->effectiveWinId(); + if(control) { + + QByteArray array; + QTextStream stream(&array); + + stream << "control: " << control << ' '; + stream << "parent " << control->Parent() << ' '; + + if(control->IsVisible()) + stream << "visible "; + else + stream << "invisible "; + + stream << control->Position().iX << ',' << control->Position().iY << ' '; + stream << control->Size().iWidth << 'x' << control->Size().iHeight; + + if(control->OwnsWindow()) + stream << " ownsWindow "; + + stream.flush(); + result.append(array); + } + } + + return result; +} + +QList<QByteArray> QAnnotatorWindow::annotation(const QObject& object) +{ + QList<QByteArray> result; + + const QWidget* widget = qobject_cast<const QWidget*>(&object); + if(widget) { + + const CCoeControl* control = widget->effectiveWinId(); + if(control) { + + RDrawableWindow& window = *(control->DrawableWindow()); + + QByteArray array; + QTextStream stream(&array); + + stream << "window: "; + + // ClientHandle() is available first in 5.0. +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + // Client-side window handle + // Cast to a void pointer so that log output is in hexadecimal format. + stream << "cli " << reinterpret_cast<const void*>(window.ClientHandle()) << ' '; +#endif + + // Server-side address of CWsWindow object + // This is useful for correlation with the window tree dumped by the window + // server (see RWsSession::LogCommand). + // Cast to a void pointer so that log output is in hexadecimal format. + stream << "srv " << reinterpret_cast<const void*>(window.WsHandle()) << ' '; + + stream << "group " << window.WindowGroupId() << ' '; + + // Client-side handle to the parent window. + // Cast to a void pointer so that log output is in hexadecimal format. + stream << "parent " << reinterpret_cast<const void*>(window.Parent()) << ' '; + + stream << window.Position().iX << ',' << window.Position().iY << ' '; + stream << '(' << window.AbsPosition().iX << ',' << window.AbsPosition().iY << ") "; + stream << window.Size().iWidth << 'x' << window.Size().iHeight << ' '; + + const TDisplayMode displayMode = window.DisplayMode(); + stream << "mode " << displayMode; + + stream.flush(); + result.append(array); + } + } + + return result; +} + +} // namespace Symbian + +void addDefaultAnnotators_sys(QDumper& dumper) +{ + dumper.addAnnotator(new Symbian::QAnnotatorControl); + dumper.addAnnotator(new Symbian::QAnnotatorWindow); +} + +void addDefaultAnnotators_sys(QVisitor& visitor) +{ + visitor.addAnnotator(new Symbian::QAnnotatorControl); + visitor.addAnnotator(new Symbian::QAnnotatorWindow); +} + +} // namespace ObjectDump + +QT_END_NAMESPACE + + diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.h b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.h new file mode 100644 index 0000000..26ab308 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objectdump_symbian.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef OBJECTDUMP_SYMBIAN_H +#define OBJECTDUMP_SYMBIAN_H + +#include "objectdump.h" + +QT_BEGIN_NAMESPACE + +namespace ObjectDump +{ +namespace Symbian +{ + +/** + * Annotator which returns control information + */ +class QAnnotatorControl : public QAnnotator +{ + Q_OBJECT +public: + QList<QByteArray> annotation(const QObject& object); +}; + +/** + * Annotator which returns window information + */ +class QAnnotatorWindow : public QAnnotator +{ + Q_OBJECT +public: + QList<QByteArray> annotation(const QObject& object); +}; + +} // namespace Symbian +} // namespace ObjectDump + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.cpp b/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.cpp new file mode 100644 index 0000000..f9d1c93 --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.cpp @@ -0,0 +1,102 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <QTextStream> +#include <QWidget> +#include "objecttree.h" + +QT_BEGIN_NAMESPACE + +namespace ObjectTree +{ + +DepthFirstConstIterator::DepthFirstConstIterator() + : m_pointee(NULL) +{ + +} + +DepthFirstConstIterator::DepthFirstConstIterator + (const QObject& root) + : m_pointee(&root) +{ + +} + +DepthFirstConstIterator& + DepthFirstConstIterator::operator++() +{ + const QObjectList& children = m_pointee->children(); + + if (children.count() == 0) { + backtrack(); + } + else { + m_history.push(0); + m_pointee = children.first(); + } + + return *this; +} + +void DepthFirstConstIterator::backtrack() +{ + if (m_history.count()) { + const int index = m_history.top(); + m_history.pop(); + + const QObjectList& siblings = m_pointee->parent()->children(); + if (siblings.count() > index + 1) { + m_history.push(index + 1); + m_pointee = siblings[index + 1]; + } + else { + m_pointee = m_pointee->parent(); + backtrack(); + } + } + else { + // Reached end of search + m_pointee = NULL; + } +} + + + +AncestorConstIterator::AncestorConstIterator() +{ + +} + +AncestorConstIterator::AncestorConstIterator(const QObject& leaf) +{ + m_ancestors.push(&leaf); + QObject* ancestor = leaf.parent(); + while(ancestor) + { + m_ancestors.push(ancestor); + ancestor = ancestor->parent(); + } +} + +} // namespace ObjectTree + +QT_END_NAMESPACE + + + diff --git a/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.h b/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.h new file mode 100644 index 0000000..f2729fa --- /dev/null +++ b/src/3rdparty/phonon/mmf/mmfphonondebug/objecttree.h @@ -0,0 +1,117 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef OBJECTTREE_H +#define OBJECTTREE_H + +#include "objectdump_global.h" + +#include <QObject> +#include <QStack> + +QT_BEGIN_NAMESPACE + +namespace ObjectTree +{ + +/** + * Depth-first iterator for QObject tree + */ +class OBJECTDUMP_EXPORT DepthFirstConstIterator +{ +public: + DepthFirstConstIterator(); + DepthFirstConstIterator(const QObject& root); + + DepthFirstConstIterator& operator++(); + + inline bool operator==(const DepthFirstConstIterator& other) const + { return other.m_pointee == m_pointee; } + + inline bool operator!=(const DepthFirstConstIterator& other) const + { return other.m_pointee != m_pointee; } + + inline const QObject* operator->() const { return m_pointee; } + inline const QObject& operator*() const { return *m_pointee; } + +private: + void backtrack(); + +private: + const QObject* m_pointee; + QStack<int> m_history; +}; + +/** + * Ancestor iterator for QObject tree + */ +class OBJECTDUMP_EXPORT AncestorConstIterator +{ +public: + AncestorConstIterator(); + AncestorConstIterator(const QObject& root); + + inline AncestorConstIterator& operator++() + { m_ancestors.pop(); return *this; } + + inline bool operator==(const AncestorConstIterator& other) const + { return other.m_ancestors == m_ancestors; } + + inline bool operator!=(const AncestorConstIterator& other) const + { return other.m_ancestors != m_ancestors; } + + inline const QObject* operator->() const { return m_ancestors.top(); } + inline const QObject& operator*() const { return *m_ancestors.top(); } + +private: + QStack<const QObject*> m_ancestors; + +}; + +/** + * Generic algorithm for visiting nodes in an object tree. Nodes in the + * tree are visited in a const context, therefore they are not modified + * by this algorithm. + * + * Visitor must provide functions with the following signatures: + * + * Called before visit begins + * void visitPrepare() + * + * Called on each node visited + * void visitNode(const QObject& object) + * + * Called when visit is complete + * void visitComplete() + */ +template <class Iterator, class Visitor> +void visit(Iterator begin, Iterator end, Visitor& visitor) +{ + visitor.visitPrepare(); + + for( ; begin != end; ++begin) + visitor.visitNode(*begin); + + visitor.visitComplete(); +} + +} // namespace ObjectTree + +QT_END_NAMESPACE + +#endif // OBJECTTREE_H diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp new file mode 100644 index 0000000..107a36d --- /dev/null +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -0,0 +1,142 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "utils.h" +#include <e32std.h> + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +_LIT(PanicCategory, "Phonon::MMF"); + +void MMF::Utils::panic(PanicCode code) +{ + User::Panic(PanicCategory, code); +} + + +static const TInt KMimePrefixLength = 6; // either "audio/" or "video/" +_LIT(KMimePrefixAudio, "audio/"); +_LIT(KMimePrefixVideo, "video/"); + +MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType) +{ + MediaType result = MediaTypeUnknown; + + if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixAudio) == 0) { + result = MediaTypeAudio; + } else if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixVideo) == 0) { + result = MediaTypeVideo; + } + + return result; +} + + +#ifdef _DEBUG + +#include <hal.h> +#include <hal_data.h> +#include <gdi.h> +#include <eikenv.h> + +struct TScreenInfo +{ + int width; + int height; + int bpp; + const char* address; + int initialOffset; + int lineOffset; + TDisplayMode displayMode; +}; + +void getScreenInfoL(TScreenInfo& info) +{ + info.displayMode = CEikonEnv::Static()->ScreenDevice()->DisplayMode(); + + // Then we must set these as the input parameter + info.width = info.displayMode; + info.height = info.displayMode; + info.initialOffset = info.displayMode; + info.lineOffset = info.displayMode; + info.bpp = info.displayMode; + + User::LeaveIfError( HAL::Get(HALData::EDisplayXPixels, info.width) ); + User::LeaveIfError( HAL::Get(HALData::EDisplayYPixels, info.width) ); + + int address; + User::LeaveIfError( HAL::Get(HALData::EDisplayMemoryAddress, address) ); + info.address = reinterpret_cast<const char*>(address); + + User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetToFirstPixel, info.initialOffset) ); + + User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetBetweenLines, info.lineOffset) ); + + User::LeaveIfError( HAL::Get(HALData::EDisplayBitsPerPixel, info.bpp) ); +} + + +QColor MMF::Utils::getScreenPixel(const QPoint& pos) +{ + TScreenInfo info; + TRAPD(err, getScreenInfoL(info)); + QColor pixel; + if(err == KErrNone and pos.x() < info.width and pos.y() < info.height) + { + const int bytesPerPixel = info.bpp / 8; + Q_ASSERT(bytesPerPixel >= 3); + + const int stride = (info.width * bytesPerPixel) + info.lineOffset; + + const char* ptr = + info.address + + info.initialOffset + + pos.y() * stride + + pos.x() * bytesPerPixel; + + // BGRA + pixel.setBlue(*ptr++); + pixel.setGreen(*ptr++); + pixel.setRed(*ptr++); + + if(bytesPerPixel == 4) + pixel.setAlpha(*ptr++); + } + return pixel; +} + +// Debugging: for debugging video visibility +void MMF::Utils::dumpScreenPixelSample() +{ + for(int i=0; i<20; ++i) { + const QPoint pos(i*10, i*10); + const QColor pixel = Utils::getScreenPixel(pos); + RDebug::Printf( + "Phonon::MMF::Utils::dumpScreenPixelSample %d %d = %d %d %d %d", + pos.x(), pos.y(), pixel.red(), pixel.green(), pixel.blue(), pixel.alpha() + ); + } +} + +#endif // _DEBUG + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h new file mode 100644 index 0000000..38964d0 --- /dev/null +++ b/src/3rdparty/phonon/mmf/utils.h @@ -0,0 +1,167 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_UTILS_H +#define PHONON_MMF_UTILS_H + +#include <private/qcore_symbian_p.h> +#include <e32debug.h> // for RDebug + +#include <QColor> + +#include "defs.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * Panic codes for fatal errors + */ +enum PanicCode { + InvalidStatePanic = 1, + InvalidMediaTypePanic = 2, + InvalidBackendInterfaceClass = 3 +}; + +namespace Utils +{ +/** + * Raise a fatal exception + */ +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); + +#ifdef _DEBUG +/** + * Retrieve color of specified pixel from the screen. + */ +QColor getScreenPixel(const QPoint& pos); + +/** + * Samples a small number of pixels from the screen, and dumps their + * colors to the debug log. + */ +void dumpScreenPixelSample(); +#endif +} + +/** + * Available trace categories; + */ +enum TTraceCategory { + /** + * Backend + */ + EBackend = 0x00000001, + + /** + * Functions which map directly to the public Phonon audio API + */ + EAudioApi = 0x00000010, + + /** + * Internal functions in the audio implementation + */ + EAudioInternal = 0x00000020, + + /** + * Functions which map directly to the public Phonon video API + */ + EVideoApi = 0x00010000, + + /** + * Internal functions in the video implementation + */ + EVideoInternal = 0x00020000 +}; + +/** + * Mask indicating which trace categories are enabled + * + * Note that, at the moment, this is a compiled static constant. For + * runtime control over enabled trace categories, this could be replaced + * by a per-thread singleton object which owns the trace mask, and which + * exposes an API allowing it to be modified. + */ +static const TUint KTraceMask = 0xffffffff; + +/** + * Data structure used by tracing macros + */ +class TTraceContext +{ +public: + TTraceContext(const TText* aFunction, const TUint aAddr, + const TUint aCategory = 0) + : iFunction(aFunction), + iAddr(aAddr), + iCategory(aCategory) { } + + /** + * Check whether iCategory appears in the trace mask + */ + TBool Enabled() const { + return (iCategory == 0) or(iCategory & KTraceMask); + } + + const TText* iFunction; // Name of function + const TUint iAddr; // 'this' pointer + const TUint iCategory; +}; + +// Macros used internally by the trace system +#define _TRACE_PRINT RDebug::Print +#define _TRACE_TEXT(x) (TPtrC((const TText *)(x))) +#define _TRACE_MODULE Phonon::MMF + +// Macros available for use by implementation code +#ifdef _DEBUG +#define TRACE_CONTEXT(_fn, _cat) const ::Phonon::MMF::TTraceContext _tc((TText*)L ## #_fn, (TUint)this, _cat); +#define TRACE_ENTRY_0() { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "+ Phonon::MMF::%s [0x%08x]"), _tc.iFunction, _tc.iAddr); } +#define TRACE_ENTRY(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "+ Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); } +#define TRACE_EXIT_0() { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "- Phonon::MMF::%s [0x%08x]"), _tc.iFunction, _tc.iAddr); } +#define TRACE_EXIT(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "- Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); } +#define TRACE_RETURN(string, result) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## "r Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, result); } return result; +#define TRACE_PANIC(code) { _TRACE_PRINT(_TRACE_TEXT(L ## "! Phonon::MMF::%s [0x%08x] panic %d"), _tc.iFunction, _tc.iAddr, code); } Utils::panic(code); +#define TRACE_0(string) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## " Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr); } +#define TRACE(string, args...) { if(_tc.Enabled()) _TRACE_PRINT(_TRACE_TEXT(L ## " Phonon::MMF::%s [0x%08x] " L ## string), _tc.iFunction, _tc.iAddr, args); } +#else +#define TRACE_CONTEXT(_fn, _cat) +#define TRACE_ENTRY_0() +#define TRACE_ENTRY(string, args...) +#define TRACE_EXIT_0() +#define TRACE_EXIT(string, args...) +#define TRACE_RETURN(string, result) return result; +#define TRACE_PANIC(code) Utils::panic(code); +#define TRACE_0(string) +#define TRACE(string, args...) +#endif +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/videooutput.cpp b/src/3rdparty/phonon/mmf/videooutput.cpp new file mode 100644 index 0000000..642de97 --- /dev/null +++ b/src/3rdparty/phonon/mmf/videooutput.cpp @@ -0,0 +1,173 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "utils.h" +#include "videooutput.h" +#include "videooutputobserver.h" + +#ifdef _DEBUG +#include "objectdump.h" +#endif + +#include <QPaintEvent> +#include <QPainter> +#include <QMoveEvent> +#include <QResizeEvent> + +#include <QtGui/private/qwidget_p.h> // to access QWExtra + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::VideoOutput::VideoOutput(QWidget* parent) + : QWidget(parent) + , m_observer(NULL) +{ + TRACE_CONTEXT(VideoOutput::VideoOutput, EVideoInternal); + TRACE_ENTRY("parent 0x%08x", parent); + + setPalette(QPalette(Qt::black)); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setAutoFillBackground(false); + + // Causes QSymbianControl::Draw not to BitBlt this widget's region of the + // backing store. Since the backing store is (by default) a 16MU bitmap, + // blitting it results in this widget's screen region in the final + // framebuffer having opaque alpha values. This in turn causes the video + // to be invisible when running on the target device. + qt_widget_private(this)->extraData()->disableBlit = true; + + dump(); + + TRACE_EXIT_0(); +} + +MMF::VideoOutput::~VideoOutput() +{ + TRACE_CONTEXT(VideoOutput::~VideoOutput, EVideoInternal); + TRACE_ENTRY_0(); + + TRACE_EXIT_0(); +} + +void MMF::VideoOutput::setFrameSize(const QSize& frameSize) +{ + TRACE_CONTEXT(VideoOutput::setFrameSize, EVideoInternal); + TRACE("oldSize %d %d newSize %d %d", + m_frameSize.width(), m_frameSize.height(), + frameSize.width(), frameSize.height()); + + if (frameSize != m_frameSize) { + m_frameSize = frameSize; + updateGeometry(); + } +} + +void MMF::VideoOutput::setObserver(VideoOutputObserver* observer) +{ + TRACE_CONTEXT(VideoOutput::setObserver, EVideoInternal); + TRACE("observer 0x%08x", observer); + + m_observer = observer; +} + + +//----------------------------------------------------------------------------- +// QWidget +//----------------------------------------------------------------------------- + +QSize MMF::VideoOutput::sizeHint() const +{ + // TODO: replace this with a more sensible default + QSize result(320, 240); + + if (!m_frameSize.isNull()) { + result = m_frameSize; + } + + return result; +} + +void MMF::VideoOutput::paintEvent(QPaintEvent* event) +{ + TRACE_CONTEXT(VideoOutput::paintEvent, EVideoInternal); + TRACE("rect %d %d - %d %d", + event->rect().left(), event->rect().top(), + event->rect().right(), event->rect().bottom()); + TRACE("regions %d", event->region().numRects()); + TRACE("type %d", event->type()); + + dump(); + + // Do not paint anything +} + +void MMF::VideoOutput::resizeEvent(QResizeEvent* event) +{ + TRACE_CONTEXT(VideoOutput::resizeEvent, EVideoInternal); + TRACE("%d %d -> %d %d", + event->oldSize().width(), event->oldSize().height(), + event->size().width(), event->size().height()); + + QWidget::resizeEvent(event); + + if (m_observer) + m_observer->videoOutputRegionChanged(); +} + +void MMF::VideoOutput::moveEvent(QMoveEvent* event) +{ + TRACE_CONTEXT(VideoOutput::moveEvent, EVideoInternal); + TRACE("%d %d -> %d %d", + event->oldPos().x(), event->oldPos().y(), + event->pos().x(), event->pos().y()); + + QWidget::moveEvent(event); + + if (m_observer) + m_observer->videoOutputRegionChanged(); +} + + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void VideoOutput::dump() const +{ +#ifdef _DEBUG + TRACE_CONTEXT(VideoOutput::dump, EVideoInternal); + QScopedPointer<ObjectDump::QVisitor> visitor(new ObjectDump::QVisitor); + visitor->setPrefix("Phonon::MMF"); // to aid searchability of logs + ObjectDump::addDefaultAnnotators(*visitor); + TRACE("Dumping tree from leaf 0x%08x:", this); + //ObjectDump::dumpAncestors(*this, *visitor); + ObjectDump::dumpTreeFromLeaf(*this, *visitor); +#endif +} + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/videooutput.h b/src/3rdparty/phonon/mmf/videooutput.h new file mode 100644 index 0000000..639a5ed --- /dev/null +++ b/src/3rdparty/phonon/mmf/videooutput.h @@ -0,0 +1,67 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_VIDEOOUTPUT_H +#define PHONON_MMF_VIDEOOUTPUT_H + +#include <QtGui/QWidget> +#include <QVector> +#include <QRect> +#include "defs.h" + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class VideoOutputObserver; + +class VideoOutput : public QWidget +{ + Q_OBJECT + +public: + explicit VideoOutput(QWidget* parent); + ~VideoOutput(); + + void setFrameSize(const QSize& size); + void setObserver(VideoOutputObserver* observer); + +protected: + // Override QWidget functions + QSize sizeHint() const; + void paintEvent(QPaintEvent* event); + void resizeEvent(QResizeEvent* event); + void moveEvent(QMoveEvent* event); + +private: + void dump() const; + +private: + QSize m_frameSize; + + // Not owned + VideoOutputObserver* m_observer; +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/videooutputobserver.h b/src/3rdparty/phonon/mmf/videooutputobserver.h new file mode 100644 index 0000000..e3ba305 --- /dev/null +++ b/src/3rdparty/phonon/mmf/videooutputobserver.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_VIDEOOUTPUTOBSERVER_H +#define PHONON_MMF_VIDEOOUTPUTOBSERVER_H + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * Interface via which VideoOutput notifies VideoPlayer of changes to the + * video output screen region. + */ +class VideoOutputObserver +{ +public: + virtual void videoOutputRegionChanged() = 0; +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp new file mode 100644 index 0000000..ac93929 --- /dev/null +++ b/src/3rdparty/phonon/mmf/videowidget.cpp @@ -0,0 +1,173 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "mediaobject.h" +#include "utils.h" +#include "videooutput.h" + +#include "videowidget.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +static const Phonon::VideoWidget::AspectRatio DefaultAspectRatio = + Phonon::VideoWidget::AspectRatioAuto; +static const qreal DefaultBrightness = 1.0; +static const Phonon::VideoWidget::ScaleMode DefaultScaleMode = + Phonon::VideoWidget::FitInView; +static const qreal DefaultContrast = 1.0; +static const qreal DefaultHue = 1.0; +static const qreal DefaultSaturation = 1.0; + + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +MMF::VideoWidget::VideoWidget(QWidget* parent) + : MediaNode(parent) + , m_widget(new VideoOutput(parent)) + , m_aspectRatio(DefaultAspectRatio) + , m_brightness(DefaultBrightness) + , m_scaleMode(DefaultScaleMode) + , m_contrast(DefaultContrast) + , m_hue(DefaultHue) + , m_saturation(DefaultSaturation) +{ + TRACE_CONTEXT(VideoWidget::VideoWidget, EVideoApi); + TRACE_ENTRY_0(); + + TRACE_EXIT_0(); +} + +MMF::VideoWidget::~VideoWidget() +{ + TRACE_CONTEXT(VideoWidget::~VideoWidget, EVideoApi); + TRACE_ENTRY_0(); + + TRACE_EXIT_0(); +} + + +//----------------------------------------------------------------------------- +// VideoWidgetInterface +//----------------------------------------------------------------------------- + +Phonon::VideoWidget::AspectRatio MMF::VideoWidget::aspectRatio() const +{ + return m_aspectRatio; +} + +void MMF::VideoWidget::setAspectRatio +(Phonon::VideoWidget::AspectRatio aspectRatio) +{ + TRACE_CONTEXT(VideoWidget::setAspectRatio, EVideoApi); + TRACE("aspectRatio %d", aspectRatio); + + m_aspectRatio = aspectRatio; +} + +qreal MMF::VideoWidget::brightness() const +{ + return m_brightness; +} + +void MMF::VideoWidget::setBrightness(qreal brightness) +{ + TRACE_CONTEXT(VideoWidget::setBrightness, EVideoApi); + TRACE("brightness %f", brightness); + + m_brightness = brightness; +} + +Phonon::VideoWidget::ScaleMode MMF::VideoWidget::scaleMode() const +{ + return m_scaleMode; +} + +void MMF::VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode) +{ + TRACE_CONTEXT(VideoWidget::setScaleMode, EVideoApi); + TRACE("setScaleMode %d", setScaleMode); + + m_scaleMode = scaleMode; +} + +qreal MMF::VideoWidget::contrast() const +{ + return m_contrast; +} + +void MMF::VideoWidget::setContrast(qreal contrast) +{ + TRACE_CONTEXT(VideoWidget::setContrast, EVideoApi); + TRACE("contrast %f", contrast); + + m_contrast = contrast; +} + +qreal MMF::VideoWidget::hue() const +{ + return m_hue; +} + +void MMF::VideoWidget::setHue(qreal hue) +{ + TRACE_CONTEXT(VideoWidget::setHue, EVideoApi); + TRACE("hue %f", hue); + + m_hue = hue; +} + +qreal MMF::VideoWidget::saturation() const +{ + return m_saturation; +} + +void MMF::VideoWidget::setSaturation(qreal saturation) +{ + TRACE_CONTEXT(VideoWidget::setSaturation, EVideoApi); + TRACE("saturation %f", saturation); + + m_saturation = saturation; +} + +QWidget* MMF::VideoWidget::widget() +{ + return m_widget.data(); +} + +VideoOutput& MMF::VideoWidget::videoOutput() +{ + return *static_cast<VideoOutput*>(widget()); +} + +bool MMF::VideoWidget::activateOnMediaObject(MediaObject *mo) +{ + mo->setVideoOutput(&videoOutput()); + return true; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h new file mode 100644 index 0000000..970f749 --- /dev/null +++ b/src/3rdparty/phonon/mmf/videowidget.h @@ -0,0 +1,82 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_VIDEOWIDGET_H +#define PHONON_MMF_VIDEOWIDGET_H + +#include "mmf_medianode.h" + +#include <QtGui/QWidget> +#include <Phonon/VideoWidget> +#include <Phonon/VideoWidgetInterface> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class VideoOutput; + +class VideoWidget : public MediaNode + , public Phonon::VideoWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(Phonon::VideoWidgetInterface) + +public: + VideoWidget(QWidget* parent); + ~VideoWidget(); + + // VideoWidgetInterface + virtual Phonon::VideoWidget::AspectRatio aspectRatio() const; + virtual void setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio); + virtual qreal brightness() const; + virtual void setBrightness(qreal brightness); + virtual Phonon::VideoWidget::ScaleMode scaleMode() const; + virtual void setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode); + virtual qreal contrast() const; + virtual void setContrast(qreal constrast); + virtual qreal hue() const; + virtual void setHue(qreal hue); + virtual qreal saturation() const; + virtual void setSaturation(qreal saturation); + virtual QWidget *widget(); + + VideoOutput& videoOutput(); + +protected: + virtual bool activateOnMediaObject(MediaObject *mo); + +private: + QScopedPointer<QWidget> m_widget; + + Phonon::VideoWidget::AspectRatio m_aspectRatio; + qreal m_brightness; + Phonon::VideoWidget::ScaleMode m_scaleMode; + qreal m_contrast; + qreal m_hue; + qreal m_saturation; + +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/volumeobserver.h b/src/3rdparty/phonon/mmf/volumeobserver.h new file mode 100644 index 0000000..bedd3de --- /dev/null +++ b/src/3rdparty/phonon/mmf/volumeobserver.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_VOLUMEOBSERVER_H +#define PHONON_MMF_VOLUMEOBSERVER_H + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * Interface used by AudioOutput to pass volume control commands + * back along the audio path to the MediaObject. + */ +class VolumeObserver +{ +public: + virtual void volumeChanged(qreal volume) = 0; +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/phonon/factory.cpp b/src/3rdparty/phonon/phonon/factory.cpp index fef88f0..5c3752a 100644 --- a/src/3rdparty/phonon/phonon/factory.cpp +++ b/src/3rdparty/phonon/phonon/factory.cpp @@ -133,9 +133,30 @@ bool FactoryPrivate::createBackend() continue; } - const QStringList files = dir.entryList(QDir::Files); - for (int i = 0; i < files.count(); ++i) { - QPluginLoader pluginLoader(libPath + files.at(i)); + QStringList plugins(dir.entryList(QDir::Files)); + +#ifdef Q_OS_SYMBIAN + /* On Symbian OS we might have two plugins, one which uses Symbian + * MMF framework("phonon_mmf"), and one which uses Real Networks's + * Helix("hxphonon"). We prefer the latter because it's more + * sophisticated, so we make sure the Helix backend is attempted + * to be loaded first, and the MMF backend is used for backup. */ + { + + const int hxphonon = plugins.indexOf(QLatin1String("hxphonon")); + if (hxphonon != -1) + plugins.move(hxphonon, 0); + + // Code for debugging the MMF backend. + if(hxphonon != -1) { + qDebug() << "Found hxphonon backend and removed it from the lookup list."; + plugins.removeAll(QLatin1String("hxphonon")); + } + } +#endif + + for (int i = 0; i < plugins.count(); ++i) { + QPluginLoader pluginLoader(libPath + plugins.at(i)); if (!pluginLoader.load()) { pDebug() << Q_FUNC_INFO << " load failed:" << pluginLoader.errorString(); diff --git a/src/3rdparty/phonon/phonon/path.cpp b/src/3rdparty/phonon/phonon/path.cpp index aec8d05..ef3530c 100644 --- a/src/3rdparty/phonon/phonon/path.cpp +++ b/src/3rdparty/phonon/phonon/path.cpp @@ -310,8 +310,8 @@ bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, if (!transaction) return false; - QList<QObjectPair>::const_iterator it = disconnections.begin(); - for(;it != disconnections.end();++it) { + QList<QObjectPair>::const_iterator it = disconnections.constBegin(); + for(;it != disconnections.constEnd();++it) { const QObjectPair &pair = *it; if (!backend->disconnectNodes(pair.first, pair.second)) { @@ -327,8 +327,8 @@ bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, } } - for(it = connections.begin(); it != connections.end();++it) { - const QObjectPair &pair = *it; + for(it = connections.constBegin(); it != connections.constEnd(); ++it) { + const QObjectPair pair = *it; if (!backend->connectNodes(pair.first, pair.second)) { //Error: a connection failed QList<QObjectPair>::const_iterator it2 = connections.begin(); diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index e58e4ad..bca9baa 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -89,6 +89,7 @@ win32 { symbian { SOURCES += io/qfilesystemwatcher_symbian.cpp HEADERS += io/qfilesystemwatcher_symbian_p.h + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE contains(QT_CONFIG, s60): LIBS += -lplatformenv } } diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 83ac5fe..472937d 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -4,6 +4,9 @@ QT = core DEFINES += QT_BUILD_GUI_LIB QT_NO_USING_NAMESPACE win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x65000000 +# These enable debugging of window management for Symbian. +#DEFINES += DEBUG_QSYMBIANCONTROL DEBUG_QWIDGET + !win32:!embedded:!mac:!symbian:CONFIG += x11 unix:QMAKE_PKGCONFIG_REQUIRES = QtCore diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index a5d07fd..c935df5 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -77,6 +77,10 @@ #include <hal.h> #include <hal_data.h> +#ifdef DEBUG_QSYMBIANCONTROL +#include <QDebug> +#endif + QT_BEGIN_NAMESPACE #if defined(QT_DEBUG) @@ -323,11 +327,34 @@ QSymbianControl::QSymbianControl(QWidget *w) void QSymbianControl::ConstructL(bool topLevel, bool desktop) { if (!desktop) - { - if (topLevel) { + { + if (topLevel or !qwidget->parentWidget()) CreateWindowL(S60->windowGroup()); - } - + else + /** + * TODO: in order to avoid creating windows for all ancestors of + * this widget up to the root window, the parameter passed to + * CreateWindowL should be + * qwidget->parentWidget()->effectiveWinId(). However, if we do + * this, then we need to take care of re-parenting when a window + * is created for a widget between this one and the root window. + */ + CreateWindowL(qwidget->parentWidget()->winId()); + + // Necessary in order to be able to track the activation status of + // the control's window + qwidget->d_func()->createExtra(); + +#ifdef DEBUG_QSYMBIANCONTROL + qDebug() << "QSymbianControl::ConstructL [" << this + << "] widget" << qwidget + << "topLevel" << topLevel + << "parentWidget" << qwidget->parentWidget() + << "OwnsWindow" << OwnsWindow() + << "Window.ClientHandle" << reinterpret_cast<const void*>(DrawableWindow()->ClientHandle()) + << "WindowGroupId" << DrawableWindow()->WindowGroupId(); +#endif + SetFocusing(true); m_longTapDetector = QLongTapTimer::NewL(this); } @@ -694,31 +721,73 @@ TCoeInputCapabilities QSymbianControl::InputCapabilities() const void QSymbianControl::Draw(const TRect& r) const { QWindowSurface *surface = qwidget->windowSurface(); - if (!surface) - return; - - QPaintEngine *engine = surface->paintDevice()->paintEngine(); + QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL; + +#ifdef DEBUG_QSYMBIANCONTROL + qDebug() << "QSymbianControl::Draw [" << this << "]" + << "rect " << r.iTl.iX << ',' << r.iTl.iY + << '-' << r.iBr.iX << ',' << r.iBr.iY + << "surface" << surface + << "engine" << engine + << "raster" << (engine ? engine->type() == QPaintEngine::Raster : false) + << "opaque" << (qwidget->d_func()->isOpaque) + << "disableBlit" << (qwidget->d_func()->extraData()->disableBlit); +#endif + if (!engine) return; + if (engine->type() == QPaintEngine::Raster) { QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + +#ifdef DEBUG_QSYMBIANCONTROL + const TDisplayMode displayMode = bitmap->DisplayMode(); + qDebug() << "QSymbianControl::Draw [" << this << "]" + << "mode " << displayMode; + + const TUint32 *address = bitmap->DataAddress(); + const int bitmapWidth = bitmap->SizeInPixels().iWidth; + const int bitmapHeight = bitmap->SizeInPixels().iHeight; + + for(int i=0; i<10 and i*10<bitmapWidth and i*10<bitmapHeight; ++i) { + const int coord = i*10; + const TUint32 *ptr = address + (coord * bitmapWidth) + coord; + const TUint32 pixel = *ptr; + qDebug() << " " << i*10 << " : " << ptr << pixel; + } + + for(int i=0; i<10 and i*10<bitmapWidth and i*10<bitmapHeight; ++i) { + TRgb color; + bitmap->GetPixel(color, TPoint(i*10, i*10)); + qDebug() << " " << i*10 << " : " << color.Red() << color.Green() << color.Blue() << color.Alpha(); + } +#endif + CWindowGc &gc = SystemGc(); if (qwidget->d_func()->isOpaque) gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); - gc.BitBlt(r.iTl, bitmap, r); + + if(!qwidget->d_func()->extraData()->disableBlit) + gc.BitBlt(r.iTl, bitmap, r); } else { surface->flush(qwidget, QRegion(qt_TRect2QRect(r)), QPoint()); } } void QSymbianControl::SizeChanged() -{ +{ CCoeControl::SizeChanged(); QSize oldSize = qwidget->size(); QSize newSize(Size().iWidth, Size().iHeight); +#ifdef DEBUG_QSYMBIANCONTROL + qDebug() << "QSymbianControl::SizeChanged [" << this << "]" + << oldSize.width() << 'x' << oldSize.height() + << "-" << newSize.width() << 'x' << newSize.height(); +#endif + if (oldSize != newSize) { QRect cr = qwidget->geometry(); cr.setSize(newSize); @@ -744,7 +813,13 @@ void QSymbianControl::PositionChanged() QPoint oldPos = qwidget->geometry().topLeft(); QPoint newPos(Position().iX, Position().iY); - + +#ifdef DEBUG_QSYMBIANCONTROL + qDebug() << "QSymbianControl::SizeChanged [" << this << "]" + << oldPos.x() << ',' << oldPos.y() + << "-" << newPos.x() << ',' << newPos.y(); +#endif + if (oldPos != newPos) { QRect cr = qwidget->geometry(); cr.moveTopLeft(newPos); @@ -1124,14 +1199,14 @@ QWidget * QApplication::topLevelAt(QPoint const& point) if (widget->geometry().adjusted(0,0,1,1).contains(point)) { // At this point we know there is a Qt widget under the point. // Now we need to make sure it is the top most in the z-order. - RDrawableWindow* rw = widget->d_func()->topData()->rwindow; - int z = rw->OrdinalPosition(); + RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow(); + int z = window->OrdinalPosition(); if (z < lowestZ) { lowestZ = z; found = widget; } } - } + } } return found; } diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index aa39f9d..a6ecc02 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -74,6 +74,8 @@ #include <eikspane.h> // CEikStatusPane #endif +#include <fbs.h> // for CFbsBitmap + QT_BEGIN_NAMESPACE // Application internal HandleResourceChangeL events, @@ -132,6 +134,8 @@ public: }; class QLongTapTimer; +class CFbsBitmap; + class QSymbianControl : public CCoeControl, public QAbstractLongTapObserver { public: @@ -167,7 +171,7 @@ private: TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); bool sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); - + private: QWidget *qwidget; bool m_ignoreFocusChanged; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 5a9c48c..fe7bacc 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -169,9 +169,6 @@ struct QTLWExtra { #ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif -#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN - uint activated : 1; // RWindowBase::Activated has been called - RDrawableWindow *rwindow; #endif }; @@ -224,6 +221,15 @@ struct QWExtra { QImage maskBits; CGImageRef imageMask; #endif +#elif defined(Q_OS_SYMBIAN) // <----------------------------------------------------- Symbian + uint activated : 1; // RWindowBase::Activated has been called + + // If set, QSymbianControl::Draw does not blit this widget + // This is to allow, for use cases such as video, widgets which, from the Qt point + // of view, are just placeholders in the scene. For these widgets, any necessary + // drawing to the UI framebuffer is done by the relevant Symbian subsystem. For + // video rendering, this would be an MMF controller, or MDF post-processor. + uint disableBlit : 1; #endif }; diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 4fef020..fad09a1 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -56,6 +56,10 @@ #include <aknappui.h> #endif +#ifdef DEBUG_QWIDGET +#include <QDebug> +#endif + QT_BEGIN_NAMESPACE extern bool qt_nograb(); @@ -78,14 +82,298 @@ static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b) return true; } -void QWidgetPrivate::setWSGeometry(bool /* dontShow */, const QRect & /* rect */) +<<<<<<< HEAD:src/gui/kernel/qwidget_s60.cpp + +void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) { +#ifdef Q_WS_S60 + Q_Q(QWidget); + if (QApplication::focusWidget() && q!=QApplication::focusWidget()) { + QList<QAction *> old = QApplication::focusWidget()->softKeys(); + if (isEqual(old, softkeys )) + return; + } + CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + QT_TRAP_THROWING(nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS)); + + int position = -1; + int command; + bool needsExitButton = true; + + for (int index = 0; index < softkeys.count(); index++) { + const QAction* softKeyAction = softkeys.at(index); + switch (softKeyAction->softKeyRole()) { + // Positive Actions go on LSK + case QAction::OptionsSoftKey: + case QAction::MenuSoftKey: + case QAction::ContextMenuSoftKey: + command = EAknSoftkeyOptions; //Calls DynInitMenuPane in AppUI + position = 0; + break; + case QAction::SelectSoftKey: + case QAction::PreviousSoftKey: + case QAction::OkSoftKey: + case QAction::EditSoftKey: + case QAction::ViewSoftKey: + case QAction::EndEditSoftKey: + case QAction::FinishSoftKey: + command = SOFTKEYSTART + index; + position = 0; + break; + // Negative Actions on the RSK + case QAction::BackSoftKey: + case QAction::NextSoftKey: + case QAction::CancelSoftKey: + case QAction::BackSpaceSoftKey: + case QAction::RevertEditSoftKey: + case QAction::DeselectSoftKey: + needsExitButton = false; + command = SOFTKEYSTART + index; + position = 2; + break; + case QAction::ExitSoftKey: + needsExitButton = false; + command = EAknSoftkeyExit; //Calls HandleCommand in AppUI + position = 2; + break; + default: + break; + } + + if (position != -1) { + TPtrC text = qt_QString2TPtrC(softKeyAction->text()); + QT_TRAP_THROWING(nativeContainer->SetCommandL(position, command, text)); + } + } + + if (needsExitButton) + QT_TRAP_THROWING(nativeContainer->SetCommandL(2, EAknSoftkeyExit, qt_QString2TPtrC(QObject::tr("Exit")))); + + nativeContainer->DrawDeferred(); // 3.1 needs an extra invitation +#else + Q_UNUSED(softkeys) +#endif +} + +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) +{ + // Note: based on x11 implementation + + static const int XCOORD_MAX = 16383; + static const int WRECT_MAX = 16383; + + Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "]" + << "q" << q; +#endif + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + /* + There are up to four different coordinate systems here: + Qt coordinate system for this widget. + X coordinate system for this widget (relative to wrect). + Qt coordinate system for parent + X coordinate system for parent (relative to parent's wrect). + */ + + QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); + QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); + QRect wrect; + //xrect is the X geometry of my widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys) + QRect xrect = data.crect; + + const QWidget *const parent = q->parentWidget(); + QRect parentWRect = parent->data->wrect; + + if (parentWRect.isValid()) { + // parent is clipped, and we have to clip to the same limit as parent + if (!parentWRect.contains(xrect)) { + xrect &= parentWRect; + wrect = xrect; + //translate from parent's to my Qt coord sys + wrect.translate(-data.crect.topLeft()); + } + //translate from parent's Qt coords to parent's X coords + xrect.translate(-parentWRect.topLeft()); + + } else { + // parent is not clipped, we may or may not have to clip + + if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) { + // This is where the main optimization is: we are already + // clipped, and if our clip is still valid, we can just + // move our window, and do not need to move or clip + // children + + QRect vrect = xrect & parent->rect(); + vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords + if (data.wrect.contains(vrect)) { + xrect = data.wrect; + xrect.translate(data.crect.topLeft()); + if (data.winid) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (1)" + << "control" << data.winid + << "SetExtent" << xrect.x() << ',' << xrect.y() + << xrect.width() << 'x' << xrect.height(); +#endif + + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + data.winid->DrawNow(); + } + return; + } + } + + if (!validRange.contains(xrect)) { + // we are too big, and must clip + xrect &=wrectRange; + wrect = xrect; + wrect.translate(-data.crect.topLeft()); + //parent's X coord system is equal to parent's Qt coord + //sys, so we don't need to map xrect. + } + + } + + // unmap if we are outside the valid window system coord system + bool outsideRange = !xrect.isValid(); + bool mapWindow = false; + if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) { + q->setAttribute(Qt::WA_OutsideWSRange, outsideRange); + if (outsideRange) { + if (data.winid) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (2)" + << "control" << data.winid + << "SetVisible(EFalse)"; +#endif + + data.winid->DrawableWindow()->SetVisible(EFalse); + } + q->setAttribute(Qt::WA_Mapped, false); + } else if (!q->isHidden()) { + mapWindow = true; + } + } + + if (outsideRange) + return; + + bool jump = (data.wrect != wrect); + data.wrect = wrect; + + + // and now recursively for all children... + // ### can be optimized + for (int i = 0; i < children.size(); ++i) { + QObject *object = children.at(i); + if (object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (3)" + << "control" << data.winid + << "child" << w->d_func(); +#endif + + w->d_func()->setWSGeometry(jump); + } + } + } + + if (data.winid) { + // move ourselves to the new position and map (if necessary) after + // the movement. Rationale: moving unmapped windows is much faster + // than moving mapped windows + if (!parent->internalWinId()) + xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0))); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (4)" + << "control" << data.winid + << "SetExtent" << xrect.x() << ',' << xrect.y() + << xrect.width() << 'x' << xrect.height(); +#endif + + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + if(!jump) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (5)" + << "control" << data.winid + << "DrawNow"; +#endif + + data.winid->DrawNow(); + } + } + + //to avoid flicker, we have to show children after the helper widget has moved + if (jump) { + for (int i = 0; i < children.size(); ++i) { + QObject *object = children.at(i); + if (object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + if (!w->testAttribute(Qt::WA_OutsideWSRange) && !w->testAttribute(Qt::WA_Mapped) && !w->isHidden()) { + w->setAttribute(Qt::WA_Mapped); + if (w->internalWinId()) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (6)" + << "control" << data.winid + << "SetVisible(ETrue)"; +#endif + + w->data->winid->DrawableWindow()->SetVisible(ETrue); + } + } + } + } + } + if (jump && data.winid) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (7)" + << "control" << data.winid + << "DrawNow" << wrect.width() << 'x' << wrect.height(); +#endif + + data.winid->DrawNow(TRect(0, 0, wrect.width(), wrect.height())); + } + + if (mapWindow and !dontShow) { + q->setAttribute(Qt::WA_Mapped); + if (q->internalWinId()) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setWSGeometry [" << this << "] (8)" + << "control" << data.winid + << "SetVisible(ETrue)"; +#endif + + q->internalWinId()->DrawableWindow()->SetVisible(ETrue); + } + } } void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setGeometry_sys [" << this << "]" + << "q" << q + << x << ',' << y << w << 'x' << h << isMove; +#endif + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if ((q->windowType() == Qt::Desktop)) @@ -119,13 +407,25 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) if (q->isWindow()) { if (w == 0 || h == 0) { q->setAttribute(Qt::WA_OutsideWSRange, true); - if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) + if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setGeometry_sys [" << this << "] (1)" + << "hide"; +#endif + hide_sys(); + } data.crect = QRect(x, y, w, h); data.window_state &= ~Qt::WindowFullScreen; } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) { q->setAttribute(Qt::WA_OutsideWSRange, false); +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setGeometry_sys [" << this << "] (2)" + << "SetRect, show"; +#endif + // put the window in its place and show it q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); data.crect.setRect(x, y, w, h); @@ -134,6 +434,12 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) } else { QRect r = QRect(x, y, w, h); data.crect = r; + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setGeometry_sys [" << this << "] (3)" + << "SetRect"; +#endif + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); topData()->normalGeometry = data.crect; } @@ -156,8 +462,15 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) if (inTopLevelResize) tlwExtra->inTopLevelResize = true; } - if (q->testAttribute(Qt::WA_WState_Created)) - setWSGeometry(); + if (q->testAttribute(Qt::WA_WState_Created)) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setGeometry_sys [" << this << "] (4)" + << "setWSGeometry"; +#endif + + setWSGeometry(); + } } if (q->isVisible()) { @@ -202,6 +515,19 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de bool desktop = (type == Qt::Desktop); //bool tool = (type == Qt::Tool || type == Qt::Drawer); +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::create_sys [" << this << "] " + << "q" << q; + qDebug() << "QWidgetPrivate::create_sys [" << this << "] " + << "type" << type + << "flags" << flags + << "parent" << parentWidget + << "topLevel" << topLevel + << "popup" << popup + << "dialog" << dialog + << "desktop" << desktop; +#endif + WId id = 0; if (popup) @@ -252,19 +578,18 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); - - QTLWExtra *topExtra = topData(); - topExtra->rwindow = control->DrawableWindow(); + + RDrawableWindow *const drawableWindow = control->DrawableWindow(); // Request mouse move events. - topExtra->rwindow->PointerFilter(EPointerFilterEnterExit + drawableWindow->PointerFilter(EPointerFilterEnterExit | EPointerFilterMove | EPointerFilterDrag, 0); - topExtra->rwindow->EnableVisibilityChangeEvents(); + drawableWindow->EnableVisibilityChangeEvents(); if (!isOpaque) { - RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); - TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); - if (rwindow->SetTransparencyAlphaChannel() == KErrNone) - rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + RWindow *const window = static_cast<RWindow *>(drawableWindow); + const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA)); + if (window->SetTransparencyAlphaChannel() == KErrNone) + window->SetBackgroundColor(TRgb(255, 255, 255, 0)); } } @@ -285,10 +610,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); - - WId parentw = parentWidget->effectiveWinId(); - QT_TRAP_THROWING(control->SetContainerWindowL(*parentw)); - + q->setAttribute(Qt::WA_WState_Created); int x, y, w, h; data.crect.getRect(&x, &y, &w, &h); @@ -305,6 +627,11 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de void QWidgetPrivate::show_sys() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::show_sys [" << this << "] " + << "q" << q; +#endif if (q->testAttribute(Qt::WA_OutsideWSRange)) return; @@ -318,20 +645,31 @@ void QWidgetPrivate::show_sys() return; } - if (q->isWindow() && q->internalWinId()) { - + if (q->internalWinId()) { + WId id = q->internalWinId(); - if (!extra->topextra->activated) { + if (!extra->activated) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::show_sys [" << this << "]" + << "id" << id + << "isWindow" << q->isWindow() + << "ActivateL"; +#endif + QT_TRAP_THROWING(id->ActivateL()); - extra->topextra->activated = 1; + extra->activated = 1; } id->MakeVisible(true); - id->SetFocus(true); + + if(q->isWindow()) + id->SetFocus(true); // Force setting of the icon after window is made visible, // this is needed even WA_SetWindowIcon is not set, as in that case we need // to reset to the application level window icon - setWindowIcon_sys(true); + if(q->isWindow()) + setWindowIcon_sys(true); } invalidateBuffer(q->rect()); @@ -340,11 +678,25 @@ void QWidgetPrivate::show_sys() void QWidgetPrivate::hide_sys() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::hide_sys [" << this << "]" + << "q" << q; +#endif + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); deactivateWidgetCleanup(); WId id = q->internalWinId(); - if (q->isWindow() && id) { - if (id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + + if (id) { + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::show_sys [" << this << "]" + << "id" << id + << "MakeVisible(false)"; +#endif + + if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() id->SetFocus(false); id->MakeVisible(false); if (QWidgetBackingStore *bs = maybeBackingStore()) @@ -368,6 +720,13 @@ void QWidgetPrivate::handleSymbianDeferredFocusChanged() { Q_Q(QWidget); WId control = q->internalWinId(); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::handleSymbianDeferredFocusChanged [" << this << "]" + << "q" << q + << "control" << control; +#endif + if (!control) { // This could happen if the widget was reparented, while the focuschange // was in the event queue. @@ -395,22 +754,31 @@ void QWidgetPrivate::handleSymbianDeferredFocusChanged() void QWidgetPrivate::raise_sys() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::raise_sys [" << this << "]" + << "q" << q; +#endif + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - QTLWExtra *tlwExtra = maybeTopData(); - if (q->internalWinId() && tlwExtra) { - tlwExtra->rwindow->SetOrdinalPosition(0); - } + if (q->internalWinId()) + q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0); } void QWidgetPrivate::lower_sys() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::lower_sys [" << this << "]" + << "q" << q; +#endif + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - QTLWExtra *tlwExtra = maybeTopData(); - if (q->internalWinId() && tlwExtra) { - tlwExtra->rwindow->SetOrdinalPosition(-1); - } - if (!q->isWindow()) + if (q->internalWinId()) + q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1); + + if(!q->isWindow()) invalidateBuffer(q->rect()); } @@ -423,17 +791,26 @@ void QWidgetPrivate::stackUnder_sys(QWidget* w) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - QTLWExtra *tlwExtra = maybeTopData(); - QTLWExtra *tlwExtraSibling = w->d_func()->maybeTopData(); - if (q->internalWinId() && tlwExtra && w->internalWinId() && tlwExtraSibling) - tlwExtra->rwindow->SetOrdinalPosition(tlwExtraSibling->rwindow->OrdinalPosition() + 1); - if (!q->isWindow() || !w->internalWinId()) + + if (q->internalWinId() && w->internalWinId()) { + RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow(); + RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow(); + thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1); + } + + if(!q->isWindow() || !w->internalWinId()) invalidateBuffer(q->rect()); } void QWidgetPrivate::reparentChildren() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::reparentChildren [" << this << "]" + << "q" << q; +#endif + QObjectList chlist = q->children(); for (int i = 0; i < chlist.size(); ++i) { // reparent children QObject *obj = chlist.at(i); @@ -464,6 +841,14 @@ void QWidgetPrivate::reparentChildren() void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::setParent_sys [" << this << "]" + << "q" << q + << "parent" << parent + << "f" << f; +#endif + bool wasCreated = q->testAttribute(Qt::WA_WState_Created); if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) @@ -526,6 +911,11 @@ void QWidgetPrivate::setConstraints_sys() void QWidgetPrivate::s60UpdateIsOpaque() { Q_Q(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidgetPrivate::s60UpdateIsOpaque [" << this << "]" + << "q" << q; +#endif if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground)) return; @@ -533,17 +923,14 @@ void QWidgetPrivate::s60UpdateIsOpaque() if ((data.window_flags & Qt::FramelessWindowHint) == 0) return; + RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow()); + if (!isOpaque) { - QTLWExtra *topExtra = topData(); - RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); - TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); - if (rwindow->SetTransparencyAlphaChannel() == KErrNone) - rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); - } else { - QTLWExtra *topExtra = topData(); - RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); - rwindow->SetTransparentRegion(TRegionFix<1>()); - } + const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA)); + if (window->SetTransparencyAlphaChannel() == KErrNone) + window->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } else + window->SetTransparentRegion(TRegionFix<1>()); } CFbsBitmap* qt_pixmapToNativeBitmap(QPixmap pixmap, bool invert) @@ -719,8 +1106,8 @@ void QWidgetPrivate::scroll_sys(int dx, int dy) scrollRect(q->rect(), dx, dy); } else { Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - RDrawableWindow* rw = topData()->rwindow; - rw->Scroll(TPoint(dx, dy)); + RDrawableWindow *const window = q->internalWinId()->DrawableWindow(); + window->Scroll(TPoint(dx, dy)); } } @@ -732,8 +1119,8 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) scrollRect(r, dx, dy); } else { Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - RDrawableWindow* rw = topData()->rwindow; - rw->Scroll(TPoint(dx, dy), qt_QRect2TRect(r)); + RDrawableWindow *const window = q->internalWinId()->DrawableWindow(); + window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r)); } } @@ -765,8 +1152,6 @@ void QWidgetPrivate::registerDropSite(bool /* on */) void QWidgetPrivate::createTLSysExtra() { extra->topextra->backingStore = 0; - extra->topextra->activated = 0; - extra->topextra->rwindow = 0; } void QWidgetPrivate::deleteTLSysExtra() @@ -777,7 +1162,8 @@ void QWidgetPrivate::deleteTLSysExtra() void QWidgetPrivate::createSysExtra() { - + extra->activated = 0; + extra->disableBlit = 0; } void QWidgetPrivate::deleteSysExtra() @@ -912,6 +1298,12 @@ QPoint QWidget::mapFromGlobal(const QPoint &pos) const void QWidget::setWindowState(Qt::WindowStates newstate) { Q_D(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidget::setWindowState [" << this << "]" + << "newstate" << newstate; +#endif + Qt::WindowStates oldstate = windowState(); if (oldstate == newstate) return; @@ -1159,6 +1551,11 @@ void QWidget::releaseMouse() void QWidget::activateWindow() { Q_D(QWidget); + +#ifdef DEBUG_QWIDGET + qDebug() << "QWidget::activateWindow [" << this << "]"; +#endif + QWidget *tlw = window(); if (tlw->isVisible()) { window()->createWinId(); diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro new file mode 100644 index 0000000..ff27ea1 --- /dev/null +++ b/src/plugins/phonon/mmf/mmf.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = mmfphonondebug plugin + +plugin.depends = mmfphonondebug diff --git a/src/plugins/phonon/mmf/mmfphonondebug/mmfphonondebug.pro b/src/plugins/phonon/mmf/mmfphonondebug/mmfphonondebug.pro new file mode 100644 index 0000000..2cfec15 --- /dev/null +++ b/src/plugins/phonon/mmf/mmfphonondebug/mmfphonondebug.pro @@ -0,0 +1,31 @@ +TEMPLATE = lib +TARGET = phonon_mmf_debug +OBJECTDUMP_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/mmf/mmfphonondebug + +CONFIG += staticlib + +DEFINES += OBJECTDUMP_LIBRARY + +HEADERS += \ + $$OBJECTDUMP_DIR/objectdump_global.h \ + $$OBJECTDUMP_DIR/objectdump.h \ + $$OBJECTDUMP_DIR/objecttree.h + +SOURCES += \ + $$OBJECTDUMP_DIR/objectdump.cpp \ + $$OBJECTDUMP_DIR/objecttree.cpp + +symbian { + HEADERS += $$OBJECTDUMP_DIR/objectdump_symbian.h + SOURCES += $$OBJECTDUMP_DIR/objectdump_symbian.cpp + + LIBS += -lcone + LIBS += -lws32 + + TARGET.CAPABILITY = all -tcb + +} else { + SOURCES += $$OBJECTDUMP_DIR/objectdump_stub.cpp +} + +TARGET.UID3=0x2001E62A diff --git a/src/plugins/phonon/mmf/plugin/plugin.pro b/src/plugins/phonon/mmf/plugin/plugin.pro new file mode 100644 index 0000000..de108a6 --- /dev/null +++ b/src/plugins/phonon/mmf/plugin/plugin.pro @@ -0,0 +1,95 @@ +# MMF Phonon backend + +QT += phonon +TARGET = phonon_mmf +PHONON_MMF_DIR = $$QT_SOURCE_TREE/src/3rdparty/phonon/mmf + +# Uncomment the following line in order to use the CDrmPlayerUtility client +# API for audio playback, rather than CMdaAudioPlayerUtility. +#CONFIG += phonon_mmf_audio_drm + +phonon_mmf_audio_drm { + LIBS += -lDrmAudioPlayUtility + + DEFINES += QT_PHONON_MMF_AUDIO_DRM +} else { + LIBS += -lmediaclientaudio +} + +# In the internal 5th SDK, DrmAudioSamplePlayer.h is placed in this folder, as +# opposed to the public, where it is placed in epoc32/include. In some cases +# it's needed for other headers as well. +INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE + +HEADERS += \ + $$PHONON_MMF_DIR/abstractaudioeffect.h \ + $$PHONON_MMF_DIR/abstractmediaplayer.h \ + $$PHONON_MMF_DIR/abstractplayer.h \ + $$PHONON_MMF_DIR/audiooutput.h \ + $$PHONON_MMF_DIR/audioequalizer.h \ + $$PHONON_MMF_DIR/audioplayer.h \ + $$PHONON_MMF_DIR/backend.h \ + $$PHONON_MMF_DIR/bassboost.h \ + $$PHONON_MMF_DIR/defs.h \ + $$PHONON_MMF_DIR/dummyplayer.h \ + $$PHONON_MMF_DIR/effectfactory.h \ + $$PHONON_MMF_DIR/mmf_medianode.h \ + $$PHONON_MMF_DIR/mediaobject.h \ + $$PHONON_MMF_DIR/utils.h \ + $$PHONON_MMF_DIR/videooutput.h \ + $$PHONON_MMF_DIR/videooutputobserver.h \ + $$PHONON_MMF_DIR/mmf_videoplayer.h \ + $$PHONON_MMF_DIR/videowidget.h \ + $$PHONON_MMF_DIR/volumeobserver.h + +SOURCES += \ + $$PHONON_MMF_DIR/abstractaudioeffect.cpp \ + $$PHONON_MMF_DIR/abstractmediaplayer.cpp \ + $$PHONON_MMF_DIR/abstractplayer.cpp \ + $$PHONON_MMF_DIR/audiooutput.cpp \ + $$PHONON_MMF_DIR/audioequalizer.cpp \ + $$PHONON_MMF_DIR/audioplayer.cpp \ + $$PHONON_MMF_DIR/backend.cpp \ + $$PHONON_MMF_DIR/bassboost.cpp \ + $$PHONON_MMF_DIR/dummyplayer.cpp \ + $$PHONON_MMF_DIR/effectfactory.cpp \ + $$PHONON_MMF_DIR/mmf_medianode.cpp \ + $$PHONON_MMF_DIR/mediaobject.cpp \ + $$PHONON_MMF_DIR/utils.cpp \ + $$PHONON_MMF_DIR/videooutput.cpp \ + $$PHONON_MMF_DIR/mmf_videoplayer.cpp \ + $$PHONON_MMF_DIR/videowidget.cpp + +debug { + INCLUDEPATH += $$PHONON_MMF_DIR/mmfphonondebug + LIBS += -lphonon_mmf_debug.lib + LIBS += -lhal +} + +LIBS += -lmediaclientvideo # For CVideoPlayerUtility +LIBS += -lcone # For CCoeEnv +LIBS += -lws32 # For RWindow +LIBS += -lefsrv # For file server +LIBS += -lapgrfx -lapmime # For recognizer + +# *** Temporary hack, necessitated by +# inline QSymbianControl::setTransparentBlit +LIBS += -lfbscli + +# These are for effects. +LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerBase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect + +# This is needed for having the .qtplugin file properly created on Symbian. +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend + +target.path = $$[QT_INSTALL_PLUGINS]/phonon_backend +INSTALLS += target + +include(../../../qpluginbase.pri) + +# We need this to be able to resolve ambiguity for VideoPlayer.h. Phonon and +# the SDK has the header. +INCLUDEPATH *= /epoc32 + +TARGET.UID3=0x2001E629 + diff --git a/src/plugins/phonon/phonon.pro b/src/plugins/phonon/phonon.pro index e43a4c2..814a062 100644 --- a/src/plugins/phonon/phonon.pro +++ b/src/plugins/phonon/phonon.pro @@ -7,3 +7,4 @@ mac:contains(QT_CONFIG, phonon-backend): SUBDIRS *= qt7 win32:!wince*:contains(QT_CONFIG, phonon-backend): SUBDIRS *= ds9 wince*:contains(QT_CONFIG, phonon-backend): SUBDIRS *= waveout wince*:contains(QT_CONFIG, directshow): SUBDIRS *= ds9 +symbian:contains(QT_CONFIG, phonon-backend): SUBDIRS *= mmf diff --git a/src/s60installs/qt.iby b/src/s60installs/qt.iby index dc9ec43..3a7f008 100644 --- a/src/s60installs/qt.iby +++ b/src/s60installs/qt.iby @@ -71,6 +71,9 @@ file=ABI_DIR\BUILD_DIR\qtwcodecs.dll SHARED_LIB_DIR\qtwcodecs.dll PAG // iconengines file=ABI_DIR\BUILD_DIR\qsvgicon.dll SHARED_LIB_DIR\qsvgicon.dll PAGED +// Phonon MMF backend +file=ABI_DIR\BUILD_DIR\phonon_mmf.dll SHARED_LIB_DIR\phonon_mmf.dll PAGED + // graphicssystems file=ABI_DIR\BUILD_DIR\qvggraphicssystem.dll SHARED_LIB_DIR\qvggraphicssystem.dll PAGED @@ -93,6 +96,9 @@ data=\epoc32\winscw\c\resource\qt\plugins\codecs\qtwcodecs.qtplugin res // iconengines stubs data=\epoc32\winscw\c\resource\qt\plugins\iconengines\qsvgicon.qtplugin resource\qt\plugins\iconengines\qsvgicon.qtplugin +// Phonon MMF backend +data=\epoc32\winscw\c\resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin + // graphicssystems data=\epoc32\winscw\c\resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin diff --git a/src/s60installs/qt_libs.pro b/src/s60installs/qt_libs.pro new file mode 100644 index 0000000..51354ee --- /dev/null +++ b/src/s60installs/qt_libs.pro @@ -0,0 +1,99 @@ +# Use subdirs template to suppress generation of unnecessary files +TEMPLATE = subdirs + +symbian: { + load(data_caging_paths) + + SUBDIRS= + TARGET = "QtLibs pre-release" + TARGET.UID3 = 0x2001E61C + VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} + + qtresources.sources = $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/s60main.rsc + qtresources.path = $$APP_RESOURCE_DIR + + qtlibraries.sources = \ + QtCore.dll \ + QtXml.dll \ + QtGui.dll \ + QtNetwork.dll \ + QtScript.dll \ + QtTest.dll \ + QtSql.dll \ + qts60plugin_3_1.dll \ + qts60plugin_3_2.dll \ + qts60plugin_5_0.dll + + + # TODO: This should be conditional in PKG file, see commented code below + # However we don't yet have such mechanism in place + contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { + contains(CONFIG, system-sqlite): qtlibraries.sources += sqlite3.dll + } + + #; EXISTS statement does not resolve !. Lets check the most common drives + #IF NOT EXISTS("c:\sys\bin\sqlite3.dll") AND NOT EXISTS("e:\sys\bin\sqlite3.dll") AND NOT EXISTS("z:\sys\bin\sqlite3.dll") + #"\Epoc32\release\armv5\UREL\sqlite3.dll"-"!:\sys\bin\sqlite3.dll" + #ENDIF + + qtlibraries.path = /sys/bin + + vendorinfo = \ + "; Localised Vendor name" \ + "%{\"Nokia, Qt Software\"}" \ + " " \ + "; Unique Vendor name" \ + ":\"Nokia, Qt Software\"" \ + " " + + + qtlibraries.pkg_prerules = vendorinfo + qtlibraries.pkg_prerules += "; Dependencies of Qt libraries" + qtlibraries.pkg_prerules += "(0x20013851), 1, 5, 1, {\"PIPS Installer\"}" + contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { + qtlibraries.pkg_prerules += "(0x200110CB), 1, 5, 1, {\"Open C LIBSSL Common\"}" + } + contains(CONFIG, stl) { + qtlibraries.pkg_prerules += "(0x2000F866), 1, 0, 0, {\"Standard C++ Library Common\"}" + } + + !contains(QT_CONFIG, no-jpeg): imageformats_plugins.sources += qjpeg.dll + !contains(QT_CONFIG, no-gif): imageformats_plugins.sources += qgif.dll + !contains(QT_CONFIG, no-mng): imageformats_plugins.sources += qmng.dll + !contains(QT_CONFIG, no-tiff): imageformats_plugins.sources += qtiff.dll + !contains(QT_CONFIG, no-ico): imageformats_plugins.sources += qico.dll + imageformats_plugins.path = $$QT_PLUGINS_BASE_DIR/imageformats + + codecs_plugins.sources = qcncodecs.dll qjpcodecs.dll qtwcodecs.dll qkrcodecs.dll + codecs_plugins.path = $$QT_PLUGINS_BASE_DIR/codecs + + contains(QT_CONFIG, phonon-backend) { + phonon_backend_plugins.sources += phonon_mmf.dll + + phonon_backend_plugins.path = $$QT_PLUGINS_BASE_DIR/phonon_backend + DEPLOYMENT += phonon_backend_plugins + } + + DEPLOYMENT += qtresources qtlibraries imageformats_plugins codecs_plugins graphicssystems_plugins + + contains(QT_CONFIG, svg): { + qtlibraries.sources += QtSvg.dll + imageformats_plugins.sources += qsvg.dll + iconengines_plugins.sources = qsvgicon.dll + iconengines_plugins.path = $$QT_PLUGINS_BASE_DIR/iconengines + DEPLOYMENT += iconengines_plugins + } + + contains(QT_CONFIG, phonon): { + qtlibraries.sources += Phonon.dll + } + + graphicssystems_plugins.path = $$QT_PLUGINS_BASE_DIR/graphicssystems + contains(QT_CONFIG, openvg) { + qtlibraries.sources = QtOpenVG.dll + graphicssystems_plugins.sources += qvggraphicssystem.dll + } + + BLD_INF_RULES.prj_exports += "qt.iby $$CORE_MW_LAYER_IBY_EXPORT_PATH(qt.iby)" + BLD_INF_RULES.prj_exports += "qtdemoapps.iby $$CORE_APP_LAYER_IBY_EXPORT_PATH(qtdemoapps.iby)" +} |