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 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 | #include <QtTest/QtTest> |
30 | #include <QDebug> |
31 | #include "qaudiodecoder.h" |
32 | |
33 | #include "../shared/mediafileselector.h" |
34 | |
35 | #define TEST_FILE_NAME "testdata/test.wav" |
36 | #define TEST_UNSUPPORTED_FILE_NAME "testdata/test-unsupported.avi" |
37 | #define TEST_CORRUPTED_FILE_NAME "testdata/test-corrupted.wav" |
38 | |
39 | QT_USE_NAMESPACE |
40 | |
41 | /* |
42 | This is the backend conformance test. |
43 | |
44 | Since it relies on platform media framework |
45 | it may be less stable. |
46 | */ |
47 | |
48 | class tst_QAudioDecoderBackend : public QObject |
49 | { |
50 | Q_OBJECT |
51 | public slots: |
52 | void init(); |
53 | void cleanup(); |
54 | void initTestCase(); |
55 | |
56 | private slots: |
57 | void fileTest(); |
58 | void unsupportedFileTest(); |
59 | void corruptedFileTest(); |
60 | void deviceTest(); |
61 | |
62 | private: |
63 | bool isWavSupported(); |
64 | }; |
65 | |
66 | void tst_QAudioDecoderBackend::init() |
67 | { |
68 | } |
69 | |
70 | void tst_QAudioDecoderBackend::initTestCase() |
71 | { |
72 | QAudioDecoder d; |
73 | if (!d.isAvailable()) |
74 | QSKIP("Audio decoder service is not available" ); |
75 | |
76 | qRegisterMetaType<QMediaContent>(); |
77 | } |
78 | |
79 | void tst_QAudioDecoderBackend::cleanup() |
80 | { |
81 | } |
82 | |
83 | bool tst_QAudioDecoderBackend::isWavSupported() |
84 | { |
85 | #ifdef WAV_SUPPORT_NOT_FORCED |
86 | return !MediaFileSelector::selectMediaFile(QStringList() << QFINDTESTDATA(TEST_FILE_NAME)).isNull(); |
87 | #else |
88 | return true; |
89 | #endif |
90 | } |
91 | |
92 | void tst_QAudioDecoderBackend::fileTest() |
93 | { |
94 | if (!isWavSupported()) |
95 | QSKIP("Sound format is not supported" ); |
96 | |
97 | QAudioDecoder d; |
98 | if (d.error() == QAudioDecoder::ServiceMissingError) |
99 | QSKIP("There is no audio decoding support on this platform." ); |
100 | QAudioBuffer buffer; |
101 | quint64 duration = 0; |
102 | int byteCount = 0; |
103 | int sampleCount = 0; |
104 | |
105 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
106 | QVERIFY(d.bufferAvailable() == false); |
107 | QCOMPARE(d.sourceFilename(), QString("" )); |
108 | QVERIFY(d.audioFormat() == QAudioFormat()); |
109 | |
110 | // Test local file |
111 | QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME)); |
112 | d.setSourceFilename(fileInfo.absoluteFilePath()); |
113 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
114 | QVERIFY(!d.bufferAvailable()); |
115 | QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath()); |
116 | |
117 | QSignalSpy readySpy(&d, SIGNAL(bufferReady())); |
118 | QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); |
119 | QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); |
120 | QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State))); |
121 | QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64))); |
122 | QSignalSpy finishedSpy(&d, SIGNAL(finished())); |
123 | QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64))); |
124 | |
125 | d.start(); |
126 | QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState); |
127 | QTRY_VERIFY(!stateSpy.isEmpty()); |
128 | QTRY_VERIFY(!readySpy.isEmpty()); |
129 | QTRY_VERIFY(!bufferChangedSpy.isEmpty()); |
130 | QVERIFY(d.bufferAvailable()); |
131 | QTRY_VERIFY(!durationSpy.isEmpty()); |
132 | QVERIFY(qAbs(d.duration() - 1000) < 20); |
133 | |
134 | buffer = d.read(); |
135 | QVERIFY(buffer.isValid()); |
136 | |
137 | // Test file is 44.1K 16bit mono, 44094 samples |
138 | QCOMPARE(buffer.format().channelCount(), 1); |
139 | QCOMPARE(buffer.format().sampleRate(), 44100); |
140 | QCOMPARE(buffer.format().sampleSize(), 16); |
141 | QCOMPARE(buffer.format().sampleType(), QAudioFormat::SignedInt); |
142 | QCOMPARE(buffer.format().codec(), QString("audio/pcm" )); |
143 | QCOMPARE(buffer.byteCount(), buffer.sampleCount() * 2); // 16bit mono |
144 | |
145 | // The decoder should still have no format set |
146 | QVERIFY(d.audioFormat() == QAudioFormat()); |
147 | |
148 | QVERIFY(errorSpy.isEmpty()); |
149 | |
150 | duration += buffer.duration(); |
151 | sampleCount += buffer.sampleCount(); |
152 | byteCount += buffer.byteCount(); |
153 | |
154 | // Now drain the decoder |
155 | if (sampleCount < 44094) { |
156 | QTRY_COMPARE(d.bufferAvailable(), true); |
157 | } |
158 | |
159 | while (d.bufferAvailable()) { |
160 | buffer = d.read(); |
161 | QVERIFY(buffer.isValid()); |
162 | QTRY_VERIFY(!positionSpy.isEmpty()); |
163 | QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000)); |
164 | |
165 | duration += buffer.duration(); |
166 | sampleCount += buffer.sampleCount(); |
167 | byteCount += buffer.byteCount(); |
168 | |
169 | if (sampleCount < 44094) { |
170 | QTRY_COMPARE(d.bufferAvailable(), true); |
171 | } |
172 | } |
173 | |
174 | // Make sure the duration is roughly correct (+/- 20ms) |
175 | QCOMPARE(sampleCount, 44094); |
176 | QCOMPARE(byteCount, 44094 * 2); |
177 | QVERIFY(qAbs(qint64(duration) - 1000000) < 20000); |
178 | QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20); |
179 | QTRY_COMPARE(finishedSpy.count(), 1); |
180 | QVERIFY(!d.bufferAvailable()); |
181 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
182 | |
183 | d.stop(); |
184 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
185 | QTRY_COMPARE(durationSpy.count(), 2); |
186 | QCOMPARE(d.duration(), qint64(-1)); |
187 | QVERIFY(!d.bufferAvailable()); |
188 | readySpy.clear(); |
189 | bufferChangedSpy.clear(); |
190 | stateSpy.clear(); |
191 | durationSpy.clear(); |
192 | finishedSpy.clear(); |
193 | positionSpy.clear(); |
194 | |
195 | // change output audio format |
196 | QAudioFormat format; |
197 | format.setChannelCount(2); |
198 | format.setSampleSize(8); |
199 | format.setSampleRate(11050); |
200 | format.setCodec("audio/pcm" ); |
201 | format.setSampleType(QAudioFormat::SignedInt); |
202 | |
203 | d.setAudioFormat(format); |
204 | |
205 | // We expect 1 second still, at 11050 * 2 samples == 22k samples. |
206 | // (at 1 byte/sample -> 22kb) |
207 | |
208 | // Make sure it stuck |
209 | QVERIFY(d.audioFormat() == format); |
210 | |
211 | duration = 0; |
212 | sampleCount = 0; |
213 | byteCount = 0; |
214 | |
215 | d.start(); |
216 | QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState); |
217 | QTRY_VERIFY(!stateSpy.isEmpty()); |
218 | QTRY_VERIFY(!readySpy.isEmpty()); |
219 | QTRY_VERIFY(!bufferChangedSpy.isEmpty()); |
220 | QVERIFY(d.bufferAvailable()); |
221 | QTRY_VERIFY(!durationSpy.isEmpty()); |
222 | QVERIFY(qAbs(d.duration() - 1000) < 20); |
223 | |
224 | buffer = d.read(); |
225 | QVERIFY(buffer.isValid()); |
226 | // See if we got the right format |
227 | QVERIFY(buffer.format() == format); |
228 | |
229 | // The decoder should still have the same format |
230 | QVERIFY(d.audioFormat() == format); |
231 | |
232 | QVERIFY(errorSpy.isEmpty()); |
233 | |
234 | duration += buffer.duration(); |
235 | sampleCount += buffer.sampleCount(); |
236 | byteCount += buffer.byteCount(); |
237 | |
238 | // Now drain the decoder |
239 | if (duration < 998000) { |
240 | QTRY_COMPARE(d.bufferAvailable(), true); |
241 | } |
242 | |
243 | while (d.bufferAvailable()) { |
244 | buffer = d.read(); |
245 | QVERIFY(buffer.isValid()); |
246 | QTRY_VERIFY(!positionSpy.isEmpty()); |
247 | QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000)); |
248 | QVERIFY(d.position() - (duration / 1000) < 20); |
249 | |
250 | duration += buffer.duration(); |
251 | sampleCount += buffer.sampleCount(); |
252 | byteCount += buffer.byteCount(); |
253 | |
254 | if (duration < 998000) { |
255 | QTRY_COMPARE(d.bufferAvailable(), true); |
256 | } |
257 | } |
258 | |
259 | // Resampling might end up with fewer or more samples |
260 | // so be a bit sloppy |
261 | QVERIFY(qAbs(sampleCount - 22047) < 100); |
262 | QVERIFY(qAbs(byteCount - 22047) < 100); |
263 | QVERIFY(qAbs(qint64(duration) - 1000000) < 20000); |
264 | QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20); |
265 | QTRY_COMPARE(finishedSpy.count(), 1); |
266 | QVERIFY(!d.bufferAvailable()); |
267 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
268 | |
269 | d.stop(); |
270 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
271 | QTRY_COMPARE(durationSpy.count(), 2); |
272 | QCOMPARE(d.duration(), qint64(-1)); |
273 | QVERIFY(!d.bufferAvailable()); |
274 | } |
275 | |
276 | /* |
277 | The avi file has an audio stream not supported by any codec. |
278 | */ |
279 | void tst_QAudioDecoderBackend::unsupportedFileTest() |
280 | { |
281 | QAudioDecoder d; |
282 | if (d.error() == QAudioDecoder::ServiceMissingError) |
283 | QSKIP("There is no audio decoding support on this platform." ); |
284 | QAudioBuffer buffer; |
285 | |
286 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
287 | QVERIFY(d.bufferAvailable() == false); |
288 | QCOMPARE(d.sourceFilename(), QString("" )); |
289 | QVERIFY(d.audioFormat() == QAudioFormat()); |
290 | |
291 | // Test local file |
292 | QFileInfo fileInfo(QFINDTESTDATA(TEST_UNSUPPORTED_FILE_NAME)); |
293 | d.setSourceFilename(fileInfo.absoluteFilePath()); |
294 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
295 | QVERIFY(!d.bufferAvailable()); |
296 | QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath()); |
297 | |
298 | QSignalSpy readySpy(&d, SIGNAL(bufferReady())); |
299 | QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); |
300 | QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); |
301 | QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State))); |
302 | QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64))); |
303 | QSignalSpy finishedSpy(&d, SIGNAL(finished())); |
304 | QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64))); |
305 | |
306 | d.start(); |
307 | QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState); |
308 | QVERIFY(!d.bufferAvailable()); |
309 | QCOMPARE(d.audioFormat(), QAudioFormat()); |
310 | QCOMPARE(d.duration(), qint64(-1)); |
311 | QCOMPARE(d.position(), qint64(-1)); |
312 | |
313 | // Check the error code. |
314 | QTRY_VERIFY(!errorSpy.isEmpty()); |
315 | |
316 | // Have to use qvariant_cast, toInt will return 0 because unrecognized type; |
317 | QAudioDecoder::Error errorCode = qvariant_cast<QAudioDecoder::Error>(v: errorSpy.takeLast().at(i: 0)); |
318 | QCOMPARE(errorCode, QAudioDecoder::FormatError); |
319 | QCOMPARE(d.error(), QAudioDecoder::FormatError); |
320 | |
321 | // Check all other spies. |
322 | QVERIFY(readySpy.isEmpty()); |
323 | QVERIFY(bufferChangedSpy.isEmpty()); |
324 | QVERIFY(stateSpy.isEmpty()); |
325 | QVERIFY(finishedSpy.isEmpty()); |
326 | QVERIFY(positionSpy.isEmpty()); |
327 | QVERIFY(durationSpy.isEmpty()); |
328 | |
329 | errorSpy.clear(); |
330 | |
331 | // Try read even if the file is not supported to test robustness. |
332 | buffer = d.read(); |
333 | QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState); |
334 | QVERIFY(!buffer.isValid()); |
335 | QVERIFY(!d.bufferAvailable()); |
336 | QCOMPARE(d.position(), qint64(-1)); |
337 | |
338 | QVERIFY(errorSpy.isEmpty()); |
339 | QVERIFY(readySpy.isEmpty()); |
340 | QVERIFY(bufferChangedSpy.isEmpty()); |
341 | QVERIFY(stateSpy.isEmpty()); |
342 | QVERIFY(finishedSpy.isEmpty()); |
343 | QVERIFY(positionSpy.isEmpty()); |
344 | QVERIFY(durationSpy.isEmpty()); |
345 | |
346 | |
347 | d.stop(); |
348 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
349 | QCOMPARE(d.duration(), qint64(-1)); |
350 | QVERIFY(!d.bufferAvailable()); |
351 | } |
352 | |
353 | /* |
354 | The corrupted file is generated by copying a few random numbers |
355 | from /dev/random on a linux machine. |
356 | */ |
357 | void tst_QAudioDecoderBackend::corruptedFileTest() |
358 | { |
359 | QAudioDecoder d; |
360 | if (d.error() == QAudioDecoder::ServiceMissingError) |
361 | QSKIP("There is no audio decoding support on this platform." ); |
362 | QAudioBuffer buffer; |
363 | |
364 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
365 | QVERIFY(d.bufferAvailable() == false); |
366 | QCOMPARE(d.sourceFilename(), QString("" )); |
367 | QVERIFY(d.audioFormat() == QAudioFormat()); |
368 | |
369 | // Test local file |
370 | QFileInfo fileInfo(QFINDTESTDATA(TEST_CORRUPTED_FILE_NAME)); |
371 | d.setSourceFilename(fileInfo.absoluteFilePath()); |
372 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
373 | QVERIFY(!d.bufferAvailable()); |
374 | QCOMPARE(d.sourceFilename(), fileInfo.absoluteFilePath()); |
375 | |
376 | QSignalSpy readySpy(&d, SIGNAL(bufferReady())); |
377 | QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); |
378 | QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); |
379 | QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State))); |
380 | QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64))); |
381 | QSignalSpy finishedSpy(&d, SIGNAL(finished())); |
382 | QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64))); |
383 | |
384 | d.start(); |
385 | QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState); |
386 | QVERIFY(!d.bufferAvailable()); |
387 | QCOMPARE(d.audioFormat(), QAudioFormat()); |
388 | QCOMPARE(d.duration(), qint64(-1)); |
389 | QCOMPARE(d.position(), qint64(-1)); |
390 | |
391 | // Check the error code. |
392 | QTRY_VERIFY(!errorSpy.isEmpty()); |
393 | |
394 | // Have to use qvariant_cast, toInt will return 0 because unrecognized type; |
395 | QAudioDecoder::Error errorCode = qvariant_cast<QAudioDecoder::Error>(v: errorSpy.takeLast().at(i: 0)); |
396 | QCOMPARE(errorCode, QAudioDecoder::FormatError); |
397 | QCOMPARE(d.error(), QAudioDecoder::FormatError); |
398 | |
399 | // Check all other spies. |
400 | QVERIFY(readySpy.isEmpty()); |
401 | QVERIFY(bufferChangedSpy.isEmpty()); |
402 | QVERIFY(stateSpy.isEmpty()); |
403 | QVERIFY(finishedSpy.isEmpty()); |
404 | QVERIFY(positionSpy.isEmpty()); |
405 | QVERIFY(durationSpy.isEmpty()); |
406 | |
407 | errorSpy.clear(); |
408 | |
409 | // Try read even if the file is corrupted to test the robustness. |
410 | buffer = d.read(); |
411 | QTRY_VERIFY(d.state() == QAudioDecoder::StoppedState); |
412 | QVERIFY(!buffer.isValid()); |
413 | QVERIFY(!d.bufferAvailable()); |
414 | QCOMPARE(d.position(), qint64(-1)); |
415 | |
416 | QVERIFY(errorSpy.isEmpty()); |
417 | QVERIFY(readySpy.isEmpty()); |
418 | QVERIFY(bufferChangedSpy.isEmpty()); |
419 | QVERIFY(stateSpy.isEmpty()); |
420 | QVERIFY(finishedSpy.isEmpty()); |
421 | QVERIFY(positionSpy.isEmpty()); |
422 | QVERIFY(durationSpy.isEmpty()); |
423 | |
424 | |
425 | d.stop(); |
426 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
427 | QCOMPARE(d.duration(), qint64(-1)); |
428 | QVERIFY(!d.bufferAvailable()); |
429 | } |
430 | |
431 | void tst_QAudioDecoderBackend::deviceTest() |
432 | { |
433 | if (!isWavSupported()) |
434 | QSKIP("Sound format is not supported" ); |
435 | |
436 | QAudioDecoder d; |
437 | if (d.error() == QAudioDecoder::ServiceMissingError) |
438 | QSKIP("There is no audio decoding support on this platform." ); |
439 | QAudioBuffer buffer; |
440 | quint64 duration = 0; |
441 | int sampleCount = 0; |
442 | |
443 | QSignalSpy readySpy(&d, SIGNAL(bufferReady())); |
444 | QSignalSpy bufferChangedSpy(&d, SIGNAL(bufferAvailableChanged(bool))); |
445 | QSignalSpy errorSpy(&d, SIGNAL(error(QAudioDecoder::Error))); |
446 | QSignalSpy stateSpy(&d, SIGNAL(stateChanged(QAudioDecoder::State))); |
447 | QSignalSpy durationSpy(&d, SIGNAL(durationChanged(qint64))); |
448 | QSignalSpy finishedSpy(&d, SIGNAL(finished())); |
449 | QSignalSpy positionSpy(&d, SIGNAL(positionChanged(qint64))); |
450 | |
451 | QVERIFY(d.state() == QAudioDecoder::StoppedState); |
452 | QVERIFY(d.bufferAvailable() == false); |
453 | QCOMPARE(d.sourceFilename(), QString("" )); |
454 | QVERIFY(d.audioFormat() == QAudioFormat()); |
455 | |
456 | QFileInfo fileInfo(QFINDTESTDATA(TEST_FILE_NAME)); |
457 | QFile file(fileInfo.absoluteFilePath()); |
458 | QVERIFY(file.open(QIODevice::ReadOnly)); |
459 | d.setSourceDevice(&file); |
460 | |
461 | QVERIFY(d.sourceDevice() == &file); |
462 | QVERIFY(d.sourceFilename().isEmpty()); |
463 | |
464 | // We haven't set the format yet |
465 | QVERIFY(d.audioFormat() == QAudioFormat()); |
466 | |
467 | d.start(); |
468 | QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState); |
469 | QTRY_VERIFY(!stateSpy.isEmpty()); |
470 | QTRY_VERIFY(!readySpy.isEmpty()); |
471 | QTRY_VERIFY(!bufferChangedSpy.isEmpty()); |
472 | QVERIFY(d.bufferAvailable()); |
473 | QTRY_VERIFY(!durationSpy.isEmpty()); |
474 | QVERIFY(qAbs(d.duration() - 1000) < 20); |
475 | |
476 | buffer = d.read(); |
477 | QVERIFY(buffer.isValid()); |
478 | |
479 | // Test file is 44.1K 16bit mono |
480 | QCOMPARE(buffer.format().channelCount(), 1); |
481 | QCOMPARE(buffer.format().sampleRate(), 44100); |
482 | QCOMPARE(buffer.format().sampleSize(), 16); |
483 | QCOMPARE(buffer.format().sampleType(), QAudioFormat::SignedInt); |
484 | QCOMPARE(buffer.format().codec(), QString("audio/pcm" )); |
485 | |
486 | QVERIFY(errorSpy.isEmpty()); |
487 | |
488 | duration += buffer.duration(); |
489 | sampleCount += buffer.sampleCount(); |
490 | |
491 | // Now drain the decoder |
492 | if (sampleCount < 44094) { |
493 | QTRY_COMPARE(d.bufferAvailable(), true); |
494 | } |
495 | |
496 | while (d.bufferAvailable()) { |
497 | buffer = d.read(); |
498 | QVERIFY(buffer.isValid()); |
499 | QTRY_VERIFY(!positionSpy.isEmpty()); |
500 | QVERIFY(positionSpy.takeLast().at(0).toLongLong() == qint64(duration / 1000)); |
501 | QVERIFY(d.position() - (duration / 1000) < 20); |
502 | |
503 | duration += buffer.duration(); |
504 | sampleCount += buffer.sampleCount(); |
505 | if (sampleCount < 44094) { |
506 | QTRY_COMPARE(d.bufferAvailable(), true); |
507 | } |
508 | } |
509 | |
510 | // Make sure the duration is roughly correct (+/- 20ms) |
511 | QCOMPARE(sampleCount, 44094); |
512 | QVERIFY(qAbs(qint64(duration) - 1000000) < 20000); |
513 | QVERIFY(qAbs((d.position() + (buffer.duration() / 1000)) - 1000) < 20); |
514 | QTRY_COMPARE(finishedSpy.count(), 1); |
515 | QVERIFY(!d.bufferAvailable()); |
516 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
517 | |
518 | d.stop(); |
519 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
520 | QVERIFY(!d.bufferAvailable()); |
521 | QTRY_COMPARE(durationSpy.count(), 2); |
522 | QCOMPARE(d.duration(), qint64(-1)); |
523 | readySpy.clear(); |
524 | bufferChangedSpy.clear(); |
525 | stateSpy.clear(); |
526 | durationSpy.clear(); |
527 | finishedSpy.clear(); |
528 | positionSpy.clear(); |
529 | |
530 | // Now try changing formats |
531 | QAudioFormat format; |
532 | format.setChannelCount(2); |
533 | format.setSampleSize(8); |
534 | format.setSampleRate(8000); |
535 | format.setCodec("audio/pcm" ); |
536 | format.setSampleType(QAudioFormat::SignedInt); |
537 | |
538 | d.setAudioFormat(format); |
539 | |
540 | // Make sure it stuck |
541 | QVERIFY(d.audioFormat() == format); |
542 | |
543 | d.start(); |
544 | QTRY_VERIFY(d.state() == QAudioDecoder::DecodingState); |
545 | QTRY_VERIFY(!stateSpy.isEmpty()); |
546 | QTRY_VERIFY(!readySpy.isEmpty()); |
547 | QTRY_VERIFY(!bufferChangedSpy.isEmpty()); |
548 | QVERIFY(d.bufferAvailable()); |
549 | QTRY_VERIFY(!durationSpy.isEmpty()); |
550 | QVERIFY(qAbs(d.duration() - 1000) < 20); |
551 | |
552 | buffer = d.read(); |
553 | QVERIFY(buffer.isValid()); |
554 | // See if we got the right format |
555 | QVERIFY(buffer.format() == format); |
556 | |
557 | // The decoder should still have the same format |
558 | QVERIFY(d.audioFormat() == format); |
559 | |
560 | QVERIFY(errorSpy.isEmpty()); |
561 | |
562 | d.stop(); |
563 | QTRY_COMPARE(d.state(), QAudioDecoder::StoppedState); |
564 | QVERIFY(!d.bufferAvailable()); |
565 | QTRY_COMPARE(durationSpy.count(), 2); |
566 | QCOMPARE(d.duration(), qint64(-1)); |
567 | } |
568 | |
569 | QTEST_MAIN(tst_QAudioDecoderBackend) |
570 | |
571 | #include "tst_qaudiodecoderbackend.moc" |
572 | |