| 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 |  |