summaryrefslogtreecommitdiffstats
path: root/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp')
-rw-r--r--tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp731
1 files changed, 558 insertions, 173 deletions
diff --git a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
index 1e582d14b..53a1445cd 100644
--- a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
+++ b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp
@@ -1,40 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include "qaudiodecoder.h"
-#include "../shared/mediafileselector.h"
+#include "mediafileselector.h"
+#include "mediabackendutils.h"
-#define TEST_FILE_NAME "testdata/test.wav"
-#define TEST_UNSUPPORTED_FILE_NAME "testdata/test-unsupported.avi"
-#define TEST_CORRUPTED_FILE_NAME "testdata/test-corrupted.wav"
+constexpr char TEST_FILE_NAME[] = "testdata/test.wav";
+constexpr char TEST_UNSUPPORTED_FILE_NAME[] = "testdata/test-unsupported.avi";
+constexpr char TEST_CORRUPTED_FILE_NAME[] = "testdata/test-corrupted.wav";
+constexpr char TEST_INVALID_SOURCE[] = "invalid";
+constexpr char TEST_NO_AUDIO_TRACK[] = "testdata/test-no-audio-track.mp4";
+
+constexpr int testFileSampleCount = 44094;
+constexpr int testFileSampleRate = 44100;
+
+constexpr std::chrono::microseconds testFileDuration = [] {
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+ auto duration = nanoseconds(1s) * testFileSampleCount / testFileSampleRate;
+ return round<microseconds>(duration);
+}();
+
+constexpr qint64 testFileDurationUs = qint64(testFileDuration.count());
QT_USE_NAMESPACE
@@ -54,13 +44,29 @@ public slots:
void initTestCase();
private slots:
+ void testMediaFilesAreSupported();
+ void directBruteForceReading();
+ void indirectReadingByBufferReadySignal();
+ void indirectReadingByBufferAvailableSignal();
+ void stopOnBufferReady();
+ void restartOnBufferReady();
+ void restartOnFinish();
void fileTest();
void unsupportedFileTest();
void corruptedFileTest();
+ void invalidSource();
void deviceTest();
+ void play_emitsFormatError_whenMediaHasNoAudioTrack();
private:
- bool isWavSupported();
+ QUrl testFileUrl(const QString filePath);
+ void checkNoMoreChanges(QAudioDecoder &decoder);
+#ifdef Q_OS_ANDROID
+ QTemporaryFile *temporaryFile = nullptr;
+#endif
+
+ MediaFileSelector m_mediaSelector;
+ MaybeUrl m_wavFile = QUnexpect{};
};
void tst_QAudioDecoderBackend::init()
@@ -70,81 +76,343 @@ void tst_QAudioDecoderBackend::init()
void tst_QAudioDecoderBackend::initTestCase()
{
QAudioDecoder d;
- if (!d.isAvailable())
+ if (!d.isSupported())
QSKIP("Audio decoder service is not available");
- qRegisterMetaType<QMediaContent>();
+ m_wavFile = m_mediaSelector.select(QFINDTESTDATA(TEST_FILE_NAME));
}
void tst_QAudioDecoderBackend::cleanup()
{
+#ifdef Q_OS_ANDROID
+ if (temporaryFile) {
+ delete temporaryFile;
+ temporaryFile = nullptr;
+ }
+#endif
}
-bool tst_QAudioDecoderBackend::isWavSupported()
+QUrl tst_QAudioDecoderBackend::testFileUrl(const QString filePath)
{
-#ifdef WAV_SUPPORT_NOT_FORCED
- return !MediaFileSelector::selectMediaFile(QStringList() << QFINDTESTDATA(TEST_FILE_NAME)).isNull();
+ QUrl url;
+#ifndef Q_OS_ANDROID
+ QFileInfo fileInfo(QFINDTESTDATA(filePath));
+ url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
#else
- return true;
+ QFile file(":/" + filePath);
+ if (temporaryFile) {
+ delete temporaryFile;
+ temporaryFile = nullptr;
+ }
+ if (file.open(QIODevice::ReadOnly)) {
+ temporaryFile = QTemporaryFile::createNativeFile(file);
+ url = QUrl(temporaryFile->fileName());
+ }
#endif
+ return url;
+}
+
+void tst_QAudioDecoderBackend::checkNoMoreChanges(QAudioDecoder &decoder)
+{
+ QSignalSpy finishedSpy(&decoder, &QAudioDecoder::finished);
+ QSignalSpy bufferReadySpy(&decoder, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferAvailableSpy(&decoder, &QAudioDecoder::bufferAvailableChanged);
+
+ QTest::qWait(50); // wait a bit to check nothing happened after finish
+
+ QCOMPARE(finishedSpy.size(), 0);
+ QCOMPARE(bufferReadySpy.size(), 0);
+ QCOMPARE(bufferAvailableSpy.size(), 0);
+}
+
+void tst_QAudioDecoderBackend::testMediaFilesAreSupported()
+{
+ QCOMPARE(m_mediaSelector.dumpErrors(), "");
+}
+
+void tst_QAudioDecoderBackend::directBruteForceReading()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decoder.isDecoding());
+
+ auto waitAndCheck = [](auto &&predicate) { QVERIFY(QTest::qWaitFor(predicate)); };
+
+ auto waitForBufferAvailable = [&]() {
+ waitAndCheck([&]() { return !decoder.isDecoding() || decoder.bufferAvailable(); });
+
+ return decoder.bufferAvailable();
+ };
+
+ while (waitForBufferAvailable()) {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ }
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+}
+
+void tst_QAudioDecoderBackend::indirectReadingByBufferReadySignal()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ QVERIFY(decoder.bufferAvailable());
+
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+ QVERIFY(!decoder.bufferAvailable());
+
+ sampleCount += buffer.sampleCount();
+ });
+
+ QSignalSpy decodingSpy(&decoder, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decodingSpy.size() >= 1);
+
+ QTRY_VERIFY(finishSpy.size() == 1);
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(finishSpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::indirectReadingByBufferAvailableSignal() {
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferAvailableChanged, this, [&](bool available) {
+ QCOMPARE(decoder.bufferAvailable(), available);
+
+ if (!available)
+ return;
+
+ while (decoder.bufferAvailable()) {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ }
+ });
+
+ QSignalSpy decodingSpy(&decoder, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ QVERIFY(!decoder.isDecoding());
+ QVERIFY(!decoder.bufferAvailable());
+
+ decoder.start();
+ QTRY_VERIFY(decodingSpy.size() >= 1);
+
+ QTRY_VERIFY(finishSpy.size() == 1);
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(finishSpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::stopOnBufferReady()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ decoder.read(); // run next reading
+ decoder.stop();
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+ QSignalSpy bufferReadySpy(&decoder, &QAudioDecoder::bufferReady);
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ bufferReadySpy.wait();
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(bufferReadySpy.size(), 1);
+}
+
+void tst_QAudioDecoderBackend::restartOnBufferReady()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ std::once_flag restartOnce;
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ QVERIFY(decoder.bufferAvailable());
+
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+ QVERIFY(!decoder.bufferAvailable());
+
+ sampleCount += buffer.sampleCount();
+
+ std::call_once(restartOnce, [&]() {
+ sampleCount = 0;
+ decoder.stop();
+ decoder.start();
+ });
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ QTRY_VERIFY2(finishSpy.size() == 2, "Wait for signals after restart and after finishing");
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+
+ QCOMPARE(sampleCount, testFileSampleCount);
+}
+
+void tst_QAudioDecoderBackend::restartOnFinish()
+{
+ CHECK_SELECTED_URL(m_wavFile);
+
+ QAudioDecoder decoder;
+ if (decoder.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+
+ int sampleCount = 0;
+
+ connect(&decoder, &QAudioDecoder::bufferReady, this, [&]() {
+ auto buffer = decoder.read();
+ QVERIFY(buffer.isValid());
+
+ sampleCount += buffer.sampleCount();
+ });
+
+ QSignalSpy finishSpy(&decoder, &QAudioDecoder::finished);
+
+ std::once_flag restartOnce;
+ connect(&decoder, &QAudioDecoder::finished, this, [&]() {
+ QVERIFY(!decoder.bufferAvailable());
+ QVERIFY(!decoder.isDecoding());
+
+ std::call_once(restartOnce, [&]() {
+ sampleCount = 0;
+ decoder.start();
+ });
+ });
+
+ decoder.setSource(*m_wavFile);
+ decoder.start();
+
+ QTRY_VERIFY(finishSpy.size() == 2);
+
+ QVERIFY(!decoder.isDecoding());
+
+ checkNoMoreChanges(decoder);
+ QCOMPARE(sampleCount, testFileSampleCount);
}
void tst_QAudioDecoderBackend::fileTest()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ CHECK_SELECTED_URL(m_wavFile);
QAudioDecoder d;
- if (d.error() == QAudioDecoder::ServiceMissingError)
+ if (d.error() == QAudioDecoder::NotSupportedError)
QSKIP("There is no audio decoding support on this platform.");
QAudioBuffer buffer;
quint64 duration = 0;
int byteCount = 0;
int sampleCount = 0;
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.sourceFilename(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME));
- d.setSourceFilename(fileInfo.absoluteFilePath());
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+
+ d.setSource(*m_wavFile);
+ QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath());
+ QCOMPARE(d.source(), *m_wavFile);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState);
- QTRY_VERIFY(!stateSpy.isEmpty());
+
+ QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
// Test file is 44.1K 16bit mono, 44094 samples
QCOMPARE(buffer.format().channelCount(), 1);
- QCOMPARE(buffer.format().sampleRate(), 44100);
- QCOMPARE(buffer.format().sampleSize(), 16);
- QCOMPARE(buffer.format().sampleType(), QAudioFormat::SignedInt);
- QCOMPARE(buffer.format().codec(), QString("audio/pcm"));
+ QCOMPARE(buffer.format().sampleRate(), testFileSampleRate);
+ QCOMPARE(buffer.format().sampleFormat(), QAudioFormat::Int16);
QCOMPARE(buffer.byteCount(), buffer.sampleCount() * 2); // 16bit mono
// The decoder should still have no format set
QVERIFY(d.audioFormat() == QAudioFormat());
-
QVERIFY(errorSpy.isEmpty());
duration += buffer.duration();
@@ -152,7 +420,7 @@ void tst_QAudioDecoderBackend::fileTest()
byteCount += buffer.byteCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
@@ -160,45 +428,46 @@ void tst_QAudioDecoderBackend::fileTest()
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000));
+ QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qint64(duration / 1000));
duration += buffer.duration();
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
}
// Make sure the duration is roughly correct (+/- 20ms)
- QCOMPARE(sampleCount, 44094);
- QCOMPARE(byteCount, 44094 * 2);
+ QCOMPARE(sampleCount, testFileSampleCount);
+ QCOMPARE(byteCount, testFileSampleCount * 2);
QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.size(), 1);
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_VERIFY(!d.isDecoding());
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
readySpy.clear();
bufferChangedSpy.clear();
- stateSpy.clear();
+ isDecodingSpy.clear();
durationSpy.clear();
finishedSpy.clear();
positionSpy.clear();
+#ifdef Q_OS_ANDROID
+ QSKIP("Setting a desired audio format is not yet supported on Android", QTest::SkipSingle);
+#endif
// change output audio format
QAudioFormat format;
format.setChannelCount(2);
- format.setSampleSize(8);
format.setSampleRate(11050);
- format.setCodec("audio/pcm");
- format.setSampleType(QAudioFormat::SignedInt);
+ format.setSampleFormat(QAudioFormat::UInt8);
d.setAudioFormat(format);
@@ -213,13 +482,16 @@ void tst_QAudioDecoderBackend::fileTest()
byteCount = 0;
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState);
- QTRY_VERIFY(!stateSpy.isEmpty());
+ QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
@@ -235,40 +507,35 @@ void tst_QAudioDecoderBackend::fileTest()
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
- // Now drain the decoder
- if (duration < 998000) {
- QTRY_COMPARE(d.bufferAvailable(), true);
- }
+ while (finishedSpy.isEmpty() || d.bufferAvailable()) {
+ if (!d.bufferAvailable()) {
+ QTest::qWait(std::chrono::milliseconds(10));
+ continue;
+ }
- while (d.bufferAvailable()) {
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000));
- QVERIFY(d.position() - (duration / 1000) < 20);
+ QCOMPARE(positionSpy.takeLast().at(0).toLongLong(), qlonglong(duration / 1000));
+ QCOMPARE_LT(d.position() - (duration / 1000), 20u);
duration += buffer.duration();
sampleCount += buffer.sampleCount();
byteCount += buffer.byteCount();
-
- if (duration < 998000) {
- QTRY_COMPARE(d.bufferAvailable(), true);
- }
}
// Resampling might end up with fewer or more samples
// so be a bit sloppy
- QVERIFY(qAbs(sampleCount - 22047) < 100);
- QVERIFY(qAbs(byteCount - 22047) < 100);
- QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
- QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QCOMPARE_LT(qAbs(sampleCount - 22047), 100);
+ QCOMPARE_LT(qAbs(byteCount - 22047), 100);
+ QCOMPARE_LT(qAbs(qint64(duration) - testFileDurationUs), 20000);
+ QCOMPARE_LT(qAbs((d.position() + (buffer.duration() / 1000)) - 1000), 20);
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QVERIFY(!d.isDecoding());
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_VERIFY(!d.isDecoding());
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
}
@@ -279,32 +546,32 @@ void tst_QAudioDecoderBackend::fileTest()
void tst_QAudioDecoderBackend::unsupportedFileTest()
{
QAudioDecoder d;
- if (d.error() == QAudioDecoder::ServiceMissingError)
+ if (d.error() == QAudioDecoder::NotSupportedError)
QSKIP("There is no audio decoding support on this platform.");
QAudioBuffer buffer;
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.sourceFilename(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_UNSUPPORTED_FILE_NAME));
- d.setSourceFilename(fileInfo.absoluteFilePath());
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QUrl url = testFileUrl(TEST_UNSUPPORTED_FILE_NAME);
+ d.setSource(url);
+ QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath());
+ QCOMPARE(d.source(), url);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.audioFormat(), QAudioFormat());
QCOMPARE(d.duration(), qint64(-1));
@@ -321,16 +588,17 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
// Check all other spies.
QVERIFY(readySpy.isEmpty());
QVERIFY(bufferChangedSpy.isEmpty());
- QVERIFY(stateSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
- QVERIFY(durationSpy.isEmpty());
+ // Either reject the file directly, or set the duration to 5secs on setUrl() and back to -1 on start()
+ QVERIFY(durationSpy.isEmpty() || durationSpy.size() == 2);
errorSpy.clear();
// Try read even if the file is not supported to test robustness.
buffer = d.read();
- QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!buffer.isValid());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.position(), qint64(-1));
@@ -338,14 +606,14 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
QVERIFY(errorSpy.isEmpty());
QVERIFY(readySpy.isEmpty());
QVERIFY(bufferChangedSpy.isEmpty());
- QVERIFY(stateSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
- QVERIFY(durationSpy.isEmpty());
+ QVERIFY(durationSpy.isEmpty() || durationSpy.size() == 2);
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
}
@@ -357,32 +625,32 @@ void tst_QAudioDecoderBackend::unsupportedFileTest()
void tst_QAudioDecoderBackend::corruptedFileTest()
{
QAudioDecoder d;
- if (d.error() == QAudioDecoder::ServiceMissingError)
+ if (d.error() == QAudioDecoder::NotSupportedError)
QSKIP("There is no audio decoding support on this platform.");
QAudioBuffer buffer;
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.sourceFilename(), QString(""));
+ QCOMPARE(d.source(), QUrl());
QVERIFY(d.audioFormat() == QAudioFormat());
// Test local file
- QFileInfo fileInfo(QFINDTESTDATA(TEST_CORRUPTED_FILE_NAME));
- d.setSourceFilename(fileInfo.absoluteFilePath());
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QUrl url = testFileUrl(TEST_CORRUPTED_FILE_NAME);
+ d.setSource(url);
+ QVERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath());
+ QCOMPARE(d.source(), url);
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.audioFormat(), QAudioFormat());
QCOMPARE(d.duration(), qint64(-1));
@@ -399,7 +667,7 @@ void tst_QAudioDecoderBackend::corruptedFileTest()
// Check all other spies.
QVERIFY(readySpy.isEmpty());
QVERIFY(bufferChangedSpy.isEmpty());
- QVERIFY(stateSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
QVERIFY(durationSpy.isEmpty());
@@ -408,7 +676,7 @@ void tst_QAudioDecoderBackend::corruptedFileTest()
// Try read even if the file is corrupted to test the robustness.
buffer = d.read();
- QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!buffer.isValid());
QVERIFY(!d.bufferAvailable());
QCOMPARE(d.position(), qint64(-1));
@@ -416,72 +684,161 @@ void tst_QAudioDecoderBackend::corruptedFileTest()
QVERIFY(errorSpy.isEmpty());
QVERIFY(readySpy.isEmpty());
QVERIFY(bufferChangedSpy.isEmpty());
- QVERIFY(stateSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
+ QVERIFY(finishedSpy.isEmpty());
+ QVERIFY(positionSpy.isEmpty());
+ QVERIFY(durationSpy.isEmpty());
+
+ d.stop();
+ QTRY_VERIFY(!d.isDecoding());
+ QCOMPARE(d.duration(), qint64(-1));
+ QVERIFY(!d.bufferAvailable());
+}
+
+void tst_QAudioDecoderBackend::invalidSource()
+{
+ QAudioDecoder d;
+ if (d.error() == QAudioDecoder::NotSupportedError)
+ QSKIP("There is no audio decoding support on this platform.");
+ QAudioBuffer buffer;
+
+ QVERIFY(!d.isDecoding());
+ QVERIFY(d.bufferAvailable() == false);
+ QCOMPARE(d.source(), QUrl());
+ QVERIFY(d.audioFormat() == QAudioFormat());
+
+ // Test invalid file source
+ QFileInfo fileInfo(TEST_INVALID_SOURCE);
+ QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ d.setSource(url);
+ QVERIFY(!d.isDecoding());
+ QVERIFY(!d.bufferAvailable());
+ QCOMPARE(d.source(), url);
+
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
+ QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
+
+ d.start();
+ QTRY_VERIFY(!d.isDecoding());
+ QVERIFY(!d.bufferAvailable());
+ QCOMPARE(d.audioFormat(), QAudioFormat());
+ QCOMPARE(d.duration(), qint64(-1));
+ QCOMPARE(d.position(), qint64(-1));
+
+ // Check the error code.
+ QTRY_VERIFY(!errorSpy.isEmpty());
+
+ // Have to use qvariant_cast, toInt will return 0 because unrecognized type;
+ QAudioDecoder::Error errorCode = qvariant_cast<QAudioDecoder::Error>(errorSpy.takeLast().at(0));
+ QCOMPARE(errorCode, QAudioDecoder::ResourceError);
+ QCOMPARE(d.error(), QAudioDecoder::ResourceError);
+
+ // Check all other spies.
+ QVERIFY(readySpy.isEmpty());
+ QVERIFY(bufferChangedSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
+ QVERIFY(finishedSpy.isEmpty());
+ QVERIFY(positionSpy.isEmpty());
+ QVERIFY(durationSpy.isEmpty());
+
+ errorSpy.clear();
+
+ d.stop();
+ QTRY_VERIFY(!d.isDecoding());
+ QCOMPARE(d.duration(), qint64(-1));
+ QVERIFY(!d.bufferAvailable());
+
+ QFile file;
+ file.setFileName(TEST_INVALID_SOURCE);
+ file.open(QIODevice::ReadOnly);
+ d.setSourceDevice(&file);
+
+ d.start();
+ QTRY_VERIFY(!d.isDecoding());
+ QVERIFY(!d.bufferAvailable());
+ QCOMPARE(d.audioFormat(), QAudioFormat());
+ QCOMPARE(d.duration(), qint64(-1));
+ QCOMPARE(d.position(), qint64(-1));
+
+ // Check the error code.
+ QTRY_VERIFY(!errorSpy.isEmpty());
+ errorCode = qvariant_cast<QAudioDecoder::Error>(errorSpy.takeLast().at(0));
+ QCOMPARE(errorCode, QAudioDecoder::ResourceError);
+ QCOMPARE(d.error(), QAudioDecoder::ResourceError);
+ // Check all other spies.
+ QVERIFY(readySpy.isEmpty());
+ QVERIFY(bufferChangedSpy.isEmpty());
+ QVERIFY(isDecodingSpy.isEmpty());
QVERIFY(finishedSpy.isEmpty());
QVERIFY(positionSpy.isEmpty());
QVERIFY(durationSpy.isEmpty());
+ errorSpy.clear();
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QCOMPARE(d.duration(), qint64(-1));
QVERIFY(!d.bufferAvailable());
}
void tst_QAudioDecoderBackend::deviceTest()
{
- if (!isWavSupported())
- QSKIP("Sound format is not supported");
+ using namespace std::chrono;
+ CHECK_SELECTED_URL(m_wavFile);
QAudioDecoder d;
- if (d.error() == QAudioDecoder::ServiceMissingError)
+ if (d.error() == QAudioDecoder::NotSupportedError)
QSKIP("There is no audio decoding support on this platform.");
QAudioBuffer buffer;
quint64 duration = 0;
int sampleCount = 0;
- QSignalSpy readySpy(&d, SIGNAL(bufferReady()));
- QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool)));
+ QSignalSpy readySpy(&d, &QAudioDecoder::bufferReady);
+ QSignalSpy bufferChangedSpy(&d, &QAudioDecoder::bufferAvailableChanged);
QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error)));
- QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State)));
- QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64)));
- QSignalSpy finishedSpy(&d, SIGNAL(finished()));
- QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64)));
+ QSignalSpy isDecodingSpy(&d, &QAudioDecoder::isDecodingChanged);
+ QSignalSpy durationSpy(&d, &QAudioDecoder::durationChanged);
+ QSignalSpy finishedSpy(&d, &QAudioDecoder::finished);
+ QSignalSpy positionSpy(&d, &QAudioDecoder::positionChanged);
- QVERIFY(d.state() == QAudioDecoder::StoppedState);
+ QVERIFY(!d.isDecoding());
QVERIFY(d.bufferAvailable() == false);
- QCOMPARE(d.sourceFilename(), QString(""));
+ QCOMPARE(d.source(), QStringLiteral(""));
QVERIFY(d.audioFormat() == QAudioFormat());
-
- QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME));
- QFile file(fileInfo.absoluteFilePath());
+ QFile file(m_wavFile->toString());
QVERIFY(file.open(QIODevice::ReadOnly));
d.setSourceDevice(&file);
QVERIFY(d.sourceDevice() == &file);
- QVERIFY(d.sourceFilename().isEmpty());
+ QVERIFY(d.source().isEmpty());
// We haven't set the format yet
QVERIFY(d.audioFormat() == QAudioFormat());
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState);
- QTRY_VERIFY(!stateSpy.isEmpty());
+
+ QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
// Test file is 44.1K 16bit mono
QCOMPARE(buffer.format().channelCount(), 1);
- QCOMPARE(buffer.format().sampleRate(), 44100);
- QCOMPARE(buffer.format().sampleSize(), 16);
- QCOMPARE(buffer.format().sampleType(), QAudioFormat::SignedInt);
- QCOMPARE(buffer.format().codec(), QString("audio/pcm"));
+ QCOMPARE(buffer.format().sampleRate(), testFileSampleRate);
+ QCOMPARE(buffer.format().sampleFormat(), QAudioFormat::Int16);
QVERIFY(errorSpy.isEmpty());
@@ -489,7 +846,7 @@ void tst_QAudioDecoderBackend::deviceTest()
sampleCount += buffer.sampleCount();
// Now drain the decoder
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
@@ -497,43 +854,50 @@ void tst_QAudioDecoderBackend::deviceTest()
buffer = d.read();
QVERIFY(buffer.isValid());
QTRY_VERIFY(!positionSpy.isEmpty());
- QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000));
+ if (isGStreamerPlatform())
+ QCOMPARE_EQ(positionSpy.takeLast().at(0).toLongLong(),
+ round<milliseconds>(microseconds{ duration }).count());
+ else
+ QCOMPARE_EQ(positionSpy.takeLast().at(0).toLongLong(),
+ floor<milliseconds>(microseconds{ duration }).count());
+
QVERIFY(d.position() - (duration / 1000) < 20);
duration += buffer.duration();
sampleCount += buffer.sampleCount();
- if (sampleCount < 44094) {
+ if (sampleCount < testFileSampleCount) {
QTRY_COMPARE(d.bufferAvailable(), true);
}
}
// Make sure the duration is roughly correct (+/- 20ms)
- QCOMPARE(sampleCount, 44094);
+ QCOMPARE(sampleCount, testFileSampleCount);
QVERIFY(qAbs(qint64(duration) - 1000000) < 20000);
QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20);
- QTRY_COMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(finishedSpy.size(), 1);
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
readySpy.clear();
bufferChangedSpy.clear();
- stateSpy.clear();
+ isDecodingSpy.clear();
durationSpy.clear();
finishedSpy.clear();
positionSpy.clear();
+#ifdef Q_OS_ANDROID
+ QSKIP("Setting a desired audio format is not yet supported on Android", QTest::SkipSingle);
+#endif
// Now try changing formats
QAudioFormat format;
format.setChannelCount(2);
- format.setSampleSize(8);
format.setSampleRate(8000);
- format.setCodec("audio/pcm");
- format.setSampleType(QAudioFormat::SignedInt);
+ format.setSampleFormat(QAudioFormat::UInt8);
d.setAudioFormat(format);
@@ -541,13 +905,18 @@ void tst_QAudioDecoderBackend::deviceTest()
QVERIFY(d.audioFormat() == format);
d.start();
- QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState);
- QTRY_VERIFY(!stateSpy.isEmpty());
+ QVERIFY(d.error() == QAudioDecoder::NoError);
+ QTRY_VERIFY(!isDecodingSpy.isEmpty());
QTRY_VERIFY(!readySpy.isEmpty());
QTRY_VERIFY(!bufferChangedSpy.isEmpty());
QVERIFY(d.bufferAvailable());
QTRY_VERIFY(!durationSpy.isEmpty());
- QVERIFY(qAbs(d.duration() - 1000) < 20);
+
+ QVERIFY(qAbs(durationSpy.front().front().value<qint64>() - 1000) < 20);
+ if (finishedSpy.empty())
+ QVERIFY(qAbs(d.duration() - 1000) < 20);
+ else
+ QCOMPARE(d.duration(), -1);
buffer = d.read();
QVERIFY(buffer.isValid());
@@ -560,12 +929,28 @@ void tst_QAudioDecoderBackend::deviceTest()
QVERIFY(errorSpy.isEmpty());
d.stop();
- QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState);
+ QTRY_VERIFY(!d.isDecoding());
QVERIFY(!d.bufferAvailable());
- QTRY_COMPARE(durationSpy.count(), 2);
+ QTRY_COMPARE(durationSpy.size(), 2);
QCOMPARE(d.duration(), qint64(-1));
}
+void tst_QAudioDecoderBackend::play_emitsFormatError_whenMediaHasNoAudioTrack()
+{
+ QSKIP_GSTREAMER("QTBUG-124206: gstreamer does not emit errors");
+
+ QAudioDecoder decoder;
+
+ QSignalSpy errors{ &decoder, qOverload<QAudioDecoder::Error>(&QAudioDecoder::error) };
+
+ decoder.setSource(testFileUrl(TEST_NO_AUDIO_TRACK));
+ decoder.start();
+
+ QTRY_VERIFY(!errors.empty());
+
+ QCOMPARE_EQ(decoder.error(), QAudioDecoder::Error::FormatError);
+}
+
QTEST_MAIN(tst_QAudioDecoderBackend)
#include "tst_qaudiodecoderbackend.moc"