summaryrefslogtreecommitdiffstats
path: root/tests/auto/mediaobject
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit356978ecce23e076e1b622d5d41dd8c04bf7bcf8 (patch)
tree8e1874cc32750e30b84b2561387d48424e076ae3 /tests/auto/mediaobject
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/mediaobject')
-rw-r--r--tests/auto/mediaobject/.gitignore1
-rw-r--r--tests/auto/mediaobject/dummy/README1
-rw-r--r--tests/auto/mediaobject/dummy/audiooutput.cpp94
-rw-r--r--tests/auto/mediaobject/dummy/audiooutput.h82
-rw-r--r--tests/auto/mediaobject/dummy/backend.cpp190
-rw-r--r--tests/auto/mediaobject/dummy/backend.h96
-rw-r--r--tests/auto/mediaobject/dummy/dummy.pro23
-rw-r--r--tests/auto/mediaobject/dummy/mediaobject.cpp438
-rw-r--r--tests/auto/mediaobject/dummy/mediaobject.h210
-rw-r--r--tests/auto/mediaobject/dummy/videowidget.cpp246
-rw-r--r--tests/auto/mediaobject/dummy/videowidget.h111
-rw-r--r--tests/auto/mediaobject/media/sax.mp3bin0 -> 417844 bytes
-rw-r--r--tests/auto/mediaobject/media/sax.oggbin0 -> 358374 bytes
-rw-r--r--tests/auto/mediaobject/media/sax.wavbin0 -> 756236 bytes
-rw-r--r--tests/auto/mediaobject/media/test.sdp32
-rwxr-xr-xtests/auto/mediaobject/mediaobject.pro24
-rw-r--r--tests/auto/mediaobject/mediaobject.qrc8
-rw-r--r--tests/auto/mediaobject/qtesthelper.h222
-rw-r--r--tests/auto/mediaobject/tst_mediaobject.cpp1220
19 files changed, 2998 insertions, 0 deletions
diff --git a/tests/auto/mediaobject/.gitignore b/tests/auto/mediaobject/.gitignore
new file mode 100644
index 0000000..2b4d356
--- /dev/null
+++ b/tests/auto/mediaobject/.gitignore
@@ -0,0 +1 @@
+tst_mediaobject
diff --git a/tests/auto/mediaobject/dummy/README b/tests/auto/mediaobject/dummy/README
new file mode 100644
index 0000000..43f69d9
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/README
@@ -0,0 +1 @@
+This is a dummy backend for phonon, used for testing purposes.
diff --git a/tests/auto/mediaobject/dummy/audiooutput.cpp b/tests/auto/mediaobject/dummy/audiooutput.cpp
new file mode 100644
index 0000000..2645e20
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/audiooutput.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "audiooutput.h"
+#include "backend.h"
+#include <phonon/audiooutput.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Dummy
+{
+AudioOutput::AudioOutput(Backend *backend, QObject *parent)
+ : QObject(parent)
+{
+ Q_UNUSED(backend)
+
+ m_volumeLevel = 100;
+}
+
+AudioOutput::~AudioOutput()
+{
+}
+
+qreal AudioOutput::volume() const
+{
+ return m_volumeLevel;
+}
+
+int AudioOutput::outputDevice() const
+{
+ return m_device;
+}
+
+void AudioOutput::setVolume(qreal newVolume)
+{
+ m_volumeLevel = newVolume;
+ emit volumeChanged(newVolume);
+}
+
+bool AudioOutput::setOutputDevice(int newDevice)
+{
+ return (newDevice == 0);
+}
+
+bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
+{
+ return setOutputDevice(newDevice.index());
+}
+
+}
+} //namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+#include "moc_audiooutput.cpp"
diff --git a/tests/auto/mediaobject/dummy/audiooutput.h b/tests/auto/mediaobject/dummy/audiooutput.h
new file mode 100644
index 0000000..4acdd8a
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/audiooutput.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PHONON_DUMMY_AUDIOOUTPUT_H
+#define PHONON_DUMMY_AUDIOOUTPUT_H
+
+#include "backend.h"
+#include <phonon/audiooutputinterface.h>
+#include <phonon/phononnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Dummy
+{
+class AudioOutput : public QObject, public AudioOutputInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::AudioOutputInterface)
+public:
+ AudioOutput(Backend *backend, QObject *parent);
+ ~AudioOutput();
+
+ qreal volume() const;
+ int outputDevice() const;
+ void setVolume(qreal newVolume);
+ bool setOutputDevice(int newDevice);
+ bool setOutputDevice(const AudioOutputDevice &newDevice);
+
+Q_SIGNALS:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+private:
+ qreal m_volumeLevel;
+ int m_device;
+};
+}
+} //namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+
+#endif // PHONON_DUMMY_AUDIOOUTPUT_H
diff --git a/tests/auto/mediaobject/dummy/backend.cpp b/tests/auto/mediaobject/dummy/backend.cpp
new file mode 100644
index 0000000..1db89cc
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/backend.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+#include "videowidget.h"
+
+#include "backend.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+#include <QtCore/QtPlugin>
+
+QT_BEGIN_NAMESPACE
+
+Q_EXPORT_PLUGIN2(phonon_dummy, Phonon::Dummy::Backend)
+
+namespace Phonon
+{
+namespace Dummy
+{
+
+Backend::Backend(QObject *parent, const QVariantList &)
+ : QObject(parent)
+{
+ qWarning()<<"Using TEST Phonon backend";
+}
+
+Backend::~Backend()
+{
+}
+
+/***
+ * !reimp
+ */
+QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+{
+ Q_UNUSED(args)
+
+ switch (c) {
+ case MediaObjectClass:
+ return new MediaObject(this, parent);
+
+ case AudioOutputClass: {
+ AudioOutput *ao = new AudioOutput(this, parent);
+ m_audioOutputs.append(ao);
+ return ao;
+ }
+ case VideoWidgetClass: {
+ QWidget *widget = qobject_cast<QWidget*>(parent);
+ return new VideoWidget(this, widget);
+ }
+ default:
+ qWarning("createObject() : Backend object not available");
+ }
+ return 0;
+}
+
+/***
+ * !reimp
+ */
+QStringList Backend::availableMimeTypes() const
+{
+ QStringList availableMimeTypes;
+ // audio *.wav and *.mp3 files
+ availableMimeTypes << QLatin1String("audio/x-mp3");
+ availableMimeTypes << QLatin1String("audio/x-wav");
+
+ // video *.ogv, *.mp4, *.avi (some)
+
+ availableMimeTypes << QLatin1String("video/mpeg");
+ availableMimeTypes << QLatin1String("video/ogg");
+ availableMimeTypes << QLatin1String("video/mp4");
+
+ return availableMimeTypes;
+}
+
+/***
+ * !reimp
+ */
+QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
+{
+ QList<int> list;
+
+ if(type == Phonon::AudioOutputDeviceType)
+ list.append(0);
+
+ return list;
+}
+
+/***
+ * !reimp
+ */
+QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
+{
+ Q_UNUSED(index);
+ QHash<QByteArray, QVariant> ret;
+
+ if(type == Phonon::AudioOutputDeviceType)
+ ret["name"] = QLatin1String("default audio device");
+
+ return ret;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::startConnectionChange(QSet<QObject *> objects)
+{
+ Q_UNUSED(objects)
+
+ return true;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::connectNodes(QObject *source, QObject *sink)
+{
+ Q_UNUSED(source)
+ Q_UNUSED(sink)
+
+ return true;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::disconnectNodes(QObject *source, QObject *sink)
+{
+ Q_UNUSED(source)
+ Q_UNUSED(sink)
+
+ return true;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::endConnectionChange(QSet<QObject *> objects)
+{
+ Q_UNUSED(objects)
+
+ return true;
+}
+
+}
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
diff --git a/tests/auto/mediaobject/dummy/backend.h b/tests/auto/mediaobject/dummy/backend.h
new file mode 100644
index 0000000..40833ea
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/backend.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PHONON_DUMMY_BACKEND_H
+#define PHONON_DUMMY_BACKEND_H
+
+#include <phonon/objectdescription.h>
+#include <phonon/backendinterface.h>
+
+#include <phonon/medianode.h>
+
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+#include <QtCore/QStringList>
+#include <QtCore/QTimer>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Dummy
+{
+class AudioOutput;
+class MediaObject;
+
+class Backend : public QObject, public BackendInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+
+public:
+ Backend(QObject *parent = 0, const QVariantList & = QVariantList());
+ virtual ~Backend();
+
+ QObject *createObject(BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+
+ QStringList availableMimeTypes() const;
+
+ QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const;
+
+ bool startConnectionChange(QSet<QObject *>);
+ bool connectNodes(QObject *, QObject *);
+ bool disconnectNodes(QObject *, QObject *);
+ bool endConnectionChange(QSet<QObject *>);
+
+Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+private:
+ QList<QPointer<AudioOutput> > m_audioOutputs;
+};
+}
+} // namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+
+#endif // PHONON_DUMMY_BACKEND_H
diff --git a/tests/auto/mediaobject/dummy/dummy.pro b/tests/auto/mediaobject/dummy/dummy.pro
new file mode 100644
index 0000000..9797500
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/dummy.pro
@@ -0,0 +1,23 @@
+TEMPLATE = lib
+
+isEmpty(QT_MAJOR_VERSION) {
+ VERSION=4.7.4
+} else {
+ VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION}
+}
+CONFIG += qt plugin
+
+TARGET = phonon_dummy
+DESTDIR = $$QT_BUILD_TREE/plugins/phonon_backend
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT += phonon
+
+
+# Input
+HEADERS += backend.h audiooutput.h mediaobject.h videowidget.h
+SOURCES += backend.cpp audiooutput.cpp mediaobject.cpp videowidget.cpp
+
+target.path = $$[QT_INSTALL_PLUGINS]/phonon_backend
+INSTALLS += target
diff --git a/tests/auto/mediaobject/dummy/mediaobject.cpp b/tests/auto/mediaobject/dummy/mediaobject.cpp
new file mode 100644
index 0000000..98ab94f
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/mediaobject.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mediaobject.h"
+#include "backend.h"
+
+#include <QtCore>
+#include <QtCore/QTimer>
+#include <QtCore/QVector>
+#include <QtCore/QFile>
+#include <QtCore/QByteRef>
+#include <QtCore/QStringList>
+#include <QtCore/QEvent>
+#include <QApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Dummy
+{
+
+static const char* riffId = "RIFF";
+
+MediaObject::MediaObject(Backend *backend, QObject *parent)
+ : QObject(parent)
+ , m_resumeState(false)
+ , m_oldState(Phonon::LoadingState)
+ , m_oldPos(0)
+ , currentPos(0)
+{
+ Q_UNUSED(backend)
+
+ m_error = Phonon::NoError;
+ m_tickInterval = 100; // 100ms
+ m_totalTime = 26000; // 26s
+ m_prefinishMark = 0;
+ m_transitionTime = 100; //100ms
+ m_hasVideo = false;
+ m_prefinishMarkReachedNotEmitted = true;
+ m_aboutToFinishEmitted = false;
+ m_pendingState = Phonon::LoadingState;
+ m_state = Phonon::LoadingState;
+ m_pendingState = Phonon::LoadingState;
+ m_tickTimer = new QTimer(this);
+ connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
+}
+
+MediaObject::~MediaObject()
+{
+ delete m_tickTimer;
+}
+
+QString stateString(const Phonon::State &state)
+{
+ switch (state) {
+ case Phonon::LoadingState:
+ return QString("LoadingState");
+ case Phonon::StoppedState:
+ return QString("StoppedState");
+ case Phonon::PlayingState:
+ return QString("PlayingState");
+ case Phonon::BufferingState:
+ return QString("BufferingState");
+ case Phonon::PausedState:
+ return QString("PausedState");
+ case Phonon::ErrorState:
+ return QString("ErrorState");
+ }
+ return QString();
+}
+
+void MediaObject::saveState()
+{
+ if (m_resumeState)
+ return;
+
+ if (m_pendingState == Phonon::PlayingState || m_pendingState == Phonon::PausedState) {
+ m_resumeState = true;
+ m_oldState = m_pendingState;
+ m_oldPos = currentPos;
+ }
+}
+
+void MediaObject::resumeState()
+{
+ if (m_resumeState)
+ QMetaObject::invokeMethod(this, "setState", Qt::QueuedConnection, Q_ARG(State, m_oldState));
+}
+
+/**
+ * !reimp
+ */
+State MediaObject::state() const
+{
+ return m_state;
+}
+
+/**
+ * !reimp
+ */
+bool MediaObject::hasVideo() const
+{
+ return m_hasVideo;
+}
+
+/**
+ * !reimp
+ */
+bool MediaObject::isSeekable() const
+{
+ return true;
+}
+
+/**
+ * !reimp
+ */
+qint64 MediaObject::currentTime() const
+{
+ if (m_resumeState)
+ return m_oldPos;
+
+ switch (state()) {
+ case Phonon::PausedState:
+ case Phonon::BufferingState:
+ case Phonon::PlayingState:
+ return currentPos;
+ case Phonon::StoppedState:
+ case Phonon::LoadingState:
+ return 0;
+ case Phonon::ErrorState:
+ break;
+ }
+ return -1;
+}
+
+/**
+ * !reimp
+ */
+qint32 MediaObject::tickInterval() const
+{
+ return m_tickInterval;
+}
+
+/**
+ * !reimp
+ */
+void MediaObject::setTickInterval(qint32 newTickInterval)
+{
+ m_tickInterval = newTickInterval;
+ if (m_tickInterval <= 0) {
+ m_tickTimer->setInterval(100);
+ } else
+ m_tickTimer->setInterval(newTickInterval);
+}
+
+/**
+ * !reimp
+ */
+void MediaObject::play()
+{
+ if(m_state == Phonon::PlayingState)
+ return;
+ if(m_state == Phonon::ErrorState)
+ return;
+
+ if(m_state != Phonon::PausedState)
+ m_tickTimer->stop();
+
+ m_prefinishMarkReachedNotEmitted = true;
+ m_aboutToFinishEmitted = false;
+
+ setState(Phonon::PlayingState);
+ m_resumeState = false;
+ m_tickTimer->start();
+}
+
+/**
+ * !reimp
+ */
+QString MediaObject::errorString() const
+{
+ return m_errorString;
+}
+
+/**
+ * !reimp
+ */
+Phonon::ErrorType MediaObject::errorType() const
+{
+ return m_error;
+}
+
+void MediaObject::setState(State newstate)
+{
+ if (m_state == newstate)
+ return;
+
+ switch (newstate) {
+ case Phonon::PausedState:
+ m_pendingState = Phonon::PausedState;
+ emit stateChanged(newstate, m_state);
+ m_state = newstate;
+ break;
+ case Phonon::StoppedState:
+ m_pendingState = Phonon::StoppedState;
+ emit stateChanged(newstate, m_state);
+ m_state = newstate;
+ break;
+ case Phonon::PlayingState:
+ m_pendingState = Phonon::PlayingState;
+ emit stateChanged(newstate, m_state);
+ m_state = newstate;
+ break;
+ case Phonon::ErrorState:
+ emit stateChanged(newstate, m_state);
+ m_state = newstate;
+ break;
+ case Phonon::BufferingState:
+ case Phonon::LoadingState:
+ emit stateChanged(newstate, m_state);
+ m_state = newstate;
+ break;
+ }
+}
+
+qint64 MediaObject::totalTime() const
+{
+ return m_totalTime;
+}
+
+qint32 MediaObject::prefinishMark() const
+{
+ return m_prefinishMark;
+}
+
+qint32 MediaObject::transitionTime() const
+{
+ return m_transitionTime;
+}
+
+void MediaObject::setTransitionTime(qint32 time)
+{
+ m_transitionTime = time;
+}
+
+qint64 MediaObject::remainingTime() const
+{
+ if(currentTime() > totalTime())
+ return 0;
+
+ return totalTime() - currentTime();
+}
+
+MediaSource MediaObject::source() const
+{
+ return m_source;
+}
+
+void MediaObject::setNextSource(const MediaSource &source)
+{
+ if (source.type() == MediaSource::Invalid &&
+ source.type() == MediaSource::Empty)
+ return;
+ m_nextSource = source;
+}
+
+/*
+ * !reimp
+ */
+void MediaObject::setSource(const MediaSource &source)
+{
+ QMultiMap<QString, QString> ret;
+
+ ret.insert(QLatin1String("ARTIST"), "Nokia Dude");
+ ret.insert(QLatin1String("ALBUM"), "Sound of silence");
+ ret.insert(QLatin1String("DATE"), "2009");
+
+ m_error = Phonon::NoError;
+ setState(Phonon::LoadingState);
+
+ m_source = source;
+ currentPos = 0;
+
+ if((source.fileName().contains(".avi")) ||
+ (source.fileName().contains(".mp4"))) {
+ m_hasVideo = true;
+ emit hasVideoChanged(m_hasVideo);
+ }
+ if(source.fileName().contains(".wav")) {
+ QFile file(source.fileName());
+ if (file.open(QIODevice::ReadOnly)) {
+ int len = file.read((char*)&header, sizeof(CombinedHeader));
+ if(len == sizeof(CombinedHeader)) {
+ if(memcmp(&header.riff.descriptor.id, riffId, 4) != 0) {
+ // Not a valid wav file, to satisfy unit test for mediaobject
+ m_error = Phonon::FatalError;
+ //m_state = Phonon::ErrorState;
+ m_errorString = "Invalid wav file";
+ setState(Phonon::ErrorState);
+ file.close();
+ return;
+ }
+ }
+ file.close();
+ }
+ }
+ emit metaDataChanged(ret);
+ emit currentSourceChanged(source);
+ emit totalTimeChanged(m_totalTime);
+
+ setState(Phonon::StoppedState);
+}
+
+void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
+{
+ m_prefinishMark = newPrefinishMark;
+ if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
+ m_prefinishMarkReachedNotEmitted = true;
+}
+
+void MediaObject::pause()
+{
+ if (state() != Phonon::PausedState)
+ setState(Phonon::PausedState);
+ m_resumeState = false;
+ m_tickTimer->stop();
+}
+
+void MediaObject::stop()
+{
+ if (state() != Phonon::StoppedState) {
+ if(m_state != Phonon::ErrorState) {
+ setState(Phonon::StoppedState);
+ }
+ m_prefinishMarkReachedNotEmitted = true;
+ }
+ m_resumeState = false;
+ m_tickTimer->stop();
+}
+
+void MediaObject::emitTick()
+{
+ if (m_resumeState) {
+ return;
+ }
+ if(m_tickInterval > 0)
+ currentPos += m_tickInterval;
+ else
+ currentPos += 100;
+
+ qint64 currentTime = currentPos;
+ qint64 totalTime = m_totalTime;
+
+ if (m_tickInterval > 0 && currentTime != m_previousTickTime) {
+ emit tick(currentTime);
+ m_previousTickTime = currentTime;
+ }
+ if (m_state == Phonon::PlayingState) {
+ if (currentTime >= totalTime - m_prefinishMark) {
+ if (m_prefinishMarkReachedNotEmitted) {
+ m_prefinishMarkReachedNotEmitted = false;
+ emit prefinishMarkReached(totalTime - currentTime);
+ }
+ }
+ // Prepare load of next source
+ if (currentTime >= totalTime - 500) {
+ if (!m_aboutToFinishEmitted) {
+ m_aboutToFinishEmitted = true; // track is about to finish
+ emit aboutToFinish();
+ }
+ }
+ if(currentTime >= totalTime) {
+ m_tickTimer->stop();
+ if(m_nextSource.type() != MediaSource::Invalid &&
+ m_nextSource.type() != MediaSource::Empty) {
+ setSource(m_nextSource);
+ m_nextSource = MediaSource();
+ m_pendingState = Phonon::PlayingState;
+ } else {
+ setState(Phonon::PausedState);
+ currentPos = 0;
+ emit finished();
+ }
+ }
+ }
+}
+
+void MediaObject::seek(qint64 time)
+{
+ // We will assume no buffering in the object so this is not needed.
+ currentPos = time;
+}
+
+} // ns Dummy
+} // ns Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_mediaobject.cpp"
diff --git a/tests/auto/mediaobject/dummy/mediaobject.h b/tests/auto/mediaobject/dummy/mediaobject.h
new file mode 100644
index 0000000..a20873b
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/mediaobject.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PHONON_DUMMY_MEDIAOBJECT_H
+#define PHONON_DUMMY_MEDIAOBJECT_H
+
+#include "backend.h"
+#include <phonon/mediaobjectinterface.h>
+#include <phonon/addoninterface.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QObject>
+#include <QtCore/QDate>
+#include <QtCore/QEvent>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+typedef QMultiMap<QString, QString> TagMap;
+
+namespace Phonon
+{
+namespace Dummy
+{
+
+class VideoWidget;
+class AudioPath;
+class VideoPath;
+class AudioOutput;
+
+class MediaObject : public QObject, public MediaObjectInterface
+{
+ friend class Stream;
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface
+ )
+
+public:
+
+ MediaObject(Backend *backend, QObject *parent);
+ ~MediaObject();
+ Phonon::State state() const;
+
+ bool hasVideo() const;
+ bool isSeekable() const;
+
+ qint64 currentTime() const;
+ qint32 tickInterval() const;
+
+ void setTickInterval(qint32 newTickInterval);
+
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 time);
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+
+ QUrl url() const;
+ qint64 totalTime() const;
+
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 newPrefinishMark);
+
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+ qint64 remainingTime() const;
+
+ void setSource(const MediaSource &source);
+ void setNextSource(const MediaSource &source);
+ MediaSource source() const;
+
+ void saveState();
+ void resumeState();
+
+public Q_SLOTS:
+ void setState(State);
+
+Q_SIGNALS:
+ void currentSourceChanged(const MediaSource &newSource);
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(QMultiMap<QString, QString>);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+
+ void finished();
+ void prefinishMarkReached(qint32);
+ void aboutToFinish();
+ void totalTimeChanged(qint64 length);
+ void bufferStatus(int percentFilled);
+
+ QMultiMap<QString, QString> metaData();
+ void setMetaData(QMultiMap<QString, QString> newData);
+
+private Q_SLOTS:
+ void emitTick();
+
+private:
+ bool m_resumeState;
+ State m_oldState;
+ quint64 m_oldPos;
+ quint64 currentPos;
+ bool m_hasVideo;
+ qint32 m_tickInterval;
+ QTimer *m_tickTimer;
+ Phonon::ErrorType m_error;
+ QString m_errorString;
+ qint64 m_totalTime;
+ qint32 m_prefinishMark;
+ qint32 m_transitionTime;
+ MediaSource m_source;
+ MediaSource m_nextSource;
+ bool m_prefinishMarkReachedNotEmitted;
+ bool m_aboutToFinishEmitted;
+ int m_previousTickTime;
+
+ State m_state;
+ State m_pendingState;
+
+ struct chunk
+ {
+ char id[4];
+ quint32 size;
+ };
+
+ struct RIFFHeader
+ {
+ chunk descriptor;
+ char type[4];
+ };
+
+ struct WAVEHeader
+ {
+ chunk descriptor;
+ quint16 audioFormat; // PCM = 1
+ quint16 numChannels;
+ quint32 sampleRate;
+ quint32 byteRate;
+ quint16 blockAlign;
+ quint16 bitsPerSample;
+ quint32 xFreq1;
+ chunk fact;
+ quint32 xfact;
+ chunk data;
+ };
+
+ struct DATAHeader
+ {
+ chunk descriptor;
+ quint8 data[];
+ };
+
+ struct CombinedHeader
+ {
+ RIFFHeader riff;
+ WAVEHeader wave;
+ DATAHeader data;
+ };
+
+ CombinedHeader header;
+};
+}
+} //namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+
+#endif // PHONON_DUMMY_MEDIAOBJECT_H
diff --git a/tests/auto/mediaobject/dummy/videowidget.cpp b/tests/auto/mediaobject/dummy/videowidget.cpp
new file mode 100644
index 0000000..f46704a
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/videowidget.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "videowidget.h"
+#include <QtCore/QEvent>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPalette>
+#include <QtGui/QImage>
+#include <QtGui/QPainter>
+#include <QtGui/QBoxLayout>
+#include <QApplication>
+#include "mediaobject.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Dummy
+{
+
+VideoWidget::VideoWidget(Backend *backend, QWidget *parent) :
+ QWidget(parent),
+ m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto),
+ m_brightness(0.0),
+ m_hue(0.0),
+ m_contrast(0.0),
+ m_saturation(0.0),
+ m_scaleMode(Phonon::VideoWidget::FitInView)
+{
+ Q_UNUSED(backend)
+
+}
+
+VideoWidget::~VideoWidget()
+{
+}
+
+void VideoWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+}
+
+void VideoWidget::setVisible(bool val)
+{
+ Q_UNUSED(val)
+}
+
+Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
+{
+ return m_aspectRatio;
+}
+
+QSize VideoWidget::sizeHint() const
+{
+ return QSize(640, 480);
+}
+
+void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio)
+{
+ Q_UNUSED(aspectRatio)
+}
+
+Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
+{
+ return m_scaleMode;
+}
+
+QRect VideoWidget::scaleToAspect(QRect srcRect, int w, int h) const
+{
+ float width = srcRect.width();
+ float height = srcRect.width() * (float(h) / float(w));
+ if (height > srcRect.height()) {
+ height = srcRect.height();
+ width = srcRect.height() * (float(w) / float(h));
+ }
+ return QRect(0, 0, (int)width, (int)height);
+}
+
+/***
+ * Calculates the actual rectangle the movie will be presented with
+ **/
+QRect VideoWidget::calculateDrawFrameRect() const
+{
+ QRect widgetRect = rect();
+ QRect drawFrameRect;
+ // Set m_drawFrameRect to be the size of the smallest possible
+ // rect conforming to the aspect and containing the whole frame:
+ switch (aspectRatio()) {
+
+ case Phonon::VideoWidget::AspectRatioWidget:
+ drawFrameRect = widgetRect;
+ // No more calculations needed.
+ return drawFrameRect;
+
+ case Phonon::VideoWidget::AspectRatio4_3:
+ drawFrameRect = scaleToAspect(widgetRect, 4, 3);
+ break;
+
+ case Phonon::VideoWidget::AspectRatio16_9:
+ drawFrameRect = scaleToAspect(widgetRect, 16, 9);
+ break;
+
+ case Phonon::VideoWidget::AspectRatioAuto:
+ default:
+ drawFrameRect = QRect(0, 0, movieSize().width(), movieSize().height());
+ break;
+ }
+
+ // Scale m_drawFrameRect to fill the widget
+ // without breaking aspect:
+ float widgetWidth = widgetRect.width();
+ float widgetHeight = widgetRect.height();
+ float frameWidth = widgetWidth;
+ float frameHeight = drawFrameRect.height() * float(widgetWidth) / float(drawFrameRect.width());
+
+ switch (scaleMode()) {
+ case Phonon::VideoWidget::ScaleAndCrop:
+ if (frameHeight < widgetHeight) {
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ case Phonon::VideoWidget::FitInView:
+ default:
+ if (frameHeight > widgetHeight) {
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ }
+ drawFrameRect.setSize(QSize(int(frameWidth), int(frameHeight)));
+ drawFrameRect.moveTo(int((widgetWidth - frameWidth) / 2.0f),
+ int((widgetHeight - frameHeight) / 2.0f));
+ return drawFrameRect;
+}
+
+void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
+{
+ Q_UNUSED(scaleMode)
+}
+
+qreal VideoWidget::brightness() const
+{
+ return m_brightness;
+}
+
+qreal clampedValue(qreal val)
+{
+ if (val > 1.0 )
+ return 1.0;
+ else if (val < -1.0)
+ return -1.0;
+ else return val;
+}
+
+void VideoWidget::setBrightness(qreal newValue)
+{
+ Q_UNUSED(newValue)
+}
+
+qreal VideoWidget::contrast() const
+{
+ return m_contrast;
+}
+
+void VideoWidget::setContrast(qreal newValue)
+{
+ Q_UNUSED(newValue)
+}
+
+qreal VideoWidget::hue() const
+{
+ return m_hue;
+}
+
+void VideoWidget::setHue(qreal newValue)
+{
+ Q_UNUSED(newValue)
+}
+
+qreal VideoWidget::saturation() const
+{
+ return m_saturation;
+}
+
+void VideoWidget::setSaturation(qreal newValue)
+{
+ Q_UNUSED(newValue)
+}
+
+bool VideoWidget::event(QEvent *event)
+{
+ return QWidget::event(event);
+}
+
+void VideoWidget::setMovieSize(const QSize &size)
+{
+ m_movieSize = size;
+ widget()->updateGeometry();
+ widget()->update();
+}
+
+}
+} //namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+
+#include "moc_videowidget.cpp"
diff --git a/tests/auto/mediaobject/dummy/videowidget.h b/tests/auto/mediaobject/dummy/videowidget.h
new file mode 100644
index 0000000..615aa02
--- /dev/null
+++ b/tests/auto/mediaobject/dummy/videowidget.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test sutie of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PHONON_DUMMY_VIDEOWIDGET_H
+#define PHONON_DUMMY_VIDEOWIDGET_H
+
+#include <phonon/videowidget.h>
+#include <phonon/videowidgetinterface.h>
+
+#include "backend.h"
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+namespace Phonon
+{
+namespace Dummy
+{
+
+class VideoWidget : public QWidget, public Phonon::VideoWidgetInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VideoWidgetInterface)
+public:
+ VideoWidget(Backend *backend, QWidget *parent = 0);
+ ~VideoWidget();
+
+ void paintEvent(QPaintEvent *event);
+ void setVisible(bool);
+
+ Phonon::VideoWidget::AspectRatio aspectRatio() const;
+ void setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio);
+ Phonon::VideoWidget::ScaleMode scaleMode() const;
+ void setScaleMode(Phonon::VideoWidget::ScaleMode);
+ qreal brightness() const;
+ void setBrightness(qreal);
+ qreal contrast() const;
+ void setContrast(qreal);
+ qreal hue() const;
+ void setHue(qreal);
+ qreal saturation() const;
+ void setSaturation(qreal);
+ void setMovieSize(const QSize &size);
+ QSize sizeHint() const;
+ QRect scaleToAspect(QRect srcRect, int w, int h) const;
+ QRect calculateDrawFrameRect() const;
+
+ QSize movieSize() const {
+ return m_movieSize;
+ }
+
+ bool event(QEvent *);
+
+ QWidget *widget() {
+ return this;
+ }
+
+protected:
+ QSize m_movieSize;
+
+private:
+ Phonon::VideoWidget::AspectRatio m_aspectRatio;
+ qreal m_brightness, m_hue, m_contrast, m_saturation;
+ Phonon::VideoWidget::ScaleMode m_scaleMode;
+};
+
+}
+} //namespace Phonon::Dummy
+
+QT_END_NAMESPACE
+
+#endif // PHONON_DUMMY_VIDEOWIDGET_H
diff --git a/tests/auto/mediaobject/media/sax.mp3 b/tests/auto/mediaobject/media/sax.mp3
new file mode 100644
index 0000000..0a078b1
--- /dev/null
+++ b/tests/auto/mediaobject/media/sax.mp3
Binary files differ
diff --git a/tests/auto/mediaobject/media/sax.ogg b/tests/auto/mediaobject/media/sax.ogg
new file mode 100644
index 0000000..12be04a
--- /dev/null
+++ b/tests/auto/mediaobject/media/sax.ogg
Binary files differ
diff --git a/tests/auto/mediaobject/media/sax.wav b/tests/auto/mediaobject/media/sax.wav
new file mode 100644
index 0000000..f3e814c
--- /dev/null
+++ b/tests/auto/mediaobject/media/sax.wav
Binary files differ
diff --git a/tests/auto/mediaobject/media/test.sdp b/tests/auto/mediaobject/media/test.sdp
new file mode 100644
index 0000000..0d8706c
--- /dev/null
+++ b/tests/auto/mediaobject/media/test.sdp
@@ -0,0 +1,32 @@
+v=0
+o=- 3476526279 2351211129 IN IP4 XXX.XXX.XXX.XXX
+s=SOME STRING
+e=support@localhost
+c=IN IP4 XXX.XXX.XXX.XXX
+t=0 0
+a=range:npt=now-
+a=random_access_denied
+a=control:rtsp://link
+m=video 0 RTP/AVP 96
+b=AS:100
+b=RR:2500
+b=RS:2500
+a=control:rtsp://link
+a=rtpmap:96 MP4V-ES/90000
+a=3GPP-Adaptation-Support:1
+a=cliprect:0,0,144,176
+a=mpeg4-esid:201
+a=x-envivio-verid:00022B15
+a=fmtp:96 profile-level-id=2;config=000001b002000001b50ea020202f000001000000012000c788ba9850584121463f
+a=framerate:15.0
+m=audio 0 RTP/AVP 97
+b=AS:14
+b=RR:350
+b=RS:350
+a=control:rtsp://link
+a=rtpmap:97 AMR/8000
+a=3GPP-Adaptation-Support:1
+a=mpeg4-esid:101
+a=x-envivio-verid:00022B15
+a=fmtp:97 octet-align=1
+a=maxptime:200
diff --git a/tests/auto/mediaobject/mediaobject.pro b/tests/auto/mediaobject/mediaobject.pro
new file mode 100755
index 0000000..23ec56b
--- /dev/null
+++ b/tests/auto/mediaobject/mediaobject.pro
@@ -0,0 +1,24 @@
+############################################################
+# Project file for autotest for file mediaobject.h
+############################################################
+
+load(qttest_p4)
+
+contains(QT_CONFIG, phonon):QT += phonon
+SOURCES += tst_mediaobject.cpp
+HEADERS += qtesthelper.h
+RESOURCES += mediaobject.qrc
+
+wince*{
+ DEPLOYMENT_PLUGIN += phonon_waveout
+ DEFINES += tst_MediaObject=tst_MediaObject_waveout
+}
+
+symbian:{
+ addFiles.files = media/test.sdp
+ addFiles.path = media
+ DEPLOYMENT += addFiles
+ LIBS += -lCommDb -lconnmon
+ TARGET.CAPABILITY += "NetworkServices"
+}
+
diff --git a/tests/auto/mediaobject/mediaobject.qrc b/tests/auto/mediaobject/mediaobject.qrc
new file mode 100644
index 0000000..77954f4
--- /dev/null
+++ b/tests/auto/mediaobject/mediaobject.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+<file>media/sax.wav</file>
+<file>media/sax.ogg</file>
+<file>media/sax.mp3</file>
+<file>media/test.sdp</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/mediaobject/qtesthelper.h b/tests/auto/mediaobject/qtesthelper.h
new file mode 100644
index 0000000..9b1ea18
--- /dev/null
+++ b/tests/auto/mediaobject/qtesthelper.h
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef QTESTHELPER_H
+#define QTESTHELPER_H
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QTimer>
+#include <QtTest/QSignalSpy>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+namespace QTest
+{
+
+ /**
+ * Starts an event loop that runs until the given signal is received. Optionally the event loop
+ * can return earlier on a timeout.
+ *
+ * \return \p true if the requested signal was received
+ * \p false on timeout
+ */
+ bool waitForSignal(QObject *obj, const char *signal, int timeout = 0)
+ {
+ QEventLoop loop;
+ QObject::connect(obj, signal, &loop, SLOT(quit()));
+ QTimer timer;
+ QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
+ if (timeout > 0) {
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ timer.setSingleShot(true);
+ timer.start(timeout);
+ }
+ loop.exec();
+ return timeoutSpy.isEmpty();
+ }
+
+
+// template<>
+ char *toString(const Phonon::State &state)
+ {
+ switch (state) {
+ case Phonon::LoadingState:
+ return qstrdup("LoadingState");
+ case Phonon::StoppedState:
+ return qstrdup("StoppedState");
+ case Phonon::PlayingState:
+ return qstrdup("PlayingState");
+ case Phonon::BufferingState:
+ return qstrdup("BufferingState");
+ case Phonon::PausedState:
+ return qstrdup("PausedState");
+ case Phonon::ErrorState:
+ return qstrdup("ErrorState");
+ }
+ return 0;
+ }
+
+// template<>
+ char *toString(const QVariant::Type &type)
+ {
+ switch (type) {
+ case QVariant::Invalid:
+ return qstrdup("QVariant::Invalid");
+ case QVariant::BitArray:
+ return qstrdup("QVariant::BitArray");
+ case QVariant::Bitmap:
+ return qstrdup("QVariant::Bitmap");
+ case QVariant::Bool:
+ return qstrdup("QVariant::Bool");
+ case QVariant::Brush:
+ return qstrdup("QVariant::Brush");
+ case QVariant::ByteArray:
+ return qstrdup("QVariant::ByteArray");
+ case QVariant::Char:
+ return qstrdup("QVariant::Char");
+ case QVariant::Color:
+ return qstrdup("QVariant::Color");
+ case QVariant::Cursor:
+ return qstrdup("QVariant::Cursor");
+ case QVariant::Date:
+ return qstrdup("QVariant::Date");
+ case QVariant::DateTime:
+ return qstrdup("QVariant::DateTime");
+ case QVariant::Double:
+ return qstrdup("QVariant::Double");
+ case QVariant::Font:
+ return qstrdup("QVariant::Font");
+ case QVariant::Icon:
+ return qstrdup("QVariant::Icon");
+ case QVariant::Image:
+ return qstrdup("QVariant::Image");
+ case QVariant::Int:
+ return qstrdup("QVariant::Int");
+ case QVariant::KeySequence:
+ return qstrdup("QVariant::KeySequence");
+ case QVariant::Line:
+ return qstrdup("QVariant::Line");
+ case QVariant::LineF:
+ return qstrdup("QVariant::LineF");
+ case QVariant::List:
+ return qstrdup("QVariant::List");
+ case QVariant::Locale:
+ return qstrdup("QVariant::Locale");
+ case QVariant::LongLong:
+ return qstrdup("QVariant::LongLong");
+ case QVariant::Map:
+ return qstrdup("QVariant::Map");
+ case QVariant::Matrix:
+ return qstrdup("QVariant::Matrix");
+ case QVariant::Transform:
+ return qstrdup("QVariant::Transform");
+ case QVariant::Palette:
+ return qstrdup("QVariant::Palette");
+ case QVariant::Pen:
+ return qstrdup("QVariant::Pen");
+ case QVariant::Pixmap:
+ return qstrdup("QVariant::Pixmap");
+ case QVariant::Point:
+ return qstrdup("QVariant::Point");
+ case QVariant::PointF:
+ return qstrdup("QVariant::PointF");
+ case QVariant::Polygon:
+ return qstrdup("QVariant::Polygon");
+ case QVariant::Rect:
+ return qstrdup("QVariant::Rect");
+ case QVariant::RectF:
+ return qstrdup("QVariant::RectF");
+ case QVariant::RegExp:
+ return qstrdup("QVariant::RegExp");
+ case QVariant::Region:
+ return qstrdup("QVariant::Region");
+ case QVariant::Size:
+ return qstrdup("QVariant::Size");
+ case QVariant::SizeF:
+ return qstrdup("QVariant::SizeF");
+ case QVariant::SizePolicy:
+ return qstrdup("QVariant::SizePolicy");
+ case QVariant::String:
+ return qstrdup("QVariant::String");
+ case QVariant::StringList:
+ return qstrdup("QVariant::StringList");
+ case QVariant::TextFormat:
+ return qstrdup("QVariant::TextFormat");
+ case QVariant::TextLength:
+ return qstrdup("QVariant::TextLength");
+ case QVariant::Time:
+ return qstrdup("QVariant::Time");
+ case QVariant::UInt:
+ return qstrdup("QVariant::UInt");
+ case QVariant::ULongLong:
+ return qstrdup("QVariant::ULongLong");
+ case QVariant::Url:
+ return qstrdup("QVariant::Url");
+ case QVariant::UserType:
+ return qstrdup("QVariant::UserType");
+ case QVariant::LastType:
+ return qstrdup("QVariant::LastType");
+ default:
+ return 0;
+ }
+ }
+} // namespace QTest
+QT_END_NAMESPACE
+
+#endif // QTESTHELPER_H
diff --git a/tests/auto/mediaobject/tst_mediaobject.cpp b/tests/auto/mediaobject/tst_mediaobject.cpp
new file mode 100644
index 0000000..b29a6db
--- /dev/null
+++ b/tests/auto/mediaobject/tst_mediaobject.cpp
@@ -0,0 +1,1220 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) version 3.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <QtTest/QtTest>
+#include <QtCore/QDate>
+#include <QtCore/QDebug>
+#include <QtCore/QObject>
+#include <QtCore/QUrl>
+
+#ifndef QT_NO_PHONON
+#include <phonon/path.h>
+#include <phonon/audiooutput.h>
+#include <phonon/mediaobject.h>
+#include <phonon/phononnamespace.h>
+#include <phonon/audiooutput.h>
+#include <phonon/seekslider.h>
+#include <phonon/mediaobject.h>
+#include <phonon/volumeslider.h>
+#include <phonon/videowidget.h>
+#include <phonon/backendcapabilities.h>
+
+#include "qtesthelper.h"
+#include <cstdlib>
+#endif
+
+#ifndef Q_WS_WIN
+#include <unistd.h>
+#endif
+
+#ifdef Q_OS_WINCE
+#define MEDIA_FILE "/sax.wav"
+#define MEDIA_FILEPATH ":/media/sax.wav"
+const qint64 SEEK_BACKWARDS = 2000;
+const qint64 ALLOWED_TIME_FOR_SEEKING = 1500; // 1.5s
+const qint64 SEEKING_TOLERANCE = 250;
+#else
+#if defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(Q_OS_SYMBIAN)
+#define MEDIA_FILE "/sax.mp3"
+#define MEDIA_FILEPATH ":/media/sax.mp3"
+#else
+#define MEDIA_FILE "/sax.ogg"
+#define MEDIA_FILEPATH ":/media/sax.ogg"
+#endif
+const qint64 SEEK_BACKWARDS = 4000;
+const qint64 ALLOWED_TIME_FOR_SEEKING = 1000; // 1s
+const qint64 SEEKING_TOLERANCE = 0;
+#endif //Q_OS_WINCE
+
+#ifdef Q_OS_SYMBIAN
+#include <cdbcols.h>
+#include <cdblen.h>
+#include <commdb.h>
+#include <rconnmon.h>
+
+const QString KDefaultIAP = QLatin1String("default");
+const QString KInvalidIAP = QLatin1String("invalid IAP");
+
+class CConnectionObserver : public CBase, public MConnectionMonitorObserver
+{
+public:
+ static CConnectionObserver* NewL()
+ {
+ CConnectionObserver* self = new (ELeave) CConnectionObserver();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+ QString currentIAP()
+ {
+ return m_currentIAPName;
+ }
+ ~CConnectionObserver()
+ {
+ m_connMon.Close();
+ }
+private:
+ CConnectionObserver()
+ {
+ }
+ void ConstructL()
+ {
+ m_connMon.ConnectL();
+ m_connMon.NotifyEventL(*this);
+ }
+ void EventL (const CConnMonEventBase &aConnEvent)
+ {
+ TInt event = aConnEvent.EventType();
+ TUint connId = aConnEvent.ConnectionId();
+ TRequestStatus status;
+ switch (event) {
+ case EConnMonCreateConnection: {
+ TBuf<KCommsDbSvrMaxColumnNameLength> iapName;
+ m_connMon.GetStringAttribute(connId, 0, KIAPName, iapName, status);
+ User::WaitForRequest(status);
+ m_currentIAPName = QString(reinterpret_cast<const QChar *>(iapName.Ptr()), iapName.Length());
+ qDebug() << "A new connection created using: " << m_currentIAPName;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+private:
+ RConnectionMonitor m_connMon;
+ QString m_currentIAPName;
+};
+
+#endif
+
+
+class tst_MediaObject : public QObject
+{
+ Q_OBJECT
+ public:
+ tst_MediaObject()
+ : m_success(false)
+ {
+ qputenv("PHONON_GST_AUDIOSINK", "fake");
+ }
+
+#ifndef QT_NO_PHONON
+
+ Q_SIGNALS:
+ void continueTestPlayOnFinish();
+
+ protected Q_SLOTS:
+ void enqueueMedia();
+ void setMediaAndPlay();
+ void stateChanged(Phonon::State, Phonon::State);
+ private Q_SLOTS:
+ void init();
+ void cleanup();
+
+ void testPlayFromResource();
+ void testPlayIllegalFile();
+ void initTestCase();
+ void checkForDefaults();
+
+ // state change tests
+ void stopToStop();
+ void stopToPause();
+ void stopToPlay();
+ void playToPlay();
+ void playToPause();
+ void playToStop();
+ void pauseToPause();
+ void pauseToPlay();
+ void pauseToStop();
+ void playSDP();
+ void playUrl_data();
+ void playUrl();
+
+ void testPrefinishMark();
+ void testSeek();
+ void testTickSignal();
+ void testJustInTimeQueuing();
+ void testPlayOnFinish();
+ void testPlayBeforeFinish();
+ void testPauseOnFinish();
+ void testReconnectBetweenTwoMediaObjects();
+ void volumeSliderMuteVisibility();
+ void cleanupTestCase();
+ private:
+ void _startPlayback(Phonon::State currentState = Phonon::StoppedState);
+ void _stopPlayback(Phonon::State currentState);
+ void _pausePlayback();
+ void _testOneSeek(qint64 seekTo);
+
+ QUrl m_url;
+ Phonon::MediaObject *m_media;
+ QSignalSpy *m_stateChangedSignalSpy;
+ QString m_tmpFileName;
+#ifdef Q_OS_SYMBIAN
+ CConnectionObserver *m_iapConnectionObserver;
+ QString getValidIAPL();
+#endif //Q_OS_SYMBIAN
+
+ static void copyMediaFile(const QString &original,
+ const QString &name,
+ QString &resultFilePath,
+ QUrl *const asURL = 0);
+#endif //QT_NO_PHONON
+ bool m_success;
+};
+
+#ifndef QT_NO_PHONON
+
+#define startPlayback() _startPlayback(); if (!m_success) return; m_success = false;
+#define startPlayback2(currentState) _startPlayback(currentState); if (!m_success) return; m_success = false;
+#define stopPlayback(currentState) _stopPlayback(currentState); if (!m_success) return; m_success = false;
+#define pausePlayback() _pausePlayback(); if (!m_success) return; m_success = false;
+#define testOneSeek(seekTo) _testOneSeek(seekTo); if (!m_success) return; m_success = false;
+
+const qint64 ALLOWED_SEEK_INACCURACY = 300; // 0.3s
+const qint64 ALLOWED_TICK_INACCURACY = 350; // allow +/- 350 ms inaccuracy
+
+using namespace Phonon;
+
+static qint64 castQVariantToInt64(const QVariant &variant)
+{
+ return *reinterpret_cast<const qint64 *>(variant.constData());
+}
+
+static qint32 castQVariantToInt32(const QVariant &variant)
+{
+ return *reinterpret_cast<const qint32 *>(variant.constData());
+}
+
+void tst_MediaObject::stateChanged(Phonon::State newstate, Phonon::State oldstate)
+{
+ if (newstate == Phonon::ErrorState)
+ QWARN(QByteArray(QByteArray(QTest::toString(oldstate)) + " to " + QByteArray(QTest::toString(newstate))));
+}
+
+void tst_MediaObject::testPlayFromResource()
+{
+ MediaObject media;
+ media.setCurrentSource(QString(MEDIA_FILEPATH));
+ QVERIFY(media.state() != Phonon::ErrorState);
+ if (media.state() != Phonon::StoppedState)
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
+ QCOMPARE(media.state(), Phonon::StoppedState);
+ media.play();
+ if (media.state() != Phonon::PlayingState)
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
+ QCOMPARE(media.state(), Phonon::PlayingState);
+}
+
+void tst_MediaObject::testPlayIllegalFile()
+{
+ QString filename = QDir::tempPath() + QString("/test.wav");
+ QFile::remove(filename);
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly);
+ for (int i=0;i<0xffff;i++) {
+ int r = qrand();
+ file.write((const char*)&r, 2);
+ }
+ file.close();
+ MediaObject media;
+ media.setCurrentSource(filename);
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
+ QCOMPARE(media.state(), Phonon::ErrorState);
+ media.play();
+ QCOMPARE(media.state(), Phonon::ErrorState);
+ QFile::remove(filename);
+}
+
+void tst_MediaObject::init()
+{
+ QCOMPARE(m_media->outputPaths().size(), 1);
+ if (m_media->state() == Phonon::ErrorState) {
+ m_media->setCurrentSource(m_url);
+ if (m_media->state() == Phonon::ErrorState) {
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ }
+ if (m_media->state() == Phonon::LoadingState) {
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ }
+ m_stateChangedSignalSpy->clear();
+ }
+
+ // Ensure that m_media is in StoppedState
+ if (m_media->state() != Phonon::StoppedState) {
+ m_media->stop();
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+ }
+}
+
+void tst_MediaObject::cleanup()
+{
+ switch (m_media->state()) {
+ case Phonon::PlayingState:
+ case Phonon::BufferingState:
+ case Phonon::PausedState:
+ stopPlayback(m_media->state());
+ break;
+ default:
+ break;
+ }
+ m_stateChangedSignalSpy->clear();
+}
+
+void tst_MediaObject::_startPlayback(Phonon::State currentState)
+{
+ m_stateChangedSignalSpy->clear();
+ Phonon::State s = m_media->state();
+ QCOMPARE(s, currentState);
+ m_media->play();
+ while (s != Phonon::PlayingState) {
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 3000);
+ QApplication::processEvents();
+ }
+ while (!m_stateChangedSignalSpy->isEmpty()) {
+ QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
+ Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(laststate, s);
+ s = qvariant_cast<Phonon::State>(args.at(0));
+ QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
+ }
+ }
+ QCOMPARE(s, Phonon::PlayingState);
+ QCOMPARE(m_media->state(), Phonon::PlayingState);
+ m_success = true;
+}
+
+void tst_MediaObject::_stopPlayback(Phonon::State currentState)
+{
+ QVERIFY(currentState != Phonon::ErrorState);
+ m_stateChangedSignalSpy->clear();
+ Phonon::State s = m_media->state();
+ QCOMPARE(s, currentState);
+ m_media->stop();
+ while (s != Phonon::StoppedState) {
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
+ }
+ while (!m_stateChangedSignalSpy->isEmpty()) {
+ QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
+ Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(laststate, s);
+ s = qvariant_cast<Phonon::State>(args.at(0));
+ if (s == Phonon::StoppedState) {
+ QVERIFY(m_stateChangedSignalSpy->isEmpty());
+ break;
+ }
+ QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
+ }
+ }
+ QCOMPARE(s, Phonon::StoppedState);
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+ m_success = true;
+}
+
+void tst_MediaObject::_pausePlayback()
+{
+ m_stateChangedSignalSpy->clear();
+ Phonon::State s = m_media->state();
+ m_media->pause();
+ while (s != Phonon::PausedState) {
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ }
+ while (!m_stateChangedSignalSpy->isEmpty()) {
+ QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
+ Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(laststate, s);
+ s = qvariant_cast<Phonon::State>(args.at(0));
+ if (s == Phonon::PausedState) {
+ QVERIFY(m_stateChangedSignalSpy->isEmpty());
+ break;
+ }
+ QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
+ }
+ }
+ QCOMPARE(s, Phonon::PausedState);
+ QCOMPARE(m_media->state(), Phonon::PausedState);
+ m_success = true;
+}
+
+/*!
+ Copies the file \a name to the testing area. The resulting file name path is
+ returned in resultFilePath, and also set as a URL in \a asURL.
+ */
+void tst_MediaObject::copyMediaFile(const QString &original,
+ const QString &name,
+ QString &resultFilePath,
+ QUrl *const asURL)
+{
+ resultFilePath = QDir::toNativeSeparators(QDir::tempPath() + name);
+ if (asURL)
+ *asURL = QUrl::fromLocalFile(resultFilePath);
+
+ QFile::remove(resultFilePath);
+ QVERIFY(QFile::copy(original, resultFilePath));
+ QFile::setPermissions(resultFilePath, QFile::permissions(resultFilePath) | QFile::WriteOther);
+}
+
+void tst_MediaObject::initTestCase()
+{
+ QCoreApplication::setApplicationName("tst_MediaObject");
+ m_stateChangedSignalSpy = 0;
+ m_media = 0;
+
+#ifdef Q_OS_WINCE
+ QString pluginsPath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
+#ifdef DEBUG
+ QVERIFY(QFile::exists(pluginsPath + "/phonon_backend/phonon_waveoutd4.dll") || QFile::exists(pluginsPath + "/phonon_backend/phonon_phonon_ds9d4.dll"));
+#else
+ QVERIFY(QFile::exists(pluginsPath + "/phonon_backend/phonon_waveout4.dll") || QFile::exists(pluginsPath + "/phonon_backend/phonon_phonon_ds94.dll"));
+#endif
+#endif
+
+
+ m_url = qgetenv("PHONON_TESTURL");
+ m_media = new MediaObject(this);
+ connect(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), SLOT(stateChanged(Phonon::State, Phonon::State)));
+ m_stateChangedSignalSpy = new QSignalSpy(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ QVERIFY(m_stateChangedSignalSpy->isValid());
+ m_stateChangedSignalSpy->clear();
+
+ if (m_url.isEmpty())
+ copyMediaFile(MEDIA_FILEPATH, MEDIA_FILE, m_tmpFileName, &m_url);
+
+ qDebug() << "Using url:" << m_url.toString();
+
+ // AudioOutput is needed else the backend might have no time source
+ AudioOutput *audioOutput = new AudioOutput(Phonon::MusicCategory, this);
+ //audioOutput->setVolume(0.0f);
+
+ QSignalSpy totalTimeChangedSignalSpy(m_media, SIGNAL(totalTimeChanged(qint64)));
+ QVERIFY(m_media->queue().isEmpty());
+ QCOMPARE(m_media->currentSource().type(), MediaSource::Empty);
+ QCOMPARE(m_media->state(), Phonon::LoadingState);
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+
+ m_media->setCurrentSource(m_url);
+ QCOMPARE(m_media->currentSource().type(), MediaSource::Url);
+ QCOMPARE(m_media->currentSource().url(), m_url);
+
+ int emits = m_stateChangedSignalSpy->count();
+ Phonon::State s = m_media->state();
+ if (s == Phonon::LoadingState) {
+ // still in LoadingState, there should be no state change
+ QCOMPARE(emits, 0);
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 6000);
+ emits = m_stateChangedSignalSpy->count();
+ s = m_media->state();
+ }
+ if (s != Phonon::LoadingState) {
+ // there should exactly be one state change
+ QCOMPARE(emits, 1);
+ QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
+ Phonon::State newstate = qvariant_cast<Phonon::State>(args.at(0));
+ Phonon::State oldstate = qvariant_cast<Phonon::State>(args.at(1));
+
+ QCOMPARE(Phonon::LoadingState, oldstate);
+ QCOMPARE(s, newstate);
+ if (Phonon::ErrorState == s) {
+#ifdef Q_WS_WIN
+ if (m_media->errorString().contains(QLatin1String("no audio hardware is available")))
+ QSKIP("On Windows we need an audio devide to perform the MediaObject tests", SkipAll);
+ else
+#endif
+ QFAIL("Loading the URL put the MediaObject into the ErrorState. Check that PHONON_TESTURL is set to a valid URL.");
+ }
+ QCOMPARE(Phonon::StoppedState, s);
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+
+ // check for totalTimeChanged signal
+ QVERIFY(totalTimeChangedSignalSpy.count() > 0);
+ args = totalTimeChangedSignalSpy.takeLast();
+ QCOMPARE(m_media->totalTime(), castQVariantToInt64(args.at(0)));
+ } else {
+ QFAIL("Still in LoadingState after a stateChange signal was emitted. Cannot go on.");
+ }
+
+ Path path = createPath(m_media, audioOutput);
+ QVERIFY(path.isValid());
+
+
+ QCOMPARE(m_media->outputPaths().size(), 1);
+ QCOMPARE(audioOutput->inputPaths().size(), 1);
+
+#ifdef Q_OS_SYMBIAN
+ TRAP_IGNORE(m_iapConnectionObserver = CConnectionObserver::NewL());
+#endif //Q_OS_SYMBIAN
+
+}
+
+void tst_MediaObject::checkForDefaults()
+{
+ QCOMPARE(m_media->tickInterval(), qint32(0));
+ QCOMPARE(m_media->prefinishMark(), qint32(0));
+}
+
+void tst_MediaObject::stopToStop()
+{
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+ m_media->stop();
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 2000);
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+}
+
+void tst_MediaObject::stopToPause()
+{
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+ m_media->pause();
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 6000));
+ }
+ QCOMPARE(m_stateChangedSignalSpy->count(), 1);
+ QCOMPARE(m_media->state(), Phonon::PausedState);
+}
+
+void tst_MediaObject::stopToPlay()
+{
+ startPlayback();
+ QTest::waitForSignal(m_media, SIGNAL(finished()), 1000);
+ stopPlayback(Phonon::PlayingState);
+}
+
+void tst_MediaObject::playToPlay()
+{
+ startPlayback();
+
+ m_media->play();
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+ QCOMPARE(m_media->state(), Phonon::PlayingState);
+
+ stopPlayback(Phonon::PlayingState);
+}
+
+void tst_MediaObject::playToPause()
+{
+ startPlayback();
+ QCOMPARE(m_media->state(), Phonon::PlayingState);
+ pausePlayback();
+ stopPlayback(Phonon::PausedState);
+}
+
+void tst_MediaObject::playToStop()
+{
+ startPlayback();
+ stopPlayback(Phonon::PlayingState);
+}
+
+void tst_MediaObject::pauseToPause()
+{
+ startPlayback();
+ pausePlayback();
+
+ m_media->pause();
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+ QCOMPARE(m_media->state(), Phonon::PausedState);
+
+ stopPlayback(Phonon::PausedState);
+}
+
+void tst_MediaObject::pauseToPlay()
+{
+ startPlayback();
+ pausePlayback();
+ startPlayback2(Phonon::PausedState);
+ stopPlayback(Phonon::PlayingState);
+}
+
+void tst_MediaObject::pauseToStop()
+{
+ startPlayback();
+ pausePlayback();
+ stopPlayback(Phonon::PausedState);
+}
+
+/*!
+
+ We attempt to play a SDP file. An SDP file essentially describes different
+ media streams and is hence a layer in front of the actual media(s).
+ Sometimes the backend handles the SDP file, in other cases not.
+
+ Some Phonon backends doesn't support SDP at all, ifdef appropriately. Real
+ Player and Helix, the two backends for Symbian, are known to support SDP.
+ */
+void tst_MediaObject::playSDP()
+{
+#ifdef Q_OS_SYMBIAN
+ QString sdpFile;
+ copyMediaFile(QLatin1String(":/media/test.sdp"), QLatin1String("test.sdp"), sdpFile);
+
+ // Let's verify our test setup.
+ QVERIFY(QFileInfo(sdpFile).isReadable());
+
+ // We need a window in order to setup the video.
+ QWidget widget;
+ widget.show();
+
+ const MediaSource oldSource(m_media->currentSource());
+ const MediaSource sdpSource(sdpFile);
+ m_media->setCurrentSource(sdpSource);
+ if (m_media->state() != Phonon::StoppedState)
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
+
+ // MediaObject should have loaded the SDP, but be in error state due to absent media
+ const bool stateMatch = (m_media->state() == Phonon::ErrorState);
+ const bool errorStringMatch = (m_media->errorString() == QString::fromLatin1("Loading clip failed: Unknown error (-39)"));
+
+ // Ensure that m_media is back in ground state prior to starting next test step
+ m_media->setCurrentSource(oldSource);
+ if (m_media->state() != Phonon::StoppedState)
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ QCOMPARE(m_media->state(), Phonon::StoppedState);
+
+ QVERIFY(stateMatch);
+ QVERIFY(errorStringMatch);
+
+#else
+ QSKIP("Unsupported on this platform.", SkipAll);
+#endif
+}
+
+/*!
+ Attempt to play from an RTSP link, and, on Symbian, to specify the IAP that
+ should be used to connect to the network. This test requires the unit under test
+ to have a default internet connection that will support streaming media, and ideally
+ one other internet connection that will also support streaming.
+ */
+void tst_MediaObject::playUrl_data()
+{
+ QTest::addColumn<QUrl>("url");
+#ifdef Q_OS_SYMBIAN
+ QTest::addColumn<QString>("iap");
+#endif //Q_OS_SYMBIAN
+
+ QUrl rtspLink("rtsp://v1.cache8.c.youtube.com/CjgLENy73wIaLwnoDBCE7tF7fxMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNgpbWqq7L7je5KDA==/0/0/0/video.3gp");
+ QUrl httpLink("http://www.theflute.co.uk/media/BachCPE_SonataAmin_1.wma");
+
+#ifdef Q_OS_SYMBIAN
+ QTest::newRow("default_IAP_rtsp") << rtspLink << KDefaultIAP;
+ QTest::newRow("invalid_IAP_rtsp") << rtspLink << KInvalidIAP;
+ //don't test HTTP link with invalid or default IAP as it will prompt the user
+ //Add tests with a valid IAP if we can get one from CommsDB
+ QString validIAP;
+ TRAPD(err, validIAP = getValidIAPL());
+ if (KErrNone == err) {
+ QTest::newRow("valid_IAP_rtsp") << rtspLink << validIAP;
+ QTest::newRow("valid_IAP_http") << httpLink << validIAP;
+ }
+#else
+ QTest::newRow("default_IAP_rtsp") << rtspLink;
+ QTest::newRow("invalid_IAP_rtsp") << rtspLink;
+#endif //Q_OS_SYMBIAN
+}
+
+#ifdef Q_OS_SYMBIAN
+QString tst_MediaObject::getValidIAPL()
+{
+ CCommsDatabase* commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP);
+ CleanupStack::PushL(commsDb);
+ commsDb->ShowHiddenRecords();
+ CCommsDbTableView* view = commsDb->OpenTableLC(TPtrC(IAP));
+ QString validIAP;
+ TBool found = EFalse;
+ TInt record = view->GotoFirstRecord();
+ while (KErrNotFound != record) {
+ TBuf<KCommsDbSvrMaxColumnNameLength> iapName;
+ view->ReadTextL(TPtrC(COMMDB_NAME), iapName);
+ validIAP = QString::fromUtf16(iapName.Ptr(),iapName.Length());
+ //We don't want the "Easy WLAN" IAP as it will try and prompt the user
+ if ("Easy WLAN" != validIAP) {
+ qDebug() << "playUrl_data() adding a valid IAP test: " << validIAP;
+ found = ETrue;
+ break;
+ }
+ record = view->GotoNextRecord();
+ }
+ CleanupStack::PopAndDestroy(2);
+ if (!found)
+ User::Leave(KErrNotFound);
+ return validIAP;
+}
+#endif //Q_OS_SYMBIAN
+
+void tst_MediaObject::playUrl()
+{
+ QFETCH(QUrl, url);
+#ifdef Q_OS_SYMBIAN
+ QFETCH(QString, iap);
+#endif
+ MediaObject media(this);
+
+ //Create a proper media path for video and audio
+ VideoWidget videoOutput;
+ Path path = createPath(&media, &videoOutput);
+ QVERIFY(path.isValid());
+ AudioOutput audioOutput(Phonon::MusicCategory, this);
+ path = createPath(&media, &audioOutput);
+ QVERIFY(path.isValid());
+
+#ifdef Q_OS_SYMBIAN
+ //The Symbian backend allows the IAP used for streaming connections to be specified
+ //by the application, using the "InternetAccessPointName" property.
+ if (KDefaultIAP != iap)
+ media.setProperty("InternetAccessPointName", iap);
+#endif //Q_OS_SYMBIAN
+ media.setCurrentSource(Phonon::MediaSource(url));
+ QVERIFY(media.state() != Phonon::ErrorState);
+
+ //we use a long 30s timeout here as it can take a long time for the streaming source to
+ //be sucessfully prepared depending on the network.
+ if (media.state() != Phonon::StoppedState)
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 30000);
+ QCOMPARE(media.state(), Phonon::StoppedState);
+
+ media.play();
+ if (media.state() != Phonon::PlayingState)
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000);
+ QCOMPARE(media.state(), Phonon::PlayingState);
+
+ //sleep and allow some of the stream to be played
+ QTest::qSleep(10000);
+
+#ifdef Q_OS_SYMBIAN
+ // Verify that the specified IAP is actually being used when we're not doing negative tests
+ if ((KDefaultIAP == iap || KInvalidIAP == iap) == false) {
+ if (m_iapConnectionObserver)
+ QCOMPARE(iap,m_iapConnectionObserver->currentIAP());
+ }
+#endif //Q_OS_SYMBIAN
+
+ media.stop();
+ if (media.state() != Phonon::StoppedState)
+ QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 15000);
+ QCOMPARE(media.state(), Phonon::StoppedState);
+}
+
+void tst_MediaObject::testPrefinishMark()
+{
+ const qint32 requestedPrefinishMarkTime = 2000;
+ m_media->setPrefinishMark(requestedPrefinishMarkTime);
+ QCOMPARE(m_media->prefinishMark(), requestedPrefinishMarkTime);
+ QSignalSpy prefinishMarkReachedSpy(m_media, SIGNAL(prefinishMarkReached(qint32)));
+ QSignalSpy finishSpy(m_media, SIGNAL(finished()));
+ startPlayback();
+ if (m_media->isSeekable()) {
+ m_media->seek(m_media->totalTime() - SEEK_BACKWARDS - requestedPrefinishMarkTime); // give it 4 seconds
+ }
+ int wait = 10000;
+ int total = 0;
+ while (prefinishMarkReachedSpy.count() == 0 && (m_media->state() == Phonon::PlayingState ||
+ m_media->state() == Phonon::BufferingState)) {
+ wait = qMax(1000, wait / 2);
+ QTest::waitForSignal(m_media, SIGNAL(prefinishMarkReached(qint32)), wait);
+ total += wait;
+ if (total >= 60*1000) // we wait 1 minute
+ QFAIL("Timeout failure waiting for signal");
+ }
+ // at this point the media should be about to finish playing
+ qint64 r = m_media->remainingTime();
+ Phonon::State state = m_media->state();
+ QCOMPARE(prefinishMarkReachedSpy.count(), 1);
+ const qint32 prefinishMark = castQVariantToInt32(prefinishMarkReachedSpy.first().at(0));
+ QVERIFY(prefinishMark <= requestedPrefinishMarkTime + 150); // allow it to be up to 150ms too early
+ if (state == Phonon::PlayingState || state == Phonon::BufferingState) {
+ if (r > prefinishMark) {
+ qDebug() << "remainingTime =" << r;
+ QFAIL("remainingTime needs to be less than or equal to prefinishMark");
+ }
+ QVERIFY(r <= prefinishMark);
+ QTest::waitForSignal(m_media, SIGNAL(finished()), 10000);
+ } else {
+ QVERIFY(prefinishMark >= 0);
+ }
+ QCOMPARE(finishSpy.count(), 1);
+}
+
+void tst_MediaObject::enqueueMedia()
+{
+ m_media->enqueue(m_url);
+}
+
+Q_DECLARE_METATYPE(Phonon::MediaSource)
+void tst_MediaObject::testJustInTimeQueuing()
+{
+#ifdef Q_OS_WINCE
+ QSKIP("crashes on Windows CE", SkipAll);
+#endif
+ qRegisterMetaType<Phonon::MediaSource>("Phonon::MediaSource");
+ QSignalSpy currentSourceChanged(m_media, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)));
+ QSignalSpy finished(m_media, SIGNAL(finished()));
+ connect(m_media, SIGNAL(aboutToFinish()), SLOT(enqueueMedia()));
+
+ startPlayback();
+ if (m_media->isSeekable()) {
+ m_media->seek(m_media->totalTime() - SEEK_BACKWARDS);
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(aboutToFinish()), 6000));
+ } else {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(aboutToFinish()), 3000 + m_media->remainingTime()));
+ }
+ disconnect(m_media, SIGNAL(aboutToFinish()), this, SLOT(enqueueMedia()));
+ if (currentSourceChanged.isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)), 3000));
+ }
+ QCOMPARE(currentSourceChanged.size(), 1);
+ QCOMPARE(finished.size(), 0);
+ QVERIFY(m_media->queue().isEmpty());
+ stopPlayback(m_media->state());
+}
+
+void tst_MediaObject::testPauseOnFinish()
+{
+ startPlayback();
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
+ QCOMPARE(m_media->state(), Phonon::PlayingState);
+ if (m_media->isSeekable() && m_media->totalTime() > 2000)
+ m_media->seek(m_media->totalTime() - 2000);
+ QTest::waitForSignal(m_media, SIGNAL(finished()), 4000);
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
+
+ QCOMPARE(m_media->state(), Phonon::PausedState);
+ connect(m_media, SIGNAL(finished()), m_media, SLOT(stop()));
+ m_media->seek(m_media->totalTime() - 2000);
+ m_media->play();
+
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
+ QCOMPARE(m_media->state(), Phonon::PlayingState);
+ QTest::waitForSignal(m_media, SIGNAL(finished()), 4000);
+ QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
+ stopPlayback(Phonon::StoppedState);
+}
+
+void tst_MediaObject::testReconnectBetweenTwoMediaObjects(){
+ // Purpose: Test that phonon can handle switching the same sink
+ // between different media objects.
+
+ Phonon::MediaObject obj1;
+ Phonon::MediaObject obj2;
+ Phonon::AudioOutput audio1;
+ Phonon::Path p1 = Phonon::createPath(&obj1, &audio1);
+ QVERIFY(p1.isValid());
+
+ QVERIFY(p1.reconnect(&obj1, &audio1));
+ QVERIFY(p1.isValid());
+ QVERIFY(p1.reconnect(&obj2, &audio1));
+ QVERIFY(p1.isValid());
+ QVERIFY(p1.reconnect(&obj1, &audio1));
+ QVERIFY(p1.isValid());
+
+ // Repeat the same test while playing:
+ QFile file(MEDIA_FILEPATH);
+ obj1.setCurrentSource(&file);
+ QFile file2(MEDIA_FILEPATH);
+ obj2.setCurrentSource(&file2);
+ obj1.play();
+ obj2.play();
+
+ QVERIFY(p1.reconnect(&obj1, &audio1));
+ QVERIFY(p1.isValid());
+ QVERIFY(p1.reconnect(&obj2, &audio1));
+ QVERIFY(p1.isValid());
+ QVERIFY(p1.reconnect(&obj1, &audio1));
+ QVERIFY(p1.isValid());
+}
+
+void tst_MediaObject::testPlayOnFinish()
+{
+ connect(m_media, SIGNAL(finished()), SLOT(setMediaAndPlay()));
+ startPlayback();
+ if (m_media->isSeekable()) {
+ m_media->seek(m_media->totalTime() - SEEK_BACKWARDS);
+ QVERIFY(QTest::waitForSignal(this, SIGNAL(continueTestPlayOnFinish()), 6000));
+ } else {
+ QVERIFY(QTest::waitForSignal(this, SIGNAL(continueTestPlayOnFinish()), 3000 + m_media->remainingTime()));
+ }
+ QTest::waitForSignal(m_media, SIGNAL(finished()), 1000);
+ stopPlayback(m_media->state());
+}
+
+void tst_MediaObject::testTickSignal()
+{
+ QTime start1;
+ QTime start2;
+#ifdef Q_OS_WINCE //On Windows CE we only provide ticks above 400ms
+ for (qint32 tickInterval = 400; tickInterval <= 1000; tickInterval *= 2)
+#else
+ for (qint32 tickInterval = 80; tickInterval <= 500; tickInterval *= 2)
+#endif
+ {
+ QSignalSpy tickSpy(m_media, SIGNAL(tick(qint64)));
+ //qDebug() << "Test 20 ticks with an interval of" << tickInterval << "ms";
+ m_media->setTickInterval(tickInterval);
+ QVERIFY(m_media->tickInterval() <= tickInterval);
+ QVERIFY(m_media->tickInterval() >= tickInterval/2);
+ QVERIFY(tickSpy.isEmpty());
+ m_media->seek(0); //let's go back to the beginning
+ start1.start();
+ startPlayback();
+ start2.start();
+ int lastCount = 0;
+ qint64 s1, s2 = start2.elapsed();
+ while (tickSpy.count() < 20 && (m_media->state() == Phonon::PlayingState || m_media->state() == Phonon::BufferingState))
+ {
+ if (tickSpy.count() > lastCount)
+ {
+ s1 = start1.elapsed();
+ qint64 tickTime = castQVariantToInt64(tickSpy.last().at(0));
+ lastCount = tickSpy.count();
+ // s1 is the time from before the beginning of the playback to
+ // after the tick signal
+ // s2 is the time from after the beginning of the playback to
+ // before the tick signal
+ // so: s2 <= s1
+ QVERIFY(tickTime <= m_media->currentTime());
+ if (s1 + ALLOWED_TICK_INACCURACY < tickTime || s2 - ALLOWED_TICK_INACCURACY > tickTime) {
+ qDebug()
+ << "\n" << lastCount << "ticks have been received"
+ << "\ntime from before playback was started to after the tick signal was received:" << s1 << "ms"
+ << "\ntime from after playback was started to before the tick signal was received:" << s2 << "ms"
+ << "\nreported tick time:" << tickTime << "ms"
+ << "\nallowed inaccuracy: +/-" << ALLOWED_TICK_INACCURACY << "ms";
+ for (int i = 0; i < tickSpy.count(); ++i) {
+ qDebug() << castQVariantToInt64(tickSpy[i].at(0));
+ }
+ }
+ QVERIFY(s1 + ALLOWED_TICK_INACCURACY >= tickTime);
+ QVERIFY(s2 - ALLOWED_TICK_INACCURACY <= tickTime);
+#ifndef Q_OS_WINCE
+ QVERIFY(s1 >= lastCount * m_media->tickInterval());
+#else
+ QVERIFY(s1 >= lastCount * m_media->tickInterval() - ALLOWED_TICK_INACCURACY);
+#endif
+ if (s2 > (lastCount + 1) * m_media->tickInterval())
+ QWARN(qPrintable(QString("%1. tick came too late: %2ms elapsed while this tick should have come before %3ms")
+ .arg(lastCount).arg(s2).arg((lastCount + 1) * m_media->tickInterval())));
+ } else if (lastCount == 0 && s2 > 20 * m_media->tickInterval()) {
+ QFAIL("no tick signals are being received");
+ }
+ s2 = start2.elapsed();
+ QTest::waitForSignal(m_media, SIGNAL(tick(qint64)), 2000);
+ }
+#ifndef Q_OS_WINCE //the shorter wave file is finished on Windows CE...
+ stopPlayback(Phonon::PlayingState);
+#else
+ stopPlayback(m_media->state());
+#endif
+ }
+}
+
+void tst_MediaObject::testSeek()
+{
+ m_media->seek(0); // let's seek back to the beginning
+ startPlayback();
+ QTime timer;
+ timer.start();
+ qint64 t = m_media->totalTime();
+ qint64 c = m_media->currentTime();
+ qint64 r = m_media->remainingTime();
+ int elapsed = timer.elapsed();
+ if (c + r > t + elapsed || c + r < t - elapsed) {
+ // qDebug() << "currentTime:" << c
+ // << "remainingTime:" << r
+ // << "totalTime:" << t;
+ QFAIL("currentTime + remainingTime doesn't come close enough to totalTime");
+ }
+
+ QVERIFY(c + r <= t + elapsed);
+ QVERIFY(c + r >= t - elapsed);
+ if (m_media->isSeekable())
+ if (r > 0)
+ {
+ m_media->setTickInterval(20);
+ qint64 s = c + r / 2;
+ testOneSeek(s);
+
+ s /= 2;
+ testOneSeek(s);
+ s = s * 3 / 2;
+ testOneSeek(s);
+
+ pausePlayback();
+
+ s = s * 3 / 2;
+ testOneSeek(s);
+ s /= 2;
+ testOneSeek(s);
+
+ m_media->setTickInterval(0);
+
+
+ stopPlayback(Phonon::PausedState);
+ return;
+ }
+ else
+ QWARN("didn't test seeking as the MediaObject reported a remaining size <= 0");
+ else
+ QWARN("didn't test seeking as the MediaObject is not seekable");
+ stopPlayback(Phonon::PlayingState);
+}
+
+
+void tst_MediaObject::setMediaAndPlay()
+{
+ m_stateChangedSignalSpy->clear();
+ QCOMPARE(m_stateChangedSignalSpy->count(), 0);
+
+ QSignalSpy totalTimeChangedSignalSpy(m_media, SIGNAL(totalTimeChanged(qint64)));
+ QVERIFY(m_media->currentSource().type() != MediaSource::Invalid);
+ Phonon::State state = m_media->state();
+ QVERIFY(state == Phonon::StoppedState || state == Phonon::PlayingState || Phonon::PausedState);
+ m_media->setCurrentSource(m_url);
+ // before calling play() we better make sure that if play() finishes very fast that we don't get
+ // called again
+ disconnect(m_media, SIGNAL(finished()), this, SLOT(setMediaAndPlay()));
+ state = m_media->state();
+ startPlayback2(state);
+
+ emit continueTestPlayOnFinish();
+}
+
+void tst_MediaObject::testPlayBeforeFinish()
+{
+ startPlayback();
+ QCOMPARE(m_stateChangedSignalSpy->size(), 0);
+ Phonon::State state = m_media->state();
+ QCOMPARE(state, Phonon::PlayingState);
+ m_media->setCurrentSource(m_url);
+ m_media->play();
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
+ }
+ // first (optional) state to reach is StoppedState
+ QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
+ Phonon::State oldstate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(oldstate, state);
+ state = qvariant_cast<Phonon::State>(args.at(0));
+ if (state == Phonon::StoppedState) {
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
+ }
+ args = m_stateChangedSignalSpy->takeFirst();
+ oldstate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(oldstate, state);
+ state = qvariant_cast<Phonon::State>(args.at(0));
+ }
+ // next LoadingState
+ QCOMPARE(state, Phonon::LoadingState);
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
+ }
+ // next either BufferingState or PlayingState
+ args = m_stateChangedSignalSpy->takeFirst();
+ oldstate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(oldstate, state);
+ state = qvariant_cast<Phonon::State>(args.at(0));
+ if (state == Phonon::BufferingState) {
+ if (m_stateChangedSignalSpy->isEmpty()) {
+ QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000)); // buffering can take a while
+ }
+ args = m_stateChangedSignalSpy->takeFirst();
+ oldstate = qvariant_cast<Phonon::State>(args.at(1));
+ QCOMPARE(oldstate, state);
+ state = qvariant_cast<Phonon::State>(args.at(0));
+ }
+#ifdef Q_WS_MAC
+ // m_media->setCurrentSource(m_url) in phonon frontend will always call
+ // 'stop' on the backend before calling 'setSource'. So the QT7 backend
+ // goes into stop, and naturally remains there after setting the new source.
+ // So going into playing state cannot happend when the backend is synchronized.
+ // Thats the reason for the ifdef.
+ QCOMPARE(state, Phonon::StoppedState);
+#else
+ stopPlayback(Phonon::PlayingState);
+#endif
+}
+
+void tst_MediaObject::cleanupTestCase()
+{
+ if (m_stateChangedSignalSpy)
+ delete m_stateChangedSignalSpy;
+ if (m_media)
+ delete m_media;
+#ifdef Q_OS_WINCE
+ QTest::qWait(200);
+#endif
+ if (!m_tmpFileName.isNull()) {
+ QVERIFY(QFile::remove(m_tmpFileName));
+ }
+#ifdef Q_OS_SYMBIAN
+ if (m_iapConnectionObserver)
+ delete m_iapConnectionObserver;
+#endif //Q_OS_SYMBIAN
+}
+
+void tst_MediaObject::_testOneSeek(qint64 seekTo)
+{
+ qint64 t = m_media->totalTime();
+ qint64 oldTime = m_media->currentTime();
+ if (oldTime == seekTo) {
+ return;
+ }
+
+ QTime seekDuration;
+ seekDuration.start();
+ m_media->seek(seekTo);
+
+ QVERIFY(oldTime == 0 || seekTo == 0 || m_media->currentTime() != 0);
+
+ int bufferingTime = 0;
+ Phonon::State s = m_media->state();
+ QTime timer;
+ if (s == Phonon::BufferingState) {
+ timer.start();
+ }
+ QEventLoop loop;
+ connect(m_media, SIGNAL(tick(qint64)), &loop, SLOT(quit()));
+ connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), &loop, SLOT(quit()));
+
+ qint64 c = m_media->currentTime();
+ qint64 r = m_media->remainingTime();
+ int elapsed = 0;
+ while (qAbs(c - seekTo) > ALLOWED_SEEK_INACCURACY){
+ QTimer::singleShot(ALLOWED_TIME_FOR_SEEKING, &loop, SLOT(quit()));
+
+ loop.exec();
+ c = m_media->currentTime();
+ r = m_media->remainingTime();
+ if (s == Phonon::BufferingState) {
+ bufferingTime += timer.restart();
+ } else {
+ timer.start();
+ }
+ s = m_media->state();
+ elapsed = seekDuration.elapsed();
+ QVERIFY(elapsed - bufferingTime < (ALLOWED_TIME_FOR_SEEKING + SEEKING_TOLERANCE));
+ }
+
+ QVERIFY(c >= seekTo - ALLOWED_SEEK_INACCURACY);
+ if (s == Phonon::PausedState) {
+ QVERIFY(bufferingTime == 0);
+ elapsed = 0;
+ }
+ if (c > seekTo + ALLOWED_SEEK_INACCURACY + elapsed - bufferingTime) {
+ QFAIL("currentTime is greater than the requested time + the time that elapsed since the seek started.");
+ }
+ if (c + r > t + 200 || c + r < t - 200) {
+ QFAIL("currentTime + remainingTime doesn't come close enough to totalTime");
+ }
+ m_success = true;
+}
+
+void tst_MediaObject::volumeSliderMuteVisibility()
+{
+ //this test doesn't really belong to mediaobject
+ // ### see if we should create a realy Phonon::VolumeSlider autotest
+ Phonon::VolumeSlider slider;
+ QVERIFY(slider.isMuteVisible()); // that is the default value
+ slider.setMuteVisible(true);
+ QVERIFY(slider.isMuteVisible());
+
+ //let's check that changing the visibility of the slider itself
+ //doesn't change what the slider reports
+ slider.setVisible(false);
+ QVERIFY(slider.isMuteVisible());
+ slider.setVisible(true);
+
+ slider.setMuteVisible(false);
+ QVERIFY(!slider.isMuteVisible());
+ slider.setMuteVisible(true);
+ QVERIFY(slider.isMuteVisible());
+}
+
+
+#endif //QT_NO_PHONON
+
+
+QTEST_MAIN(tst_MediaObject)
+
+#include "tst_mediaobject.moc"
+// vim: sw=4 ts=4