summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/qmediaplayer/mediaplayer.cpp16
-rw-r--r--demos/qmediaplayer/mediaplayer.h1
-rw-r--r--dist/README4
-rw-r--r--doc/src/platforms/symbian-introduction.qdoc28
-rw-r--r--examples/webkit/domtraversal/domtraversal.pro5
-rw-r--r--examples/webkit/fancybrowser/fancybrowser.pro5
-rw-r--r--examples/webkit/googlechat/googlechat.pro5
-rw-r--r--examples/webkit/simpleselector/simpleselector.pro5
-rw-r--r--qmake/generators/symbian/symmake.cpp7
-rw-r--r--src/3rdparty/phonon/mmf/abstractaudioeffect.cpp53
-rw-r--r--src/3rdparty/phonon/mmf/abstractaudioeffect.h26
-rw-r--r--src/3rdparty/phonon/mmf/abstractmediaplayer.cpp226
-rw-r--r--src/3rdparty/phonon/mmf/abstractmediaplayer.h41
-rw-r--r--src/3rdparty/phonon/mmf/abstractplayer.cpp34
-rw-r--r--src/3rdparty/phonon/mmf/abstractplayer.h32
-rw-r--r--src/3rdparty/phonon/mmf/audioequalizer.cpp32
-rw-r--r--src/3rdparty/phonon/mmf/audioequalizer.h12
-rw-r--r--src/3rdparty/phonon/mmf/audiooutput.cpp13
-rw-r--r--src/3rdparty/phonon/mmf/audiooutput.h4
-rw-r--r--src/3rdparty/phonon/mmf/audioplayer.cpp99
-rw-r--r--src/3rdparty/phonon/mmf/audioplayer.h59
-rw-r--r--src/3rdparty/phonon/mmf/backend.cpp29
-rw-r--r--src/3rdparty/phonon/mmf/bassboost.cpp15
-rw-r--r--src/3rdparty/phonon/mmf/bassboost.h11
-rw-r--r--src/3rdparty/phonon/mmf/dummyplayer.cpp19
-rw-r--r--src/3rdparty/phonon/mmf/dummyplayer.h8
-rw-r--r--src/3rdparty/phonon/mmf/effectfactory.cpp2
-rw-r--r--src/3rdparty/phonon/mmf/mediaobject.cpp91
-rw-r--r--src/3rdparty/phonon/mmf/mediaobject.h17
-rw-r--r--src/3rdparty/phonon/mmf/mmf_medianode.cpp153
-rw-r--r--src/3rdparty/phonon/mmf/mmf_medianode.h76
-rw-r--r--src/3rdparty/phonon/mmf/mmf_videoplayer.cpp104
-rw-r--r--src/3rdparty/phonon/mmf/mmf_videoplayer.h41
-rw-r--r--src/3rdparty/phonon/mmf/objectdump.cpp2
-rw-r--r--src/3rdparty/phonon/mmf/utils.cpp96
-rw-r--r--src/3rdparty/phonon/mmf/utils.h25
-rw-r--r--src/3rdparty/phonon/mmf/videowidget.cpp14
-rw-r--r--src/3rdparty/phonon/mmf/videowidget.h4
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc7
-rw-r--r--src/gui/dialogs/qdialog.cpp9
-rw-r--r--src/gui/kernel/qapplication_s60.cpp2
-rw-r--r--src/gui/kernel/qsoftkeymanager.cpp3
-rw-r--r--src/gui/painting/qpaintengine_s60.cpp13
-rw-r--r--src/gui/s60framework/qs60mainappui.cpp12
-rw-r--r--src/s60installs/s60installs.pro7
-rw-r--r--src/s60installs/sqlite3.sisbin0 -> 286192 bytes
-rw-r--r--tests/auto/qapplication/heart.svg55
-rw-r--r--tests/auto/qapplication/test/test.pro4
-rw-r--r--tests/auto/qapplication/tst_qapplication.cpp88
-rw-r--r--tools/runonphone/main.cpp4
-rw-r--r--tools/runonphone/runonphone.pro3
-rw-r--r--tools/runonphone/serenum_win.cpp11
53 files changed, 1087 insertions, 546 deletions
diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp
index 8f6848f..8471ebd 100644
--- a/demos/qmediaplayer/mediaplayer.cpp
+++ b/demos/qmediaplayer/mediaplayer.cpp
@@ -673,6 +673,13 @@ void MediaPlayer::setFile(const QString &fileName)
m_MediaObject.play();
}
+void MediaPlayer::setLocation(const QString& location)
+{
+ setWindowTitle(location.right(location.length() - location.lastIndexOf('/') - 1));
+ m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(location.toUtf8())));
+ m_MediaObject.play();
+}
+
bool MediaPlayer::playPauseForDialog()
{
// If we're running on a small screen, we want to pause the video when
@@ -850,9 +857,7 @@ void MediaPlayer::openUrl()
bool ok = false;
sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok);
if (ok && !sourceURL.isEmpty()) {
- setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1));
- m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8())));
- m_MediaObject.play();
+ setLocation(sourceURL);
settings.setValue("location", sourceURL);
}
}
@@ -892,10 +897,11 @@ void MediaPlayer::openRamFile()
}
if (!list.isEmpty()) {
- m_MediaObject.setCurrentSource(Phonon::MediaSource(list[0]));
- m_MediaObject.play();
+ m_MediaObject.clearQueue();
+ setLocation(list[0].toString());
for (int i = 1; i < list.count(); i++)
m_MediaObject.enqueue(Phonon::MediaSource(list[i]));
+ m_MediaObject.play();
}
forwardButton->setEnabled(!m_MediaObject.queue().isEmpty());
diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h
index 14ed4ac..fc1bd90 100644
--- a/demos/qmediaplayer/mediaplayer.h
+++ b/demos/qmediaplayer/mediaplayer.h
@@ -112,6 +112,7 @@ public:
void dropEvent(QDropEvent *e);
void handleDrop(QDropEvent *e);
void setFile(const QString &text);
+ void setLocation(const QString &location);
void initVideoWindow();
void initSettingsDialog();
diff --git a/dist/README b/dist/README
index e7dfb19..73c8be1 100644
--- a/dist/README
+++ b/dist/README
@@ -26,6 +26,10 @@ For Mac OS X Cocoa, the binary package requires Mac OS X 10.5 (Leopard) or
later and GCC 4.0.1 to develop applications. Its applications will run
on Mac OS X 10.5 and above.
+If you want to install the precompiled binary package for Symbian,
+follow these instructions:
+http://qt.nokia.com/doc/%SHORTVERSION%/install-symbian-installer.html
+
DEMOS AND EXAMPLES
diff --git a/doc/src/platforms/symbian-introduction.qdoc b/doc/src/platforms/symbian-introduction.qdoc
index 477e629..4d06bbc 100644
--- a/doc/src/platforms/symbian-introduction.qdoc
+++ b/doc/src/platforms/symbian-introduction.qdoc
@@ -124,12 +124,8 @@
\row \o \c release-gcce \o Build release binaries for hardware using GCCE.
\row \o \c debug-armv5 \o Build debug binaries for hardware using RVCT.
\row \o \c release-armv5 \o Build release binaries for hardware using RVCT.
- \row \o \c run \o Run the application. Environment variable
- \c QT_SIS_TARGET (see below) can be used to specify which
- build target is run. By default it is the last build target.
- Note that running the application on real device
- using this command requires \c TRK application to be running
- on the device.
+ \row \o \c run \o Run the application on the emulator.
+ \row \o \c runonphone \o Run the application on a device.
\row \o \c sis \o Create signed \c .sis file for project.
\endtable
@@ -199,4 +195,24 @@
with the \c QT_SIS_OPTIONS=-i, like this:
\snippet doc/src/snippets/code/doc_src_symbian-introduction.qdoc 5
+
+ \section1 Running applications from command line
+
+ The application can be launched on the emulator using \c{make run} command.
+
+ The application can be launched on a device using \c{make runonphone} command.
+ When this command is invoked, a \c .sis file is first created as if \c{make sis}
+ command was invoked (see above for details).
+ \bold{Note:} Running the application on a device using this command requires
+ \c TRK application to be running on the device.
+
+ Additional environment variables that can be utilized with these commands are:
+ \table
+ \row \o \c QT_RUN_OPTIONS \o Any command line parameters you wish to pass
+ to your application.
+ \row \o \c QT_RUN_ON_PHONE_OPTIONS \o Options for runonphone application.
+ Execute \c runonphone from command line for
+ more information about available options.
+ \c{make runonphone} only.
+ \endtable
*/
diff --git a/examples/webkit/domtraversal/domtraversal.pro b/examples/webkit/domtraversal/domtraversal.pro
index 49400de..ba5f2d8 100644
--- a/examples/webkit/domtraversal/domtraversal.pro
+++ b/examples/webkit/domtraversal/domtraversal.pro
@@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal
sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/domtraversal
INSTALLS += target sources
+
+symbian {
+ TARGET.UID3 = 0xA000D7CB
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/examples/webkit/fancybrowser/fancybrowser.pro b/examples/webkit/fancybrowser/fancybrowser.pro
index e496241..3786d9c 100644
--- a/examples/webkit/fancybrowser/fancybrowser.pro
+++ b/examples/webkit/fancybrowser/fancybrowser.pro
@@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/fancybrowser
INSTALLS += target sources
-symbian:TARGET.UID3 = 0xA000CF6C
+symbian {
+ TARGET.UID3 = 0xA000CF6C
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/examples/webkit/googlechat/googlechat.pro b/examples/webkit/googlechat/googlechat.pro
index 8e4f9a6..3d32c1b 100644
--- a/examples/webkit/googlechat/googlechat.pro
+++ b/examples/webkit/googlechat/googlechat.pro
@@ -10,4 +10,7 @@ sources.files = $$SOURCES $$HEADERS $$FORMS *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/googlechat
INSTALLS += target sources
-symbian:TARGET.UID3 = 0xA000CF6E
+symbian {
+ TARGET.UID3 = 0xA000CF6E
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/examples/webkit/simpleselector/simpleselector.pro b/examples/webkit/simpleselector/simpleselector.pro
index 3f3037f..acd0ae7 100644
--- a/examples/webkit/simpleselector/simpleselector.pro
+++ b/examples/webkit/simpleselector/simpleselector.pro
@@ -9,3 +9,8 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector
sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/webkit/simpleselector
INSTALLS += target sources
+
+symbian {
+ TARGET.UID3 = 0xA000D7CC
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+}
diff --git a/qmake/generators/symbian/symmake.cpp b/qmake/generators/symbian/symmake.cpp
index b2709d1..81f2d15 100644
--- a/qmake/generators/symbian/symmake.cpp
+++ b/qmake/generators/symbian/symmake.cpp
@@ -1857,16 +1857,11 @@ void SymbianMakefileGenerator::generateExecutionTargets(QTextStream& t, const QS
// create execution targets
if (targetType == TypeExe) {
if (platforms.contains("winscw")) {
- t << "ifeq (\"DEBUG-winscw\", \"$(QT_SIS_TARGET)\")" << endl;
t << "run:" << endl;
t << "\t-call " << epocRoot() << "epoc32/release/winscw/udeb/" << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl;
- t << "else" << endl;
}
- t << "run: sis" << endl;
+ t << "runonphone: sis" << endl;
t << "\trunonphone $(QT_RUN_ON_PHONE_OPTIONS) --sis " << fixedTarget << "_$(QT_SIS_TARGET).sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl;
- if (platforms.contains("winscw")) {
- t << "endif" << endl;
- }
t << endl;
}
}
diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp
index a559249..e7ef9b2 100644
--- a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp
+++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp
@@ -19,6 +19,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "mediaobject.h"
#include "abstractaudioeffect.h"
+#include "audioplayer.h"
+#include "mmf_videoplayer.h"
QT_BEGIN_NAMESPACE
@@ -34,18 +36,13 @@ using namespace Phonon::MMF;
*/
AbstractAudioEffect::AbstractAudioEffect(QObject *parent,
- const QList<EffectParameter> &params) : MediaNode::MediaNode(parent)
- , m_params(params)
+ const QList<EffectParameter> &params)
+ : MediaNode::MediaNode(parent)
+ , m_player(0)
+ , m_params(params)
{
}
-bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target)
-{
- MediaNode::disconnectMediaNode(target);
- m_effect.reset();
- return true;
-}
-
QList<EffectParameter> AbstractAudioEffect::parameters() const
{
return m_params;
@@ -61,21 +58,39 @@ QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam
return val;
}
-bool AbstractAudioEffect::activateOnMediaObject(MediaObject *mo)
-{
- AudioPlayer *const ap = qobject_cast<AudioPlayer *>(mo->abstractPlayer());
-
- if (ap)
- return activateOn(ap->player());
- else
- return true;
-}
-
void AbstractAudioEffect::setParameterValue(const EffectParameter &param,
const QVariant &newValue)
{
m_values.insert(param.id(), newValue);
parameterChanged(param.id(), newValue);
+ // TODO: handle audio effect errors
+ TRAP_IGNORE(m_effect->ApplyL());
+}
+
+void AbstractAudioEffect::connectMediaObject(MediaObject *mediaObject)
+{
+ Q_ASSERT_X(!m_player, Q_FUNC_INFO, "Player already connected");
+ Q_ASSERT_X(!m_effect.data(), Q_FUNC_INFO, "Effect already created");
+
+ AbstractMediaPlayer *const player =
+ qobject_cast<AbstractMediaPlayer *>(mediaObject->abstractPlayer());
+
+ if (player) {
+ m_player = player;
+
+ if (AudioPlayer *audioPlayer = qobject_cast<AudioPlayer *>(player)) {
+ connectAudioPlayer(audioPlayer->nativePlayer());
+ applyParameters();
+ // TODO: handle audio effect errors
+ TRAP_IGNORE(m_effect->EnableL());
+ }
+ }
+}
+
+void AbstractAudioEffect::disconnectMediaObject(MediaObject * /*mediaObject*/)
+{
+ m_player = 0;
+ m_effect.reset();
}
QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h
index 01542c9..6f74a73 100644
--- a/src/3rdparty/phonon/mmf/abstractaudioeffect.h
+++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h
@@ -19,15 +19,16 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#ifndef PHONON_MMF_ABSTRACTEFFECT_H
#define PHONON_MMF_ABSTRACTEFFECT_H
-#include "mmf_medianode.h"
-
#include <QScopedPointer>
#include <AudioEffectBase.h>
#include <Phonon/EffectInterface>
#include <Phonon/EffectParameter>
+
#include "audioplayer.h"
+#include "mmf_medianode.h"
+#include "mmf_videoplayer.h"
QT_BEGIN_NAMESPACE
@@ -35,6 +36,7 @@ namespace Phonon
{
namespace MMF
{
+class AbstractMediaPlayer;
/**
* @short Base class for all effects for MMF.
@@ -66,8 +68,6 @@ public:
virtual void setParameterValue(const EffectParameter &,
const QVariant &newValue);
- virtual bool disconnectMediaNode(MediaNode *target);
-
enum Type
{
EffectAudioEqualizer = 1,
@@ -81,21 +81,25 @@ public:
};
protected:
- virtual bool activateOn(CPlayerType *player) = 0;
+ // MediaNode
+ void connectMediaObject(MediaObject *mediaObject);
+ void disconnectMediaObject(MediaObject *mediaObject);
+
+ virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player) = 0;
+ virtual void applyParameters() = 0;
+
virtual void parameterChanged(const int id,
const QVariant &value) = 0;
- /**
- * Part of the implementation of AbstractAudioEffect. Forwards the call to
- * activateOn(), essentially.
- */
- virtual bool activateOnMediaObject(MediaObject *mo);
-
+protected:
QScopedPointer<CAudioEffect> m_effect;
+
private:
+ AbstractMediaPlayer * m_player;
const QList<EffectParameter> m_params;
QHash<int, QVariant> m_values;
};
+
}
}
diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
index 99e96cd..544762a 100644
--- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
+++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
@@ -20,6 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "abstractmediaplayer.h"
#include "defs.h"
+#include "mediaobject.h"
#include "utils.h"
QT_BEGIN_NAMESPACE
@@ -36,27 +37,26 @@ using namespace Phonon::MMF;
//-----------------------------------------------------------------------------
const int NullMaxVolume = -1;
+const int BufferStatusTimerInterval = 100; // ms
//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::AbstractMediaPlayer::AbstractMediaPlayer() :
- m_playPending(false)
- , m_tickTimer(new QTimer(this))
- , m_mmfMaxVolume(NullMaxVolume)
-{
- connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
-}
-
-MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) :
- AbstractPlayer(player)
+MMF::AbstractMediaPlayer::AbstractMediaPlayer
+ (MediaObject *parent, const AbstractPlayer *player)
+ : AbstractPlayer(player)
+ , m_parent(parent)
, m_playPending(false)
- , m_tickTimer(new QTimer(this))
+ , m_positionTimer(new QTimer(this))
+ , m_bufferStatusTimer(new QTimer(this))
, m_mmfMaxVolume(NullMaxVolume)
+ , m_prefinishMarkSent(false)
+ , m_aboutToFinishSent(false)
{
- connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick()));
+ connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick()));
+ connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick()));
}
//-----------------------------------------------------------------------------
@@ -70,7 +70,7 @@ void MMF::AbstractMediaPlayer::play()
switch (privateState()) {
case GroundState:
- setError(NormalError);
+ setError(tr("Not ready to play"));
break;
case LoadingState:
@@ -80,7 +80,7 @@ void MMF::AbstractMediaPlayer::play()
case StoppedState:
case PausedState:
doPlay();
- startTickTimer();
+ startPositionTimer();
changeState(PlayingState);
break;
@@ -104,21 +104,22 @@ void MMF::AbstractMediaPlayer::pause()
TRACE_ENTRY("state %d", privateState());
m_playPending = false;
+ stopTimers();
switch (privateState()) {
case GroundState:
case LoadingState:
case PausedState:
+ case StoppedState:
// Do nothing
break;
- case StoppedState:
case PlayingState:
- case ErrorState:
case BufferingState:
- doPause();
- stopTickTimer();
changeState(PausedState);
+ // Fall through
+ case ErrorState:
+ doPause();
break;
// Protection against adding new states and forgetting to update this switch
@@ -135,6 +136,7 @@ void MMF::AbstractMediaPlayer::stop()
TRACE_ENTRY("state %d", privateState());
m_playPending = false;
+ stopTimers();
switch (privateState()) {
case GroundState:
@@ -148,7 +150,6 @@ void MMF::AbstractMediaPlayer::stop()
case BufferingState:
case PausedState:
doStop();
- stopTickTimer();
changeState(StoppedState);
break;
@@ -173,14 +174,21 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms)
case PlayingState:
case LoadingState:
{
- const bool tickTimerWasRunning = m_tickTimer->isActive();
- stopTickTimer();
+ bool wasPlaying = false;
+ if (state() == PlayingState) {
+ stopPositionTimer();
+ doPause();
+ wasPlaying = true;
+ }
doSeek(ms);
+ resetMarksIfRewound();
- if (tickTimerWasRunning) {
- startTickTimer();
+ if(wasPlaying && state() != ErrorState) {
+ doPlay();
+ startPositionTimer();
}
+
break;
}
case BufferingState:
@@ -203,17 +211,12 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);
- m_tickTimer->setInterval(interval);
+ m_positionTimer->setInterval(interval);
TRACE_EXIT_0();
}
-MediaSource MMF::AbstractMediaPlayer::source() const
-{
- return m_source;
-}
-
-void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file)
+void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file)
{
TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
TRACE_ENTRY("state %d source.type %d", privateState(), source.type());
@@ -221,15 +224,14 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f
close();
changeState(GroundState);
- // TODO: is it correct to assign even if the media type is not supported in
- // the switch statement below?
- m_source = source;
-
TInt symbianErr = KErrNone;
+ QString errorMessage;
- switch (m_source.type()) {
+ switch (source.type()) {
case MediaSource::LocalFile: {
symbianErr = openFile(file);
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening file");
break;
}
@@ -238,68 +240,76 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f
if (url.scheme() == QLatin1String("file")) {
symbianErr = openFile(file);
- }
- else {
- TRACE_0("Source type not supported");
- // TODO: support network URLs
- symbianErr = KErrNotSupported;
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening file");
+ } else {
+ symbianErr = openUrl(url.toString());
+ if (KErrNone != symbianErr)
+ errorMessage = tr("Error opening URL");
}
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;
+ // Other source types are handled in MediaObject::createPlayer
- // Protection against adding new media types and forgetting to update this switch
+ // Protection against adding new media types and forgetting to update this switch
default:
TRACE_PANIC(InvalidMediaTypePanic);
}
- if (KErrNone == symbianErr) {
+ if (errorMessage.isEmpty()) {
changeState(LoadingState);
} else {
- TRACE("error %d", symbianErr)
- setError(NormalError);
+ if (symbianErr)
+ setError(errorMessage, symbianErr);
+ else
+ setError(errorMessage);
}
TRACE_EXIT_0();
}
-void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source)
+void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
{
- TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi);
+ TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
TRACE_ENTRY("state %d", privateState());
- // TODO: handle 'next source'
-
- m_nextSource = source;
- Q_UNUSED(source);
+ AbstractPlayer::volumeChanged(volume);
+ doVolumeChanged();
TRACE_EXIT_0();
}
+//-----------------------------------------------------------------------------
+// Private functions
+//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
+void MMF::AbstractMediaPlayer::startPositionTimer()
{
- TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
- TRACE_ENTRY("state %d", privateState());
+ m_positionTimer->start(tickInterval());
+}
- AbstractPlayer::volumeChanged(volume);
- doVolumeChanged();
+void MMF::AbstractMediaPlayer::stopPositionTimer()
+{
+ m_positionTimer->stop();
+}
- TRACE_EXIT_0();
+void MMF::AbstractMediaPlayer::startBufferStatusTimer()
+{
+ m_bufferStatusTimer->start(BufferStatusTimerInterval);
}
+void MMF::AbstractMediaPlayer::stopBufferStatusTimer()
+{
+ m_bufferStatusTimer->stop();
+}
+
+void MMF::AbstractMediaPlayer::stopTimers()
+{
+ stopPositionTimer();
+ stopBufferStatusTimer();
+}
void MMF::AbstractMediaPlayer::doVolumeChanged()
{
@@ -318,7 +328,7 @@ void MMF::AbstractMediaPlayer::doVolumeChanged()
const int err = setDeviceVolume(volume);
if (KErrNone != err) {
- setError(NormalError);
+ setError(tr("Setting volume failed"), err);
}
break;
}
@@ -330,19 +340,23 @@ void MMF::AbstractMediaPlayer::doVolumeChanged()
}
}
-
//-----------------------------------------------------------------------------
// Protected functions
//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::startTickTimer()
+void MMF::AbstractMediaPlayer::bufferingStarted()
{
- m_tickTimer->start(tickInterval());
+ m_stateBeforeBuffering = privateState();
+ changeState(BufferingState);
+ bufferStatusTick();
+ startBufferStatusTimer();
}
-void MMF::AbstractMediaPlayer::stopTickTimer()
+void MMF::AbstractMediaPlayer::bufferingComplete()
{
- m_tickTimer->stop();
+ stopBufferStatusTimer();
+ emit MMF::AbstractPlayer::bufferStatus(100);
+ changeState(m_stateBeforeBuffering);
}
void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
@@ -351,6 +365,23 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
doVolumeChanged();
}
+void MMF::AbstractMediaPlayer::playbackComplete(int error)
+{
+ stopTimers();
+
+ if (KErrNone == error) {
+ changeState(StoppedState);
+
+ // MediaObject::switchToNextSource deletes the current player, so we
+ // call it via delayed slot invokation to ensure that this object does
+ // not get deleted during execution of a member function.
+ QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection);
+ }
+ else {
+ setError(tr("Playback complete"), error);
+ }
+}
+
qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
{
return in.Int64() / 1000;
@@ -360,10 +391,53 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds
// Slots
//-----------------------------------------------------------------------------
-void MMF::AbstractMediaPlayer::tick()
+void MMF::AbstractMediaPlayer::positionTick()
+{
+ emitMarksIfReached();
+
+ const qint64 current = currentTime();
+ emit MMF::AbstractPlayer::tick(current);
+}
+
+void MMF::AbstractMediaPlayer::emitMarksIfReached()
+{
+ const qint64 current = currentTime();
+ const qint64 total = totalTime();
+ const qint64 remaining = total - current;
+
+ if (prefinishMark() && !m_prefinishMarkSent) {
+ if (remaining < (prefinishMark() + tickInterval()/2)) {
+ m_prefinishMarkSent = true;
+ emit prefinishMarkReached(remaining);
+ }
+ }
+
+ if (!m_aboutToFinishSent) {
+ if (remaining < tickInterval()) {
+ m_aboutToFinishSent = true;
+ emit aboutToFinish();
+ }
+ }
+}
+
+void MMF::AbstractMediaPlayer::resetMarksIfRewound()
+{
+ const qint64 current = currentTime();
+ const qint64 total = totalTime();
+ const qint64 remaining = total - current;
+
+ if (prefinishMark() && m_prefinishMarkSent)
+ if (remaining >= (prefinishMark() + tickInterval()/2))
+ m_prefinishMarkSent = false;
+
+ if (m_aboutToFinishSent)
+ if (remaining >= tickInterval())
+ m_aboutToFinishSent = false;
+}
+
+void MMF::AbstractMediaPlayer::bufferStatusTick()
{
- // For the MWC compiler, we need to qualify the base class.
- emit MMF::AbstractPlayer::tick(currentTime());
+ emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
}
void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h
index cb6e437..abd6bff 100644
--- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h
+++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h
@@ -33,6 +33,7 @@ namespace Phonon
namespace MMF
{
class AudioOutput;
+class MediaObject;
/**
* Interface via which MMF client APIs for both audio and video can be
@@ -43,19 +44,17 @@ class AbstractMediaPlayer : public AbstractPlayer
Q_OBJECT
protected:
- AbstractMediaPlayer();
- explicit AbstractMediaPlayer(const AbstractPlayer& player);
+ AbstractMediaPlayer(MediaObject *parent, const AbstractPlayer *player);
public:
+ virtual void open(const Phonon::MediaSource&, RFile&);
+
// MediaObjectInterface
virtual void play();
virtual void pause();
virtual void stop();
virtual void seek(qint64 milliseconds);
virtual bool isSeekable() const;
- virtual MediaSource source() const;
- virtual void setFileSource(const Phonon::MediaSource&, RFile&);
- virtual void setNextSource(const MediaSource &source);
virtual void volumeChanged(qreal volume);
protected:
@@ -68,6 +67,8 @@ protected:
virtual void doSeek(qint64 pos) = 0;
virtual int setDeviceVolume(int mmfVolume) = 0;
virtual int openFile(RFile& file) = 0;
+ virtual int openUrl(const QString& url) = 0;
+ virtual int bufferStatus() const = 0;
virtual void close() = 0;
virtual void changeState(PrivateState newState);
@@ -76,23 +77,30 @@ protected:
virtual QPair<QString, QString> metaDataEntry(int index) const = 0;
protected:
- bool tickTimerRunning() const;
- void startTickTimer();
- void stopTickTimer();
+ void bufferingStarted();
+ void bufferingComplete();
void maxVolumeChanged(int maxVolume);
+ void playbackComplete(int error);
static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &);
private:
+ void startPositionTimer();
+ void stopPositionTimer();
+ void startBufferStatusTimer();
+ void stopBufferStatusTimer();
+ void stopTimers();
void doVolumeChanged();
+ void emitMarksIfReached();
+ void resetMarksIfRewound();
private Q_SLOTS:
- /**
- * Receives signal from m_tickTimer
- */
- void tick();
+ void positionTick();
+ void bufferStatusTick();
private:
+ MediaObject *const m_parent;
+
/**
* This flag is set to true if play is called when the object is
* in a Loading state. Once loading is complete, playback will
@@ -100,12 +108,15 @@ private:
*/
bool m_playPending;
- QScopedPointer<QTimer> m_tickTimer;
+ QScopedPointer<QTimer> m_positionTimer;
+
+ QScopedPointer<QTimer> m_bufferStatusTimer;
+ PrivateState m_stateBeforeBuffering;
int m_mmfMaxVolume;
- MediaSource m_source;
- MediaSource m_nextSource;
+ bool m_prefinishMarkSent;
+ bool m_aboutToFinishSent;
QMultiMap<QString, QString> m_metaData;
diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp
index caf4092..53973eb 100644
--- a/src/3rdparty/phonon/mmf/abstractplayer.cpp
+++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp
@@ -33,7 +33,7 @@ using namespace Phonon::MMF;
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::AbstractPlayer::AbstractPlayer()
+MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer *player)
: m_videoOutput(0)
, m_volume(InitialVolume)
, m_state(GroundState)
@@ -42,19 +42,13 @@ MMF::AbstractPlayer::AbstractPlayer()
, m_transitionTime(0)
, m_prefinishMark(0)
{
-
-}
-
-MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer& player)
- : m_videoOutput(player.m_videoOutput)
- , m_volume(player.m_volume)
- , m_state(GroundState)
- , m_error(NoError)
- , m_tickInterval(player.tickInterval())
- , m_transitionTime(player.transitionTime())
- , m_prefinishMark(player.prefinishMark())
-{
-
+ if(player) {
+ m_videoOutput = player->m_videoOutput;
+ m_volume = player->m_volume;
+ m_tickInterval = player->m_tickInterval;
+ m_transitionTime = player->m_transitionTime;
+ m_prefinishMark = player->m_prefinishMark;
+ }
}
//-----------------------------------------------------------------------------
@@ -113,19 +107,23 @@ void MMF::AbstractPlayer::videoOutputChanged()
// Default behaviour is empty - overridden by VideoPlayer
}
-void MMF::AbstractPlayer::setError(Phonon::ErrorType error,
- const QString &errorMessage)
+void MMF::AbstractPlayer::setError(const QString &errorMessage)
{
TRACE_CONTEXT(AbstractPlayer::setError, EAudioInternal);
- TRACE_ENTRY("state %d error %d", m_state, error);
+ TRACE_ENTRY("state %d", m_state);
- m_error = error;
+ m_error = Phonon::NormalError;
m_errorString = errorMessage;
changeState(ErrorState);
TRACE_EXIT_0();
}
+void MMF::AbstractPlayer::setError(const QString &errorMessage, int symbianError)
+{
+ setError(errorMessage + ": " + Utils::symbianErrorToString(symbianError));
+}
+
Phonon::ErrorType MMF::AbstractPlayer::errorType() const
{
const Phonon::ErrorType result = (ErrorState == m_state)
diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h
index 2e9cfa0..40ad7f8 100644
--- a/src/3rdparty/phonon/mmf/abstractplayer.h
+++ b/src/3rdparty/phonon/mmf/abstractplayer.h
@@ -53,8 +53,9 @@ class AbstractPlayer : public QObject
Q_OBJECT
public:
- AbstractPlayer();
- explicit AbstractPlayer(const AbstractPlayer& player);
+ AbstractPlayer(const AbstractPlayer *player);
+
+ virtual void open(const Phonon::MediaSource&, RFile&) = 0;
// MediaObjectInterface (implemented)
qint32 tickInterval() const;
@@ -75,22 +76,28 @@ public:
virtual Phonon::ErrorType errorType() const;
virtual QString errorString() const;
virtual qint64 totalTime() const = 0;
- virtual Phonon::MediaSource source() const = 0;
- // This is a temporary hack to work around KErrInUse from MMF
- // client utility OpenFileL calls
- //virtual void setSource(const Phonon::MediaSource &) = 0;
- virtual void setFileSource(const Phonon::MediaSource&, RFile&) = 0;
- virtual void setNextSource(const Phonon::MediaSource &) = 0;
virtual void volumeChanged(qreal volume);
void setVideoOutput(VideoOutput* videoOutput);
/**
- * Records error and changes state to ErrorState
+ * Records error message and changes state to ErrorState
+ */
+ void setError(const QString &errorMessage);
+
+ /**
+ * Records error message and changes state to ErrorState
+ *
+ * Appends a human-readable version of symbianErrorCode to the error message,
+ * e.g.
+ * @code
+ * setError("Opening file failed", KErrPermissionDenied)
+ * @endcode
+ * results in the following error message:
+ * "Opening file failed: permission denied"
*/
- void setError(Phonon::ErrorType error,
- const QString &errorMessage = QString());
+ void setError(const QString &errorMessage, int symbianErrorCode);
Phonon::State state() const;
@@ -98,9 +105,12 @@ Q_SIGNALS:
void totalTimeChanged(qint64 length);
void finished();
void tick(qint64 time);
+ void bufferStatus(int percentFilled);
void stateChanged(Phonon::State oldState,
Phonon::State newState);
void metaDataChanged(const QMultiMap<QString, QString>& metaData);
+ void aboutToFinish();
+ void prefinishMarkReached(qint32 remaining);
protected:
/**
diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp
index 7cc9bc7..c2936c5 100644
--- a/src/3rdparty/phonon/mmf/audioequalizer.cpp
+++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp
@@ -16,6 +16,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <AudioEqualizerBase.h>
#include "audioequalizer.h"
QT_BEGIN_NAMESPACE
@@ -34,18 +35,37 @@ AudioEqualizer::AudioEqualizer(QObject *parent) : AbstractAudioEffect::AbstractA
void AudioEqualizer::parameterChanged(const int pid,
const QVariant &value)
{
- // There is no way to return an error from this function, so we just
- // have to trap and ignore exceptions.
- TRAP_IGNORE(static_cast<CAudioEqualizer *>(m_effect.data())->SetBandLevelL(pid, value.toInt()));
+ if (m_effect.data()) {
+ const int band = pid;
+ const int level = value.toInt();
+ setBandLevel(band, level);
+ }
}
-bool AudioEqualizer::activateOn(CPlayerType *player)
+void AudioEqualizer::connectAudioPlayer(AudioPlayer::NativePlayer *player)
{
CAudioEqualizer *ptr = 0;
QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player));
m_effect.reset(ptr);
+}
- return true;
+void AudioEqualizer::applyParameters()
+{
+ if (m_effect.data()) {
+ EffectParameter param;
+ foreach (param, parameters()) {
+ const int band = param.id();
+ const int level = parameterValue(param).toInt();
+ setBandLevel(band, level);
+ }
+ }
+}
+
+void AudioEqualizer::setBandLevel(int band, int level)
+{
+ CAudioEqualizer *const effect = static_cast<CAudioEqualizer *>(m_effect.data());
+ // TODO: handle audio effect errors
+ TRAP_IGNORE(effect->SetBandLevelL(band, level));
}
QList<EffectParameter> AudioEqualizer::createParams()
@@ -57,7 +77,7 @@ QList<EffectParameter> AudioEqualizer::createParams()
AudioPlayer dummyPlayer;
CAudioEqualizer *eqPtr = 0;
- QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.player());)
+ QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.nativePlayer()));
QScopedPointer<CAudioEqualizer> e(eqPtr);
TInt32 dbMin;
diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h
index d4c8165..10fe9ad 100644
--- a/src/3rdparty/phonon/mmf/audioequalizer.h
+++ b/src/3rdparty/phonon/mmf/audioequalizer.h
@@ -19,7 +19,6 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#ifndef PHONON_MMF_AUDIOEQUALIZER_H
#define PHONON_MMF_AUDIOEQUALIZER_H
-#include <AudioEqualizerBase.h>
#include "abstractaudioeffect.h"
QT_BEGIN_NAMESPACE
@@ -43,14 +42,17 @@ public:
AudioEqualizer(QObject *parent);
protected:
- virtual void parameterChanged(const int id,
- const QVariant &value);
+ // AbstractAudioEffect
+ virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player);
+ virtual void applyParameters();
+ virtual void parameterChanged(const int id, const QVariant &value);
- virtual bool activateOn(CPlayerType *player);
+private:
+ void setBandLevel(int band, int level);
private:
static QList<EffectParameter> createParams();
- QScopedPointer<CAudioEqualizer> m_bassBoost;
+
};
}
}
diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp
index d6e0c13..c6be20b 100644
--- a/src/3rdparty/phonon/mmf/audiooutput.cpp
+++ b/src/3rdparty/phonon/mmf/audiooutput.cpp
@@ -81,13 +81,18 @@ bool MMF::AudioOutput::setOutputDevice(int index)
return true;
}
-bool MMF::AudioOutput::activateOnMediaObject(MediaObject *mo)
+void MMF::AudioOutput::connectMediaObject(MediaObject *mediaObject)
{
// Ensure that the MediaObject has the correct initial volume
- mo->volumeChanged(m_volume);
+ mediaObject->volumeChanged(m_volume);
// Connect MediaObject to receive future volume changes
- connect(this, SIGNAL(volumeChanged(qreal)), mo, SLOT(volumeChanged(qreal)));
- return true;
+ connect(this, SIGNAL(volumeChanged(qreal)), mediaObject, SLOT(volumeChanged(qreal)));
+}
+
+void MMF::AudioOutput::disconnectMediaObject(MediaObject *mediaObject)
+{
+ // Disconnect all signal-slot connections
+ disconnect(this, 0, mediaObject, 0);
}
QHash<QByteArray, QVariant> MMF::AudioOutput::audioOutputDescription(int index)
diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h
index 1e1e134..67aaa38 100644
--- a/src/3rdparty/phonon/mmf/audiooutput.h
+++ b/src/3rdparty/phonon/mmf/audiooutput.h
@@ -74,7 +74,9 @@ public:
};
protected:
- virtual bool activateOnMediaObject(MediaObject *mo);
+ // MediaNode
+ void connectMediaObject(MediaObject *mediaObject);
+ void disconnectMediaObject(MediaObject *mediaObject);
Q_SIGNALS:
void volumeChanged(qreal volume);
diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp
index 8fccfe6..ee07229 100644
--- a/src/3rdparty/phonon/mmf/audioplayer.cpp
+++ b/src/3rdparty/phonon/mmf/audioplayer.cpp
@@ -34,13 +34,9 @@ using namespace Phonon::MMF;
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::AudioPlayer::AudioPlayer()
-{
- construct();
-}
-
-MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player)
- : AbstractMediaPlayer(player)
+MMF::AudioPlayer::AudioPlayer(MediaObject *parent, const AbstractPlayer *player)
+ : AbstractMediaPlayer(parent, player)
+ , m_totalTime(0)
{
construct();
}
@@ -50,10 +46,10 @@ void MMF::AudioPlayer::construct()
TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi);
TRACE_ENTRY_0();
- TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone)));
- if (KErrNone != err) {
- changeState(ErrorState);
- }
+ NativePlayer *player = 0;
+ QT_TRAP_THROWING(player = NativePlayer::NewL(*this, 0, EMdaPriorityPreferenceNone));
+ m_player.reset(player);
+ m_player->RegisterForAudioLoadingNotification(*this);
TRACE_EXIT_0();
}
@@ -66,6 +62,11 @@ MMF::AudioPlayer::~AudioPlayer()
TRACE_EXIT_0();
}
+MMF::AudioPlayer::NativePlayer *MMF::AudioPlayer::nativePlayer() const
+{
+ return m_player.data();
+}
+
//-----------------------------------------------------------------------------
// Public API
//-----------------------------------------------------------------------------
@@ -125,6 +126,24 @@ int MMF::AudioPlayer::openFile(RFile& file)
return err;
}
+int MMF::AudioPlayer::openUrl(const QString& /*url*/)
+{
+ // Streaming playback is generally not supported by the implementation
+ // of the audio player API, so we use CVideoPlayerUtility for both
+ // audio and video streaming.
+ Utils::panic(AudioUtilityUrlNotSupported);
+
+ // Silence warning
+ return 0;
+}
+
+int MMF::AudioPlayer::bufferStatus() const
+{
+ int result = 0;
+ TRAP_IGNORE(m_player->GetAudioLoadingProgressL(result));
+ return result;
+}
+
void MMF::AudioPlayer::close()
{
m_player->Close();
@@ -151,7 +170,7 @@ qint64 MMF::AudioPlayer::currentTime() const
// If we don't cast away constness here, we simply have to ignore
// the error.
- const_cast<AudioPlayer*>(this)->setError(NormalError);
+ const_cast<AudioPlayer*>(this)->setError(tr("Getting position failed"), err);
}
return result;
@@ -159,7 +178,7 @@ qint64 MMF::AudioPlayer::currentTime() const
qint64 MMF::AudioPlayer::totalTime() const
{
- return toMilliSeconds(m_player->Duration());
+ return m_totalTime;
}
@@ -182,12 +201,12 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError,
if (KErrNone == aError) {
maxVolumeChanged(m_player->MaxVolume());
- emit totalTimeChanged(totalTime());
+ m_totalTime = toMilliSeconds(m_player->Duration());
+ emit totalTimeChanged(m_totalTime);
updateMetaData();
changeState(StoppedState);
} else {
- // TODO: set different error states according to value of aError?
- setError(NormalError);
+ setError(tr("Opening clip failed"), aError);
}
TRACE_EXIT_0();
@@ -202,53 +221,39 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError)
TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal);
TRACE_ENTRY("state %d error %d", state(), aError);
- stopTickTimer();
+ // Call base class function which handles end of playback for both
+ // audio and video clips.
+ playbackComplete(aError);
- if (KErrNone == aError) {
- changeState(StoppedState);
- // TODO: move on to m_nextSource
- } else {
- // TODO: do something with aError?
- setError(NormalError);
- }
+ TRACE_EXIT_0();
+}
- /*
- 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);
- }
- */
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+void MMF::AudioPlayer::MaloLoadingStarted()
+{
- TRACE_EXIT_0();
}
-CPlayerType *MMF::AudioPlayer::player() const
+void MMF::AudioPlayer::MaloLoadingComplete()
{
- return m_player.data();
+
}
+#endif // QT_PHONON_MMF_AUDIO_DRM
-#ifdef QT_PHONON_MMF_AUDIO_DRM
+//-----------------------------------------------------------------------------
+// MAudioLoadingObserver callbacks
+//-----------------------------------------------------------------------------
+
void MMF::AudioPlayer::MaloLoadingStarted()
{
-
+ bufferingStarted();
}
void MMF::AudioPlayer::MaloLoadingComplete()
{
-
+ bufferingComplete();
}
-#endif // QT_PHONON_MMF_AUDIO_DRM
//-----------------------------------------------------------------------------
diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h
index bc60076..0eb8bb7 100644
--- a/src/3rdparty/phonon/mmf/audioplayer.h
+++ b/src/3rdparty/phonon/mmf/audioplayer.h
@@ -26,12 +26,10 @@ class TTimeIntervalMicroSeconds;
#ifdef QT_PHONON_MMF_AUDIO_DRM
#include <drmaudiosampleplayer.h>
-typedef CDrmPlayerUtility CPlayerType;
-typedef MDrmAudioPlayerCallback MPlayerObserverType;
+typedef MDrmAudioPlayerCallback NativePlayerObserver;
#else
#include <mdaaudiosampleplayer.h>
-typedef CMdaAudioPlayerUtility CPlayerType;
-typedef MMdaAudioPlayerCallback MPlayerObserverType;
+typedef MMdaAudioPlayerCallback NativePlayerObserver;
#endif
QT_BEGIN_NAMESPACE
@@ -44,18 +42,23 @@ namespace MMF
* @short Wrapper over MMF audio client utility
*/
class AudioPlayer : public AbstractMediaPlayer
- , public MPlayerObserverType // typedef
-#ifdef QT_PHONON_MMF_AUDIO_DRM
+ , public NativePlayerObserver
, public MAudioLoadingObserver
-#endif
{
Q_OBJECT
public:
- AudioPlayer();
- explicit AudioPlayer(const AbstractPlayer& player);
+ AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0);
virtual ~AudioPlayer();
+#ifdef QT_PHONON_MMF_AUDIO_DRM
+typedef CDrmPlayerUtility NativePlayer;
+#else
+typedef CMdaAudioPlayerUtility NativePlayer;
+#endif
+
+ NativePlayer *nativePlayer() const;
+
// AbstractMediaPlayer
virtual void doPlay();
virtual void doPause();
@@ -63,6 +66,8 @@ public:
virtual void doSeek(qint64 milliseconds);
virtual int setDeviceVolume(int mmfVolume);
virtual int openFile(RFile& file);
+ virtual int openUrl(const QString& url);
+ virtual int bufferStatus() const;
virtual void close();
// MediaObjectInterface
@@ -70,15 +75,24 @@ public:
virtual qint64 currentTime() const;
virtual qint64 totalTime() const;
+ // AbstractMediaPlayer
+ virtual int numberOfMetaDataEntries() const;
+ virtual QPair<QString, QString> metaDataEntry(int index) const;
+
+ /**
+ * This class owns the pointer.
+ */
+ NativePlayer *player() const;
+
+private:
+ void construct();
+
+private:
#ifdef QT_PHONON_MMF_AUDIO_DRM
// MDrmAudioPlayerCallback
virtual void MdapcInitComplete(TInt aError,
const TTimeIntervalMicroSeconds &aDuration);
virtual void MdapcPlayComplete(TInt aError);
-
- // MAudioLoadingObserver
- virtual void MaloLoadingStarted();
- virtual void MaloLoadingComplete();
#else
// MMdaAudioPlayerCallback
virtual void MapcInitComplete(TInt aError,
@@ -86,24 +100,19 @@ public:
virtual void MapcPlayComplete(TInt aError);
#endif
- /**
- * This class owns the pointer.
- */
- CPlayerType *player() const;
-
-private:
- void construct();
-
- // AbstractMediaPlayer
- virtual int numberOfMetaDataEntries() const;
- virtual QPair<QString, QString> metaDataEntry(int index) const;
+ // MAudioLoadingObserver
+ virtual void MaloLoadingStarted();
+ virtual void MaloLoadingComplete();
private:
/**
* Using CPlayerType typedef in order to be able to easily switch between
* CMdaAudioPlayerUtility and CDrmPlayerUtility
*/
- QScopedPointer<CPlayerType> m_player;
+ QScopedPointer<NativePlayer> m_player;
+
+ qint64 m_totalTime;
+
};
}
}
diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp
index 7e3a67f..0c07f66 100644
--- a/src/3rdparty/phonon/mmf/backend.cpp
+++ b/src/3rdparty/phonon/mmf/backend.cpp
@@ -139,29 +139,32 @@ bool Backend::startConnectionChange(QSet<QObject *>)
return true;
}
-bool Backend::connectNodes(QObject *source, QObject *target)
+bool Backend::connectNodes(QObject *sourceObject, QObject *targetObject)
{
TRACE_CONTEXT(Backend::connectNodes, EBackend);
- TRACE_ENTRY("source 0x%08x target 0x%08x", source, target);
- Q_ASSERT(qobject_cast<MediaNode *>(source));
- Q_ASSERT(qobject_cast<MediaNode *>(target));
+ TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject);
- MediaNode *const mediaSource = static_cast<MediaNode *>(source);
- MediaNode *const mediaTarget = static_cast<MediaNode *>(target);
+ MediaNode *const source = qobject_cast<MediaNode *>(sourceObject);
+ MediaNode *const target = qobject_cast<MediaNode *>(targetObject);
- return mediaSource->connectMediaNode(mediaTarget);
+ Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode");
+ Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode");
+
+ return source->connectOutput(target);
}
-bool Backend::disconnectNodes(QObject *source, QObject *target)
+bool Backend::disconnectNodes(QObject *sourceObject, QObject *targetObject)
{
TRACE_CONTEXT(Backend::disconnectNodes, EBackend);
- TRACE_ENTRY("source 0x%08x target 0x%08x", source, target);
- Q_ASSERT(qobject_cast<MediaNode *>(source));
- Q_ASSERT(qobject_cast<MediaNode *>(target));
+ TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject);
+
+ MediaNode *const source = qobject_cast<MediaNode *>(sourceObject);
+ MediaNode *const target = qobject_cast<MediaNode *>(targetObject);
- const bool result = static_cast<MediaNode *>(source)->disconnectMediaNode(static_cast<MediaNode *>(target));
+ Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode");
+ Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode");
- TRACE_RETURN("%d", result);
+ return source->disconnectOutput(target);
}
bool Backend::endConnectionChange(QSet<QObject *>)
diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp
index e34f9e7..ae96b45 100644
--- a/src/3rdparty/phonon/mmf/bassboost.cpp
+++ b/src/3rdparty/phonon/mmf/bassboost.cpp
@@ -16,6 +16,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <BassBoostBase.h>
#include "bassboost.h"
QT_BEGIN_NAMESPACE
@@ -35,13 +36,19 @@ BassBoost::BassBoost(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect
void BassBoost::parameterChanged(const int,
const QVariant &)
{
- // We should never be called, because we have no parameters.
+ Q_ASSERT_X(false, Q_FUNC_INFO, "BassBoost has not parameters");
}
-bool BassBoost::activateOn(CPlayerType *player)
+void BassBoost::connectAudioPlayer(AudioPlayer::NativePlayer *player)
{
- m_effect.reset(CBassBoost::NewL(*player, true));
- return true;
+ CBassBoost *ptr = 0;
+ QT_TRAP_THROWING(ptr = CBassBoost::NewL(*player));
+ m_effect.reset(ptr);
+}
+
+void BassBoost::applyParameters()
+{
+ // No parameters to apply
}
QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h
index c16393a..4ad0a6c 100644
--- a/src/3rdparty/phonon/mmf/bassboost.h
+++ b/src/3rdparty/phonon/mmf/bassboost.h
@@ -19,7 +19,6 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#ifndef PHONON_MMF_BASSBOOST_H
#define PHONON_MMF_BASSBOOST_H
-#include <BassBoostBase.h>
#include "abstractaudioeffect.h"
QT_BEGIN_NAMESPACE
@@ -41,13 +40,11 @@ public:
BassBoost(QObject *parent);
protected:
- virtual void parameterChanged(const int id,
- const QVariant &value);
+ // AbstractAudioEffect
+ virtual void connectAudioPlayer(AudioPlayer::NativePlayer *player);
+ virtual void applyParameters();
+ virtual void parameterChanged(const int id, const QVariant &value);
- virtual bool activateOn(CPlayerType *player);
-
-private:
- QScopedPointer<CBassBoost> m_bassBoost;
};
}
}
diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp
index e6f3855..6970088 100644
--- a/src/3rdparty/phonon/mmf/dummyplayer.cpp
+++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp
@@ -31,12 +31,7 @@ using namespace Phonon::MMF;
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::DummyPlayer::DummyPlayer()
-{
-
-}
-
-MMF::DummyPlayer::DummyPlayer(const AbstractPlayer& player)
+MMF::DummyPlayer::DummyPlayer(const AbstractPlayer *player)
: AbstractPlayer(player)
{
@@ -97,17 +92,7 @@ qint64 MMF::DummyPlayer::totalTime() const
return 0;
}
-MediaSource MMF::DummyPlayer::source() const
-{
- return MediaSource();
-}
-
-void MMF::DummyPlayer::setFileSource(const Phonon::MediaSource &, RFile &)
-{
-
-}
-
-void MMF::DummyPlayer::setNextSource(const MediaSource &)
+void MMF::DummyPlayer::open(const Phonon::MediaSource &, RFile &)
{
}
diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h
index c6270c9..6841b5d 100644
--- a/src/3rdparty/phonon/mmf/dummyplayer.h
+++ b/src/3rdparty/phonon/mmf/dummyplayer.h
@@ -42,8 +42,7 @@ class AudioOutput;
class DummyPlayer : public AbstractPlayer
{
public:
- DummyPlayer();
- DummyPlayer(const AbstractPlayer& player);
+ DummyPlayer(const AbstractPlayer *player = 0);
// MediaObjectInterface
virtual void play();
@@ -56,12 +55,9 @@ public:
virtual Phonon::State state() const;
virtual Phonon::ErrorType errorType() const;
virtual qint64 totalTime() const;
- virtual MediaSource source() const;
- // virtual void setSource(const MediaSource &);
- virtual void setFileSource(const Phonon::MediaSource&, RFile&);
- virtual void setNextSource(const MediaSource &source);
// AbstractPlayer
+ virtual void open(const Phonon::MediaSource&, RFile&);
virtual void doSetTickInterval(qint32 interval);
};
}
diff --git a/src/3rdparty/phonon/mmf/effectfactory.cpp b/src/3rdparty/phonon/mmf/effectfactory.cpp
index e9c5e27..cc94367 100644
--- a/src/3rdparty/phonon/mmf/effectfactory.cpp
+++ b/src/3rdparty/phonon/mmf/effectfactory.cpp
@@ -113,7 +113,7 @@ bool isEffectSupported()
AudioPlayer audioPlayer;
QScopedPointer<TEffect> eff;
- TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player())));
+ TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.nativePlayer())));
return errorCode != KErrNone;
}
diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp
index 21dcfe1..4653fee 100644
--- a/src/3rdparty/phonon/mmf/mediaobject.cpp
+++ b/src/3rdparty/phonon/mmf/mediaobject.cpp
@@ -45,6 +45,7 @@ using namespace Phonon::MMF;
MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent)
, m_recognizerOpened(false)
+ , m_nextSourceSet(false)
{
m_player.reset(new DummyPlayer());
@@ -211,18 +212,20 @@ qint64 MMF::MediaObject::totalTime() const
MediaSource MMF::MediaObject::source() const
{
- return m_player->source();
+ return m_source;
}
void MMF::MediaObject::setSource(const MediaSource &source)
{
- createPlayer(source);
-
- // This is a hack to work around KErrInUse from MMF client utility
- // OpenFileL calls
- m_player->setFileSource(source, m_file);
+ switchToSource(source);
+}
- emit currentSourceChanged(source);
+void MMF::MediaObject::switchToSource(const MediaSource &source)
+{
+ createPlayer(source);
+ m_source = source;
+ m_player->open(m_source, m_file);
+ emit currentSourceChanged(m_source);
}
void MMF::MediaObject::createPlayer(const MediaSource &source)
@@ -238,7 +241,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
const bool oldPlayerHasVideo = oldPlayer->hasVideo();
const bool oldPlayerSeekable = oldPlayer->isSeekable();
- Phonon::ErrorType error = NoError;
QString errorMessage;
// Determine media type
@@ -254,8 +256,10 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
mediaType = fileMediaType(url.toLocalFile());
}
else {
- errorMessage = QLatin1String("Network streaming not supported yet");
- error = NormalError;
+ // Streaming playback is generally not supported by the implementation
+ // of the audio player API, so we use CVideoPlayerUtility for both
+ // audio and video streaming.
+ mediaType = MediaTypeVideo;
}
}
break;
@@ -263,8 +267,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
case MediaSource::Invalid:
case MediaSource::Disc:
case MediaSource::Stream:
- TRACE_0("Unsupported media type");
- error = NormalError;
+ errorMessage = tr("Error opening source: type not supported");
break;
case MediaSource::Empty:
@@ -281,30 +284,16 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
switch (mediaType) {
case MediaTypeUnknown:
TRACE_0("Media type could not be determined");
- if (oldPlayer) {
- newPlayer = new DummyPlayer(*oldPlayer);
- } else {
- newPlayer = new DummyPlayer();
- }
-
- error = NormalError;
- errorMessage = tr("Media type could not be determined");
+ newPlayer = new DummyPlayer(oldPlayer);
+ errorMessage = tr("Error opening source: media type could not be determined");
break;
case MediaTypeAudio:
- if (oldPlayer) {
- newPlayer = new AudioPlayer(*oldPlayer);
- } else {
- newPlayer = new AudioPlayer();
- }
+ newPlayer = new AudioPlayer(this, oldPlayer);
break;
case MediaTypeVideo:
- if (oldPlayer) {
- newPlayer = new VideoPlayer(*oldPlayer);
- } else {
- newPlayer = new VideoPlayer();
- }
+ newPlayer = new VideoPlayer(this, oldPlayer);
break;
}
@@ -322,13 +311,16 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
connect(m_player.data(), SIGNAL(stateChanged(Phonon::State,Phonon::State)), SIGNAL(stateChanged(Phonon::State,Phonon::State)));
connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished()));
connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64)));
+ connect(m_player.data(), SIGNAL(bufferStatus(int)), SIGNAL(bufferStatus(int)));
connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)));
+ connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish()));
+ connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(tick(qint32)));
// We need to call setError() after doing the connects, otherwise the
// error won't be received.
- if (error != NoError) {
+ if (!errorMessage.isEmpty()) {
Q_ASSERT(m_player);
- m_player->setError(error, errorMessage);
+ m_player->setError(errorMessage);
}
TRACE_EXIT_0();
@@ -336,7 +328,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source)
void MMF::MediaObject::setNextSource(const MediaSource &source)
{
- m_player->setNextSource(source);
+ m_nextSource = source;
+ m_nextSourceSet = true;
}
qint32 MMF::MediaObject::prefinishMark() const
@@ -365,6 +358,25 @@ void MMF::MediaObject::volumeChanged(qreal volume)
}
//-----------------------------------------------------------------------------
+// MediaNode
+//-----------------------------------------------------------------------------
+
+void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/)
+{
+ // This function should never be called - see MediaNode::setMediaObject()
+ Q_ASSERT_X(false, Q_FUNC_INFO,
+ "Connection of MediaObject to MediaObject");
+}
+
+void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/)
+{
+ // This function should never be called - see MediaNode::setMediaObject()
+ Q_ASSERT_X(false, Q_FUNC_INFO,
+ "Disconnection of MediaObject from MediaObject");
+}
+
+
+//-----------------------------------------------------------------------------
// Video output
//-----------------------------------------------------------------------------
@@ -379,10 +391,17 @@ AbstractPlayer *MMF::MediaObject::abstractPlayer() const
return m_player.data();
}
-bool MMF::MediaObject::activateOnMediaObject(MediaObject *)
+//-----------------------------------------------------------------------------
+// Playlist support
+//-----------------------------------------------------------------------------
+
+void MMF::MediaObject::switchToNextSource()
{
- // Guess what, we do nothing.
- return true;
+ if (m_nextSourceSet) {
+ m_nextSourceSet = false;
+ switchToSource(m_nextSource);
+ play();
+ }
}
QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h
index ee94ea2..668b953 100644
--- a/src/3rdparty/phonon/mmf/mediaobject.h
+++ b/src/3rdparty/phonon/mmf/mediaobject.h
@@ -75,6 +75,10 @@ public:
virtual qint32 transitionTime() const;
virtual void setTransitionTime(qint32);
+ // MediaNode
+ void connectMediaObject(MediaObject *mediaObject);
+ void disconnectMediaObject(MediaObject *mediaObject);
+
/**
* This class owns the AbstractPlayer, and will delete it upon
* destruction.
@@ -83,21 +87,17 @@ public:
void setVideoOutput(VideoOutput* videoOutput);
- virtual bool activateOnMediaObject(MediaObject *);
-
public Q_SLOTS:
void volumeChanged(qreal volume);
+ void switchToNextSource();
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);
+ void prefinishMarkReached(qint32 remaining);
// TODO: emit metaDataChanged from MediaObject
void metaDataChanged(const QMultiMap<QString, QString>& metaData);
void currentSourceChanged(const MediaSource& source);
@@ -107,6 +107,7 @@ Q_SIGNALS:
void tick(qint64 time);
private:
+ void switchToSource(const MediaSource &source);
void createPlayer(const MediaSource &source);
bool openRecognizer();
@@ -123,6 +124,10 @@ private:
RApaLsSession m_recognizer;
RFs m_fileServer;
+ MediaSource m_source;
+ MediaSource m_nextSource;
+ bool m_nextSourceSet;
+
// Storing the file handle here to work around KErrInUse error
// from MMF player utility OpenFileL functions
RFile m_file;
diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.cpp b/src/3rdparty/phonon/mmf/mmf_medianode.cpp
index 253c5e7..ca413d9 100644
--- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp
+++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp
@@ -29,92 +29,123 @@ using namespace Phonon::MMF;
\internal
*/
-MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent)
- , m_source(0)
- , m_target(0)
- , m_isApplied(false)
+MMF::MediaNode::MediaNode(QObject *parent)
+ : QObject(parent)
+ , m_mediaObject(qobject_cast<MediaObject *>(this))
+ , m_input(0)
{
-}
-
-bool MMF::MediaNode::connectMediaNode(MediaNode *target)
-{
- m_target = target;
- m_target->setSource(this);
- return applyNodesOnMediaObject(target);
}
-bool MMF::MediaNode::disconnectMediaNode(MediaNode *target)
+MMF::MediaNode::~MediaNode()
{
- Q_UNUSED(target);
- m_target = 0;
- m_isApplied = false;
- return true;
+ // Phonon framework ensures nodes are disconnected before being destroyed.
+ Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO,
+ "Media node not disconnected before destruction");
}
-void MMF::MediaNode::setSource(MediaNode *source)
+bool MMF::MediaNode::connectOutput(MediaNode *output)
{
- m_source = source;
+ Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer");
+
+ bool connected = false;
+
+ // Check that this connection will not result in a graph which
+ // containing more than one MediaObject
+ const bool mediaObjectMisMatch =
+ m_mediaObject
+ && output->m_mediaObject
+ && m_mediaObject != output->m_mediaObject;
+
+ const bool canConnect =
+ !output->isMediaObject()
+ && !output->m_input
+ && !m_outputs.contains(output);
+
+ if (canConnect && !mediaObjectMisMatch) {
+ output->m_input = this;
+ m_outputs += output;
+ updateMediaObject();
+ connected = true;
+ }
+
+ return connected;
}
-MMF::MediaNode *MMF::MediaNode::source() const
+bool MMF::MediaNode::disconnectOutput(MediaNode *output)
{
- return m_source;
+ Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer");
+
+ bool disconnected = false;
+
+ if (m_outputs.contains(output) && this == output->m_input) {
+ output->m_input = 0;
+ const bool removed = m_outputs.removeOne(output);
+ Q_ASSERT_X(removed, Q_FUNC_INFO, "Output removal failed");
+
+ Q_ASSERT_X(!m_outputs.contains(output), Q_FUNC_INFO,
+ "Output list contains duplicate entries");
+
+ // Perform traversal across each of the two graphs separately
+ updateMediaObject();
+ output->updateMediaObject();
+
+ disconnected = true;
+ }
+
+ return disconnected;
}
-MMF::MediaNode *MMF::MediaNode::target() const
+bool MMF::MediaNode::isMediaObject() const
{
- return m_target;
+ return (qobject_cast<const MediaObject *>(this) != 0);
}
-bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *)
+void MMF::MediaNode::updateMediaObject()
{
- // Algorithmically, this can be expressed in a more efficient way by
- // exercising available assumptions, but it complicates code for input
- // data(length of the graph) which typically is very small.
-
- // First, we go to the very beginning of the graph.
- MMF::MediaNode *current = this;
- do {
- MediaNode *const candidate = current->source();
- if (candidate)
- current = candidate;
- else
- break;
- }
- while (current);
-
- // Now we do two things, while walking to the other end:
- // 1. Find the MediaObject, if present
- // 2. Collect a list of all unapplied MediaNodes
-
- QList<MediaNode *> unapplied;
- MMF::MediaObject *mo = 0;
+ QList<MediaNode *> nodes;
+ MediaObject *mediaObject = 0;
- do {
- if (!current->m_isApplied)
- unapplied.append(current);
+ // Traverse the graph, collecting a list of nodes, and locating
+ // the MediaObject node, if present
+ visit(nodes, mediaObject);
- if (!mo)
- mo = qobject_cast<MMF::MediaObject *>(current);
+ MediaNode *node = 0;
+ foreach(node, nodes)
+ node->setMediaObject(mediaObject);
+}
- current = current->target();
+void MMF::MediaNode::setMediaObject(MediaObject *mediaObject)
+{
+ if(!isMediaObject() && m_mediaObject != mediaObject) {
+ if (!mediaObject)
+ disconnectMediaObject(m_mediaObject);
+ else {
+ Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, "MediaObject already set");
+ connectMediaObject(mediaObject);
+ }
+ m_mediaObject = mediaObject;
}
- while (current);
+}
- // Now, lets activate all the objects, if we found the MediaObject.
+void MMF::MediaNode::visit(QList<MediaNode *>& visited, MediaObject*& mediaObject)
+{
+ if (isMediaObject()) {
+ // There can never be more than one MediaObject per graph, due to the
+ // mediaObjectMisMatch test in connectOutput().
+ Q_ASSERT_X(!mediaObject, Q_FUNC_INFO, "MediaObject already found");
+ mediaObject = static_cast<MediaObject *>(this);
+ }
- if (mo) {
- for (int i = 0; i < unapplied.count(); ++i) {
- MediaNode *const at = unapplied.at(i);
+ visited += this;
- // We don't want to apply MediaObject on itself.
- if (at != mo)
- at->activateOnMediaObject(mo);
- }
- }
+ if (m_input && !visited.contains(m_input))
+ m_input->visit(visited, mediaObject);
- return true;
+ MediaNode *output = 0;
+ foreach (output, m_outputs)
+ if (!visited.contains(output))
+ output->visit(visited, mediaObject);
}
QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.h b/src/3rdparty/phonon/mmf/mmf_medianode.h
index 4616ff1..0ed21c4 100644
--- a/src/3rdparty/phonon/mmf/mmf_medianode.h
+++ b/src/3rdparty/phonon/mmf/mmf_medianode.h
@@ -43,54 +43,62 @@ class MediaObject;
/**
* @short Base class for all nodes in the MMF backend.
*
- * MediaNode is the base class for all nodes in the chain for MMF. Currently
- * they are:
+ * MediaNode is the base class for all nodes created by the MMF
+ * backend.
*
- * - MediaObject: a source of media
- * - AbstractEffect: supplying audio effects
- * - AudioOutput: pretty much a dummy interface, but is also MediaNode in order
- * to simplify connection/disconnection.
+ * These nodes may be one of the following types:
*
- * MediaNode provides spectatability into the chain, and also allows the
- * connection code to be written in a polymorphic manner, instead of putting it
- * all in the Backend class. Due to that MMF has no concept of chaining, the
- * order of the nodes in the graph has no meaning.
+ * - MediaObject
+ * This represents the source of media data. It encapsulates the
+ * appropriate MMF client API for playing audio or video.
+ * - AudioOutput
+ * This represents the audio output device. Since the MMF client API
+ * does not expose the output device directly, this backend node
+ * simply forwards volume control commands to the MediaObject.
+ * - VideoWidget
+ * A native widget on which video will be rendered.
+ * - An audio effect, derived form AbstractAudioEffect
+ *
+ * Because the MMF API does not support the concept of a media filter graph,
+ * this class must ensure the following:
+ *
+ * - Each media graph contains at most one MediaObject instance.
+ * - Every non-MediaObject node holds a reference to the MediaObject. This
+ * allows commands to be sent through the graph to the encapsulated MMF client
+ * API.
*/
class MediaNode : public QObject
{
Q_OBJECT
public:
MediaNode(QObject *parent);
+ ~MediaNode();
+
+ bool connectOutput(MediaNode *output);
+ bool disconnectOutput(MediaNode *output);
+
+ virtual void connectMediaObject(MediaObject *mediaObject) = 0;
+ virtual void disconnectMediaObject(MediaObject *mediaObject) = 0;
- virtual bool connectMediaNode(MediaNode *target);
- virtual bool disconnectMediaNode(MediaNode *target);
- void setSource(MediaNode *source);
+private:
+ bool isMediaObject() const;
- MediaNode *source() const;
- MediaNode *target() const;
+ void updateMediaObject();
+ void setMediaObject(MediaObject *mediaObject);
-protected:
- /**
- * When connectMediaNode() is called and a MediaObject is part of
- * the its graph, this function will be called for each MediaNode in the
- * graph for which it hasn't been called yet.
- *
- * The caller guarantees that @p mo is always non-null.
- */
- virtual bool activateOnMediaObject(MediaObject *mo) = 0;
+ typedef QList<const MediaNode *> NodeList;
+ void visit(QList<MediaNode *>& visited, MediaObject*& mediaObject);
private:
- /**
- * Finds a MediaObject anywhere in the graph @p target is apart of, and
- * calls activateOnMediaObject() for all MediaNodes in the graph for which
- * it hasn't been applied to already.
- */
- bool applyNodesOnMediaObject(MediaNode *target);
-
- MediaNode * m_source;
- MediaNode * m_target;
- bool m_isApplied;
+ MediaObject * m_mediaObject;
+
+ // All nodes except MediaObject may have an input
+ MediaNode * m_input;
+
+ // Only MediaObject can have more than one output
+ QList<MediaNode *> m_outputs;
};
+
}
}
diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp
index b6f53ae..127edb4 100644
--- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp
+++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp
@@ -44,20 +44,8 @@ using namespace Phonon::MMF;
// Constructor / destructor
//-----------------------------------------------------------------------------
-MMF::VideoPlayer::VideoPlayer()
- : m_wsSession(CCoeEnv::Static()->WsSession())
- , m_screenDevice(*CCoeEnv::Static()->ScreenDevice())
- , m_window(0)
- , m_totalTime(0)
- , m_pendingChanges(false)
- , m_dsaActive(false)
- , m_dsaWasActive(false)
-{
- construct();
-}
-
-MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player)
- : AbstractMediaPlayer(player)
+MMF::VideoPlayer::VideoPlayer(MediaObject *parent, const AbstractPlayer *player)
+ : AbstractMediaPlayer(parent, player)
, m_wsSession(CCoeEnv::Static()->WsSession())
, m_screenDevice(*CCoeEnv::Static()->ScreenDevice())
, m_window(0)
@@ -78,22 +66,22 @@ void MMF::VideoPlayer::construct()
const TInt priority = 0;
const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;
- TRAPD(err,
- m_player.reset(CVideoPlayerUtility::NewL
+ CVideoPlayerUtility *player = 0;
+ QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL
(
*this,
priority, preference,
m_wsSession, m_screenDevice,
*m_window,
m_videoRect, m_videoRect
- ))
+ )
);
+ m_player.reset(player);
// CVideoPlayerUtility::NewL starts DSA
m_dsaActive = true;
- if (KErrNone != err)
- changeState(ErrorState);
+ m_player->RegisterForVideoLoadingNotification(*this);
TRACE_EXIT_0();
}
@@ -109,6 +97,11 @@ MMF::VideoPlayer::~VideoPlayer()
TRACE_EXIT_0();
}
+CVideoPlayerUtility* MMF::VideoPlayer::nativePlayer() const
+{
+ return m_player.data();
+}
+
//-----------------------------------------------------------------------------
// Public API
//-----------------------------------------------------------------------------
@@ -127,9 +120,9 @@ void MMF::VideoPlayer::doPause()
TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi);
TRAPD(err, m_player->PauseL());
- if (KErrNone != err) {
+ if (KErrNone != err && state() != ErrorState) {
TRACE("PauseL error %d", err);
- setError(NormalError);
+ setError(tr("Pause failed"), err);
}
}
@@ -142,24 +135,10 @@ void MMF::VideoPlayer::doSeek(qint64 ms)
{
TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi);
- bool wasPlaying = false;
- if (state() == PlayingState) {
- // The call to SetPositionL does not have any effect if playback is
- // ongoing, so we pause before seeking.
- doPause();
- wasPlaying = true;
- }
-
TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000)));
- if (KErrNone == err) {
- if (wasPlaying)
- doPlay();
- }
- else {
- TRACE("SetPositionL error %d", err);
- setError(NormalError);
- }
+ if(KErrNone != err)
+ setError(tr("Seek failed"), err);
}
int MMF::VideoPlayer::setDeviceVolume(int mmfVolume)
@@ -174,6 +153,19 @@ int MMF::VideoPlayer::openFile(RFile& file)
return err;
}
+int MMF::VideoPlayer::openUrl(const QString& url)
+{
+ TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url)));
+ return err;
+}
+
+int MMF::VideoPlayer::bufferStatus() const
+{
+ int result = 0;
+ TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result));
+ return result;
+}
+
void MMF::VideoPlayer::close()
{
m_player->Close();
@@ -200,7 +192,7 @@ qint64 MMF::VideoPlayer::currentTime() const
// If we don't cast away constness here, we simply have to ignore
// the error.
- const_cast<VideoPlayer*>(this)->setError(NormalError);
+ const_cast<VideoPlayer*>(this)->setError(tr("Getting position failed"), err);
}
return result;
@@ -226,7 +218,7 @@ void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError)
if (KErrNone == aError)
m_player->Prepare();
else
- setError(NormalError);
+ setError(tr("Opening clip failed"), aError);
TRACE_EXIT_0();
}
@@ -252,7 +244,7 @@ void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError)
emit totalTimeChanged(totalTime());
changeState(StoppedState);
} else {
- setError(NormalError);
+ setError(tr("Buffering clip failed"), err);
}
TRACE_EXIT_0();
@@ -277,7 +269,6 @@ void MMF::VideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError)
TRACE_CONTEXT(VideoPlayer::MvpuoFrameReady, EVideoApi);
TRACE_ENTRY("state %d error %d", state(), aError);
- // TODO
Q_UNUSED(aFrame);
Q_UNUSED(aError); // suppress warnings in release builds
@@ -289,8 +280,9 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError)
TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi)
TRACE_ENTRY("state %d error %d", state(), aError);
- Q_UNUSED(aError); // suppress warnings in release builds
- changeState(StoppedState);
+ // Call base class function which handles end of playback for both
+ // audio and video clips.
+ playbackComplete(aError);
TRACE_EXIT_0();
}
@@ -300,7 +292,6 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent)
TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi);
TRACE_ENTRY("state %d", state());
- // TODO
Q_UNUSED(aEvent);
TRACE_EXIT_0();
@@ -308,6 +299,21 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent)
//-----------------------------------------------------------------------------
+// MVideoLoadingObserver callbacks
+//-----------------------------------------------------------------------------
+
+void MMF::VideoPlayer::MvloLoadingStarted()
+{
+ bufferingStarted();
+}
+
+void MMF::VideoPlayer::MvloLoadingComplete()
+{
+ bufferingComplete();
+}
+
+
+//-----------------------------------------------------------------------------
// Video window updates
//-----------------------------------------------------------------------------
@@ -412,7 +418,7 @@ void MMF::VideoPlayer::startDirectScreenAccess()
if(KErrNone == err)
m_dsaActive = true;
else
- setError(NormalError);
+ setError(tr("Video display error"), err);
}
}
@@ -424,7 +430,7 @@ bool MMF::VideoPlayer::stopDirectScreenAccess()
if(KErrNone == err)
m_dsaActive = false;
else
- setError(NormalError);
+ setError(tr("Video display error"), err);
}
return dsaWasActive;
}
@@ -600,7 +606,7 @@ void MMF::VideoPlayer::applyVideoWindowChange()
TRAPD(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias));
if(KErrNone != err) {
TRACE("SetScaleFactorL (1) err %d", err);
- setError(NormalError);
+ setError(tr("Video display error"), err);
}
if(KErrNone == err) {
@@ -615,13 +621,13 @@ void MMF::VideoPlayer::applyVideoWindowChange()
if (KErrNone != err) {
TRACE("SetDisplayWindowL err %d", err);
- setError(NormalError);
+ setError(tr("Video display error"), err);
} else {
m_dsaActive = true;
TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias));
if(KErrNone != err) {
TRACE("SetScaleFactorL (2) err %d", err);
- setError(NormalError);
+ setError(tr("Video display error"), err);
}
}
}
diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h
index abb1da8..0253ab9 100644
--- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h
+++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h
@@ -39,14 +39,17 @@ namespace MMF
*/
class VideoPlayer : public AbstractMediaPlayer
, public MVideoPlayerUtilityObserver
+ , public MVideoLoadingObserver
{
Q_OBJECT
public:
- VideoPlayer();
- explicit VideoPlayer(const AbstractPlayer& player);
+ VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0);
virtual ~VideoPlayer();
+ typedef CVideoPlayerUtility NativePlayer;
+ NativePlayer *nativePlayer() const;
+
// AbstractPlayer
virtual void doPlay();
virtual void doPause();
@@ -54,6 +57,8 @@ public:
virtual void doSeek(qint64 milliseconds);
virtual int setDeviceVolume(int mmfVolume);
virtual int openFile(RFile& file);
+ virtual int openUrl(const QString& url);
+ virtual int bufferStatus() const;
virtual void close();
// MediaObjectInterface
@@ -61,12 +66,12 @@ public:
virtual qint64 currentTime() const;
virtual qint64 totalTime() const;
- // MVideoPlayerUtilityObserver
- virtual void MvpuoOpenComplete(TInt aError);
- virtual void MvpuoPrepareComplete(TInt aError);
- virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError);
- virtual void MvpuoPlayComplete(TInt aError);
- virtual void MvpuoEvent(const TMMFEvent &aEvent);
+ // AbstractPlayer
+ virtual void videoOutputChanged();
+
+ // AbstractMediaPlayer
+ virtual int numberOfMetaDataEntries() const;
+ virtual QPair<QString, QString> metaDataEntry(int index) const;
public Q_SLOTS:
void videoWindowChanged();
@@ -80,12 +85,8 @@ private:
void doPrepareCompleteL(TInt aError);
- // AbstractPlayer
- virtual void videoOutputChanged();
-
void getVideoWindow();
void initVideoOutput();
-
void updateVideoRect();
void applyPendingChanges();
@@ -94,12 +95,20 @@ private:
void startDirectScreenAccess();
bool stopDirectScreenAccess();
- // AbstractMediaPlayer
- virtual int numberOfMetaDataEntries() const;
- virtual QPair<QString, QString> metaDataEntry(int index) const;
+private:
+ // MVideoPlayerUtilityObserver
+ virtual void MvpuoOpenComplete(TInt aError);
+ virtual void MvpuoPrepareComplete(TInt aError);
+ virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError);
+ virtual void MvpuoPlayComplete(TInt aError);
+ virtual void MvpuoEvent(const TMMFEvent &aEvent);
+
+ // MVideoLoadingObserver
+ virtual void MvloLoadingStarted();
+ virtual void MvloLoadingComplete();
private:
- QScopedPointer<CVideoPlayerUtility> m_player;
+ QScopedPointer<NativePlayer> m_player;
// Not owned
RWsSession& m_wsSession;
diff --git a/src/3rdparty/phonon/mmf/objectdump.cpp b/src/3rdparty/phonon/mmf/objectdump.cpp
index 3d10be4..778cde9 100644
--- a/src/3rdparty/phonon/mmf/objectdump.cpp
+++ b/src/3rdparty/phonon/mmf/objectdump.cpp
@@ -390,7 +390,7 @@ void QVisitorPrivate::dumpNode
// No annotations - just dump the object pointer
const bool isNodeLine = true;
QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild);
- qDebug() << 0; // TODO
+ qDebug() << 0;
}
else {
// Dump annotations
diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp
index d728fcf..2d17bd2 100644
--- a/src/3rdparty/phonon/mmf/utils.cpp
+++ b/src/3rdparty/phonon/mmf/utils.cpp
@@ -18,6 +18,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "utils.h"
#include <e32std.h>
+#include <mmf/common/mmferrors.h>
QT_BEGIN_NAMESPACE
@@ -69,6 +70,101 @@ MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType)
return result;
}
+QString MMF::Utils::symbianErrorToString(int errorCode)
+{
+ /**
+ * Here we translate only the error codes which are likely to be
+ * meaningful to the user. For example, when an error occurs
+ * during opening of a media file, displaying "not found" or
+ * "permission denied" is informative. On the other hand,
+ * differentiating between KErrGeneral and KErrArgument at the UI
+ * level does not make sense.
+ */
+ switch (errorCode)
+ {
+ // System-wide errors
+ case KErrNone:
+ return tr("No error");
+ case KErrNotFound:
+ return tr("Not found");
+ case KErrNoMemory:
+ return tr("Out of memory");
+ case KErrNotSupported:
+ return tr("Not supported");
+ case KErrOverflow:
+ return tr("Overflow");
+ case KErrUnderflow:
+ return tr("Underflow");
+ case KErrAlreadyExists:
+ return tr("Already exists");
+ case KErrPathNotFound:
+ return tr("Path not found");
+ case KErrInUse:
+ return tr("In use");
+ case KErrNotReady:
+ return tr("Not ready");
+ case KErrAccessDenied:
+ return tr("Access denied");
+ case KErrCouldNotConnect:
+ return tr("Could not connect");
+ case KErrDisconnected:
+ return tr("Disconnected");
+ case KErrPermissionDenied:
+ return tr("Permission denied");
+
+ // Multimedia framework errors
+ case KErrMMNotEnoughBandwidth:
+ return tr("Insufficient bandwidth");
+ case KErrMMSocketServiceNotFound:
+ case KErrMMServerSocket:
+ return tr("Network unavailable");
+ case KErrMMNetworkRead:
+ case KErrMMNetworkWrite:
+ case KErrMMUDPReceive:
+ return tr("Network communication error");
+ case KErrMMServerNotSupported:
+ return tr("Streaming not supported");
+ case KErrMMServerAlert:
+ return tr("Server alert");
+ case KErrMMInvalidProtocol:
+ return tr("Invalid protocol");
+ case KErrMMInvalidURL:
+ return tr("Invalid URL");
+ case KErrMMMulticast:
+ return tr("Multicast error");
+ case KErrMMProxyServer:
+ case KErrMMProxyServerConnect:
+ return tr("Proxy server error");
+ case KErrMMProxyServerNotSupported:
+ return tr("Proxy server not supported");
+ case KErrMMAudioDevice:
+ return tr("Audio output error");
+ case KErrMMVideoDevice:
+ return tr("Video output error");
+ case KErrMMDecoder:
+ return tr("Decoder error");
+ case KErrMMPartialPlayback:
+ return tr("Audio or video components could not be played");
+ case KErrMMDRMNotAuthorized:
+ return tr("DRM error");
+
+ /*
+ // We don't use QoS settings
+ case KErrMMQosLowBandwidth:
+ case KErrMMQosUnsupportedTrafficClass:
+ case KErrMMQosPoorTrafficClass:
+ case KErrMMQosUnsupportedParameters:
+ case KErrMMQosPoorParameters:
+ case KErrMMQosNotSupported:
+ */
+
+ // Catch-all for errors other than those above
+ default:
+ {
+ return tr("Unknown error (%1)").arg(errorCode);
+ }
+ }
+}
#ifndef QT_NO_DEBUG
diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h
index 7e363e8..56ccafc 100644
--- a/src/3rdparty/phonon/mmf/utils.h
+++ b/src/3rdparty/phonon/mmf/utils.h
@@ -21,7 +21,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <private/qcore_symbian_p.h>
#include <e32debug.h> // for RDebug
-
+#include <QtCore/QCoreApplication> // for Q_DECLARE_TR_FUNCTIONS
#include <QColor>
#include "defs.h"
@@ -38,35 +38,44 @@ namespace MMF
enum PanicCode {
InvalidStatePanic = 1,
InvalidMediaTypePanic = 2,
- InvalidBackendInterfaceClass = 3
+ InvalidBackendInterfaceClass = 3,
+ AudioUtilityUrlNotSupported = 4
};
-namespace Utils
+class Utils
{
+ Q_DECLARE_TR_FUNCTIONS(Utils)
+
+public:
/**
* Raise a fatal exception
*/
-void panic(PanicCode code);
+static void panic(PanicCode code);
/**
* Determines whether the provided MIME type is an audio or video
* type. If it is neither, the function returns MediaTypeUnknown.
*/
-MediaType mimeTypeToMediaType(const TDesC& mimeType);
+static MediaType mimeTypeToMediaType(const TDesC& mimeType);
+
+/**
+ * Translates a Symbian error code into a user-readable string.
+ */
+static QString symbianErrorToString(int errorCode);
#ifndef QT_NO_DEBUG
/**
* Retrieve color of specified pixel from the screen.
*/
-QColor getScreenPixel(const QPoint& pos);
+static QColor getScreenPixel(const QPoint& pos);
/**
* Samples a small number of pixels from the screen, and dumps their
* colors to the debug log.
*/
-void dumpScreenPixelSample();
+static void dumpScreenPixelSample();
#endif
-}
+};
/**
* Available trace categories;
diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp
index bd22307..bc9acfd 100644
--- a/src/3rdparty/phonon/mmf/videowidget.cpp
+++ b/src/3rdparty/phonon/mmf/videowidget.cpp
@@ -157,10 +157,18 @@ QWidget* MMF::VideoWidget::widget()
return m_videoOutput.data();
}
-bool MMF::VideoWidget::activateOnMediaObject(MediaObject *mo)
+//-----------------------------------------------------------------------------
+// MediaNode
+//-----------------------------------------------------------------------------
+
+void MMF::VideoWidget::connectMediaObject(MediaObject *mediaObject)
+{
+ mediaObject->setVideoOutput(m_videoOutput.data());
+}
+
+void MMF::VideoWidget::disconnectMediaObject(MediaObject *mediaObject)
{
- mo->setVideoOutput(m_videoOutput.data());
- return true;
+ mediaObject->setVideoOutput(0);
}
QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h
index 2f0978b..a876748 100644
--- a/src/3rdparty/phonon/mmf/videowidget.h
+++ b/src/3rdparty/phonon/mmf/videowidget.h
@@ -61,7 +61,9 @@ public:
virtual QWidget *widget();
protected:
- virtual bool activateOnMediaObject(MediaObject *mo);
+ // MediaNode
+ void connectMediaObject(MediaObject *mediaObject);
+ void disconnectMediaObject(MediaObject *mediaObject);
private:
QScopedPointer<VideoOutput> m_videoOutput;
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 0ee9cd2..c40308c 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -511,6 +511,7 @@ public:
AA_MacPluginApplication = 5,
AA_DontUseNativeMenuBar = 6,
AA_MacDontSwapCtrlAndMeta = 7,
+ AA_S60DontConstructApplicationPanes = 8,
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 7ee7a76..5a80d56 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -134,7 +134,6 @@
\value AA_DontShowIconsInMenus Actions with the Icon property won't be
shown in any menus unless specifically set by the
QAction::iconVisibleInMenu property.
-
Menus that are currently open or menus already created in the native
Mac OS X menubar \e{may not} pick up a change in this attribute. Changes
in the QAction::iconVisibleInMenu property will always be picked up.
@@ -164,6 +163,12 @@
Command+C on the keyboard regardless of the value set, though what is output for
QKeySequence::toString(QKeySequence::PortableText) will be different).
+ \value AA_S60DontConstructApplicationPanes Stops Qt from initializing the S60 status
+ pane and softkey pane on Symbian. This is useful to save memory and reduce
+ startup time for applications that will run in fullscreen mode during their
+ whole lifetime. This attribute must be set before QApplication is
+ constructed.
+
\omitvalue AA_AttributeCount
*/
diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp
index ed2d676..d7653e5 100644
--- a/src/gui/dialogs/qdialog.cpp
+++ b/src/gui/dialogs/qdialog.cpp
@@ -888,7 +888,14 @@ bool QDialog::s60AdjustedPosition()
if (doS60Positioning) {
// naive way to deduce screen orientation
if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
- p.setY(S60->screenHeightInPixels-height()-qt_TSize2QSize(S60->buttonGroupContainer()->Size()).height());
+ int cbaHeight;
+ const CEikButtonGroupContainer* bgContainer = S60->buttonGroupContainer();
+ if (!bgContainer) {
+ cbaHeight = 0;
+ } else {
+ cbaHeight = qt_TSize2QSize(bgContainer->Size()).height();
+ }
+ p.setY(S60->screenHeightInPixels-height()-cbaHeight);
p.setX(0);
} else {
const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index 27f2644..aee4324 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -930,7 +930,7 @@ void QSymbianControl::PositionChanged()
void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
{
- if (m_ignoreFocusChanged)
+ if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
return;
// Popups never get focused, but still receive the FocusChanged when they are hidden.
diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp
index 0e98f39..b09ab8f 100644
--- a/src/gui/kernel/qsoftkeymanager.cpp
+++ b/src/gui/kernel/qsoftkeymanager.cpp
@@ -211,7 +211,8 @@ bool QSoftKeyManager::event(QEvent *e)
void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys)
{
// lets not update softkeys if s60 native dialog or menu is shown
- if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog())
+ if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
+ || CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog())
return;
CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer();
diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp
index 6f4f398..c5840f1 100644
--- a/src/gui/painting/qpaintengine_s60.cpp
+++ b/src/gui/painting/qpaintengine_s60.cpp
@@ -47,18 +47,25 @@ QT_BEGIN_NAMESPACE
class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate
{
public:
- QS60PaintEnginePrivate(QS60PaintEngine *engine) { Q_UNUSED(engine); }
+ QS60PaintEnginePrivate() {}
};
QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data)
- : QRasterPaintEngine(*(new QS60PaintEnginePrivate(this)), device), pixmapData(data)
+ : QRasterPaintEngine(*(new QS60PaintEnginePrivate), device), pixmapData(data)
{
}
bool QS60PaintEngine::begin(QPaintDevice *device)
{
+ Q_D(QS60PaintEngine);
+
pixmapData->beginDataAccess();
- return QRasterPaintEngine::begin(device);
+ bool ret = QRasterPaintEngine::begin(device);
+ // Make sure QPaintEngine::paintDevice() returns the proper device.
+ // QRasterPaintEngine changes pdev to QImage in case of RasterClass QPixmapData
+ // which is incorrect in Symbian.
+ d->pdev = device;
+ return ret;
}
bool QS60PaintEngine::end()
diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp
index 4c4c994..4813fb2 100644
--- a/src/gui/s60framework/qs60mainappui.cpp
+++ b/src/gui/s60framework/qs60mainappui.cpp
@@ -104,10 +104,16 @@ void QS60MainAppUi::ConstructL()
// ENoAppResourceFile and ENonStandardResourceFile makes UI to work without
// resource files in most SDKs. S60 3rd FP1 public seems to require resource file
// even these flags are defined
- BaseConstructL(CAknAppUi::EAknEnableSkin);
+ TInt flags = CAknAppUi::EAknEnableSkin;
+ if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)) {
+ flags |= CAknAppUi::ENoScreenFurniture | CAknAppUi::ENonStandardResourceFile;
+ }
+ BaseConstructL(flags);
- CEikButtonGroupContainer* nativeContainer = Cba();
- nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
+ if (!QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)) {
+ CEikButtonGroupContainer* nativeContainer = Cba();
+ nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
+ }
}
/*!
diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro
index e024396..eb35419 100644
--- a/src/s60installs/s60installs.pro
+++ b/src/s60installs/s60installs.pro
@@ -35,10 +35,8 @@ symbian: {
qtlibraries.pkg_postrules += qts60plugindeployment
sqlitedeployment = \
- "; Deploy sqlite onto phone that does not have it (this should be replaced with embedded sis file when available)" \
- "IF NOT package(0x2002533b) " \
- "\"$${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/sqlite3.dll\" - \"c:\\sys\\bin\\sqlite3.dll\"" \
- "ENDIF"
+ "; Deploy sqlite onto phone that does not have it already" \
+ "@\"sqlite3.sis\", (0x2002af5f)"
qtlibraries.pkg_postrules += sqlitedeployment
qtlibraries.path = c:/sys/bin
@@ -61,6 +59,7 @@ symbian: {
contains(CONFIG, stl) {
qtlibraries.pkg_prerules += "(0x2000F866), 1, 0, 0, {\"Standard C++ Library Common\"}"
}
+ qtlibraries.pkg_prerules += "(0x2002af5f), 0, 5, 0, {\"sqlite3\"}"
!contains(QT_CONFIG, no-jpeg): imageformats_plugins.sources += qjpeg.dll
!contains(QT_CONFIG, no-gif): imageformats_plugins.sources += qgif.dll
diff --git a/src/s60installs/sqlite3.sis b/src/s60installs/sqlite3.sis
new file mode 100644
index 0000000..1785365
--- /dev/null
+++ b/src/s60installs/sqlite3.sis
Binary files differ
diff --git a/tests/auto/qapplication/heart.svg b/tests/auto/qapplication/heart.svg
new file mode 100644
index 0000000..8c982cd
--- /dev/null
+++ b/tests/auto/qapplication/heart.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="841.88976pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
+<metadata>
+<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<cc:Work rdf:about="">
+<dc:title>Heart Left-Highlight</dc:title>
+<dc:description>This is a normal valentines day heart.</dc:description>
+<dc:subject>
+<rdf:Bag>
+<rdf:li>holiday</rdf:li>
+<rdf:li>valentines</rdf:li>
+<rdf:li></rdf:li>
+<rdf:li>valentine</rdf:li>
+<rdf:li>hash(0x8a091c0)</rdf:li>
+<rdf:li>hash(0x8a0916c)</rdf:li>
+<rdf:li>signs_and_symbols</rdf:li>
+<rdf:li>hash(0x8a091f0)</rdf:li>
+<rdf:li>day</rdf:li>
+</rdf:Bag>
+</dc:subject>
+<dc:publisher>
+<cc:Agent rdf:about="http://www.openclipart.org">
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:publisher>
+<dc:creator>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:creator>
+<dc:rights>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:rights>
+<dc:date></dc:date>
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
+<dc:language>en</dc:language>
+</cc:Work>
+<cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
+<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
+</cc:License>
+</rdf:RDF>
+</metadata>
+<defs id="defs3"/>
+<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/>
+<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
+<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+</g>
+</svg>
diff --git a/tests/auto/qapplication/test/test.pro b/tests/auto/qapplication/test/test.pro
index 7c3de3c..e68af26 100644
--- a/tests/auto/qapplication/test/test.pro
+++ b/tests/auto/qapplication/test/test.pro
@@ -16,7 +16,9 @@ symbian*: {
additional.path = desktopsettingsaware
someTest.sources = test.pro
someTest.path = test
- DEPLOYMENT = additional deploy someTest
+ windowIcon.sources = ../heart.svg
+ DEPLOYMENT = additional deploy someTest windowIcon
+ LIBS += -lcone -lavkon
}
win32 {
diff --git a/tests/auto/qapplication/tst_qapplication.cpp b/tests/auto/qapplication/tst_qapplication.cpp
index 5888866..ed614e15 100644
--- a/tests/auto/qapplication/tst_qapplication.cpp
+++ b/tests/auto/qapplication/tst_qapplication.cpp
@@ -53,6 +53,9 @@
#ifdef Q_OS_WINCE
#include <windows.h>
#endif
+#ifdef Q_OS_SYMBIAN
+#include <aknenv.h>
+#endif
//TESTED_CLASS=
//TESTED_FILES=
@@ -138,6 +141,8 @@ private slots:
void touchEventPropagation();
+ void symbianNoApplicationPanes();
+
void symbianNeedForTraps();
void symbianLeaveThroughMain();
};
@@ -2036,6 +2041,89 @@ void tst_QApplication::touchEventPropagation()
}
}
+void tst_QApplication::symbianNoApplicationPanes()
+{
+#ifndef Q_OS_SYMBIAN
+ QSKIP("This is a Symbian only test", SkipAll);
+#else
+ QApplication::setAttribute(Qt::AA_S60DontConstructApplicationPanes);
+
+ // Run in a block so that QApplication is destroyed before resetting the attribute.
+ {
+ // Actually I wasn't able to get the forced orientation change to work properly,
+ // but I'll leave the code here for the future in case we manage to test that
+ // later. If someone knows how to force an orientation switch in an autotest, do
+ // feel free to fix this testcase.
+ int argc = 0;
+ QApplication app(argc, 0);
+ QWidget *w;
+
+ w = new QWidget;
+ w->show();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape));
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->show();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait));
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->showMaximized();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape));
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->showMaximized();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait));
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->showFullScreen();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape));
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->showFullScreen();
+ QT_TRAP_THROWING(static_cast<CAknAppUi *>(CCoeEnv::Static()->AppUi())
+ ->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait));
+ app.processEvents();
+ delete w;
+
+ // These will have no effect, since there is no status pane, but they shouldn't
+ // crash either.
+ w = new QWidget;
+ w->show();
+ w->setWindowTitle("Testing title");
+ app.processEvents();
+ delete w;
+
+ w = new QWidget;
+ w->show();
+ w->setWindowIcon(QIcon(QPixmap("heart.svg")));
+ app.processEvents();
+ delete w;
+
+ QDesktopWidget desktop;
+ QCOMPARE(desktop.availableGeometry(), desktop.screenGeometry());
+ }
+
+ QApplication::setAttribute(Qt::AA_S60DontConstructApplicationPanes, false);
+
+ // No other error condition. Program will crash if unsuccessful.
+#endif
+}
+
#ifdef Q_OS_SYMBIAN
class CBaseDummy : public CBase
{
diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp
index e2f6758..6081e67 100644
--- a/tools/runonphone/main.cpp
+++ b/tools/runonphone/main.cpp
@@ -155,6 +155,10 @@ int main(int argc, char *argv[])
serialPortName = id.portName;
}
}
+ if(serialPortName.isEmpty()) {
+ errstream << "No phone found, ensure USB cable is connected or specify manually with -p" << endl;
+ return 1;
+ }
}
QScopedPointer<trk::Launcher> launcher;
diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro
index d243121..cf0c055 100644
--- a/tools/runonphone/runonphone.pro
+++ b/tools/runonphone/runonphone.pro
@@ -15,5 +15,6 @@ HEADERS += trksignalhandler.h \
windows {
SOURCES += serenum_win.cpp
LIBS += -lsetupapi \
- -luuid
+ -luuid \
+ -ladvapi32
}
diff --git a/tools/runonphone/serenum_win.cpp b/tools/runonphone/serenum_win.cpp
index ec11c3c..23e3862 100644
--- a/tools/runonphone/serenum_win.cpp
+++ b/tools/runonphone/serenum_win.cpp
@@ -77,8 +77,7 @@ QList<SerialPortId> enumerateSerialPorts()
}
HKEY key = SetupDiOpenDevRegKey(infoset, &info, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if(key != INVALID_HANDLE_VALUE) {
-#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
- //RegGetValue not supported on XP, SHRegGetValue not supported by mingw :(
+ //RegGetValue not supported on XP, SHRegGetValue not supported by mingw, so use the old method of enumerating all the values
for (DWORD dwi=0;;dwi++) {
DWORD vsize = valueName.size();
if (ERROR_SUCCESS == RegEnumValue(key, dwi, (WCHAR*)(valueName.data()), &vsize, 0, 0, 0, &size)) {
@@ -93,14 +92,6 @@ QList<SerialPortId> enumerateSerialPorts()
break;
}
}
-#else
- if (ERROR_SUCCESS == SHRegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, 0, &size)) {
- QByteArray ba(size, 0);
- if (ERROR_SUCCESS == RegGetValue(key, 0, "PortName", SRRF_RT_REG_SZ, (BYTE*)(ba.data()), &size)) {
- portName = QString((const QChar*)(ba.constData()), ba.size() / 2 - 1);
- }
- }
-#endif
RegCloseKey(key);
}
SerialPortId id;