tests/auto/mediaobject/tst_mediaobject.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 /*  This file is part of the KDE project
       
    42     Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
       
    43 
       
    44     This program is free software; you can redistribute it and/or
       
    45     modify it under the terms of the GNU General Public License as
       
    46     published by the Free Software Foundation; either version 2 of
       
    47     the License, or (at your option) version 3.
       
    48 
       
    49     This program is distributed in the hope that it will be useful,
       
    50     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    51     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    52     GNU General Public License for more details.
       
    53 
       
    54     You should have received a copy of the GNU General Public License
       
    55     along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    56 
       
    57 */
       
    58 
       
    59 #include <QtTest/QtTest>
       
    60 #include <QtCore/QDate>
       
    61 #include <QtCore/QDebug>
       
    62 #include <QtCore/QObject>
       
    63 #include <QtCore/QUrl>
       
    64 
       
    65 #ifndef QT_NO_PHONON
       
    66 #include <phonon/path.h>
       
    67 #include <phonon/audiooutput.h>
       
    68 #include <phonon/mediaobject.h>
       
    69 #include <phonon/phononnamespace.h>
       
    70 #include <phonon/audiooutput.h>
       
    71 #include <phonon/seekslider.h>
       
    72 #include <phonon/mediaobject.h>
       
    73 #include <phonon/volumeslider.h>
       
    74 #include <phonon/videowidget.h>
       
    75 #include <phonon/backendcapabilities.h>
       
    76 
       
    77 #include "qtesthelper.h"
       
    78 #include <cstdlib>
       
    79 #endif
       
    80 
       
    81 #ifndef Q_WS_WIN
       
    82 #include <unistd.h>
       
    83 #endif
       
    84 
       
    85 #ifdef Q_OS_WINCE
       
    86 #define MEDIA_FILE "/sax.wav"
       
    87 #define MEDIA_FILEPATH ":/media/sax.wav"
       
    88 const qint64 SEEK_BACKWARDS = 2000;
       
    89 const qint64 ALLOWED_TIME_FOR_SEEKING = 1500; // 1.5s
       
    90 const qint64 SEEKING_TOLERANCE = 250;
       
    91 #else 
       
    92 #if defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(Q_OS_SYMBIAN)
       
    93 #define MEDIA_FILE "/sax.mp3"
       
    94 #define MEDIA_FILEPATH ":/media/sax.mp3"
       
    95 #else
       
    96 #define MEDIA_FILE "/sax.ogg"
       
    97 #define MEDIA_FILEPATH ":/media/sax.ogg"
       
    98 #endif
       
    99 const qint64 SEEK_BACKWARDS = 4000;
       
   100 const qint64 ALLOWED_TIME_FOR_SEEKING = 1000; // 1s
       
   101 const qint64 SEEKING_TOLERANCE = 0;
       
   102 #endif //Q_OS_WINCE
       
   103 
       
   104 class tst_MediaObject : public QObject
       
   105 {
       
   106     Q_OBJECT
       
   107     public:
       
   108         tst_MediaObject()
       
   109             : m_success(false)
       
   110     {
       
   111         qputenv("PHONON_GST_AUDIOSINK", "fake");
       
   112     }
       
   113 
       
   114 #ifndef QT_NO_PHONON
       
   115 
       
   116     Q_SIGNALS:
       
   117         void continueTestPlayOnFinish();
       
   118 
       
   119     protected Q_SLOTS:
       
   120         void enqueueMedia();
       
   121         void setMediaAndPlay();
       
   122         void stateChanged(Phonon::State, Phonon::State);
       
   123     private Q_SLOTS:
       
   124         void init();
       
   125         void cleanup();
       
   126 
       
   127         void testPlayFromResource();
       
   128         void testPlayIllegalFile();
       
   129         void initTestCase();
       
   130         void checkForDefaults();
       
   131 
       
   132         // state change tests
       
   133         void stopToStop();
       
   134         void stopToPause();
       
   135         void stopToPlay();
       
   136         void playToPlay();
       
   137         void playToPause();
       
   138         void playToStop();
       
   139         void pauseToPause();
       
   140         void pauseToPlay();
       
   141         void pauseToStop();
       
   142 
       
   143         void testPrefinishMark();
       
   144         void testSeek();
       
   145         void testTickSignal();
       
   146         void testJustInTimeQueuing();
       
   147         void testPlayOnFinish();
       
   148         void testPlayBeforeFinish();
       
   149         void testPauseOnFinish();
       
   150         void testReconnectBetweenTwoMediaObjects();
       
   151         void volumeSliderMuteVisibility();
       
   152         void cleanupTestCase();
       
   153     private:
       
   154         void _startPlayback(Phonon::State currentState = Phonon::StoppedState);
       
   155         void _stopPlayback(Phonon::State currentState);
       
   156         void _pausePlayback();
       
   157         void _testOneSeek(qint64 seekTo);
       
   158 
       
   159         QUrl m_url;
       
   160         Phonon::MediaObject *m_media;
       
   161         QSignalSpy *m_stateChangedSignalSpy;
       
   162         QString m_tmpFileName;
       
   163 #endif //QT_NO_PHONON
       
   164         bool m_success;
       
   165 };
       
   166 
       
   167 #ifndef QT_NO_PHONON
       
   168 
       
   169 #define startPlayback() _startPlayback(); if (!m_success) return; m_success = false;
       
   170 #define startPlayback2(currentState) _startPlayback(currentState); if (!m_success) return; m_success = false;
       
   171 #define stopPlayback(currentState) _stopPlayback(currentState); if (!m_success) return; m_success = false;
       
   172 #define pausePlayback() _pausePlayback(); if (!m_success) return; m_success = false;
       
   173 #define testOneSeek(seekTo) _testOneSeek(seekTo); if (!m_success) return; m_success = false;
       
   174 
       
   175 const qint64 ALLOWED_SEEK_INACCURACY = 300; // 0.3s
       
   176 const qint64 ALLOWED_TICK_INACCURACY = 350; // allow +/- 350 ms inaccuracy
       
   177 
       
   178 using namespace Phonon;
       
   179 
       
   180 static qint64 castQVariantToInt64(const QVariant &variant)
       
   181 {
       
   182     return *reinterpret_cast<const qint64 *>(variant.constData());
       
   183 }
       
   184 
       
   185 static qint32 castQVariantToInt32(const QVariant &variant)
       
   186 {
       
   187     return *reinterpret_cast<const qint32 *>(variant.constData());
       
   188 }
       
   189 
       
   190 static const char *const red    = "\033[0;31m";
       
   191 static const char *const green  = "\033[0;32m";
       
   192 static const char *const yellow = "\033[0;33m";
       
   193 static const char *const blue   = "\033[0;34m";
       
   194 static const char *const purple = "\033[0;35m";
       
   195 static const char *const cyan   = "\033[0;36m";
       
   196 static const char *const white  = "\033[0;37m";
       
   197 static const char *const normal = "\033[0m";
       
   198 
       
   199 void tst_MediaObject::stateChanged(Phonon::State newstate, Phonon::State oldstate)
       
   200 {
       
   201     if (newstate == Phonon::ErrorState) {
       
   202         QWARN(QByteArray(QByteArray(red) + ".......................................................... ") + QByteArray(QTest::toString(oldstate)) + " to " + QByteArray(QTest::toString(newstate)) + normal);
       
   203     } else {
       
   204         //qDebug() << ".........................................................." << cyan << QTest::toString(oldstate) << "to" << QTest::toString(newstate) << normal;
       
   205     }
       
   206 }
       
   207 
       
   208 void tst_MediaObject::testPlayFromResource()
       
   209 {
       
   210 #ifdef Q_OS_SYMBIAN
       
   211     QSKIP("Not implemented yet.", SkipAll);
       
   212     return;
       
   213 #endif
       
   214 
       
   215     QFile file(MEDIA_FILEPATH);
       
   216     MediaObject media;
       
   217     media.setCurrentSource(&file);
       
   218     QVERIFY(media.state() != Phonon::ErrorState);
       
   219     if (media.state() != Phonon::StoppedState)
       
   220         QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
       
   221     QCOMPARE(media.state(), Phonon::StoppedState);
       
   222     media.play();
       
   223     if (media.state() != Phonon::PlayingState)
       
   224         QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
       
   225     QCOMPARE(media.state(), Phonon::PlayingState);
       
   226 }
       
   227 
       
   228 void tst_MediaObject::testPlayIllegalFile()
       
   229 {
       
   230     QString filename = QDir::tempPath() + QString("/test.wav");
       
   231     QFile::remove(filename);
       
   232     QFile file(filename);
       
   233     file.open(QIODevice::WriteOnly);
       
   234     for (int i=0;i<0xffff;i++) {
       
   235         int r = qrand();
       
   236         file.write((const char*)&r, 2);
       
   237     }
       
   238     file.close();
       
   239     MediaObject media;
       
   240     media.setCurrentSource(filename);
       
   241     QTest::waitForSignal(&media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 10000);
       
   242     QCOMPARE(media.state(), Phonon::ErrorState);
       
   243     media.play();
       
   244     QCOMPARE(media.state(), Phonon::ErrorState);
       
   245     QFile::remove(filename);
       
   246 }
       
   247 
       
   248 void tst_MediaObject::init()
       
   249 {
       
   250     QCOMPARE(m_media->outputPaths().size(), 1);
       
   251     if (m_media->state() == Phonon::ErrorState) {
       
   252         m_media->setCurrentSource(m_url);
       
   253         if (m_media->state() == Phonon::ErrorState) {
       
   254             QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
       
   255         }
       
   256         if (m_media->state() == Phonon::LoadingState) {
       
   257             QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
       
   258         }
       
   259         m_stateChangedSignalSpy->clear();
       
   260     }
       
   261 }
       
   262 
       
   263 void tst_MediaObject::cleanup()
       
   264 {
       
   265     switch (m_media->state()) {
       
   266     case Phonon::PlayingState:
       
   267     case Phonon::BufferingState:
       
   268     case Phonon::PausedState:
       
   269         stopPlayback(m_media->state());
       
   270         break;
       
   271     default:
       
   272         break;
       
   273     }
       
   274     m_stateChangedSignalSpy->clear();
       
   275 }
       
   276 
       
   277 void tst_MediaObject::_startPlayback(Phonon::State currentState)
       
   278 {
       
   279     m_stateChangedSignalSpy->clear();
       
   280     Phonon::State s = m_media->state();
       
   281     QCOMPARE(s, currentState);
       
   282     m_media->play();
       
   283     while (s != Phonon::PlayingState) {
       
   284         if (m_stateChangedSignalSpy->isEmpty()) {
       
   285             QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 3000);
       
   286             QApplication::processEvents();
       
   287         }
       
   288         while (!m_stateChangedSignalSpy->isEmpty()) {
       
   289             QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
       
   290             Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
       
   291             QCOMPARE(laststate, s);
       
   292             s = qvariant_cast<Phonon::State>(args.at(0));
       
   293             QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
       
   294         }
       
   295     }
       
   296     QCOMPARE(s, Phonon::PlayingState);
       
   297     QCOMPARE(m_media->state(), Phonon::PlayingState);
       
   298     m_success = true;
       
   299 }
       
   300 
       
   301 void tst_MediaObject::_stopPlayback(Phonon::State currentState)
       
   302 {
       
   303     QVERIFY(currentState != Phonon::ErrorState);
       
   304     m_stateChangedSignalSpy->clear();
       
   305     Phonon::State s = m_media->state();
       
   306     QCOMPARE(s, currentState);
       
   307     m_media->stop();
       
   308     while (s != Phonon::StoppedState) {
       
   309         if (m_stateChangedSignalSpy->isEmpty()) {
       
   310             QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
       
   311         }
       
   312         while (!m_stateChangedSignalSpy->isEmpty()) {
       
   313             QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
       
   314             Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
       
   315             QCOMPARE(laststate, s);
       
   316             s = qvariant_cast<Phonon::State>(args.at(0));
       
   317             if (s == Phonon::StoppedState) {
       
   318                 QVERIFY(m_stateChangedSignalSpy->isEmpty());
       
   319                 break;
       
   320             }
       
   321             QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
       
   322         }
       
   323     }
       
   324     QCOMPARE(s, Phonon::StoppedState);
       
   325     QCOMPARE(m_media->state(), Phonon::StoppedState);
       
   326     m_success = true;
       
   327 }
       
   328 
       
   329 void tst_MediaObject::_pausePlayback()
       
   330 {
       
   331     m_stateChangedSignalSpy->clear();
       
   332     Phonon::State s = m_media->state();
       
   333     m_media->pause();
       
   334     while (s != Phonon::PausedState) {
       
   335         if (m_stateChangedSignalSpy->isEmpty()) {
       
   336             QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
       
   337         }
       
   338         while (!m_stateChangedSignalSpy->isEmpty()) {
       
   339             QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
       
   340             Phonon::State laststate = qvariant_cast<Phonon::State>(args.at(1));
       
   341             QCOMPARE(laststate, s);
       
   342             s = qvariant_cast<Phonon::State>(args.at(0));
       
   343             if (s == Phonon::PausedState) {
       
   344                 QVERIFY(m_stateChangedSignalSpy->isEmpty());
       
   345                 break;
       
   346             }
       
   347             QVERIFY(s == Phonon::BufferingState || s == Phonon::PlayingState);
       
   348         }
       
   349     }
       
   350     QCOMPARE(s, Phonon::PausedState);
       
   351     QCOMPARE(m_media->state(), Phonon::PausedState);
       
   352     m_success = true;
       
   353 }
       
   354 
       
   355 void tst_MediaObject::initTestCase()
       
   356 {
       
   357     QCoreApplication::setApplicationName("tst_MediaObject");
       
   358     m_stateChangedSignalSpy = 0;
       
   359     m_media = 0;
       
   360 
       
   361 #ifdef Q_OS_WINCE
       
   362     QString pluginsPath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
       
   363 #ifdef DEBUG
       
   364     QVERIFY(QFile::exists(pluginsPath + "/phonon_backend/phonon_waveoutd4.dll") || QFile::exists(pluginsPath + "/phonon_backend/phonon_phonon_ds9d4.dll"));
       
   365 #else
       
   366     QVERIFY(QFile::exists(pluginsPath + "/phonon_backend/phonon_waveout4.dll") || QFile::exists(pluginsPath + "/phonon_backend/phonon_phonon_ds94.dll"));
       
   367 #endif
       
   368 #endif
       
   369 
       
   370 
       
   371     m_url = qgetenv("PHONON_TESTURL");
       
   372     m_media = new MediaObject(this);
       
   373     connect(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), SLOT(stateChanged(Phonon::State, Phonon::State)));
       
   374     m_stateChangedSignalSpy = new QSignalSpy(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
       
   375     QVERIFY(m_stateChangedSignalSpy->isValid());
       
   376     m_stateChangedSignalSpy->clear();
       
   377 
       
   378     if (m_url.isEmpty()) {
       
   379         m_tmpFileName = QDir::toNativeSeparators(QDir::tempPath() + MEDIA_FILE);
       
   380         QFile::remove(m_tmpFileName);
       
   381         QVERIFY(QFile::copy(MEDIA_FILEPATH, m_tmpFileName));
       
   382         QFile::Permissions p = QFile::permissions(m_tmpFileName);
       
   383         QFile::setPermissions(m_tmpFileName, p | QFile::WriteOther);
       
   384         m_url = QUrl::fromLocalFile(m_tmpFileName);
       
   385     }
       
   386     
       
   387     qDebug() << "Using url:" << m_url.toString();
       
   388 
       
   389     // AudioOutput is needed else the backend might have no time source
       
   390     AudioOutput *audioOutput = new AudioOutput(Phonon::MusicCategory, this);
       
   391     //audioOutput->setVolume(0.0f);
       
   392 
       
   393     QSignalSpy totalTimeChangedSignalSpy(m_media, SIGNAL(totalTimeChanged(qint64)));
       
   394     QVERIFY(m_media->queue().isEmpty());
       
   395     QCOMPARE(m_media->currentSource().type(), MediaSource::Empty);
       
   396     QCOMPARE(m_media->state(), Phonon::LoadingState);
       
   397     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   398 
       
   399     m_media->setCurrentSource(m_url);
       
   400     QCOMPARE(m_media->currentSource().type(), MediaSource::Url);
       
   401     QCOMPARE(m_media->currentSource().url(), m_url);
       
   402 
       
   403     int emits = m_stateChangedSignalSpy->count();
       
   404     Phonon::State s = m_media->state();
       
   405     if (s == Phonon::LoadingState) {
       
   406         // still in LoadingState, there should be no state change
       
   407         QCOMPARE(emits, 0);
       
   408         QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 6000);
       
   409         emits = m_stateChangedSignalSpy->count();
       
   410         s = m_media->state();
       
   411     }
       
   412     if (s != Phonon::LoadingState) {
       
   413         // there should exactly be one state change
       
   414         QCOMPARE(emits, 1);
       
   415         QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
       
   416         Phonon::State newstate = qvariant_cast<Phonon::State>(args.at(0));
       
   417         Phonon::State oldstate = qvariant_cast<Phonon::State>(args.at(1));
       
   418 
       
   419         QCOMPARE(Phonon::LoadingState, oldstate);
       
   420         QCOMPARE(s, newstate);
       
   421         if (Phonon::ErrorState == s) {
       
   422 #ifdef Q_WS_WIN
       
   423             if (m_media->errorString().contains(QLatin1String("no audio hardware is available")))
       
   424                 QSKIP("On Windows we need an audio devide to perform the MediaObject tests", SkipAll); 
       
   425             else
       
   426 #endif
       
   427             QFAIL("Loading the URL put the MediaObject into the ErrorState. Check that PHONON_TESTURL is set to a valid URL.");
       
   428         }
       
   429         QCOMPARE(Phonon::StoppedState, s);
       
   430         QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   431 
       
   432         // check for totalTimeChanged signal
       
   433         QVERIFY(totalTimeChangedSignalSpy.count() > 0);
       
   434         args = totalTimeChangedSignalSpy.takeLast();
       
   435         QCOMPARE(m_media->totalTime(), castQVariantToInt64(args.at(0)));
       
   436     } else {
       
   437         QFAIL("Still in LoadingState after a stateChange signal was emitted. Cannot go on.");
       
   438     }
       
   439 
       
   440     Path path = createPath(m_media, audioOutput);
       
   441     QVERIFY(path.isValid());
       
   442 
       
   443 
       
   444     QCOMPARE(m_media->outputPaths().size(), 1);
       
   445     QCOMPARE(audioOutput->inputPaths().size(), 1);
       
   446 
       
   447 }
       
   448 
       
   449 void tst_MediaObject::checkForDefaults()
       
   450 {
       
   451     QCOMPARE(m_media->tickInterval(), qint32(0));
       
   452     QCOMPARE(m_media->prefinishMark(), qint32(0));
       
   453 }
       
   454 
       
   455 void tst_MediaObject::stopToStop()
       
   456 {
       
   457     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   458     QCOMPARE(m_media->state(), Phonon::StoppedState);
       
   459     m_media->stop();
       
   460     QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 2000);
       
   461     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   462     QCOMPARE(m_media->state(), Phonon::StoppedState);
       
   463 }
       
   464 
       
   465 void tst_MediaObject::stopToPause()
       
   466 {
       
   467     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   468     QCOMPARE(m_media->state(), Phonon::StoppedState);
       
   469     m_media->pause();
       
   470     if (m_stateChangedSignalSpy->isEmpty()) {
       
   471         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 6000));
       
   472     }
       
   473     QCOMPARE(m_stateChangedSignalSpy->count(), 1);
       
   474     QCOMPARE(m_media->state(), Phonon::PausedState);
       
   475 }
       
   476 
       
   477 void tst_MediaObject::stopToPlay()
       
   478 {
       
   479     startPlayback();
       
   480     QTest::waitForSignal(m_media, SIGNAL(finished()), 1000);
       
   481     stopPlayback(Phonon::PlayingState);
       
   482 }
       
   483 
       
   484 void tst_MediaObject::playToPlay()
       
   485 {
       
   486     startPlayback();
       
   487 
       
   488     m_media->play();
       
   489     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   490     QCOMPARE(m_media->state(), Phonon::PlayingState);
       
   491 
       
   492     stopPlayback(Phonon::PlayingState);
       
   493 }
       
   494 
       
   495 void tst_MediaObject::playToPause()
       
   496 {
       
   497     startPlayback();
       
   498     QCOMPARE(m_media->state(), Phonon::PlayingState);
       
   499     pausePlayback();
       
   500     stopPlayback(Phonon::PausedState);
       
   501 }
       
   502 
       
   503 void tst_MediaObject::playToStop()
       
   504 {
       
   505     startPlayback();
       
   506     stopPlayback(Phonon::PlayingState);
       
   507 }
       
   508 
       
   509 void tst_MediaObject::pauseToPause()
       
   510 {
       
   511     startPlayback();
       
   512     pausePlayback();
       
   513 
       
   514     m_media->pause();
       
   515     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   516     QCOMPARE(m_media->state(), Phonon::PausedState);
       
   517 
       
   518     stopPlayback(Phonon::PausedState);
       
   519 }
       
   520 
       
   521 void tst_MediaObject::pauseToPlay()
       
   522 {
       
   523     startPlayback();
       
   524     pausePlayback();
       
   525     startPlayback2(Phonon::PausedState);
       
   526     stopPlayback(Phonon::PlayingState);
       
   527 }
       
   528 
       
   529 void tst_MediaObject::pauseToStop()
       
   530 {
       
   531     startPlayback();
       
   532     pausePlayback();
       
   533     stopPlayback(Phonon::PausedState);
       
   534 }
       
   535 
       
   536 void tst_MediaObject::testPrefinishMark()
       
   537 {
       
   538     const qint32 requestedPrefinishMarkTime = 2000;
       
   539     m_media->setPrefinishMark(requestedPrefinishMarkTime);
       
   540     QCOMPARE(m_media->prefinishMark(), requestedPrefinishMarkTime);
       
   541     QSignalSpy prefinishMarkReachedSpy(m_media, SIGNAL(prefinishMarkReached(qint32)));
       
   542     QSignalSpy finishSpy(m_media, SIGNAL(finished()));
       
   543     startPlayback();
       
   544     if (m_media->isSeekable()) {
       
   545         m_media->seek(m_media->totalTime() - SEEK_BACKWARDS - requestedPrefinishMarkTime); // give it 4 seconds
       
   546     }
       
   547     int wait = 10000;
       
   548     int total = 0;
       
   549     while (prefinishMarkReachedSpy.count() == 0 && (m_media->state() == Phonon::PlayingState ||
       
   550                 m_media->state() == Phonon::BufferingState)) {
       
   551         wait = qMax(1000, wait / 2);
       
   552         QTest::waitForSignal(m_media, SIGNAL(prefinishMarkReached(qint32)), wait);
       
   553         total += wait;
       
   554         if (total >= 60*1000) // we wait 1 minute
       
   555             QFAIL("Timeout failure waiting for signal");
       
   556     }
       
   557     // at this point the media should be about to finish playing
       
   558     qint64 r = m_media->remainingTime();
       
   559     Phonon::State state = m_media->state();
       
   560     QCOMPARE(prefinishMarkReachedSpy.count(), 1);
       
   561     const qint32 prefinishMark = castQVariantToInt32(prefinishMarkReachedSpy.first().at(0));
       
   562     QVERIFY(prefinishMark <= requestedPrefinishMarkTime + 150); // allow it to be up to 150ms too early
       
   563     if (state == Phonon::PlayingState || state == Phonon::BufferingState) {
       
   564         if (r > prefinishMark) {
       
   565             qDebug() << "remainingTime =" << r;
       
   566             QFAIL("remainingTime needs to be less than or equal to prefinishMark");
       
   567         }
       
   568         QVERIFY(r <= prefinishMark);
       
   569         QTest::waitForSignal(m_media, SIGNAL(finished()), 10000);
       
   570     } else {
       
   571         QVERIFY(prefinishMark >= 0);
       
   572     }
       
   573     QCOMPARE(finishSpy.count(), 1);
       
   574 }
       
   575 
       
   576 void tst_MediaObject::enqueueMedia()
       
   577 {
       
   578     m_media->enqueue(m_url);
       
   579 }
       
   580 
       
   581 Q_DECLARE_METATYPE(Phonon::MediaSource)
       
   582 void tst_MediaObject::testJustInTimeQueuing()
       
   583 {
       
   584 #ifdef Q_OS_WINCE
       
   585     QSKIP("crashes on Windows CE", SkipAll);
       
   586 #endif
       
   587     qRegisterMetaType<Phonon::MediaSource>("Phonon::MediaSource");
       
   588     QSignalSpy currentSourceChanged(m_media, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)));
       
   589     QSignalSpy finished(m_media, SIGNAL(finished()));
       
   590     connect(m_media, SIGNAL(aboutToFinish()), SLOT(enqueueMedia()));
       
   591 
       
   592     startPlayback();
       
   593     if (m_media->isSeekable()) {
       
   594         m_media->seek(m_media->totalTime() - SEEK_BACKWARDS);
       
   595         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(aboutToFinish()), 6000));
       
   596     } else {
       
   597         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(aboutToFinish()), 3000 + m_media->remainingTime()));
       
   598     }
       
   599     disconnect(m_media, SIGNAL(aboutToFinish()), this, SLOT(enqueueMedia()));
       
   600     if (currentSourceChanged.isEmpty()) {
       
   601         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)), 3000));
       
   602     }
       
   603     QCOMPARE(currentSourceChanged.size(), 1);
       
   604     QCOMPARE(finished.size(), 0);
       
   605     QVERIFY(m_media->queue().isEmpty());
       
   606     stopPlayback(m_media->state());
       
   607 }
       
   608 
       
   609 void tst_MediaObject::testPauseOnFinish()
       
   610 {
       
   611     startPlayback();
       
   612     QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
       
   613     QCOMPARE(m_media->state(), Phonon::PlayingState);
       
   614     if (m_media->isSeekable() && m_media->totalTime() > 2000)
       
   615         m_media->seek(m_media->totalTime() - 2000);
       
   616     QTest::waitForSignal(m_media, SIGNAL(finished()), 4000);
       
   617     QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
       
   618 
       
   619     QCOMPARE(m_media->state(), Phonon::PausedState);
       
   620     connect(m_media, SIGNAL(finished()), m_media, SLOT(stop()));
       
   621     m_media->seek(m_media->totalTime() - 2000);
       
   622     m_media->play();
       
   623 
       
   624     QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
       
   625     QCOMPARE(m_media->state(), Phonon::PlayingState);
       
   626     QTest::waitForSignal(m_media, SIGNAL(finished()), 4000);
       
   627     QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 1000);
       
   628     stopPlayback(Phonon::StoppedState);
       
   629 }
       
   630 
       
   631 void tst_MediaObject::testReconnectBetweenTwoMediaObjects(){
       
   632     // Purpose: Test that phonon can handle swithing the same sink
       
   633     // between different media objects.
       
   634 
       
   635     Phonon::MediaObject obj1;
       
   636     Phonon::MediaObject obj2;
       
   637     Phonon::AudioOutput audio1;
       
   638     Phonon::Path p1 = Phonon::createPath(&obj1, &audio1);
       
   639     QVERIFY(p1.isValid());
       
   640 
       
   641     QVERIFY(p1.reconnect(&obj1, &audio1));
       
   642     QVERIFY(p1.isValid());
       
   643     QVERIFY(p1.reconnect(&obj2, &audio1));
       
   644     QVERIFY(p1.isValid());
       
   645     QVERIFY(p1.reconnect(&obj1, &audio1));
       
   646     QVERIFY(p1.isValid());
       
   647 
       
   648     // Repeat the same test while playing:
       
   649     QFile file(MEDIA_FILEPATH);
       
   650     obj1.setCurrentSource(&file);
       
   651     QFile file2(MEDIA_FILEPATH);
       
   652     obj2.setCurrentSource(&file2);
       
   653     obj1.play();
       
   654     obj2.play();
       
   655     
       
   656     QVERIFY(p1.reconnect(&obj1, &audio1));
       
   657     QVERIFY(p1.isValid());
       
   658     QVERIFY(p1.reconnect(&obj2, &audio1));
       
   659     QVERIFY(p1.isValid());
       
   660     QVERIFY(p1.reconnect(&obj1, &audio1));
       
   661     QVERIFY(p1.isValid());
       
   662 }
       
   663 
       
   664 void tst_MediaObject::testPlayOnFinish()
       
   665 {
       
   666     connect(m_media, SIGNAL(finished()), SLOT(setMediaAndPlay()));
       
   667     startPlayback();
       
   668     if (m_media->isSeekable()) {
       
   669         m_media->seek(m_media->totalTime() - SEEK_BACKWARDS);
       
   670         QVERIFY(QTest::waitForSignal(this, SIGNAL(continueTestPlayOnFinish()), 6000));
       
   671     } else {
       
   672         QVERIFY(QTest::waitForSignal(this, SIGNAL(continueTestPlayOnFinish()), 3000 + m_media->remainingTime()));
       
   673     }
       
   674     QTest::waitForSignal(m_media, SIGNAL(finished()), 1000);
       
   675     stopPlayback(m_media->state());
       
   676 }
       
   677 
       
   678 void tst_MediaObject::testTickSignal()
       
   679 {
       
   680     QTime start1;
       
   681     QTime start2;
       
   682 #ifdef Q_OS_WINCE //On Windows CE we only provide ticks above 400ms
       
   683     for (qint32 tickInterval = 400; tickInterval <= 1000; tickInterval *= 2)
       
   684 #else
       
   685     for (qint32 tickInterval = 80; tickInterval <= 500; tickInterval *= 2)
       
   686 #endif
       
   687     {
       
   688         QSignalSpy tickSpy(m_media, SIGNAL(tick(qint64)));
       
   689         //qDebug() << "Test 20 ticks with an interval of" <<  tickInterval << "ms";
       
   690         m_media->setTickInterval(tickInterval);
       
   691         QVERIFY(m_media->tickInterval() <= tickInterval);
       
   692         QVERIFY(m_media->tickInterval() >= tickInterval/2);
       
   693         QVERIFY(tickSpy.isEmpty());
       
   694         m_media->seek(0); //let's go back to the beginning
       
   695         start1.start();
       
   696         startPlayback();
       
   697         start2.start();
       
   698         int lastCount = 0;
       
   699         qint64 s1, s2 = start2.elapsed();
       
   700         while (tickSpy.count() < 20 && (m_media->state() == Phonon::PlayingState || m_media->state() == Phonon::BufferingState))
       
   701         {
       
   702             if (tickSpy.count() > lastCount)
       
   703             {
       
   704                 s1 = start1.elapsed();
       
   705                 qint64 tickTime = castQVariantToInt64(tickSpy.last().at(0));
       
   706                 lastCount = tickSpy.count();
       
   707                 // s1 is the time from before the beginning of the playback to
       
   708                 // after the tick signal
       
   709                 // s2 is the time from after the beginning of the playback to
       
   710                 // before the tick signal
       
   711                 // so: s2 <= s1
       
   712                 QVERIFY(tickTime <= m_media->currentTime());
       
   713                 if (s1 + ALLOWED_TICK_INACCURACY < tickTime || s2 - ALLOWED_TICK_INACCURACY > tickTime) {
       
   714                     qDebug()
       
   715                         << "\n" << lastCount << "ticks have been received"
       
   716                         << "\ntime from before playback was started to after the tick signal was received:" << s1 << "ms"
       
   717                         << "\ntime from after playback was started to before the tick signal was received:" << s2 << "ms"
       
   718                         << "\nreported tick time:" << tickTime << "ms"
       
   719                         << "\nallowed inaccuracy: +/-" << ALLOWED_TICK_INACCURACY << "ms";
       
   720                     for (int i = 0; i < tickSpy.count(); ++i) {
       
   721                         qDebug() << castQVariantToInt64(tickSpy[i].at(0));
       
   722                     }
       
   723                 }
       
   724                 QVERIFY(s1 + ALLOWED_TICK_INACCURACY >= tickTime);
       
   725                 QVERIFY(s2 - ALLOWED_TICK_INACCURACY <= tickTime);
       
   726 #ifndef Q_OS_WINCE
       
   727                 QVERIFY(s1 >= lastCount * m_media->tickInterval());
       
   728 #else
       
   729                 QVERIFY(s1 >= lastCount * m_media->tickInterval() - ALLOWED_TICK_INACCURACY);
       
   730 #endif
       
   731                 if (s2 > (lastCount + 1) * m_media->tickInterval())
       
   732                     QWARN(qPrintable(QString("%1. tick came too late: %2ms elapsed while this tick should have come before %3ms")
       
   733                             .arg(lastCount).arg(s2).arg((lastCount + 1) * m_media->tickInterval())));
       
   734             } else if (lastCount == 0 && s2 > 20 * m_media->tickInterval()) {
       
   735                 QFAIL("no tick signals are being received");
       
   736             }
       
   737             s2 = start2.elapsed();
       
   738             QTest::waitForSignal(m_media, SIGNAL(tick(qint64)), 2000);
       
   739         }
       
   740 #ifndef Q_OS_WINCE //the shorter wave file is finished on Windows CE...
       
   741         stopPlayback(Phonon::PlayingState);
       
   742 #else
       
   743         stopPlayback(m_media->state());
       
   744 #endif
       
   745     }
       
   746 }
       
   747 
       
   748 void tst_MediaObject::testSeek()
       
   749 {
       
   750     m_media->seek(0); // let's seek back to the beginning
       
   751     startPlayback();
       
   752     QTime timer;
       
   753     timer.start();
       
   754     qint64 t = m_media->totalTime();
       
   755     qint64 c = m_media->currentTime();
       
   756     qint64 r = m_media->remainingTime();
       
   757     int elapsed = timer.elapsed();
       
   758     if (c + r > t + elapsed || c + r < t - elapsed) {
       
   759     //  qDebug() << "currentTime:" << c
       
   760     //      << "remainingTime:" << r
       
   761     //      << "totalTime:" << t;
       
   762         QFAIL("currentTime + remainingTime doesn't come close enough to totalTime");
       
   763     }
       
   764 
       
   765     QVERIFY(c + r <= t + elapsed);
       
   766     QVERIFY(c + r >= t - elapsed);
       
   767     if (m_media->isSeekable())
       
   768         if (r > 0)
       
   769         {
       
   770             m_media->setTickInterval(20);
       
   771             qint64 s = c + r / 2;
       
   772             testOneSeek(s);
       
   773 
       
   774             s /= 2;
       
   775             testOneSeek(s);
       
   776             s = s * 3 / 2;
       
   777             testOneSeek(s);
       
   778 
       
   779             pausePlayback();
       
   780 
       
   781             s = s * 3 / 2;
       
   782             testOneSeek(s);
       
   783             s /= 2;
       
   784             testOneSeek(s);
       
   785 
       
   786             m_media->setTickInterval(0);
       
   787 
       
   788 
       
   789             stopPlayback(Phonon::PausedState);
       
   790             return;
       
   791         }
       
   792         else
       
   793             QWARN("didn't test seeking as the MediaObject reported a remaining size <= 0");
       
   794     else
       
   795         QWARN("didn't test seeking as the MediaObject is not seekable");
       
   796     stopPlayback(Phonon::PlayingState);
       
   797 }
       
   798 
       
   799 
       
   800 void tst_MediaObject::setMediaAndPlay()
       
   801 {
       
   802     m_stateChangedSignalSpy->clear();
       
   803     QCOMPARE(m_stateChangedSignalSpy->count(), 0);
       
   804 
       
   805     QSignalSpy totalTimeChangedSignalSpy(m_media, SIGNAL(totalTimeChanged(qint64)));
       
   806     QVERIFY(m_media->currentSource().type() != MediaSource::Invalid);
       
   807     Phonon::State state = m_media->state();
       
   808     QVERIFY(state == Phonon::StoppedState || state == Phonon::PlayingState || Phonon::PausedState);
       
   809     m_media->setCurrentSource(m_url);
       
   810     // before calling play() we better make sure that if play() finishes very fast that we don't get
       
   811     // called again
       
   812     disconnect(m_media, SIGNAL(finished()), this, SLOT(setMediaAndPlay()));
       
   813     state = m_media->state();
       
   814     startPlayback2(state);
       
   815 
       
   816     emit continueTestPlayOnFinish();
       
   817 }
       
   818 
       
   819 void tst_MediaObject::testPlayBeforeFinish()
       
   820 {
       
   821     startPlayback();
       
   822     QCOMPARE(m_stateChangedSignalSpy->size(), 0);
       
   823     Phonon::State state = m_media->state();
       
   824     QCOMPARE(state, Phonon::PlayingState);
       
   825     m_media->setCurrentSource(m_url);
       
   826     m_media->play();
       
   827     if (m_stateChangedSignalSpy->isEmpty()) {
       
   828         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
       
   829     }
       
   830     // first (optional) state to reach is StoppedState
       
   831     QList<QVariant> args = m_stateChangedSignalSpy->takeFirst();
       
   832     Phonon::State oldstate = qvariant_cast<Phonon::State>(args.at(1));
       
   833     QCOMPARE(oldstate, state);
       
   834     state = qvariant_cast<Phonon::State>(args.at(0));
       
   835     if (state == Phonon::StoppedState) {
       
   836         if (m_stateChangedSignalSpy->isEmpty()) {
       
   837             QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
       
   838         }
       
   839         args = m_stateChangedSignalSpy->takeFirst();
       
   840         oldstate = qvariant_cast<Phonon::State>(args.at(1));
       
   841         QCOMPARE(oldstate, state);
       
   842         state = qvariant_cast<Phonon::State>(args.at(0));
       
   843     }
       
   844     // next LoadingState
       
   845     QCOMPARE(state, Phonon::LoadingState);
       
   846     if (m_stateChangedSignalSpy->isEmpty()) {
       
   847         QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000));
       
   848     }
       
   849     // next either BufferingState or PlayingState
       
   850     args = m_stateChangedSignalSpy->takeFirst();
       
   851     oldstate = qvariant_cast<Phonon::State>(args.at(1));
       
   852     QCOMPARE(oldstate, state);
       
   853     state = qvariant_cast<Phonon::State>(args.at(0));
       
   854     if (state == Phonon::BufferingState) {
       
   855         if (m_stateChangedSignalSpy->isEmpty()) {
       
   856             QVERIFY(QTest::waitForSignal(m_media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 4000)); // buffering can take a while
       
   857         }
       
   858         args = m_stateChangedSignalSpy->takeFirst();
       
   859         oldstate = qvariant_cast<Phonon::State>(args.at(1));
       
   860         QCOMPARE(oldstate, state);
       
   861         state = qvariant_cast<Phonon::State>(args.at(0));
       
   862     }
       
   863 #ifdef Q_WS_MAC
       
   864     // m_media->setCurrentSource(m_url) in phonon frontend will always call
       
   865     // 'stop' on the backend before calling 'setSource'. So the QT7 backend
       
   866     // goes into stop, and naturally remains there after setting the new source.
       
   867     // So going into playing state cannot happend when the backend is synchronized.
       
   868     // Thats the reason for the ifdef.
       
   869     QCOMPARE(state, Phonon::StoppedState);
       
   870 #else
       
   871     stopPlayback(Phonon::PlayingState);
       
   872 #endif
       
   873 }
       
   874 
       
   875 void tst_MediaObject::cleanupTestCase()
       
   876 {
       
   877     if (m_stateChangedSignalSpy)
       
   878       delete m_stateChangedSignalSpy;
       
   879     if (m_media)
       
   880       delete m_media;
       
   881 #ifdef Q_OS_WINCE
       
   882     QTest::qWait(200);
       
   883 #endif
       
   884     if (!m_tmpFileName.isNull()) {
       
   885         QVERIFY(QFile::remove(m_tmpFileName));
       
   886     }
       
   887 }
       
   888 
       
   889 void tst_MediaObject::_testOneSeek(qint64 seekTo)
       
   890 {
       
   891    qint64 t = m_media->totalTime();
       
   892     qint64 oldTime = m_media->currentTime();
       
   893     if (oldTime == seekTo) {
       
   894         return;
       
   895     }
       
   896 
       
   897     QTime seekDuration;
       
   898     seekDuration.start();
       
   899     m_media->seek(seekTo);
       
   900 
       
   901     QVERIFY(oldTime == 0 || seekTo == 0 || m_media->currentTime() != 0);
       
   902 
       
   903     int bufferingTime = 0;
       
   904     Phonon::State s = m_media->state();
       
   905     QTime timer;
       
   906     if (s == Phonon::BufferingState) {
       
   907         timer.start();
       
   908     }
       
   909     QEventLoop loop;
       
   910     connect(m_media, SIGNAL(tick(qint64)), &loop, SLOT(quit()));
       
   911     connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), &loop, SLOT(quit()));
       
   912 
       
   913     qint64 c = m_media->currentTime();
       
   914     qint64 r = m_media->remainingTime();
       
   915     int elapsed = 0;
       
   916     while (qAbs(c - seekTo) > ALLOWED_SEEK_INACCURACY){
       
   917         QTimer::singleShot(ALLOWED_TIME_FOR_SEEKING, &loop, SLOT(quit()));
       
   918 
       
   919         loop.exec();
       
   920         c = m_media->currentTime();
       
   921         r = m_media->remainingTime();
       
   922         if (s == Phonon::BufferingState) {
       
   923             bufferingTime += timer.restart();
       
   924         } else {
       
   925             timer.start();
       
   926         }
       
   927         s = m_media->state();
       
   928         elapsed = seekDuration.elapsed();
       
   929         QVERIFY(elapsed - bufferingTime < (ALLOWED_TIME_FOR_SEEKING + SEEKING_TOLERANCE));
       
   930     }
       
   931 
       
   932     QVERIFY(c >= seekTo - ALLOWED_SEEK_INACCURACY);
       
   933     if (s == Phonon::PausedState) {
       
   934         QVERIFY(bufferingTime == 0);
       
   935         elapsed = 0;
       
   936     }
       
   937     if (c > seekTo + ALLOWED_SEEK_INACCURACY + elapsed - bufferingTime) {
       
   938         QFAIL("currentTime is greater than the requested time + the time that elapsed since the seek started.");
       
   939     }
       
   940     if (c + r > t + 200 || c + r < t - 200) {
       
   941         QFAIL("currentTime + remainingTime doesn't come close enough to totalTime");
       
   942     }
       
   943     m_success = true;
       
   944 }
       
   945 
       
   946 void tst_MediaObject::volumeSliderMuteVisibility()
       
   947 {
       
   948     //this test doesn't really belong to mediaobject
       
   949     // ### see if we should create a realy Phonon::VolumeSlider autotest
       
   950     Phonon::VolumeSlider slider;
       
   951     QVERIFY(slider.isMuteVisible()); // that is the default value
       
   952     slider.setMuteVisible(true);
       
   953     QVERIFY(slider.isMuteVisible());
       
   954 
       
   955     //let's check that changing the visibility of the slider itself
       
   956     //doesn't change what the slider reports
       
   957     slider.setVisible(false);
       
   958     QVERIFY(slider.isMuteVisible());
       
   959     slider.setVisible(true);
       
   960 
       
   961     slider.setMuteVisible(false);
       
   962     QVERIFY(!slider.isMuteVisible());
       
   963     slider.setMuteVisible(true);
       
   964     QVERIFY(slider.isMuteVisible());
       
   965 }
       
   966 
       
   967 
       
   968 #endif //QT_NO_PHONON
       
   969 
       
   970 
       
   971 QTEST_MAIN(tst_MediaObject)
       
   972 
       
   973 #include "tst_mediaobject.moc"
       
   974 // vim: sw=4 ts=4