From 87ec3461c135990f9e01d7cb71bc6016c3538db1 Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Mon, 6 Feb 2012 17:45:10 +1000 Subject: Add the audio decoder variant of QMediaPlayer. Rather than the probe based way of doing it. Initially private. Change-Id: I30005f8da22f6451cb9de8eb3f0e193838d48c93 Reviewed-by: Ling Hu Reviewed-by: Jonas Rabbe --- tests/auto/unit/multimedia.pro | 3 +- tests/auto/unit/qaudiodecoder/qaudiodecoder.pro | 22 ++ .../auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp | 306 +++++++++++++++++++++ .../qmultimedia_common/mockaudiodecodercontrol.h | 204 ++++++++++++++ .../qmultimedia_common/mockaudiodecoderservice.h | 82 ++++++ tests/auto/unit/qmultimedia_common/mockdecoder.pri | 9 + 6 files changed, 625 insertions(+), 1 deletion(-) create mode 100644 tests/auto/unit/qaudiodecoder/qaudiodecoder.pro create mode 100644 tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp create mode 100644 tests/auto/unit/qmultimedia_common/mockaudiodecodercontrol.h create mode 100644 tests/auto/unit/qmultimedia_common/mockaudiodecoderservice.h create mode 100644 tests/auto/unit/qmultimedia_common/mockdecoder.pri (limited to 'tests/auto/unit') diff --git a/tests/auto/unit/multimedia.pro b/tests/auto/unit/multimedia.pro index ee5dba821..3fa3f9821 100644 --- a/tests/auto/unit/multimedia.pro +++ b/tests/auto/unit/multimedia.pro @@ -31,4 +31,5 @@ SUBDIRS += \ qwavedecoder \ qaudiobuffer \ qdeclarativeaudio \ - qdeclarativeaudio_4 + qdeclarativeaudio_4 \ + qaudiodecoder diff --git a/tests/auto/unit/qaudiodecoder/qaudiodecoder.pro b/tests/auto/unit/qaudiodecoder/qaudiodecoder.pro new file mode 100644 index 000000000..5b189522f --- /dev/null +++ b/tests/auto/unit/qaudiodecoder/qaudiodecoder.pro @@ -0,0 +1,22 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2012-02-07T15:27:07 +# +#------------------------------------------------- + +QT += multimedia multimedia-private testlib gui + +TARGET = tst_qaudiodecoder + +CONFIG += testcase no_private_qt_headers_warning + +TEMPLATE = app + +INCLUDEPATH += \ + ../../../../src/multimedia/audio + +include (../qmultimedia_common/mock.pri) +include (../qmultimedia_common/mockdecoder.pri) + +SOURCES += tst_qaudiodecoder.cpp +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp b/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp new file mode 100644 index 000000000..aacc607f9 --- /dev/null +++ b/tests/auto/unit/qaudiodecoder/tst_qaudiodecoder.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +#include "qaudiodecoder_p.h" +#include "mockaudiodecoderservice.h" +#include "mockmediaserviceprovider.h" + +class tst_QAudioDecoder : public QObject +{ + Q_OBJECT + +public: + tst_QAudioDecoder(); + +private Q_SLOTS: + void init(); + void ctors(); + void read(); + void stop(); + void format(); + void source(); + +private: + MockAudioDecoderService *mockAudioDecoderService; + MockMediaServiceProvider *mockProvider; +}; + +tst_QAudioDecoder::tst_QAudioDecoder() +{ +} + +void tst_QAudioDecoder::init() +{ + mockAudioDecoderService = new MockAudioDecoderService(this); + mockProvider = new MockMediaServiceProvider(mockAudioDecoderService); + + QMediaServiceProvider::setDefaultServiceProvider(mockProvider); +} + +void tst_QAudioDecoder::ctors() +{ + QAudioDecoder d; + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + QCOMPARE(d.sourceFilename(), QString("")); + + d.setSourceFilename(""); + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + QCOMPARE(d.sourceFilename(), QString("")); +} + +void tst_QAudioDecoder::read() +{ + QAudioDecoder d; + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + + QSignalSpy readySpy(&d, SIGNAL(bufferReady())); + QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); + QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); + + // Starting with empty source == error + d.start(); + + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + + QCOMPARE(readySpy.count(), 0); + QCOMPARE(bufferChangedSpy.count(), 0); + QCOMPARE(errorSpy.count(), 1); + + // Set the source to something + d.setSourceFilename("Blah"); + QCOMPARE(d.sourceFilename(), QString("Blah")); + + readySpy.clear(); + errorSpy.clear(); + bufferChangedSpy.clear(); + + d.start(); + QCOMPARE(d.state(), QAudioDecoder::DecodingState); + QCOMPARE(d.bufferAvailable(), false); // not yet + + // Try to read + bool ok = false; + QAudioBuffer b = d.read(&ok); + + QVERIFY(ok == false); + QVERIFY(!b.isValid()); + + // Read again with no parameter + b = d.read(); + QVERIFY(!b.isValid()); + + // Wait a while + QTRY_COMPARE(d.bufferAvailable(), 1); + + QVERIFY(d.bufferAvailable()); + + b = d.read(&ok); + QVERIFY(b.format().isValid()); + QVERIFY(b.isValid()); + QVERIFY(b.format().channelCount() == 1); + QVERIFY(b.sampleCount() == 4); + + QVERIFY(readySpy.count() >= 1); + QVERIFY(errorSpy.count() == 0); + + if (d.bufferAvailable()) { + QVERIFY(bufferChangedSpy.count() == 1); + } else { + QVERIFY(bufferChangedSpy.count() == 2); + } +} + +void tst_QAudioDecoder::stop() +{ + QAudioDecoder d; + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + + QSignalSpy readySpy(&d, SIGNAL(bufferReady())); + QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); + QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); + + // Starting with empty source == error + d.start(); + + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + + QCOMPARE(readySpy.count(), 0); + QCOMPARE(bufferChangedSpy.count(), 0); + QCOMPARE(errorSpy.count(), 1); + + // Set the source to something + d.setSourceFilename("Blah"); + QCOMPARE(d.sourceFilename(), QString("Blah")); + + readySpy.clear(); + errorSpy.clear(); + bufferChangedSpy.clear(); + + d.start(); + QCOMPARE(d.state(), QAudioDecoder::DecodingState); + QCOMPARE(d.bufferAvailable(), false); // not yet + + // Try to read + bool ok = false; + QAudioBuffer b = d.read(&ok); + + QVERIFY(ok == false); + QVERIFY(!b.isValid()); + + // Read again with no parameter + b = d.read(); + QVERIFY(!b.isValid()); + + // Wait a while + QTRY_COMPARE(d.bufferAvailable(), 1); + + QVERIFY(d.bufferAvailable()); + + // Now stop + d.stop(); + + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); +} + +void tst_QAudioDecoder::format() +{ + QAudioDecoder d; + QVERIFY(d.state() == QAudioDecoder::StoppedState); + QVERIFY(d.bufferAvailable() == false); + + QSignalSpy readySpy(&d, SIGNAL(bufferReady())); + QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); + QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); + + // Set the source to something + d.setSourceFilename("Blah"); + QCOMPARE(d.sourceFilename(), QString("Blah")); + + readySpy.clear(); + errorSpy.clear(); + bufferChangedSpy.clear(); + + d.start(); + QCOMPARE(d.state(), QAudioDecoder::DecodingState); + QCOMPARE(d.bufferAvailable(), false); // not yet + + // Try to read + bool ok = false; + QAudioBuffer b = d.read(&ok); + + QVERIFY(ok == false); + QVERIFY(!b.isValid()); + + // Read again with no parameter + b = d.read(); + QVERIFY(!b.isValid()); + + // Wait a while + QTRY_COMPARE(d.bufferAvailable(), 1); + + b = d.read(&ok); + QVERIFY(d.audioFormat() == b.format()); + + // Setting format while decoding is forbidden + QAudioFormat f(d.audioFormat()); + f.setChannelCount(2); + + d.setAudioFormat(f); + QVERIFY(d.audioFormat() != f); + QVERIFY(d.audioFormat() == b.format()); + + // Now stop, and set something specific + d.stop(); + d.setAudioFormat(f); + QVERIFY(d.audioFormat() == f); + + // Decode again + d.start(); + QTRY_COMPARE(d.bufferAvailable(), 1); + + b = d.read(&ok); + QVERIFY(d.audioFormat() == f); + QVERIFY(b.format() == f); +} + +void tst_QAudioDecoder::source() +{ + QAudioDecoder d; + + QVERIFY(d.sourceFilename().isEmpty()); + QVERIFY(d.sourceDevice() == 0); + + QFile f; + d.setSourceDevice(&f); + QVERIFY(d.sourceFilename().isEmpty()); + QVERIFY(d.sourceDevice() == &f); + + d.setSourceFilename("Foo"); + QVERIFY(d.sourceFilename() == QString("Foo")); + QVERIFY(d.sourceDevice() == 0); + + d.setSourceDevice(0); + QVERIFY(d.sourceFilename().isEmpty()); + QVERIFY(d.sourceDevice() == 0); + + d.setSourceFilename("Foo"); + QVERIFY(d.sourceFilename() == QString("Foo")); + QVERIFY(d.sourceDevice() == 0); + + d.setSourceFilename(QString()); + QVERIFY(d.sourceFilename() == QString()); + QVERIFY(d.sourceDevice() == 0); +} + +QTEST_MAIN(tst_QAudioDecoder) + +#include "tst_qaudiodecoder.moc" diff --git a/tests/auto/unit/qmultimedia_common/mockaudiodecodercontrol.h b/tests/auto/unit/qmultimedia_common/mockaudiodecodercontrol.h new file mode 100644 index 000000000..938da31c0 --- /dev/null +++ b/tests/auto/unit/qmultimedia_common/mockaudiodecodercontrol.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKAUDIODECODERCONTROL_H +#define MOCKAUDIODECODERCONTROL_H + +#include "qmediacontrol.h" +#include + +#include + +#include "qaudiobuffer.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class MockAudioDecoderControl : public QAudioDecoderControl +{ + Q_OBJECT + +public: + MockAudioDecoderControl(QObject *parent = 0) + : QAudioDecoderControl(parent) + , mState(QAudioDecoder::StoppedState) + , mDevice(0) + , mSerial(0) + { + mFormat.setChannels(1); + mFormat.setSampleSize(8); + mFormat.setFrequency(1000); + mFormat.setCodec("audio/x-raw"); + mFormat.setSampleType(QAudioFormat::UnSignedInt); + } + + QAudioDecoder::State state() const + { + return mState; + } + + QString sourceFilename() const + { + return mSource; + } + + QAudioFormat audioFormat() const + { + return mFormat; + } + + void setAudioFormat(const QAudioFormat &format) + { + if (mFormat != format) { + mFormat = format; + emit formatChanged(mFormat); + } + } + + void setSourceFilename(const QString &fileName) + { + mSource = fileName; + mDevice = 0; + stop(); + } + + QIODevice* sourceDevice() const + { + return mDevice; + } + + void setSourceDevice(QIODevice *device) + { + mDevice = device; + mSource.clear(); + stop(); + } + + // When decoding we decode to first buffer, then second buffer + // we then stop until the first is read again and so on, for + // 5 buffers + void start() + { + if (mState == QAudioDecoder::StoppedState) { + if (!mSource.isEmpty()) { + mState = QAudioDecoder::DecodingState; + emit stateChanged(mState); + + QTimer::singleShot(50, this, SLOT(pretendDecode())); + } else { + emit error(QAudioDecoder::ResourceError, "No source set"); + } + } + } + + void stop() + { + if (mState != QAudioDecoder::StoppedState) { + mState = QAudioDecoder::StoppedState; + mSerial = 0; + mBuffers.clear(); + emit stateChanged(mState); + emit bufferAvailableChanged(false); + } + } + + QAudioBuffer read(bool *ok) + { + if (mBuffers.length() > 0) { + if (ok) + *ok = true; + QAudioBuffer a = mBuffers.takeFirst(); + if (mBuffers.length() == 0) + emit bufferAvailableChanged(false); + QTimer::singleShot(50, this, SLOT(pretendDecode())); + return a; + } else { + // Can't do anything here :( + if (ok) + *ok = false; + return QAudioBuffer(); + } + } + + bool bufferAvailable() const + { + return mBuffers.length() > 0; + } + +private slots: + void pretendDecode() + { + // We just keep the length of mBuffers to 3 or less. + if (mBuffers.length() < 3) { + QByteArray b(sizeof(mSerial), 0); + memcpy(b.data(), &mSerial, sizeof(mSerial)); + mSerial++; + mBuffers.push_back(QAudioBuffer(b, mFormat)); + emit bufferReady(); + if (mBuffers.count() == 1) + emit bufferAvailableChanged(true); + } else { + // Can't do anything here, wait for a read to restart the timer + mState = QAudioDecoder::WaitingState; + emit stateChanged(mState); + } + } + +public: + QAudioDecoder::State mState; + QString mSource; + QIODevice *mDevice; + QAudioFormat mFormat; + + int mSerial; + QList mBuffers; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODECODERCONTROL_H diff --git a/tests/auto/unit/qmultimedia_common/mockaudiodecoderservice.h b/tests/auto/unit/qmultimedia_common/mockaudiodecoderservice.h new file mode 100644 index 000000000..35db819e7 --- /dev/null +++ b/tests/auto/unit/qmultimedia_common/mockaudiodecoderservice.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKAUDIODECODERSERVICE_H +#define MOCKAUDIODECODERSERVICE_H + +#include "qmediaservice.h" + +#include "mockaudiodecodercontrol.h" + +class MockAudioDecoderService : public QMediaService +{ + Q_OBJECT + +public: + MockAudioDecoderService(QObject *parent = 0) + : QMediaService(parent) + { + mockControl = new MockAudioDecoderControl(this); + } + + ~MockAudioDecoderService() + { + delete mockControl; + } + + QMediaControl* requestControl(const char *iid) + { + if (qstrcmp(iid, QAudioDecoderControl_iid) == 0) + return mockControl; + return 0; + } + + void releaseControl(QMediaControl *control) + { + Q_UNUSED(control); + } + + MockAudioDecoderControl *mockControl; +}; + + + +#endif // MOCKAUDIODECODERSERVICE_H diff --git a/tests/auto/unit/qmultimedia_common/mockdecoder.pri b/tests/auto/unit/qmultimedia_common/mockdecoder.pri new file mode 100644 index 000000000..8b486e475 --- /dev/null +++ b/tests/auto/unit/qmultimedia_common/mockdecoder.pri @@ -0,0 +1,9 @@ +# Audio decoder related mock backend files +INCLUDEPATH += $$PWD \ + ../../../src/multimedia \ + ../../../src/multimedia/audio \ + ../../../src/multimedia/controls + +HEADERS *= \ + ../qmultimedia_common/mockaudiodecoderservice.h \ + ../qmultimedia_common/mockaudiodecodercontrol.h -- cgit v1.2.3