1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29//TESTED_COMPONENT=src/multimedia
30
31#include <QtTest/QtTest>
32#include <QtCore/qlocale.h>
33#include <qaudiooutput.h>
34#include <qaudiodeviceinfo.h>
35#include <qaudio.h>
36#include "qsoundeffect.h"
37
38class tst_QSoundEffect : public QObject
39{
40 Q_OBJECT
41public:
42 tst_QSoundEffect(QObject* parent=0) : QObject(parent) {}
43
44public slots:
45 void init();
46 void cleanup();
47
48private slots:
49 void initTestCase();
50 void testSource();
51 void testLooping();
52 void testVolume();
53 void testMuting();
54
55 void testPlaying();
56 void testStatus();
57
58 void testDestroyWhilePlaying();
59 void testDestroyWhileRestartPlaying();
60
61 void testSetSourceWhileLoading();
62 void testSetSourceWhilePlaying();
63 void testSupportedMimeTypes_data();
64 void testSupportedMimeTypes();
65 void testCorruptFile();
66 void testPlaying24Bits();
67
68private:
69 QSoundEffect* sound;
70 QUrl url; // test.wav: pcm_s16le, 48000 Hz, stereo, s16
71 QUrl url2; // test_tone.wav: pcm_s16le, 44100 Hz, mono
72 QUrl urlCorrupted; // test_corrupted.wav: corrupted
73 QUrl url24Bits; // test24.wav pcm_s24le, 44100 Hz, mono
74};
75
76void tst_QSoundEffect::init()
77{
78 sound->stop();
79 sound->setSource(QUrl());
80 sound->setLoopCount(1);
81 sound->setVolume(1.0);
82 sound->setMuted(false);
83}
84
85void tst_QSoundEffect::cleanup()
86{
87}
88
89void tst_QSoundEffect::initTestCase()
90{
91 // Only perform tests if audio device exists
92 QStringList mimeTypes = sound->supportedMimeTypes();
93 if (mimeTypes.empty())
94 QSKIP("No audio devices available");
95
96 QString testFileName = QStringLiteral("test.wav");
97 QString fullPath = QFINDTESTDATA(testFileName);
98 QVERIFY2(!fullPath.isEmpty(), qPrintable(QStringLiteral("Unable to locate ") + testFileName));
99 url = QUrl::fromLocalFile(localfile: fullPath);
100
101 testFileName = QStringLiteral("test_tone.wav");
102 fullPath = QFINDTESTDATA(testFileName);
103 QVERIFY2(!fullPath.isEmpty(), qPrintable(QStringLiteral("Unable to locate ") + testFileName));
104 url2 = QUrl::fromLocalFile(localfile: fullPath);
105
106 testFileName = QStringLiteral("test_corrupted.wav");
107 fullPath = QFINDTESTDATA(testFileName);
108 QVERIFY2(!fullPath.isEmpty(), qPrintable(QStringLiteral("Unable to locate ") + testFileName));
109 urlCorrupted = QUrl::fromLocalFile(localfile: fullPath);
110
111 testFileName = QStringLiteral("test24.wav");
112 fullPath = QFINDTESTDATA(testFileName);
113 QVERIFY2(!fullPath.isEmpty(), qPrintable(QStringLiteral("Unable to locate ") + testFileName));
114 url24Bits = QUrl::fromLocalFile(localfile: fullPath);
115
116 sound = new QSoundEffect(this);
117
118 QVERIFY(sound->source().isEmpty());
119 QVERIFY(sound->loopCount() == 1);
120 QVERIFY(sound->volume() == 1);
121 QVERIFY(sound->isMuted() == false);
122}
123
124void tst_QSoundEffect::testSource()
125{
126 QSignalSpy readSignal(sound, SIGNAL(sourceChanged()));
127
128 sound->setSource(url);
129 sound->setVolume(0.1f);
130
131 QCOMPARE(sound->source(),url);
132 QCOMPARE(readSignal.count(),1);
133
134 QTestEventLoop::instance().enterLoop(secs: 1);
135 sound->play();
136
137 QTest::qWait(ms: 3000);
138}
139
140void tst_QSoundEffect::testLooping()
141{
142 sound->setSource(url);
143 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
144
145 QSignalSpy readSignal_Count(sound, SIGNAL(loopCountChanged()));
146 QSignalSpy readSignal_Remaining(sound, SIGNAL(loopsRemainingChanged()));
147
148 sound->setLoopCount(5);
149 sound->setVolume(0.1f);
150 QCOMPARE(sound->loopCount(), 5);
151 QCOMPARE(readSignal_Count.count(), 1);
152 QCOMPARE(sound->loopsRemaining(), 0);
153 QCOMPARE(readSignal_Remaining.count(), 0);
154
155 sound->play();
156 QVERIFY(readSignal_Remaining.count() > 0);
157
158 // test.wav is about 200ms, wait until it has finished playing 5 times
159 QTestEventLoop::instance().enterLoop(secs: 3);
160
161 QTRY_COMPARE(sound->loopsRemaining(), 0);
162 QVERIFY(readSignal_Remaining.count() >= 6);
163 QTRY_VERIFY(!sound->isPlaying());
164
165 // QTBUG-36643 (setting the loop count while playing should work)
166 {
167 readSignal_Count.clear();
168 readSignal_Remaining.clear();
169
170 sound->setLoopCount(30);
171 QCOMPARE(sound->loopCount(), 30);
172 QCOMPARE(readSignal_Count.count(), 1);
173 QCOMPARE(sound->loopsRemaining(), 0);
174 QCOMPARE(readSignal_Remaining.count(), 0);
175
176 sound->play();
177 QVERIFY(readSignal_Remaining.count() > 0);
178
179 // wait for the sound to be played several times
180 QTRY_VERIFY(sound->loopsRemaining() <= 20);
181 QVERIFY(readSignal_Remaining.count() >= 10);
182 readSignal_Count.clear();
183 readSignal_Remaining.clear();
184
185 // change the loop count while playing
186 sound->setLoopCount(5);
187 QCOMPARE(sound->loopCount(), 5);
188 QCOMPARE(readSignal_Count.count(), 1);
189 QCOMPARE(sound->loopsRemaining(), 5);
190 QCOMPARE(readSignal_Remaining.count(), 1);
191
192 // wait for all the loops to be completed
193 QTRY_COMPARE(sound->loopsRemaining(), 0);
194 QTRY_VERIFY(readSignal_Remaining.count() >= 6);
195 QTRY_VERIFY(!sound->isPlaying());
196 }
197
198 {
199 readSignal_Count.clear();
200 readSignal_Remaining.clear();
201
202 sound->setLoopCount(QSoundEffect::Infinite);
203 QCOMPARE(sound->loopCount(), int(QSoundEffect::Infinite));
204 QCOMPARE(readSignal_Count.count(), 1);
205 QCOMPARE(sound->loopsRemaining(), 0);
206 QCOMPARE(readSignal_Remaining.count(), 0);
207
208 sound->play();
209 QTRY_COMPARE(sound->loopsRemaining(), int(QSoundEffect::Infinite));
210 QCOMPARE(readSignal_Remaining.count(), 1);
211
212 QTest::qWait(ms: 1500);
213 QVERIFY(sound->isPlaying());
214 readSignal_Count.clear();
215 readSignal_Remaining.clear();
216
217 // Setting the loop count to 0 should play it one last time
218 sound->setLoopCount(0);
219 QCOMPARE(sound->loopCount(), 1);
220 QCOMPARE(readSignal_Count.count(), 1);
221 QCOMPARE(sound->loopsRemaining(), 1);
222 QCOMPARE(readSignal_Remaining.count(), 1);
223
224 QTRY_COMPARE(sound->loopsRemaining(), 0);
225 QTRY_VERIFY(readSignal_Remaining.count() >= 2);
226 QTRY_VERIFY(!sound->isPlaying());
227 }
228}
229
230void tst_QSoundEffect::testVolume()
231{
232 QSignalSpy readSignal(sound, SIGNAL(volumeChanged()));
233
234 sound->setVolume(0.5);
235 QCOMPARE(sound->volume(),0.5);
236
237 QTest::qWait(ms: 20);
238 QCOMPARE(readSignal.count(),1);
239}
240
241void tst_QSoundEffect::testMuting()
242{
243 QSignalSpy readSignal(sound, SIGNAL(mutedChanged()));
244
245 sound->setMuted(true);
246 QCOMPARE(sound->isMuted(),true);
247
248 QTest::qWait(ms: 20);
249 QCOMPARE(readSignal.count(),1);
250}
251
252void tst_QSoundEffect::testPlaying()
253{
254 sound->setLoopCount(QSoundEffect::Infinite);
255 sound->setVolume(0.1f);
256 //valid source
257 sound->setSource(url);
258 QTestEventLoop::instance().enterLoop(secs: 1);
259 sound->play();
260 QTestEventLoop::instance().enterLoop(secs: 1);
261 QTRY_COMPARE(sound->isPlaying(), true);
262 sound->stop();
263
264 //empty source
265 sound->setSource(QUrl());
266 QTestEventLoop::instance().enterLoop(secs: 1);
267 sound->play();
268 QTestEventLoop::instance().enterLoop(secs: 1);
269 QTRY_COMPARE(sound->isPlaying(), false);
270
271 //invalid source
272 sound->setSource(QUrl((QLatin1String("invalid source"))));
273 QTestEventLoop::instance().enterLoop(secs: 1);
274 sound->play();
275 QTestEventLoop::instance().enterLoop(secs: 1);
276 QTRY_COMPARE(sound->isPlaying(), false);
277
278 sound->setLoopCount(1); // TODO: What if one of the tests fail?
279}
280
281void tst_QSoundEffect::testStatus()
282{
283 sound->setSource(QUrl());
284 QCOMPARE(sound->status(), QSoundEffect::Null);
285
286 //valid source
287 sound->setSource(url);
288
289 QTestEventLoop::instance().enterLoop(secs: 1);
290 QCOMPARE(sound->status(), QSoundEffect::Ready);
291
292 //empty source
293 sound->setSource(QUrl());
294 QTestEventLoop::instance().enterLoop(secs: 1);
295 QCOMPARE(sound->status(), QSoundEffect::Null);
296
297 //invalid source
298 sound->setLoopCount(QSoundEffect::Infinite);
299
300 sound->setSource(QUrl(QLatin1String("invalid source")));
301 QTestEventLoop::instance().enterLoop(secs: 1);
302 QCOMPARE(sound->status(), QSoundEffect::Error);
303}
304
305void tst_QSoundEffect::testDestroyWhilePlaying()
306{
307 QSoundEffect *instance = new QSoundEffect();
308 instance->setSource(url);
309 instance->setVolume(0.1f);
310 QTestEventLoop::instance().enterLoop(secs: 1);
311 instance->play();
312 QTest::qWait(ms: 500);
313 delete instance;
314 QTestEventLoop::instance().enterLoop(secs: 1);
315}
316
317void tst_QSoundEffect::testDestroyWhileRestartPlaying()
318{
319 QSoundEffect *instance = new QSoundEffect();
320 instance->setSource(url);
321 instance->setVolume(0.1f);
322 QTestEventLoop::instance().enterLoop(secs: 1);
323 instance->play();
324 QTest::qWait(ms: 1000);
325 //restart playing
326 instance->play();
327 delete instance;
328 QTestEventLoop::instance().enterLoop(secs: 1);
329}
330
331void tst_QSoundEffect::testSetSourceWhileLoading()
332{
333 for (int i = 0; i < 10; i++) {
334 sound->setSource(url);
335 QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Ready);
336 sound->setSource(url); // set same source again
337 QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Ready);
338 QTRY_COMPARE(sound->status(), QSoundEffect::Ready); // make sure it switches to ready state
339 sound->play();
340 QVERIFY(sound->isPlaying());
341
342 sound->setSource(QUrl());
343 QCOMPARE(sound->status(), QSoundEffect::Null);
344
345 sound->setSource(url2);
346 QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Ready);
347 sound->setSource(url); // set different source
348 QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Ready);
349 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
350 sound->play();
351 QVERIFY(sound->isPlaying());
352 sound->stop();
353
354 sound->setSource(QUrl());
355 QCOMPARE(sound->status(), QSoundEffect::Null);
356 }
357}
358
359void tst_QSoundEffect::testSetSourceWhilePlaying()
360{
361 for (int i = 0; i < 10; i++) {
362 sound->setSource(url);
363 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
364 sound->play();
365 QVERIFY(sound->isPlaying());
366 sound->setSource(url); // set same source again
367 QCOMPARE(sound->status(), QSoundEffect::Ready);
368 QVERIFY(sound->isPlaying()); // playback doesn't stop, URL is the same
369 sound->play();
370 QVERIFY(sound->isPlaying());
371
372 sound->setSource(QUrl());
373 QCOMPARE(sound->status(), QSoundEffect::Null);
374
375 sound->setSource(url2);
376 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
377 sound->play();
378 QVERIFY(sound->isPlaying());
379 sound->setSource(url); // set different source
380 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
381 QVERIFY(!sound->isPlaying()); // playback stops, URL is different
382 sound->play();
383 QVERIFY(sound->isPlaying());
384 sound->stop();
385
386 sound->setSource(QUrl());
387 QCOMPARE(sound->status(), QSoundEffect::Null);
388 }
389}
390
391void tst_QSoundEffect::testSupportedMimeTypes_data()
392{
393 // Verify also passing of audio device info as parameter
394 QTest::addColumn<QSoundEffect*>(name: "instance");
395 QTest::newRow(dataTag: "without QAudioDeviceInfo") << sound;
396 QAudioDeviceInfo deviceInfo(QAudioDeviceInfo::defaultOutputDevice());
397 QTest::newRow(dataTag: "with QAudioDeviceInfo") << new QSoundEffect(deviceInfo, this);
398}
399
400void tst_QSoundEffect::testSupportedMimeTypes()
401{
402 QFETCH(QSoundEffect*, instance);
403 QStringList mimeTypes = instance->supportedMimeTypes();
404 QVERIFY(!mimeTypes.empty());
405 QVERIFY(mimeTypes.indexOf(QLatin1String("audio/wav")) != -1 ||
406 mimeTypes.indexOf(QLatin1String("audio/x-wav")) != -1 ||
407 mimeTypes.indexOf(QLatin1String("audio/wave")) != -1 ||
408 mimeTypes.indexOf(QLatin1String("audio/x-pn-wav")) != -1);
409}
410
411void tst_QSoundEffect::testCorruptFile()
412{
413 for (int i = 0; i < 10; i++) {
414 QSignalSpy statusSpy(sound, SIGNAL(statusChanged()));
415 sound->setSource(urlCorrupted);
416 QVERIFY(!sound->isPlaying());
417 QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Error);
418 QTRY_COMPARE(sound->status(), QSoundEffect::Error);
419 QCOMPARE(statusSpy.count(), 2);
420 sound->play();
421 QVERIFY(!sound->isPlaying());
422
423 sound->setSource(url);
424 QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
425 sound->play();
426 QVERIFY(sound->isPlaying());
427 }
428}
429
430void tst_QSoundEffect::testPlaying24Bits()
431{
432 sound->setLoopCount(QSoundEffect::Infinite);
433 sound->setSource(url24Bits);
434 QTestEventLoop::instance().enterLoop(secs: 1);
435 sound->play();
436 QTestEventLoop::instance().enterLoop(secs: 1);
437 QTRY_COMPARE(sound->isPlaying(), true);
438 sound->stop();
439
440 QSignalSpy readSignal(sound, SIGNAL(volumeChanged()));
441 sound->setVolume(0.5);
442 QCOMPARE(sound->volume(), 0.5);
443 sound->play();
444 QTestEventLoop::instance().enterLoop(secs: 1);
445 QTRY_COMPARE(sound->isPlaying(), true);
446 QCOMPARE(readSignal.count(), 1);
447 sound->stop();
448}
449
450QTEST_MAIN(tst_QSoundEffect)
451
452#include "tst_qsoundeffect.moc"
453

source code of qtmultimedia/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp