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 | //TESTED_COMPONENT=plugins/declarative/multimedia |
30 | |
31 | #include <QtTest/QtTest> |
32 | |
33 | #include "qdeclarativeaudio_p.h" |
34 | #include "qdeclarativemediametadata_p.h" |
35 | |
36 | #include "mockmediaserviceprovider.h" |
37 | #include "mockmediaplayerservice.h" |
38 | |
39 | #include <QtMultimedia/qmediametadata.h> |
40 | #include <qmediaplayercontrol.h> |
41 | #include <qmediaservice.h> |
42 | #include <private/qmediaserviceprovider_p.h> |
43 | #include <private/qdeclarativevideooutput_p.h> |
44 | #include <qmetadatareadercontrol.h> |
45 | #include <QAbstractVideoSurface> |
46 | |
47 | #include <QtGui/qguiapplication.h> |
48 | #include <QtQml/qqmlengine.h> |
49 | #include <QtQml/qqmlcomponent.h> |
50 | |
51 | class tst_QDeclarativeAudio : public QObject |
52 | { |
53 | Q_OBJECT |
54 | public slots: |
55 | void initTestCase(); |
56 | |
57 | private slots: |
58 | void nullPlayerControl(); |
59 | void nullMetaDataControl(); |
60 | void nullService(); |
61 | |
62 | void source(); |
63 | void autoLoad(); |
64 | void playing(); |
65 | void paused(); |
66 | void duration(); |
67 | void position(); |
68 | void volume(); |
69 | void muted(); |
70 | void bufferProgress(); |
71 | void seekable(); |
72 | void playbackRate(); |
73 | void status(); |
74 | void metaData_data(); |
75 | void metaData(); |
76 | void error(); |
77 | void loops(); |
78 | void audioRole(); |
79 | void customAudioRole(); |
80 | void videoOutput(); |
81 | |
82 | private: |
83 | void enumerator(const QMetaObject *object, const char *name, QMetaEnum *result); |
84 | QMetaEnum enumerator(const QMetaObject *object, const char *name); |
85 | void keyToValue(const QMetaEnum &enumeration, const char *key, int *result); |
86 | int keyToValue(const QMetaEnum &enumeration, const char *key); |
87 | }; |
88 | |
89 | Q_DECLARE_METATYPE(QDeclarativeAudio::Error); |
90 | Q_DECLARE_METATYPE(QDeclarativeAudio::AudioRole); |
91 | |
92 | class QtTestMediaPlayerControl : public QMediaPlayerControl |
93 | { |
94 | Q_OBJECT |
95 | public: |
96 | QtTestMediaPlayerControl(QObject *parent = 0) |
97 | : QMediaPlayerControl(parent) |
98 | , m_state(QMediaPlayer::StoppedState) |
99 | , m_mediaStatus(QMediaPlayer::NoMedia) |
100 | , m_duration(0) |
101 | , m_position(0) |
102 | , m_playbackRate(1.0) |
103 | , m_volume(100) |
104 | , m_bufferStatus(0) |
105 | , m_muted(false) |
106 | , m_audioAvailable(false) |
107 | , m_videoAvailable(false) |
108 | , m_seekable(false) |
109 | { |
110 | } |
111 | |
112 | QMediaPlayer::State state() const { return m_state; } |
113 | void updateState(QMediaPlayer::State state) { emit stateChanged(newState: m_state = state); } |
114 | |
115 | QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } |
116 | void updateMediaStatus(QMediaPlayer::MediaStatus status) { |
117 | emit mediaStatusChanged(status: m_mediaStatus = status); } |
118 | void updateMediaStatus(QMediaPlayer::MediaStatus status, QMediaPlayer::State state) |
119 | { |
120 | m_mediaStatus = status; |
121 | m_state = state; |
122 | |
123 | emit mediaStatusChanged(status: m_mediaStatus); |
124 | emit stateChanged(newState: m_state); |
125 | } |
126 | |
127 | qint64 duration() const { return m_duration; } |
128 | void setDuration(qint64 duration) { emit durationChanged(duration: m_duration = duration); } |
129 | |
130 | qint64 position() const { return m_position; } |
131 | void setPosition(qint64 position) { emit positionChanged(position: m_position = position); } |
132 | |
133 | int volume() const { return m_volume; } |
134 | void setVolume(int volume) { emit volumeChanged(volume: m_volume = volume); } |
135 | |
136 | bool isMuted() const { return m_muted; } |
137 | void setMuted(bool muted) { emit mutedChanged(mute: m_muted = muted); } |
138 | |
139 | int bufferStatus() const { return m_bufferStatus; } |
140 | void setBufferStatus(int status) { emit bufferStatusChanged(percentFilled: m_bufferStatus = status); } |
141 | |
142 | bool isAudioAvailable() const { return m_audioAvailable; } |
143 | void setAudioAvailable(bool available) { |
144 | emit audioAvailableChanged(audioAvailable: m_audioAvailable = available); } |
145 | bool isVideoAvailable() const { return m_videoAvailable; } |
146 | void setVideoAvailable(bool available) { |
147 | emit videoAvailableChanged(videoAvailable: m_videoAvailable = available); } |
148 | |
149 | bool isSeekable() const { return m_seekable; } |
150 | void setSeekable(bool seekable) { emit seekableChanged(seekable: m_seekable = seekable); } |
151 | |
152 | QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); } |
153 | |
154 | qreal playbackRate() const { return m_playbackRate; } |
155 | void setPlaybackRate(qreal rate) { emit playbackRateChanged(rate: m_playbackRate = rate); } |
156 | |
157 | QMediaContent media() const { return m_media; } |
158 | const QIODevice *mediaStream() const { return 0; } |
159 | void setMedia(const QMediaContent &media, QIODevice *) |
160 | { |
161 | m_media = media; |
162 | |
163 | m_mediaStatus = m_media.isNull() |
164 | ? QMediaPlayer::NoMedia |
165 | : QMediaPlayer::LoadingMedia; |
166 | |
167 | emit mediaChanged(content: m_media); |
168 | emit mediaStatusChanged(status: m_mediaStatus); |
169 | } |
170 | |
171 | void play() |
172 | { |
173 | m_state = QMediaPlayer::PlayingState; |
174 | if (m_mediaStatus == QMediaPlayer::EndOfMedia) |
175 | updateMediaStatus(status: QMediaPlayer::LoadedMedia); |
176 | emit stateChanged(newState: m_state); |
177 | } |
178 | void pause() { emit stateChanged(newState: m_state = QMediaPlayer::PausedState); } |
179 | void stop() { emit stateChanged(newState: m_state = QMediaPlayer::StoppedState); } |
180 | |
181 | void emitError(QMediaPlayer::Error err, const QString &errorString) { |
182 | emit error(error: err, errorString); } |
183 | |
184 | private: |
185 | QMediaPlayer::State m_state; |
186 | QMediaPlayer::MediaStatus m_mediaStatus; |
187 | qint64 m_duration; |
188 | qint64 m_position; |
189 | qreal m_playbackRate; |
190 | int m_volume; |
191 | int m_bufferStatus; |
192 | bool m_muted; |
193 | bool m_audioAvailable; |
194 | bool m_videoAvailable; |
195 | bool m_seekable; |
196 | QMediaContent m_media; |
197 | }; |
198 | |
199 | class QtTestMetaDataControl : public QMetaDataReaderControl |
200 | { |
201 | Q_OBJECT |
202 | public: |
203 | QtTestMetaDataControl(QObject *parent = 0) |
204 | : QMetaDataReaderControl(parent) |
205 | { |
206 | } |
207 | |
208 | bool isMetaDataAvailable() const { return true; } |
209 | |
210 | QVariant metaData(const QString &key) const { return m_metaData.value(akey: key); } |
211 | void setMetaData(const QString &key, const QVariant &value) { |
212 | m_metaData.insert(key, value); emit metaDataChanged(); } |
213 | |
214 | QStringList availableMetaData() const { return m_metaData.keys(); } |
215 | |
216 | private: |
217 | QMap<QString, QVariant> m_metaData; |
218 | }; |
219 | |
220 | class QtTestMediaService : public QMediaService |
221 | { |
222 | Q_OBJECT |
223 | public: |
224 | QtTestMediaService( |
225 | QtTestMediaPlayerControl *playerControl, |
226 | QtTestMetaDataControl *metaDataControl, |
227 | QObject *parent) |
228 | : QMediaService(parent) |
229 | , playerControl(playerControl) |
230 | , metaDataControl(metaDataControl) |
231 | { |
232 | } |
233 | |
234 | QMediaControl *requestControl(const char *name) |
235 | { |
236 | if (qstrcmp(str1: name, QMediaPlayerControl_iid) == 0) |
237 | return playerControl; |
238 | else if (qstrcmp(str1: name, QMetaDataReaderControl_iid) == 0) |
239 | return metaDataControl; |
240 | else |
241 | return 0; |
242 | } |
243 | |
244 | void releaseControl(QMediaControl *) {} |
245 | |
246 | QtTestMediaPlayerControl *playerControl; |
247 | QtTestMetaDataControl *metaDataControl; |
248 | }; |
249 | |
250 | class QtTestMediaServiceProvider : public QMediaServiceProvider |
251 | { |
252 | Q_OBJECT |
253 | public: |
254 | QtTestMediaServiceProvider() |
255 | : service(new QtTestMediaService( |
256 | new QtTestMediaPlayerControl(this), new QtTestMetaDataControl(this), this)) |
257 | { |
258 | setDefaultServiceProvider(this); |
259 | } |
260 | |
261 | QtTestMediaServiceProvider(QtTestMediaService *service) |
262 | : service(service) |
263 | { |
264 | setDefaultServiceProvider(this); |
265 | } |
266 | |
267 | QtTestMediaServiceProvider( |
268 | QtTestMediaPlayerControl *playerControl, QtTestMetaDataControl *metaDataControl) |
269 | : service(new QtTestMediaService(playerControl, metaDataControl, this)) |
270 | { |
271 | setDefaultServiceProvider(this); |
272 | } |
273 | |
274 | ~QtTestMediaServiceProvider() |
275 | { |
276 | setDefaultServiceProvider(0); |
277 | } |
278 | |
279 | QMediaService *requestService( |
280 | const QByteArray &type, |
281 | const QMediaServiceProviderHint & = QMediaServiceProviderHint()) |
282 | { |
283 | requestedService = type; |
284 | |
285 | return service; |
286 | } |
287 | |
288 | void releaseService(QMediaService *) {} |
289 | |
290 | inline QtTestMediaPlayerControl *playerControl() { return service->playerControl; } |
291 | inline QtTestMetaDataControl *metaDataControl() { return service->metaDataControl; } |
292 | |
293 | QtTestMediaService *service; |
294 | QByteArray requestedService; |
295 | }; |
296 | |
297 | void tst_QDeclarativeAudio::initTestCase() |
298 | { |
299 | qRegisterMetaType<QDeclarativeAudio::Error>(); |
300 | qRegisterMetaType<QDeclarativeAudio::AudioRole>(); |
301 | } |
302 | |
303 | void tst_QDeclarativeAudio::nullPlayerControl() |
304 | { |
305 | QtTestMetaDataControl metaDataControl; |
306 | QtTestMediaServiceProvider provider(0, &metaDataControl); |
307 | |
308 | QDeclarativeAudio audio; |
309 | audio.classBegin(); |
310 | |
311 | QCOMPARE(audio.source(), QUrl()); |
312 | audio.setSource(QUrl("http://example.com" )); |
313 | QCOMPARE(audio.source(), QUrl("http://example.com" )); |
314 | |
315 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
316 | audio.play(); |
317 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
318 | audio.pause(); |
319 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
320 | |
321 | QCOMPARE(audio.duration(), 0); |
322 | |
323 | QCOMPARE(audio.position(), 0); |
324 | audio.seek(position: 10000); |
325 | QCOMPARE(audio.position(), 10000); |
326 | |
327 | QCOMPARE(audio.volume(), qreal(1.0)); |
328 | audio.setVolume(0.5); |
329 | QCOMPARE(audio.volume(), qreal(0.5)); |
330 | |
331 | QCOMPARE(audio.isMuted(), false); |
332 | audio.setMuted(true); |
333 | QCOMPARE(audio.isMuted(), true); |
334 | |
335 | QCOMPARE(audio.bufferProgress(), qreal(0)); |
336 | |
337 | QCOMPARE(audio.isSeekable(), false); |
338 | |
339 | QCOMPARE(audio.playbackRate(), qreal(1.0)); |
340 | |
341 | QCOMPARE(audio.status(), QDeclarativeAudio::NoMedia); |
342 | |
343 | QCOMPARE(audio.error(), QDeclarativeAudio::ServiceMissing); |
344 | } |
345 | |
346 | void tst_QDeclarativeAudio::nullMetaDataControl() |
347 | { |
348 | QtTestMediaPlayerControl playerControl; |
349 | QtTestMediaServiceProvider provider(&playerControl, 0); |
350 | |
351 | QDeclarativeAudio audio; |
352 | audio.classBegin(); |
353 | audio.componentComplete(); |
354 | |
355 | QVERIFY(audio.metaData()); |
356 | } |
357 | |
358 | void tst_QDeclarativeAudio::nullService() |
359 | { |
360 | QtTestMediaServiceProvider provider(0); |
361 | |
362 | QDeclarativeAudio audio; |
363 | audio.classBegin(); |
364 | |
365 | QCOMPARE(audio.source(), QUrl()); |
366 | audio.setSource(QUrl("http://example.com" )); |
367 | QCOMPARE(audio.source(), QUrl("http://example.com" )); |
368 | |
369 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
370 | audio.play(); |
371 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
372 | audio.pause(); |
373 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
374 | |
375 | QCOMPARE(audio.duration(), 0); |
376 | |
377 | QCOMPARE(audio.position(), 0); |
378 | audio.seek(position: 10000); |
379 | QCOMPARE(audio.position(), 10000); |
380 | |
381 | QCOMPARE(audio.volume(), qreal(1.0)); |
382 | audio.setVolume(0.5); |
383 | QCOMPARE(audio.volume(), qreal(0.5)); |
384 | |
385 | QCOMPARE(audio.isMuted(), false); |
386 | audio.setMuted(true); |
387 | QCOMPARE(audio.isMuted(), true); |
388 | |
389 | QCOMPARE(audio.bufferProgress(), qreal(0)); |
390 | |
391 | QCOMPARE(audio.isSeekable(), false); |
392 | |
393 | QCOMPARE(audio.playbackRate(), qreal(1.0)); |
394 | |
395 | QCOMPARE(audio.status(), QDeclarativeAudio::NoMedia); |
396 | |
397 | QCOMPARE(audio.error(), QDeclarativeAudio::ServiceMissing); |
398 | |
399 | QVERIFY(audio.metaData()); |
400 | } |
401 | |
402 | void tst_QDeclarativeAudio::source() |
403 | { |
404 | const QUrl url1("http://example.com" ); |
405 | const QUrl url2("file:///local/path" ); |
406 | const QUrl url3; |
407 | |
408 | QtTestMediaServiceProvider provider; |
409 | QDeclarativeAudio audio; |
410 | audio.classBegin(); |
411 | audio.componentComplete(); |
412 | |
413 | QSignalSpy spy(&audio, SIGNAL(sourceChanged())); |
414 | |
415 | audio.setSource(url1); |
416 | QCOMPARE(audio.source(), url1); |
417 | QCOMPARE(provider.playerControl()->media().request().url(), url1); |
418 | QCOMPARE(spy.count(), 1); |
419 | |
420 | audio.setSource(url2); |
421 | QCOMPARE(audio.source(), url2); |
422 | QCOMPARE(provider.playerControl()->media().request().url(), url2); |
423 | QCOMPARE(spy.count(), 2); |
424 | |
425 | audio.setSource(url3); |
426 | QCOMPARE(audio.source(), url3); |
427 | QCOMPARE(provider.playerControl()->media().request().url(), url3); |
428 | QCOMPARE(spy.count(), 3); |
429 | } |
430 | |
431 | void tst_QDeclarativeAudio::autoLoad() |
432 | { |
433 | QtTestMediaServiceProvider provider; |
434 | QDeclarativeAudio audio; |
435 | audio.classBegin(); |
436 | audio.componentComplete(); |
437 | |
438 | QSignalSpy spy(&audio, SIGNAL(autoLoadChanged())); |
439 | |
440 | QCOMPARE(audio.isAutoLoad(), true); |
441 | |
442 | audio.setAutoLoad(false); |
443 | QCOMPARE(audio.isAutoLoad(), false); |
444 | QCOMPARE(spy.count(), 1); |
445 | |
446 | audio.setSource(QUrl("http://example.com" )); |
447 | QCOMPARE(audio.source(), QUrl("http://example.com" )); |
448 | audio.play(); |
449 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
450 | audio.stop(); |
451 | |
452 | audio.setAutoLoad(true); |
453 | audio.setSource(QUrl("http://example.com" )); |
454 | audio.pause(); |
455 | QCOMPARE(spy.count(), 2); |
456 | QCOMPARE(audio.playbackState(), audio.PausedState); |
457 | } |
458 | |
459 | void tst_QDeclarativeAudio::playing() |
460 | { |
461 | QtTestMediaServiceProvider provider; |
462 | QDeclarativeAudio audio; |
463 | audio.classBegin(); |
464 | |
465 | QSignalSpy stateChangedSpy(&audio, SIGNAL(playbackStateChanged())); |
466 | QSignalSpy playingSpy(&audio, SIGNAL(playing())); |
467 | QSignalSpy stoppedSpy(&audio, SIGNAL(stopped())); |
468 | |
469 | int stateChanged = 0; |
470 | int playing = 0; |
471 | int stopped = 0; |
472 | |
473 | audio.componentComplete(); |
474 | audio.setSource(QUrl("http://example.com" )); |
475 | |
476 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
477 | |
478 | // play() when stopped. |
479 | audio.play(); |
480 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
481 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
482 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
483 | QCOMPARE(playingSpy.count(), ++playing); |
484 | QCOMPARE(stoppedSpy.count(), stopped); |
485 | |
486 | // stop() when playing. |
487 | audio.stop(); |
488 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
489 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
490 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
491 | QCOMPARE(playingSpy.count(), playing); |
492 | QCOMPARE(stoppedSpy.count(), ++stopped); |
493 | |
494 | // stop() when stopped. |
495 | audio.stop(); |
496 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
497 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
498 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
499 | QCOMPARE(playingSpy.count(), playing); |
500 | QCOMPARE(stoppedSpy.count(), stopped); |
501 | |
502 | audio.play(); |
503 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
504 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
505 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
506 | QCOMPARE(playingSpy.count(), ++playing); |
507 | QCOMPARE(stoppedSpy.count(), stopped); |
508 | |
509 | // play() when playing. |
510 | audio.play(); |
511 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
512 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
513 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
514 | QCOMPARE(playingSpy.count(), playing); |
515 | QCOMPARE(stoppedSpy.count(), stopped); |
516 | } |
517 | |
518 | void tst_QDeclarativeAudio::paused() |
519 | { |
520 | QtTestMediaServiceProvider provider; |
521 | QDeclarativeAudio audio; |
522 | audio.classBegin(); |
523 | |
524 | QSignalSpy stateChangedSpy(&audio, SIGNAL(playbackStateChanged())); |
525 | QSignalSpy pausedSpy(&audio, SIGNAL(paused())); |
526 | int stateChanged = 0; |
527 | int pausedCount = 0; |
528 | |
529 | audio.componentComplete(); |
530 | audio.setSource(QUrl("http://example.com" )); |
531 | |
532 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
533 | |
534 | // play() when stopped. |
535 | audio.play(); |
536 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
537 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
538 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
539 | QCOMPARE(pausedSpy.count(), pausedCount); |
540 | |
541 | // pause() when playing. |
542 | audio.pause(); |
543 | QCOMPARE(audio.playbackState(), audio.PausedState); |
544 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); |
545 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
546 | QCOMPARE(pausedSpy.count(), ++pausedCount); |
547 | |
548 | // pause() when paused. |
549 | audio.pause(); |
550 | QCOMPARE(audio.playbackState(), audio.PausedState); |
551 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); |
552 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
553 | QCOMPARE(pausedSpy.count(), pausedCount); |
554 | |
555 | // stop() when paused. |
556 | audio.stop(); |
557 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
558 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
559 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
560 | QCOMPARE(pausedSpy.count(), pausedCount); |
561 | |
562 | // pause() when stopped. |
563 | audio.pause(); |
564 | QCOMPARE(audio.playbackState(), audio.PausedState); |
565 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); |
566 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
567 | QCOMPARE(pausedSpy.count(), ++pausedCount); |
568 | |
569 | // play() when paused. |
570 | audio.play(); |
571 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
572 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
573 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
574 | QCOMPARE(pausedSpy.count(), pausedCount); |
575 | } |
576 | |
577 | void tst_QDeclarativeAudio::duration() |
578 | { |
579 | QtTestMediaServiceProvider provider; |
580 | QDeclarativeAudio audio; |
581 | audio.classBegin(); |
582 | audio.componentComplete(); |
583 | |
584 | QSignalSpy spy(&audio, SIGNAL(durationChanged())); |
585 | |
586 | QCOMPARE(audio.duration(), 0); |
587 | |
588 | provider.playerControl()->setDuration(4040); |
589 | QCOMPARE(audio.duration(), 4040); |
590 | QCOMPARE(spy.count(), 1); |
591 | |
592 | provider.playerControl()->setDuration(-129); |
593 | QCOMPARE(audio.duration(), -129); |
594 | QCOMPARE(spy.count(), 2); |
595 | |
596 | provider.playerControl()->setDuration(0); |
597 | QCOMPARE(audio.duration(), 0); |
598 | QCOMPARE(spy.count(), 3); |
599 | |
600 | // Unnecessary duration changed signals aren't filtered. |
601 | provider.playerControl()->setDuration(0); |
602 | QCOMPARE(audio.duration(), 0); |
603 | QCOMPARE(spy.count(), 4); |
604 | } |
605 | |
606 | void tst_QDeclarativeAudio::position() |
607 | { |
608 | QtTestMediaServiceProvider provider; |
609 | QDeclarativeAudio audio; |
610 | audio.classBegin(); |
611 | audio.componentComplete(); |
612 | |
613 | QSignalSpy spy(&audio, SIGNAL(positionChanged())); |
614 | |
615 | QCOMPARE(audio.position(), 0); |
616 | |
617 | // QDeclarativeAudio won't bound set positions to the duration. A media service may though. |
618 | QCOMPARE(audio.duration(), 0); |
619 | |
620 | audio.seek(position: 450); |
621 | QCOMPARE(audio.position(), 450); |
622 | QCOMPARE(provider.playerControl()->position(), qint64(450)); |
623 | QCOMPARE(spy.count(), 1); |
624 | |
625 | audio.seek(position: -5403); |
626 | QCOMPARE(audio.position(), 0); |
627 | QCOMPARE(provider.playerControl()->position(), qint64(0)); |
628 | QCOMPARE(spy.count(), 2); |
629 | |
630 | audio.seek(position: -5403); |
631 | QCOMPARE(audio.position(), 0); |
632 | QCOMPARE(provider.playerControl()->position(), qint64(0)); |
633 | QCOMPARE(spy.count(), 2); |
634 | |
635 | // Check the signal change signal is emitted if the change originates from the media service. |
636 | provider.playerControl()->setPosition(450); |
637 | QCOMPARE(audio.position(), 450); |
638 | QCOMPARE(spy.count(), 3); |
639 | |
640 | connect(sender: &audio, SIGNAL(positionChanged()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
641 | |
642 | provider.playerControl()->updateState(state: QMediaPlayer::PlayingState); |
643 | QTestEventLoop::instance().enterLoop(secs: 2); |
644 | QVERIFY(spy.count() > 3 && spy.count() < 6); // 4 or 5 |
645 | |
646 | provider.playerControl()->updateState(state: QMediaPlayer::PausedState); |
647 | QTestEventLoop::instance().enterLoop(secs: 1); |
648 | QVERIFY(spy.count() < 6); |
649 | } |
650 | |
651 | void tst_QDeclarativeAudio::volume() |
652 | { |
653 | QtTestMediaServiceProvider provider; |
654 | QDeclarativeAudio audio; |
655 | audio.classBegin(); |
656 | audio.componentComplete(); |
657 | |
658 | QSignalSpy spy(&audio, SIGNAL(volumeChanged())); |
659 | |
660 | QCOMPARE(audio.volume(), qreal(1.0)); |
661 | |
662 | audio.setVolume(0.7); |
663 | QCOMPARE(audio.volume(), qreal(0.7)); |
664 | QCOMPARE(provider.playerControl()->volume(), 70); |
665 | QCOMPARE(spy.count(), 1); |
666 | |
667 | audio.setVolume(0.7); |
668 | QCOMPARE(audio.volume(), qreal(0.7)); |
669 | QCOMPARE(provider.playerControl()->volume(), 70); |
670 | QCOMPARE(spy.count(), 1); |
671 | |
672 | provider.playerControl()->setVolume(30); |
673 | QCOMPARE(audio.volume(), qreal(0.3)); |
674 | QCOMPARE(spy.count(), 2); |
675 | } |
676 | |
677 | void tst_QDeclarativeAudio::muted() |
678 | { |
679 | QtTestMediaServiceProvider provider; |
680 | QDeclarativeAudio audio; |
681 | audio.classBegin(); |
682 | audio.componentComplete(); |
683 | |
684 | QSignalSpy spy(&audio, SIGNAL(mutedChanged())); |
685 | |
686 | QCOMPARE(audio.isMuted(), false); |
687 | |
688 | audio.setMuted(true); |
689 | QCOMPARE(audio.isMuted(), true); |
690 | QCOMPARE(provider.playerControl()->isMuted(), true); |
691 | QCOMPARE(spy.count(), 1); |
692 | |
693 | provider.playerControl()->setMuted(false); |
694 | QCOMPARE(audio.isMuted(), false); |
695 | QCOMPARE(spy.count(), 2); |
696 | |
697 | audio.setMuted(false); |
698 | QCOMPARE(audio.isMuted(), false); |
699 | QCOMPARE(provider.playerControl()->isMuted(), false); |
700 | QCOMPARE(spy.count(), 2); |
701 | } |
702 | |
703 | void tst_QDeclarativeAudio::bufferProgress() |
704 | { |
705 | QtTestMediaServiceProvider provider; |
706 | QDeclarativeAudio audio; |
707 | audio.classBegin(); |
708 | audio.componentComplete(); |
709 | |
710 | QSignalSpy spy(&audio, SIGNAL(bufferProgressChanged())); |
711 | |
712 | QCOMPARE(audio.bufferProgress(), qreal(0.0)); |
713 | |
714 | provider.playerControl()->setBufferStatus(20); |
715 | QCOMPARE(audio.bufferProgress(), qreal(0.2)); |
716 | QCOMPARE(spy.count(), 1); |
717 | |
718 | provider.playerControl()->setBufferStatus(20); |
719 | QCOMPARE(audio.bufferProgress(), qreal(0.2)); |
720 | QCOMPARE(spy.count(), 2); |
721 | |
722 | provider.playerControl()->setBufferStatus(40); |
723 | QCOMPARE(audio.bufferProgress(), qreal(0.4)); |
724 | QCOMPARE(spy.count(), 3); |
725 | |
726 | connect(sender: &audio, SIGNAL(positionChanged()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
727 | |
728 | provider.playerControl()->updateMediaStatus( |
729 | status: QMediaPlayer::BufferingMedia, state: QMediaPlayer::PlayingState); |
730 | QTestEventLoop::instance().enterLoop(secs: 2); |
731 | QVERIFY(spy.count() > 3 && spy.count() < 6); // 4 or 5 |
732 | |
733 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferedMedia); |
734 | QTestEventLoop::instance().enterLoop(secs: 1); |
735 | QVERIFY(spy.count() < 6); |
736 | } |
737 | |
738 | void tst_QDeclarativeAudio::seekable() |
739 | { |
740 | QtTestMediaServiceProvider provider; |
741 | QDeclarativeAudio audio; |
742 | audio.classBegin(); |
743 | audio.componentComplete(); |
744 | |
745 | QSignalSpy spy(&audio, SIGNAL(seekableChanged())); |
746 | |
747 | QCOMPARE(audio.isSeekable(), false); |
748 | |
749 | provider.playerControl()->setSeekable(true); |
750 | QCOMPARE(audio.isSeekable(), true); |
751 | QCOMPARE(spy.count(), 1); |
752 | |
753 | provider.playerControl()->setSeekable(true); |
754 | QCOMPARE(audio.isSeekable(), true); |
755 | QCOMPARE(spy.count(), 2); |
756 | |
757 | provider.playerControl()->setSeekable(false); |
758 | QCOMPARE(audio.isSeekable(), false); |
759 | QCOMPARE(spy.count(), 3); |
760 | } |
761 | |
762 | void tst_QDeclarativeAudio::playbackRate() |
763 | { |
764 | QtTestMediaServiceProvider provider; |
765 | QDeclarativeAudio audio; |
766 | audio.classBegin(); |
767 | audio.componentComplete(); |
768 | |
769 | QSignalSpy spy(&audio, SIGNAL(playbackRateChanged())); |
770 | |
771 | QCOMPARE(audio.playbackRate(), qreal(1.0)); |
772 | |
773 | audio.setPlaybackRate(0.5); |
774 | QCOMPARE(audio.playbackRate(), qreal(0.5)); |
775 | QCOMPARE(provider.playerControl()->playbackRate(), qreal(0.5)); |
776 | QCOMPARE(spy.count(), 1); |
777 | |
778 | provider.playerControl()->setPlaybackRate(2.0); |
779 | QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0)); |
780 | QCOMPARE(spy.count(), 2); |
781 | |
782 | audio.setPlaybackRate(2.0); |
783 | QCOMPARE(audio.playbackRate(), qreal(2.0)); |
784 | QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0)); |
785 | QCOMPARE(spy.count(), 2); |
786 | } |
787 | |
788 | void tst_QDeclarativeAudio::status() |
789 | { |
790 | QtTestMediaServiceProvider provider; |
791 | QDeclarativeAudio audio; |
792 | audio.classBegin(); |
793 | audio.componentComplete(); |
794 | |
795 | QSignalSpy statusChangedSpy(&audio, SIGNAL(statusChanged())); |
796 | |
797 | QCOMPARE(audio.status(), QDeclarativeAudio::NoMedia); |
798 | |
799 | // Set media, start loading. |
800 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::LoadingMedia); |
801 | QCOMPARE(audio.status(), QDeclarativeAudio::Loading); |
802 | QCOMPARE(statusChangedSpy.count(), 1); |
803 | |
804 | // Finish loading. |
805 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::LoadedMedia); |
806 | QCOMPARE(audio.status(), QDeclarativeAudio::Loaded); |
807 | QCOMPARE(statusChangedSpy.count(), 2); |
808 | |
809 | // Play, start buffering. |
810 | provider.playerControl()->updateMediaStatus( |
811 | status: QMediaPlayer::StalledMedia, state: QMediaPlayer::PlayingState); |
812 | QCOMPARE(audio.status(), QDeclarativeAudio::Stalled); |
813 | QCOMPARE(statusChangedSpy.count(), 3); |
814 | |
815 | // Enough data buffered to proceed. |
816 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferingMedia); |
817 | QCOMPARE(audio.status(), QDeclarativeAudio::Buffering); |
818 | QCOMPARE(statusChangedSpy.count(), 4); |
819 | |
820 | // Errant second buffering status changed. |
821 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferingMedia); |
822 | QCOMPARE(audio.status(), QDeclarativeAudio::Buffering); |
823 | QCOMPARE(statusChangedSpy.count(), 4); |
824 | |
825 | // Buffer full. |
826 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferedMedia); |
827 | QCOMPARE(audio.status(), QDeclarativeAudio::Buffered); |
828 | QCOMPARE(statusChangedSpy.count(), 5); |
829 | |
830 | // Buffer getting low. |
831 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferingMedia); |
832 | QCOMPARE(audio.status(), QDeclarativeAudio::Buffering); |
833 | QCOMPARE(statusChangedSpy.count(), 6); |
834 | |
835 | // Buffer full. |
836 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::BufferedMedia); |
837 | QCOMPARE(audio.status(), QDeclarativeAudio::Buffered); |
838 | QCOMPARE(statusChangedSpy.count(), 7); |
839 | |
840 | // Finished. |
841 | provider.playerControl()->updateMediaStatus( |
842 | status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
843 | QCOMPARE(audio.status(), QDeclarativeAudio::EndOfMedia); |
844 | QCOMPARE(statusChangedSpy.count(), 8); |
845 | } |
846 | |
847 | void tst_QDeclarativeAudio::metaData_data() |
848 | { |
849 | QTest::addColumn<QByteArray>(name: "propertyName" ); |
850 | QTest::addColumn<QString>(name: "propertyKey" ); |
851 | QTest::addColumn<QVariant>(name: "value" ); |
852 | |
853 | QTest::newRow(dataTag: "title" ) |
854 | << QByteArray("title" ) |
855 | << QMediaMetaData::Title |
856 | << QVariant(QString::fromLatin1(str: "This is a title" )); |
857 | |
858 | QTest::newRow(dataTag: "genre" ) |
859 | << QByteArray("genre" ) |
860 | << QMediaMetaData::Genre |
861 | << QVariant(QString::fromLatin1(str: "rock" )); |
862 | |
863 | QTest::newRow(dataTag: "trackNumber" ) |
864 | << QByteArray("trackNumber" ) |
865 | << QMediaMetaData::TrackNumber |
866 | << QVariant(8); |
867 | } |
868 | |
869 | void tst_QDeclarativeAudio::metaData() |
870 | { |
871 | QFETCH(QByteArray, propertyName); |
872 | QFETCH(QString, propertyKey); |
873 | QFETCH(QVariant, value); |
874 | |
875 | QtTestMediaServiceProvider provider; |
876 | QDeclarativeAudio audio; |
877 | audio.classBegin(); |
878 | audio.componentComplete(); |
879 | |
880 | QSignalSpy spy(audio.metaData(), SIGNAL(metaDataChanged())); |
881 | |
882 | const int index = audio.metaData()->metaObject()->indexOfProperty(name: propertyName.constData()); |
883 | QVERIFY(index != -1); |
884 | |
885 | QMetaProperty property = audio.metaData()->metaObject()->property(index); |
886 | QCOMPARE(property.read(&audio), QVariant()); |
887 | |
888 | property.write(obj: audio.metaData(), value); |
889 | QCOMPARE(property.read(audio.metaData()), QVariant()); |
890 | QCOMPARE(provider.metaDataControl()->metaData(propertyKey), QVariant()); |
891 | QCOMPARE(spy.count(), 0); |
892 | |
893 | provider.metaDataControl()->setMetaData(key: propertyKey, value); |
894 | QCOMPARE(property.read(audio.metaData()), value); |
895 | QCOMPARE(spy.count(), 1); |
896 | } |
897 | |
898 | void tst_QDeclarativeAudio::error() |
899 | { |
900 | const QString errorString = QLatin1String("Failed to open device." ); |
901 | |
902 | QtTestMediaServiceProvider provider; |
903 | QDeclarativeAudio audio; |
904 | audio.classBegin(); |
905 | audio.componentComplete(); |
906 | |
907 | QSignalSpy errorSpy(&audio, SIGNAL(error(QDeclarativeAudio::Error,QString))); |
908 | QSignalSpy errorChangedSpy(&audio, SIGNAL(errorChanged())); |
909 | |
910 | QCOMPARE(audio.error(), QDeclarativeAudio::NoError); |
911 | QCOMPARE(audio.errorString(), QString()); |
912 | |
913 | provider.playerControl()->emitError(err: QMediaPlayer::ResourceError, errorString); |
914 | |
915 | QCOMPARE(audio.error(), QDeclarativeAudio::ResourceError); |
916 | QCOMPARE(audio.errorString(), errorString); |
917 | QCOMPARE(errorSpy.count(), 1); |
918 | QCOMPARE(errorChangedSpy.count(), 1); |
919 | |
920 | // Changing the source resets the error properties. |
921 | audio.setSource(QUrl("http://example.com" )); |
922 | QCOMPARE(audio.error(), QDeclarativeAudio::NoError); |
923 | QCOMPARE(audio.errorString(), QString()); |
924 | QCOMPARE(errorSpy.count(), 1); |
925 | QCOMPARE(errorChangedSpy.count(), 2); |
926 | |
927 | // But isn't noisy. |
928 | audio.setSource(QUrl("file:///file/path" )); |
929 | QCOMPARE(audio.error(), QDeclarativeAudio::NoError); |
930 | QCOMPARE(audio.errorString(), QString()); |
931 | QCOMPARE(errorSpy.count(), 1); |
932 | QCOMPARE(errorChangedSpy.count(), 2); |
933 | } |
934 | |
935 | void tst_QDeclarativeAudio::loops() |
936 | { |
937 | QtTestMediaServiceProvider provider; |
938 | QDeclarativeAudio audio; |
939 | |
940 | QSignalSpy loopsChangedSpy(&audio, SIGNAL(loopCountChanged())); |
941 | QSignalSpy stateChangedSpy(&audio, SIGNAL(playbackStateChanged())); |
942 | QSignalSpy stoppedSpy(&audio, SIGNAL(stopped())); |
943 | |
944 | int stateChanged = 0; |
945 | int loopsChanged = 0; |
946 | int stoppedCount = 0; |
947 | |
948 | audio.classBegin(); |
949 | audio.componentComplete(); |
950 | |
951 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
952 | |
953 | //setLoopCount(3) when stopped. |
954 | audio.setLoopCount(3); |
955 | QCOMPARE(audio.loopCount(), 3); |
956 | QCOMPARE(loopsChangedSpy.count(), ++loopsChanged); |
957 | |
958 | //play till end |
959 | audio.play(); |
960 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
961 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
962 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
963 | QCOMPARE(stoppedSpy.count(), stoppedCount); |
964 | |
965 | // play() when playing. |
966 | audio.play(); |
967 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
968 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
969 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
970 | QCOMPARE(stoppedSpy.count(), stoppedCount); |
971 | |
972 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
973 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
974 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
975 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
976 | QCOMPARE(stoppedSpy.count(), stoppedCount); |
977 | |
978 | //play to end |
979 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
980 | QCOMPARE(stoppedSpy.count(), stoppedCount); |
981 | //play to end |
982 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
983 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
984 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
985 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
986 | QCOMPARE(stoppedSpy.count(), ++stoppedCount); |
987 | |
988 | // stop when playing |
989 | audio.play(); |
990 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
991 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
992 | QCOMPARE(stoppedSpy.count(), stoppedCount); |
993 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
994 | audio.stop(); |
995 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
996 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
997 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
998 | QCOMPARE(stoppedSpy.count(), ++stoppedCount); |
999 | |
1000 | //play() with infinite loop |
1001 | audio.setLoopCount(-1); |
1002 | QCOMPARE(audio.loopCount(), -1); |
1003 | QCOMPARE(loopsChangedSpy.count(), ++loopsChanged); |
1004 | audio.play(); |
1005 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
1006 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
1007 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
1008 | provider.playerControl()->updateMediaStatus(status: QMediaPlayer::EndOfMedia, state: QMediaPlayer::StoppedState); |
1009 | QCOMPARE(audio.playbackState(), audio.PlayingState); |
1010 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); |
1011 | QCOMPARE(stateChangedSpy.count(), stateChanged); |
1012 | |
1013 | // stop() when playing in infinite loop. |
1014 | audio.stop(); |
1015 | QCOMPARE(audio.playbackState(), audio.StoppedState); |
1016 | QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); |
1017 | QCOMPARE(stateChangedSpy.count(), ++stateChanged); |
1018 | QCOMPARE(stoppedSpy.count(), ++stoppedCount); |
1019 | |
1020 | qDebug() << "Testing version 5" ; |
1021 | } |
1022 | |
1023 | void tst_QDeclarativeAudio::audioRole() |
1024 | { |
1025 | MockMediaPlayerService mockService; |
1026 | MockMediaServiceProvider mockProvider(&mockService); |
1027 | QMediaServiceProvider::setDefaultServiceProvider(&mockProvider); |
1028 | |
1029 | QQmlEngine engine; |
1030 | QQmlComponent component(&engine); |
1031 | component.setData("import QtQuick 2.0 \n import QtMultimedia 5.6 \n Audio { }" , baseUrl: QUrl()); |
1032 | |
1033 | { |
1034 | mockService.setHasAudioRole(false); |
1035 | QDeclarativeAudio *audio = static_cast<QDeclarativeAudio*>(component.create()); |
1036 | |
1037 | QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole); |
1038 | QVERIFY(audio->supportedAudioRoles().isArray()); |
1039 | QVERIFY(audio->supportedAudioRoles().toVariant().toList().isEmpty()); |
1040 | |
1041 | QSignalSpy spy(audio, SIGNAL(audioRoleChanged())); |
1042 | audio->setAudioRole(QDeclarativeAudio::MusicRole); |
1043 | QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole); |
1044 | QCOMPARE(spy.count(), 0); |
1045 | } |
1046 | |
1047 | { |
1048 | mockService.reset(); |
1049 | mockService.setHasAudioRole(true); |
1050 | QDeclarativeAudio *audio = static_cast<QDeclarativeAudio*>(component.create()); |
1051 | QSignalSpy spy(audio, SIGNAL(audioRoleChanged())); |
1052 | |
1053 | QCOMPARE(audio->audioRole(), QDeclarativeAudio::UnknownRole); |
1054 | QVERIFY(audio->supportedAudioRoles().isArray()); |
1055 | QVERIFY(!audio->supportedAudioRoles().toVariant().toList().isEmpty()); |
1056 | |
1057 | audio->setAudioRole(QDeclarativeAudio::MusicRole); |
1058 | QCOMPARE(audio->audioRole(), QDeclarativeAudio::MusicRole); |
1059 | QCOMPARE(mockService.mockAudioRoleControl->audioRole(), QAudio::MusicRole); |
1060 | QCOMPARE(spy.count(), 1); |
1061 | } |
1062 | } |
1063 | |
1064 | void tst_QDeclarativeAudio::customAudioRole() |
1065 | { |
1066 | MockMediaPlayerService mockService; |
1067 | MockMediaServiceProvider mockProvider(&mockService); |
1068 | QMediaServiceProvider::setDefaultServiceProvider(&mockProvider); |
1069 | |
1070 | QQmlEngine engine; |
1071 | QQmlComponent component(&engine); |
1072 | component.setData("import QtQuick 2.0 \n import QtMultimedia 5.11 \n Audio { }" , baseUrl: QUrl()); |
1073 | |
1074 | { |
1075 | mockService.setHasCustomAudioRole(false); |
1076 | QObject *audio = component.create(); |
1077 | QVERIFY(audio); |
1078 | |
1079 | QMetaEnum audioRoleEnum = enumerator(object: audio->metaObject(), name: "AudioRole" ); |
1080 | int AudioRole_UnknownRoleValue = keyToValue(enumeration: audioRoleEnum, key: "UnknownRole" ); |
1081 | QVERIFY(!QTest::currentTestFailed()); |
1082 | |
1083 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1084 | |
1085 | QSignalSpy spyRole(audio, SIGNAL(audioRoleChanged())); |
1086 | QSignalSpy spyCustomRole(audio, SIGNAL(customAudioRoleChanged())); |
1087 | audio->setProperty(name: "customAudioRole" , QStringLiteral("customRole" )); |
1088 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_UnknownRoleValue); |
1089 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1090 | QCOMPARE(spyRole.count(), 0); |
1091 | QCOMPARE(spyCustomRole.count(), 0); |
1092 | } |
1093 | |
1094 | { |
1095 | mockService.reset(); |
1096 | mockService.setHasAudioRole(false); |
1097 | |
1098 | QObject *audio = component.create(); |
1099 | QVERIFY(audio); |
1100 | |
1101 | QMetaEnum audioRoleEnum = enumerator(object: audio->metaObject(), name: "AudioRole" ); |
1102 | int AudioRole_UnknownRoleValue = keyToValue(enumeration: audioRoleEnum, key: "UnknownRole" ); |
1103 | QVERIFY(!QTest::currentTestFailed()); |
1104 | |
1105 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1106 | |
1107 | QSignalSpy spyRole(audio, SIGNAL(audioRoleChanged())); |
1108 | QSignalSpy spyCustomRole(audio, SIGNAL(customAudioRoleChanged())); |
1109 | audio->setProperty(name: "customAudioRole" , QStringLiteral("customRole" )); |
1110 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_UnknownRoleValue); |
1111 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1112 | QCOMPARE(spyRole.count(), 0); |
1113 | QCOMPARE(spyCustomRole.count(), 0); |
1114 | } |
1115 | |
1116 | { |
1117 | mockService.reset(); |
1118 | |
1119 | QObject *audio = component.create(); |
1120 | QVERIFY(audio); |
1121 | |
1122 | QMetaEnum audioRoleEnum = enumerator(object: audio->metaObject(), name: "AudioRole" ); |
1123 | int AudioRole_UnknownRoleValue = keyToValue(enumeration: audioRoleEnum, key: "UnknownRole" ); |
1124 | int AudioRole_CustomRoleValue = keyToValue(enumeration: audioRoleEnum, key: "CustomRole" ); |
1125 | int AudioRole_MusicRoleValue = keyToValue(enumeration: audioRoleEnum, key: "MusicRole" ); |
1126 | QVERIFY(!QTest::currentTestFailed()); |
1127 | |
1128 | QSignalSpy spyRole(audio, SIGNAL(audioRoleChanged())); |
1129 | QSignalSpy spyCustomRole(audio, SIGNAL(customAudioRoleChanged())); |
1130 | |
1131 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_UnknownRoleValue); |
1132 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1133 | |
1134 | QString customRole(QStringLiteral("customRole" )); |
1135 | audio->setProperty(name: "customAudioRole" , value: customRole); |
1136 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_CustomRoleValue); |
1137 | QCOMPARE(audio->property("customAudioRole" ).toString(), customRole); |
1138 | QCOMPARE(mockService.mockAudioRoleControl->audioRole(), QAudio::CustomRole); |
1139 | QCOMPARE(mockService.mockCustomAudioRoleControl->customAudioRole(), customRole); |
1140 | QCOMPARE(spyRole.count(), 1); |
1141 | QCOMPARE(spyCustomRole.count(), 1); |
1142 | |
1143 | spyRole.clear(); |
1144 | spyCustomRole.clear(); |
1145 | |
1146 | QString customRole2(QStringLiteral("customRole2" )); |
1147 | audio->setProperty(name: "customAudioRole" , value: customRole2); |
1148 | QCOMPARE(audio->property("customAudioRole" ).toString(), customRole2); |
1149 | QCOMPARE(mockService.mockCustomAudioRoleControl->customAudioRole(), customRole2); |
1150 | QCOMPARE(spyRole.count(), 0); |
1151 | QCOMPARE(spyCustomRole.count(), 1); |
1152 | |
1153 | spyRole.clear(); |
1154 | spyCustomRole.clear(); |
1155 | |
1156 | audio->setProperty(name: "audioRole" , value: AudioRole_MusicRoleValue); |
1157 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_MusicRoleValue); |
1158 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1159 | QCOMPARE(mockService.mockAudioRoleControl->audioRole(), QAudio::MusicRole); |
1160 | QVERIFY(mockService.mockCustomAudioRoleControl->customAudioRole().isEmpty()); |
1161 | QCOMPARE(spyRole.count(), 1); |
1162 | QCOMPARE(spyCustomRole.count(), 1); |
1163 | |
1164 | spyRole.clear(); |
1165 | spyCustomRole.clear(); |
1166 | |
1167 | audio->setProperty(name: "audioRole" , value: AudioRole_CustomRoleValue); |
1168 | QCOMPARE(audio->property("audioRole" ).toInt(), AudioRole_CustomRoleValue); |
1169 | QVERIFY(audio->property("customAudioRole" ).toString().isEmpty()); |
1170 | QCOMPARE(mockService.mockAudioRoleControl->audioRole(), QAudio::CustomRole); |
1171 | QVERIFY(mockService.mockCustomAudioRoleControl->customAudioRole().isEmpty()); |
1172 | QCOMPARE(spyRole.count(), 1); |
1173 | QCOMPARE(spyCustomRole.count(), 0); |
1174 | } |
1175 | } |
1176 | |
1177 | void tst_QDeclarativeAudio::enumerator(const QMetaObject *object, |
1178 | const char *name, |
1179 | QMetaEnum *result) |
1180 | { |
1181 | int index = object->indexOfEnumerator(name); |
1182 | QVERIFY(index >= 0); |
1183 | *result = object->enumerator(index); |
1184 | } |
1185 | |
1186 | QMetaEnum tst_QDeclarativeAudio::enumerator(const QMetaObject *object, const char *name) |
1187 | { |
1188 | QMetaEnum result; |
1189 | enumerator(object, name, result: &result); |
1190 | return result; |
1191 | } |
1192 | |
1193 | void tst_QDeclarativeAudio::keyToValue(const QMetaEnum &enumeration, const char *key, int *result) |
1194 | { |
1195 | bool ok = false; |
1196 | *result = enumeration.keyToValue(key, ok: &ok); |
1197 | QVERIFY(ok); |
1198 | } |
1199 | |
1200 | int tst_QDeclarativeAudio::keyToValue(const QMetaEnum &enumeration, const char *key) |
1201 | { |
1202 | int result; |
1203 | keyToValue(enumeration, key, result: &result); |
1204 | return result; |
1205 | } |
1206 | |
1207 | struct Surface : QAbstractVideoSurface |
1208 | { |
1209 | Surface(QObject *parent = nullptr) : QAbstractVideoSurface(parent) { } |
1210 | QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override |
1211 | { |
1212 | return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB32; |
1213 | } |
1214 | |
1215 | bool present(const QVideoFrame &) override { return true; } |
1216 | }; |
1217 | |
1218 | void tst_QDeclarativeAudio::videoOutput() |
1219 | { |
1220 | QtTestMediaPlayerControl playerControl; |
1221 | QtTestMediaServiceProvider provider(&playerControl, 0); |
1222 | |
1223 | QDeclarativeAudio audio; |
1224 | QSignalSpy spy(&audio, &QDeclarativeAudio::videoOutputChanged); |
1225 | |
1226 | audio.classBegin(); |
1227 | audio.componentComplete(); |
1228 | |
1229 | QVERIFY(audio.videoOutput().isNull()); |
1230 | |
1231 | QVariant surface; |
1232 | surface.setValue(new Surface(this)); |
1233 | audio.setVideoOutput(surface); |
1234 | QCOMPARE(audio.videoOutput(), surface); |
1235 | QCOMPARE(spy.count(), 1); |
1236 | |
1237 | QQmlEngine engine; |
1238 | QJSValue jsArray = engine.newArray(length: 5); |
1239 | jsArray.setProperty(arrayIndex: 0, value: engine.newQObject(object: new Surface(this))); |
1240 | jsArray.setProperty(arrayIndex: 1, value: engine.newQObject(object: new Surface(this))); |
1241 | QDeclarativeVideoOutput output; |
1242 | jsArray.setProperty(arrayIndex: 2, value: engine.newQObject(object: &output)); |
1243 | jsArray.setProperty(arrayIndex: 3, value: 123); |
1244 | jsArray.setProperty(arrayIndex: 4, value: QLatin1String("ignore this" )); |
1245 | |
1246 | QVariant surfaces; |
1247 | surfaces.setValue(jsArray); |
1248 | audio.setVideoOutput(surfaces); |
1249 | QCOMPARE(audio.videoOutput(), surfaces); |
1250 | QCOMPARE(spy.count(), 2); |
1251 | } |
1252 | |
1253 | QTEST_MAIN(tst_QDeclarativeAudio) |
1254 | |
1255 | #include "tst_qdeclarativeaudio.moc" |
1256 | |