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:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qmediaplayer.h"
41#include "qvideosurfaceoutput_p.h"
42
43#include "qmediaobject_p.h"
44#include <qmediaservice.h>
45#include <qmediaplayercontrol.h>
46#include <qmediaserviceprovider_p.h>
47#include <qmediaplaylist.h>
48#include <qmediaplaylistcontrol_p.h>
49#include <qmediaplaylistsourcecontrol_p.h>
50#include <qmedianetworkaccesscontrol.h>
51#include <qaudiorolecontrol.h>
52#include <qcustomaudiorolecontrol.h>
53
54#include <QtCore/qcoreevent.h>
55#include <QtCore/qmetaobject.h>
56#include <QtCore/qtimer.h>
57#include <QtCore/qdebug.h>
58#include <QtCore/qpointer.h>
59#include <QtCore/qfileinfo.h>
60#include <QtCore/qtemporaryfile.h>
61
62QT_BEGIN_NAMESPACE
63
64/*!
65 \class QMediaPlayer
66 \brief The QMediaPlayer class allows the playing of a media source.
67 \inmodule QtMultimedia
68 \ingroup multimedia
69 \ingroup multimedia_playback
70
71 The QMediaPlayer class is a high level media playback class. It can be used
72 to playback such content as songs, movies and internet radio. The content
73 to playback is specified as a QMediaContent object, which can be thought of as a
74 main or canonical URL with additional information attached. When provided
75 with a QMediaContent playback may be able to commence.
76
77 \snippet multimedia-snippets/media.cpp Player
78
79 QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist
80 for accessing playlist functionality.
81
82 \snippet multimedia-snippets/media.cpp Movie playlist
83
84 Since QMediaPlayer is a QMediaObject, you can use several of the QMediaObject
85 functions for things like:
86
87 \list
88 \li Accessing the currently playing media's metadata (\l {QMediaObject::metaData()} and \l {QMediaMetaData}{predefined meta-data keys})
89 \li Checking to see if the media playback service is currently available (\l {QMediaObject::availability()})
90 \endlist
91
92 \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist
93*/
94
95static void qRegisterMediaPlayerMetaTypes()
96{
97 qRegisterMetaType<QMediaPlayer::State>("QMediaPlayer::State");
98 qRegisterMetaType<QMediaPlayer::MediaStatus>("QMediaPlayer::MediaStatus");
99 qRegisterMetaType<QMediaPlayer::Error>("QMediaPlayer::Error");
100}
101
102Q_CONSTRUCTOR_FUNCTION(qRegisterMediaPlayerMetaTypes)
103
104#define MAX_NESTED_PLAYLISTS 16
105
106class QMediaPlayerPrivate : public QMediaObjectPrivate
107{
108 Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer)
109
110public:
111 QMediaPlayerPrivate()
112 : provider(0)
113 , control(0)
114 , audioRoleControl(0)
115 , customAudioRoleControl(0)
116 , playlist(0)
117 , networkAccessControl(0)
118 , state(QMediaPlayer::StoppedState)
119 , status(QMediaPlayer::UnknownMediaStatus)
120 , error(QMediaPlayer::NoError)
121 , ignoreNextStatusChange(-1)
122 , nestedPlaylists(0)
123 , hasStreamPlaybackFeature(false)
124 {}
125
126 QMediaServiceProvider *provider;
127 QMediaPlayerControl* control;
128 QAudioRoleControl *audioRoleControl;
129 QCustomAudioRoleControl *customAudioRoleControl;
130 QString errorString;
131
132 QPointer<QObject> videoOutput;
133 QMediaPlaylist *playlist;
134 QMediaNetworkAccessControl *networkAccessControl;
135 QVideoSurfaceOutput surfaceOutput;
136 QMediaContent qrcMedia;
137 QScopedPointer<QFile> qrcFile;
138
139 QMediaContent rootMedia;
140 QMediaContent pendingPlaylist;
141 QMediaPlayer::State state;
142 QMediaPlayer::MediaStatus status;
143 QMediaPlayer::Error error;
144 int ignoreNextStatusChange;
145 int nestedPlaylists;
146 bool hasStreamPlaybackFeature;
147
148 QMediaPlaylist *parentPlaylist(QMediaPlaylist *pls);
149 bool isInChain(const QUrl &url);
150
151 void setMedia(const QMediaContent &media, QIODevice *stream = 0);
152
153 void setPlaylist(QMediaPlaylist *playlist);
154 void setPlaylistMedia();
155 void loadPlaylist();
156 void disconnectPlaylist();
157 void connectPlaylist();
158
159 void _q_stateChanged(QMediaPlayer::State state);
160 void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
161 void _q_error(int error, const QString &errorString);
162 void _q_updateMedia(const QMediaContent&);
163 void _q_playlistDestroyed();
164 void _q_handleMediaChanged(const QMediaContent&);
165 void _q_handlePlaylistLoaded();
166 void _q_handlePlaylistLoadFailed();
167};
168
169QMediaPlaylist *QMediaPlayerPrivate::parentPlaylist(QMediaPlaylist *pls)
170{
171 // This function finds a parent playlist for an item in the active chain of playlists.
172 // Every item in the chain comes from currentMedia() of its parent.
173 // We don't need to travers the whole tree of playlists,
174 // but only the subtree of active ones.
175 for (QMediaPlaylist *current = rootMedia.playlist(); current && current != pls; current = current->currentMedia().playlist())
176 if (current->currentMedia().playlist() == pls)
177 return current;
178 return 0;
179}
180
181bool QMediaPlayerPrivate::isInChain(const QUrl &url)
182{
183 // Check whether a URL is already in the chain of playlists.
184 // Also see a comment in parentPlaylist().
185 for (QMediaPlaylist *current = rootMedia.playlist(); current && current != playlist; current = current->currentMedia().playlist())
186 if (current->currentMedia().canonicalUrl() == url) {
187 return true;
188 }
189 return false;
190}
191
192void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps)
193{
194 Q_Q(QMediaPlayer);
195
196 // Backend switches into stopped state every time new media is about to be loaded.
197 // If media player has a playlist loaded make sure player doesn' stop.
198 if (playlist && playlist->currentIndex() != -1 && ps != state && ps == QMediaPlayer::StoppedState) {
199 if (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
200 control->mediaStatus() == QMediaPlayer::InvalidMedia) {
201 // if media player is not stopped, and
202 // we have finished playback for the current media,
203 // advance to the next item in the playlist
204 Q_ASSERT(state != QMediaPlayer::StoppedState);
205 playlist->next();
206 return;
207 } else if (control->mediaStatus() == QMediaPlayer::LoadingMedia) {
208 return;
209 }
210 }
211
212 if (ps != state) {
213 state = ps;
214
215 if (ps == QMediaPlayer::PlayingState)
216 q->addPropertyWatch("position");
217 else
218 q->removePropertyWatch("position");
219
220 emit q->stateChanged(ps);
221 }
222}
223
224void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus s)
225{
226 Q_Q(QMediaPlayer);
227
228 if (int(s) == ignoreNextStatusChange) {
229 ignoreNextStatusChange = -1;
230 return;
231 }
232
233 if (s != status) {
234 status = s;
235
236 switch (s) {
237 case QMediaPlayer::StalledMedia:
238 case QMediaPlayer::BufferingMedia:
239 q->addPropertyWatch("bufferStatus");
240 break;
241 default:
242 q->removePropertyWatch("bufferStatus");
243 break;
244 }
245
246 emit q->mediaStatusChanged(s);
247 }
248}
249
250void QMediaPlayerPrivate::_q_error(int error, const QString &errorString)
251{
252 Q_Q(QMediaPlayer);
253
254 if (error == int(QMediaPlayer::MediaIsPlaylist)) {
255 loadPlaylist();
256 } else {
257 this->error = QMediaPlayer::Error(error);
258 this->errorString = errorString;
259 emit q->error(this->error);
260
261 if (playlist)
262 playlist->next();
263 }
264}
265
266void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
267{
268 Q_Q(QMediaPlayer);
269
270 if (!control)
271 return;
272
273 // check if the current playlist is a top-level playlist
274 Q_ASSERT(playlist);
275 if (media.isNull() && playlist != rootMedia.playlist()) {
276 // switch back to parent playlist
277 QMediaPlaylist *pls = parentPlaylist(playlist);
278 Q_ASSERT(pls);
279 disconnectPlaylist();
280 playlist = pls;
281 connectPlaylist();
282
283 Q_ASSERT(!pendingPlaylist.playlist());
284 nestedPlaylists--;
285 Q_ASSERT(nestedPlaylists >= 0);
286
287 playlist->next();
288 return;
289 }
290
291 if (media.playlist()) {
292 if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
293 nestedPlaylists++;
294 Q_ASSERT(!pendingPlaylist.playlist());
295
296 // disconnect current playlist
297 disconnectPlaylist();
298 // new playlist signals are connected
299 // in the call to setPlaylist() in _q_handlePlaylistLoaded()
300 playlist = media.playlist();
301 emit q->currentMediaChanged(media);
302 _q_handlePlaylistLoaded();
303 return;
304 } else if (playlist) {
305 playlist->next();
306 }
307 return;
308 }
309
310 const QMediaPlayer::State currentState = state;
311
312 setMedia(media, 0);
313
314 if (!media.isNull()) {
315 switch (currentState) {
316 case QMediaPlayer::PlayingState:
317 control->play();
318 break;
319 case QMediaPlayer::PausedState:
320 control->pause();
321 break;
322 default:
323 break;
324 }
325 }
326
327 _q_stateChanged(control->state());
328}
329
330void QMediaPlayerPrivate::_q_playlistDestroyed()
331{
332 playlist = 0;
333 setMedia(QMediaContent(), 0);
334}
335
336void QMediaPlayerPrivate::setMedia(const QMediaContent &media, QIODevice *stream)
337{
338 Q_Q(QMediaPlayer);
339
340 if (!control)
341 return;
342
343 QScopedPointer<QFile> file;
344
345 // Backends can't play qrc files directly.
346 // If the backend supports StreamPlayback, we pass a QFile for that resource.
347 // If it doesn't, we copy the data to a temporary file and pass its path.
348 if (!media.isNull() && !stream && media.canonicalUrl().scheme() == QLatin1String("qrc")) {
349 qrcMedia = media;
350
351 file.reset(new QFile(QLatin1Char(':') + media.canonicalUrl().path()));
352 if (!file->open(QFile::ReadOnly)) {
353 QMetaObject::invokeMethod(q, "_q_error", Qt::QueuedConnection,
354 Q_ARG(int, QMediaPlayer::ResourceError),
355 Q_ARG(QString, QMediaPlayer::tr("Attempting to play invalid Qt resource")));
356 QMetaObject::invokeMethod(q, "_q_mediaStatusChanged", Qt::QueuedConnection,
357 Q_ARG(QMediaPlayer::MediaStatus, QMediaPlayer::InvalidMedia));
358 file.reset();
359 // Ignore the next NoMedia status change, we just want to clear the current media
360 // on the backend side since we can't load the new one and we want to be in the
361 // InvalidMedia status.
362 ignoreNextStatusChange = QMediaPlayer::NoMedia;
363 control->setMedia(QMediaContent(), 0);
364
365 } else if (hasStreamPlaybackFeature) {
366 control->setMedia(media, file.data());
367 } else {
368#if QT_CONFIG(temporaryfile)
369 QTemporaryFile *tempFile = new QTemporaryFile;
370
371 // Preserve original file extension, some backends might not load the file if it doesn't
372 // have an extension.
373 const QString suffix = QFileInfo(*file).suffix();
374 if (!suffix.isEmpty())
375 tempFile->setFileTemplate(tempFile->fileTemplate() + QLatin1Char('.') + suffix);
376
377 // Copy the qrc data into the temporary file
378 tempFile->open();
379 char buffer[4096];
380 while (true) {
381 qint64 len = file->read(buffer, sizeof(buffer));
382 if (len < 1)
383 break;
384 tempFile->write(buffer, len);
385 }
386 tempFile->close();
387
388 file.reset(tempFile);
389 control->setMedia(QMediaContent(QUrl::fromLocalFile(file->fileName())), 0);
390#else
391 qWarning("Qt was built with -no-feature-temporaryfile: playback from resource file is not supported!");
392#endif
393 }
394 } else {
395 qrcMedia = QMediaContent();
396 control->setMedia(media, stream);
397 }
398
399 qrcFile.swap(file); // Cleans up any previous file
400}
401
402void QMediaPlayerPrivate::_q_handleMediaChanged(const QMediaContent &media)
403{
404 Q_Q(QMediaPlayer);
405
406 emit q->currentMediaChanged(qrcMedia.isNull() ? media : qrcMedia);
407}
408
409void QMediaPlayerPrivate::setPlaylist(QMediaPlaylist *pls)
410{
411 disconnectPlaylist();
412 playlist = pls;
413
414 setPlaylistMedia();
415}
416
417void QMediaPlayerPrivate::setPlaylistMedia()
418{
419 // This function loads current playlist media into backend.
420 // If current media is a playlist, the function recursively
421 // loads media from the playlist.
422 // It also makes sure the correct playlist signals are connected.
423 Q_Q(QMediaPlayer);
424
425 if (playlist) {
426 connectPlaylist();
427 if (playlist->currentMedia().playlist()) {
428 if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
429 emit q->currentMediaChanged(playlist->currentMedia());
430 // rewind nested playlist to start
431 playlist->currentMedia().playlist()->setCurrentIndex(0);
432 nestedPlaylists++;
433 setPlaylist(playlist->currentMedia().playlist());
434 } else {
435 playlist->next();
436 }
437 return;
438 } else {
439 // If we've just switched to a new playlist,
440 // then last emitted currentMediaChanged was a playlist.
441 // Make sure we emit currentMediaChanged if new playlist has
442 // the same media as the previous one:
443 // sample.m3u
444 // test.wav -- processed by backend
445 // nested.m3u -- processed by frontend
446 // test.wav -- processed by backend,
447 // media is not changed,
448 // frontend needs to emit currentMediaChanged
449 bool isSameMedia = (q->currentMedia() == playlist->currentMedia());
450 setMedia(playlist->currentMedia(), 0);
451 if (isSameMedia) {
452 emit q->currentMediaChanged(q->currentMedia());
453 }
454 }
455 } else {
456 setMedia(QMediaContent(), 0);
457 }
458}
459
460void QMediaPlayerPrivate::loadPlaylist()
461{
462 Q_Q(QMediaPlayer);
463 Q_ASSERT(pendingPlaylist.isNull());
464
465 // Do not load a playlist if there are more than MAX_NESTED_PLAYLISTS in the chain already,
466 // or if the playlist URL is already in the chain, i.e. do not allow recursive playlists and loops.
467 if (nestedPlaylists < MAX_NESTED_PLAYLISTS && !q->currentMedia().canonicalUrl().isEmpty() && !isInChain(q->currentMedia().canonicalUrl())) {
468 pendingPlaylist = QMediaContent(new QMediaPlaylist, q->currentMedia().canonicalUrl(), true);
469 QObject::connect(pendingPlaylist.playlist(), SIGNAL(loaded()), q, SLOT(_q_handlePlaylistLoaded()));
470 QObject::connect(pendingPlaylist.playlist(), SIGNAL(loadFailed()), q, SLOT(_q_handlePlaylistLoadFailed()));
471 pendingPlaylist.playlist()->load(pendingPlaylist.canonicalRequest());
472 } else if (playlist) {
473 playlist->next();
474 }
475}
476
477void QMediaPlayerPrivate::disconnectPlaylist()
478{
479 Q_Q(QMediaPlayer);
480 if (playlist) {
481 QObject::disconnect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
482 q, SLOT(_q_updateMedia(QMediaContent)));
483 QObject::disconnect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
484 q->unbind(playlist);
485 }
486}
487
488void QMediaPlayerPrivate::connectPlaylist()
489{
490 Q_Q(QMediaPlayer);
491 if (playlist) {
492 q->bind(playlist);
493 QObject::connect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
494 q, SLOT(_q_updateMedia(QMediaContent)));
495 QObject::connect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
496 }
497}
498
499void QMediaPlayerPrivate::_q_handlePlaylistLoaded()
500{
501 Q_Q(QMediaPlayer);
502
503 if (pendingPlaylist.playlist()) {
504 Q_ASSERT(!q->currentMedia().playlist());
505 // if there is an active playlist
506 if (playlist) {
507 Q_ASSERT(playlist->currentIndex() >= 0);
508 disconnectPlaylist();
509 playlist->insertMedia(playlist->currentIndex() + 1, pendingPlaylist);
510 playlist->removeMedia(playlist->currentIndex());
511 nestedPlaylists++;
512 } else {
513 Q_ASSERT(!rootMedia.playlist());
514 rootMedia = pendingPlaylist;
515 emit q->mediaChanged(rootMedia);
516 }
517
518 playlist = pendingPlaylist.playlist();
519 emit q->currentMediaChanged(pendingPlaylist);
520 }
521 pendingPlaylist = QMediaContent();
522
523 playlist->next();
524 setPlaylistMedia();
525
526 switch (state) {
527 case QMediaPlayer::PausedState:
528 control->pause();
529 break;
530 case QMediaPlayer::PlayingState:
531 control->play();
532 break;
533 case QMediaPlayer::StoppedState:
534 break;
535 }
536}
537
538void QMediaPlayerPrivate::_q_handlePlaylistLoadFailed()
539{
540 pendingPlaylist = QMediaContent();
541
542 if (!control)
543 return;
544
545 if (playlist)
546 playlist->next();
547 else
548 setMedia(QMediaContent(), 0);
549}
550
551static QMediaService *playerService(QMediaPlayer::Flags flags)
552{
553 QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
554 if (flags) {
555 QMediaServiceProviderHint::Features features = 0;
556 if (flags & QMediaPlayer::LowLatency)
557 features |= QMediaServiceProviderHint::LowLatencyPlayback;
558
559 if (flags & QMediaPlayer::StreamPlayback)
560 features |= QMediaServiceProviderHint::StreamPlayback;
561
562 if (flags & QMediaPlayer::VideoSurface)
563 features |= QMediaServiceProviderHint::VideoSurface;
564
565 return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER,
566 QMediaServiceProviderHint(features));
567 }
568
569 return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER);
570}
571
572
573/*!
574 Construct a QMediaPlayer instance
575 parented to \a parent and with \a flags.
576*/
577
578QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
579 QMediaObject(*new QMediaPlayerPrivate,
580 parent,
581 playerService(flags))
582{
583 Q_D(QMediaPlayer);
584
585 d->provider = QMediaServiceProvider::defaultServiceProvider();
586 if (d->service == 0) {
587 d->error = ServiceMissingError;
588 } else {
589 d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid));
590 d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid));
591 if (d->control != 0) {
592 connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SLOT(_q_handleMediaChanged(QMediaContent)));
593 connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
594 connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
595 SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
596 connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString)));
597
598 connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
599 connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64)));
600 connect(d->control, SIGNAL(audioAvailableChanged(bool)), SIGNAL(audioAvailableChanged(bool)));
601 connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool)));
602 connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int)));
603 connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool)));
604 connect(d->control, SIGNAL(seekableChanged(bool)), SIGNAL(seekableChanged(bool)));
605 connect(d->control, SIGNAL(playbackRateChanged(qreal)), SIGNAL(playbackRateChanged(qreal)));
606 connect(d->control, SIGNAL(bufferStatusChanged(int)), SIGNAL(bufferStatusChanged(int)));
607
608 d->state = d->control->state();
609 d->status = d->control->mediaStatus();
610
611 if (d->state == PlayingState)
612 addPropertyWatch("position");
613
614 if (d->status == StalledMedia || d->status == BufferingMedia)
615 addPropertyWatch("bufferStatus");
616
617 d->hasStreamPlaybackFeature = d->provider->supportedFeatures(d->service).testFlag(QMediaServiceProviderHint::StreamPlayback);
618
619 d->audioRoleControl = qobject_cast<QAudioRoleControl*>(d->service->requestControl(QAudioRoleControl_iid));
620 if (d->audioRoleControl) {
621 connect(d->audioRoleControl, &QAudioRoleControl::audioRoleChanged,
622 this, &QMediaPlayer::audioRoleChanged);
623
624 d->customAudioRoleControl = qobject_cast<QCustomAudioRoleControl *>(
625 d->service->requestControl(QCustomAudioRoleControl_iid));
626 if (d->customAudioRoleControl) {
627 connect(d->customAudioRoleControl,
628 &QCustomAudioRoleControl::customAudioRoleChanged,
629 this,
630 &QMediaPlayer::customAudioRoleChanged);
631 }
632 }
633 }
634 if (d->networkAccessControl != 0) {
635 connect(d->networkAccessControl, SIGNAL(configurationChanged(QNetworkConfiguration)),
636 this, SIGNAL(networkConfigurationChanged(QNetworkConfiguration)));
637 }
638 }
639}
640
641
642/*!
643 Destroys the player object.
644*/
645
646QMediaPlayer::~QMediaPlayer()
647{
648 Q_D(QMediaPlayer);
649
650 d->disconnectPlaylist();
651
652 if (d->service) {
653 if (d->control)
654 d->service->releaseControl(d->control);
655 if (d->audioRoleControl)
656 d->service->releaseControl(d->audioRoleControl);
657 if (d->customAudioRoleControl)
658 d->service->releaseControl(d->customAudioRoleControl);
659
660 d->provider->releaseService(d->service);
661 }
662}
663
664QMediaContent QMediaPlayer::media() const
665{
666 Q_D(const QMediaPlayer);
667
668 return d->rootMedia;
669}
670
671/*!
672 Returns the stream source of media data.
673
674 This is only valid if a stream was passed to setMedia().
675
676 \sa setMedia()
677*/
678
679const QIODevice *QMediaPlayer::mediaStream() const
680{
681 Q_D(const QMediaPlayer);
682
683 // When playing a resource file, we might have passed a QFile to the backend. Hide it from
684 // the user.
685 if (d->control && d->qrcMedia.isNull())
686 return d->control->mediaStream();
687
688 return 0;
689}
690
691QMediaPlaylist *QMediaPlayer::playlist() const
692{
693 Q_D(const QMediaPlayer);
694
695 return d->rootMedia.playlist();
696}
697
698QMediaContent QMediaPlayer::currentMedia() const
699{
700 Q_D(const QMediaPlayer);
701
702 // When playing a resource file, don't return the backend's current media, which
703 // can be a temporary file.
704 if (!d->qrcMedia.isNull())
705 return d->qrcMedia;
706
707 if (d->control)
708 return d->control->media();
709
710 return QMediaContent();
711}
712
713void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
714{
715 QMediaContent m(playlist, QUrl(), false);
716 setMedia(m);
717}
718
719/*!
720 Sets the network access points for remote media playback.
721 \a configurations contains, in ascending preferential order, a list of
722 configuration that can be used for network access.
723
724 This will invalidate the choice of previous configurations.
725*/
726void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations)
727{
728 Q_D(QMediaPlayer);
729
730 if (d->networkAccessControl)
731 d->networkAccessControl->setConfigurations(configurations);
732}
733
734QMediaPlayer::State QMediaPlayer::state() const
735{
736 Q_D(const QMediaPlayer);
737
738 // In case if EndOfMedia status is already received
739 // but state is not.
740 if (d->control != 0
741 && d->status == QMediaPlayer::EndOfMedia
742 && d->state != d->control->state()) {
743 return d->control->state();
744 }
745
746 return d->state;
747}
748
749QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
750{
751 return d_func()->status;
752}
753
754qint64 QMediaPlayer::duration() const
755{
756 Q_D(const QMediaPlayer);
757
758 if (d->control != 0)
759 return d->control->duration();
760
761 return -1;
762}
763
764qint64 QMediaPlayer::position() const
765{
766 Q_D(const QMediaPlayer);
767
768 if (d->control != 0)
769 return d->control->position();
770
771 return 0;
772}
773
774int QMediaPlayer::volume() const
775{
776 Q_D(const QMediaPlayer);
777
778 if (d->control != 0)
779 return d->control->volume();
780
781 return 0;
782}
783
784bool QMediaPlayer::isMuted() const
785{
786 Q_D(const QMediaPlayer);
787
788 if (d->control != 0)
789 return d->control->isMuted();
790
791 return false;
792}
793
794int QMediaPlayer::bufferStatus() const
795{
796 Q_D(const QMediaPlayer);
797
798 if (d->control != 0)
799 return d->control->bufferStatus();
800
801 return 0;
802}
803
804bool QMediaPlayer::isAudioAvailable() const
805{
806 Q_D(const QMediaPlayer);
807
808 if (d->control != 0)
809 return d->control->isAudioAvailable();
810
811 return false;
812}
813
814bool QMediaPlayer::isVideoAvailable() const
815{
816 Q_D(const QMediaPlayer);
817
818 if (d->control != 0)
819 return d->control->isVideoAvailable();
820
821 return false;
822}
823
824bool QMediaPlayer::isSeekable() const
825{
826 Q_D(const QMediaPlayer);
827
828 if (d->control != 0)
829 return d->control->isSeekable();
830
831 return false;
832}
833
834qreal QMediaPlayer::playbackRate() const
835{
836 Q_D(const QMediaPlayer);
837
838 if (d->control != 0)
839 return d->control->playbackRate();
840
841 return 0.0;
842}
843
844/*!
845 Returns the current error state.
846*/
847
848QMediaPlayer::Error QMediaPlayer::error() const
849{
850 return d_func()->error;
851}
852
853QString QMediaPlayer::errorString() const
854{
855 return d_func()->errorString;
856}
857
858/*!
859 Returns the current network access point in use.
860 If a default contructed QNetworkConfiguration is returned
861 this feature is not available or that none of the
862 current supplied configurations are in use.
863*/
864QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const
865{
866 Q_D(const QMediaPlayer);
867
868 if (d->networkAccessControl)
869 return d_func()->networkAccessControl->currentConfiguration();
870
871 return QNetworkConfiguration();
872}
873
874//public Q_SLOTS:
875/*!
876 Start or resume playing the current source.
877*/
878
879void QMediaPlayer::play()
880{
881 Q_D(QMediaPlayer);
882
883 if (d->control == 0) {
884 QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection,
885 Q_ARG(int, QMediaPlayer::ServiceMissingError),
886 Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")));
887 return;
888 }
889
890 //if playlist control is available, the service should advance itself
891 if (d->rootMedia.playlist() && !d->rootMedia.playlist()->isEmpty()) {
892 // switch to playing state
893 if (d->state != QMediaPlayer::PlayingState)
894 d->_q_stateChanged(QMediaPlayer::PlayingState);
895
896 if (d->rootMedia.playlist()->currentIndex() == -1) {
897 if (d->playlist != d->rootMedia.playlist())
898 d->setPlaylist(d->rootMedia.playlist());
899 Q_ASSERT(d->playlist == d->rootMedia.playlist());
900
901 emit currentMediaChanged(d->rootMedia);
902 d->playlist->setCurrentIndex(0);
903 }
904 }
905
906 // Reset error conditions
907 d->error = NoError;
908 d->errorString = QString();
909
910 d->control->play();
911}
912
913/*!
914 Pause playing the current source.
915*/
916
917void QMediaPlayer::pause()
918{
919 Q_D(QMediaPlayer);
920
921 if (d->control != 0)
922 d->control->pause();
923}
924
925/*!
926 Stop playing, and reset the play position to the beginning.
927*/
928
929void QMediaPlayer::stop()
930{
931 Q_D(QMediaPlayer);
932
933 if (d->control != 0)
934 d->control->stop();
935
936 // If media player didn't stop in response to control.
937 // This happens if we have an active playlist and control
938 // media status is
939 // QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
940 // see QMediaPlayerPrivate::_q_stateChanged()
941 if (d->playlist && d->state != QMediaPlayer::StoppedState) {
942 d->state = QMediaPlayer::StoppedState;
943 removePropertyWatch("position");
944 emit stateChanged(QMediaPlayer::StoppedState);
945 }
946}
947
948void QMediaPlayer::setPosition(qint64 position)
949{
950 Q_D(QMediaPlayer);
951
952 if (d->control == 0)
953 return;
954
955 d->control->setPosition(qMax(position, 0ll));
956}
957
958void QMediaPlayer::setVolume(int v)
959{
960 Q_D(QMediaPlayer);
961
962 if (d->control == 0)
963 return;
964
965 int clamped = qBound(0, v, 100);
966 if (clamped == volume())
967 return;
968
969 d->control->setVolume(clamped);
970}
971
972void QMediaPlayer::setMuted(bool muted)
973{
974 Q_D(QMediaPlayer);
975
976 if (d->control == 0 || muted == isMuted())
977 return;
978
979 d->control->setMuted(muted);
980}
981
982void QMediaPlayer::setPlaybackRate(qreal rate)
983{
984 Q_D(QMediaPlayer);
985
986 if (d->control != 0)
987 d->control->setPlaybackRate(rate);
988}
989
990/*!
991 Sets the current \a media source.
992
993 If a \a stream is supplied; media data will be read from it instead of resolving the media
994 source. In this case the media source may still be used to resolve additional information
995 about the media such as mime type. The \a stream must be open and readable.
996
997 Setting the media to a null QMediaContent will cause the player to discard all
998 information relating to the current media source and to cease all I/O operations related
999 to that media.
1000
1001 \note This function returns immediately after recording the specified source of the media.
1002 It does not wait for the media to finish loading and does not check for errors. Listen for
1003 the mediaStatusChanged() and error() signals to be notified when the media is loaded and
1004 when an error occurs during loading.
1005*/
1006
1007void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
1008{
1009 Q_D(QMediaPlayer);
1010 stop();
1011
1012 QMediaContent oldMedia = d->rootMedia;
1013 d->disconnectPlaylist();
1014 d->playlist = 0;
1015 d->rootMedia = media;
1016 d->nestedPlaylists = 0;
1017
1018 if (oldMedia != media)
1019 emit mediaChanged(d->rootMedia);
1020
1021 if (media.playlist()) {
1022 // reset playlist to the 1st item
1023 media.playlist()->setCurrentIndex(0);
1024 d->setPlaylist(media.playlist());
1025 } else {
1026 d->setMedia(media, stream);
1027 }
1028}
1029
1030/*!
1031 \internal
1032*/
1033
1034bool QMediaPlayer::bind(QObject *obj)
1035{
1036 return QMediaObject::bind(obj);
1037}
1038
1039/*!
1040 \internal
1041*/
1042
1043void QMediaPlayer::unbind(QObject *obj)
1044{
1045 QMediaObject::unbind(obj);
1046}
1047
1048/*!
1049 Returns the level of support a media player has for a \a mimeType and a set of \a codecs.
1050
1051 The \a flags argument allows additional requirements such as performance indicators to be
1052 specified.
1053*/
1054QMultimedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType,
1055 const QStringList& codecs,
1056 Flags flags)
1057{
1058 return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1059 mimeType,
1060 codecs,
1061 flags);
1062}
1063
1064/*!
1065 \deprecated
1066 Returns a list of MIME types supported by the media player.
1067
1068 The \a flags argument causes the resultant list to be restricted to MIME types which can be supported
1069 given additional requirements, such as performance indicators.
1070
1071 This function may not return useful results on some platforms, and support for a specific file of a
1072 given mime type is not guaranteed even if the mime type is in general supported. In addition, in some
1073 cases this function will need to load all available media plugins and query them for their support, which
1074 may take some time.
1075*/
1076QStringList QMediaPlayer::supportedMimeTypes(Flags flags)
1077{
1078 return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1079 flags);
1080}
1081
1082/*!
1083 \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output)
1084
1085 Attach a QVideoWidget video \a output to the media player.
1086
1087 If the media player has already video output attached,
1088 it will be replaced with a new one.
1089*/
1090void QMediaPlayer::setVideoOutput(QVideoWidget *output)
1091{
1092 Q_D(QMediaPlayer);
1093
1094 if (d->videoOutput)
1095 unbind(d->videoOutput);
1096
1097 // We don't know (in this library) that QVideoWidget inherits QObject
1098 QObject *outputObject = reinterpret_cast<QObject*>(output);
1099
1100 d->videoOutput = outputObject && bind(outputObject) ? outputObject : 0;
1101}
1102
1103/*!
1104 \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output)
1105
1106 Attach a QGraphicsVideoItem video \a output to the media player.
1107
1108 If the media player has already video output attached,
1109 it will be replaced with a new one.
1110*/
1111void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output)
1112{
1113 Q_D(QMediaPlayer);
1114
1115 if (d->videoOutput)
1116 unbind(d->videoOutput);
1117
1118 // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject
1119 // but QObject inheritance depends on QObject coming first, so try this out.
1120 QObject *outputObject = reinterpret_cast<QObject*>(output);
1121
1122 d->videoOutput = outputObject && bind(outputObject) ? outputObject : 0;
1123}
1124
1125/*!
1126 Sets a video \a surface as the video output of a media player.
1127
1128 If a video output has already been set on the media player the new surface
1129 will replace it.
1130*/
1131
1132void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
1133{
1134 Q_D(QMediaPlayer);
1135
1136 d->surfaceOutput.setVideoSurface(surface);
1137
1138 if (d->videoOutput != &d->surfaceOutput) {
1139 if (d->videoOutput)
1140 unbind(d->videoOutput);
1141
1142 d->videoOutput = 0;
1143
1144 if (surface && bind(&d->surfaceOutput))
1145 d->videoOutput = &d->surfaceOutput;
1146 } else if (!surface) {
1147 //unbind the surfaceOutput if null surface is set
1148 unbind(&d->surfaceOutput);
1149 d->videoOutput = 0;
1150 }
1151}
1152
1153/*! \reimp */
1154QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
1155{
1156 Q_D(const QMediaPlayer);
1157
1158 if (!d->control)
1159 return QMultimedia::ServiceMissing;
1160
1161 return QMediaObject::availability();
1162}
1163
1164QAudio::Role QMediaPlayer::audioRole() const
1165{
1166 Q_D(const QMediaPlayer);
1167
1168 if (d->audioRoleControl != NULL)
1169 return d->audioRoleControl->audioRole();
1170
1171 return QAudio::UnknownRole;
1172}
1173
1174void QMediaPlayer::setAudioRole(QAudio::Role audioRole)
1175{
1176 Q_D(QMediaPlayer);
1177
1178 if (d->audioRoleControl) {
1179 if (d->customAudioRoleControl != nullptr && d->audioRoleControl->audioRole() != audioRole) {
1180 d->customAudioRoleControl->setCustomAudioRole(QString());
1181 }
1182
1183 d->audioRoleControl->setAudioRole(audioRole);
1184 }
1185}
1186
1187/*!
1188 Returns a list of supported audio roles.
1189
1190 If setting the audio role is not supported, an empty list is returned.
1191
1192 \since 5.6
1193 \sa audioRole
1194*/
1195QList<QAudio::Role> QMediaPlayer::supportedAudioRoles() const
1196{
1197 Q_D(const QMediaPlayer);
1198
1199 if (d->audioRoleControl)
1200 return d->audioRoleControl->supportedAudioRoles();
1201
1202 return QList<QAudio::Role>();
1203}
1204
1205QString QMediaPlayer::customAudioRole() const
1206{
1207 Q_D(const QMediaPlayer);
1208
1209 if (audioRole() != QAudio::CustomRole)
1210 return QString();
1211
1212 if (d->customAudioRoleControl != nullptr)
1213 return d->customAudioRoleControl->customAudioRole();
1214
1215 return QString();
1216}
1217
1218void QMediaPlayer::setCustomAudioRole(const QString &audioRole)
1219{
1220 Q_D(QMediaPlayer);
1221
1222 if (d->customAudioRoleControl) {
1223 Q_ASSERT(d->audioRoleControl);
1224 setAudioRole(QAudio::CustomRole);
1225 d->customAudioRoleControl->setCustomAudioRole(audioRole);
1226 }
1227}
1228
1229/*!
1230 Returns a list of supported custom audio roles. An empty list may
1231 indicate that the supported custom audio roles aren't known. The
1232 list may not be complete.
1233
1234 \since 5.11
1235 \sa customAudioRole
1236*/
1237QStringList QMediaPlayer::supportedCustomAudioRoles() const
1238{
1239 Q_D(const QMediaPlayer);
1240
1241 if (d->customAudioRoleControl)
1242 return d->customAudioRoleControl->supportedCustomAudioRoles();
1243
1244 return QStringList();
1245}
1246
1247// Enums
1248/*!
1249 \enum QMediaPlayer::State
1250
1251 Defines the current state of a media player.
1252
1253 \value StoppedState The media player is not playing content, playback will begin from the start
1254 of the current track.
1255 \value PlayingState The media player is currently playing content.
1256 \value PausedState The media player has paused playback, playback of the current track will
1257 resume from the position the player was paused at.
1258*/
1259
1260/*!
1261 \enum QMediaPlayer::MediaStatus
1262
1263 Defines the status of a media player's current media.
1264
1265 \value UnknownMediaStatus The status of the media cannot be determined.
1266 \value NoMedia The is no current media. The player is in the StoppedState.
1267 \value LoadingMedia The current media is being loaded. The player may be in any state.
1268 \value LoadedMedia The current media has been loaded. The player is in the StoppedState.
1269 \value StalledMedia Playback of the current media has stalled due to insufficient buffering or
1270 some other temporary interruption. The player is in the PlayingState or PausedState.
1271 \value BufferingMedia The player is buffering data but has enough data buffered for playback to
1272 continue for the immediate future. The player is in the PlayingState or PausedState.
1273 \value BufferedMedia The player has fully buffered the current media. The player is in the
1274 PlayingState or PausedState.
1275 \value EndOfMedia Playback has reached the end of the current media. The player is in the
1276 StoppedState.
1277 \value InvalidMedia The current media cannot be played. The player is in the StoppedState.
1278*/
1279
1280/*!
1281 \enum QMediaPlayer::Error
1282
1283 Defines a media player error condition.
1284
1285 \value NoError No error has occurred.
1286 \value ResourceError A media resource couldn't be resolved.
1287 \value FormatError The format of a media resource isn't (fully) supported. Playback may still
1288 be possible, but without an audio or video component.
1289 \value NetworkError A network error occurred.
1290 \value AccessDeniedError There are not the appropriate permissions to play a media resource.
1291 \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
1292 \omitvalue MediaIsPlaylist
1293*/
1294
1295// Signals
1296/*!
1297 \fn QMediaPlayer::error(QMediaPlayer::Error error)
1298
1299 Signals that an \a error condition has occurred.
1300
1301 \sa errorString()
1302*/
1303
1304/*!
1305 \fn void QMediaPlayer::stateChanged(State state)
1306
1307 Signal the \a state of the Player object has changed.
1308*/
1309
1310/*!
1311 \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
1312
1313 Signals that the \a status of the current media has changed.
1314
1315 \sa mediaStatus()
1316*/
1317
1318/*!
1319 \fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
1320
1321 Signals that the media source has been changed to \a media.
1322
1323 \sa media(), currentMediaChanged()
1324*/
1325
1326/*!
1327 \fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
1328
1329 Signals that the current playing content has been changed to \a media.
1330
1331 \sa currentMedia(), mediaChanged()
1332*/
1333
1334/*!
1335 \fn void QMediaPlayer::playbackRateChanged(qreal rate);
1336
1337 Signals the playbackRate has changed to \a rate.
1338*/
1339
1340/*!
1341 \fn void QMediaPlayer::seekableChanged(bool seekable);
1342
1343 Signals the \a seekable status of the player object has changed.
1344*/
1345
1346/*!
1347 \fn void QMediaPlayer::audioRoleChanged(QAudio::Role role)
1348
1349 Signals that the audio \a role of the media player has changed.
1350
1351 \since 5.6
1352*/
1353
1354/*!
1355 \fn void QMediaPlayer::customAudioRoleChanged(const QString &role)
1356
1357 Signals that the audio \a role of the media player has changed.
1358
1359 \since 5.11
1360*/
1361
1362// Properties
1363/*!
1364 \property QMediaPlayer::state
1365 \brief the media player's playback state.
1366
1367 By default this property is QMediaPlayer::Stopped
1368
1369 \sa mediaStatus(), play(), pause(), stop()
1370*/
1371
1372/*!
1373 \property QMediaPlayer::error
1374 \brief a string describing the last error condition.
1375
1376 \sa error()
1377*/
1378
1379/*!
1380 \property QMediaPlayer::media
1381 \brief the active media source being used by the player object.
1382
1383 The player object will use the QMediaContent for selection of the content to
1384 be played.
1385
1386 By default this property has a null QMediaContent.
1387
1388 Setting this property to a null QMediaContent will cause the player to discard all
1389 information relating to the current media source and to cease all I/O operations related
1390 to that media.
1391
1392 \sa QMediaContent, currentMedia()
1393*/
1394
1395/*!
1396 \property QMediaPlayer::currentMedia
1397 \brief the current active media content being played by the player object.
1398 This value could be different from QMediaPlayer::media property if a playlist is used.
1399 In this case currentMedia indicates the current media content being processed
1400 by the player, while QMediaPlayer::media property contains the original playlist.
1401
1402 \sa QMediaContent, media()
1403*/
1404
1405/*!
1406 \property QMediaPlayer::playlist
1407 \brief the media playlist being used by the player object.
1408
1409 The player object will use the current playlist item for selection of the content to
1410 be played.
1411
1412 By default this property is set to null.
1413
1414 If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
1415 a current playlist item. The current source should be selected with
1416 QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
1417 otherwise the current playlist will be discarded.
1418
1419 \sa QMediaContent
1420*/
1421
1422
1423/*!
1424 \property QMediaPlayer::mediaStatus
1425 \brief the status of the current media stream.
1426
1427 The stream status describes how the playback of the current stream is
1428 progressing.
1429
1430 By default this property is QMediaPlayer::NoMedia
1431
1432 \sa state
1433*/
1434
1435/*!
1436 \property QMediaPlayer::duration
1437 \brief the duration of the current media.
1438
1439 The value is the total playback time in milliseconds of the current media.
1440 The value may change across the life time of the QMediaPlayer object and
1441 may not be available when initial playback begins, connect to the
1442 durationChanged() signal to receive status notifications.
1443*/
1444
1445/*!
1446 \property QMediaPlayer::position
1447 \brief the playback position of the current media.
1448
1449 The value is the current playback position, expressed in milliseconds since
1450 the beginning of the media. Periodically changes in the position will be
1451 indicated with the signal positionChanged(), the interval between updates
1452 can be set with QMediaObject's method setNotifyInterval().
1453*/
1454
1455/*!
1456 \property QMediaPlayer::volume
1457 \brief the current playback volume.
1458
1459 The playback volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
1460 Values outside this range will be clamped.
1461
1462 By default the volume is \c 100.
1463
1464 UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale
1465 will produce linear changes in perceived loudness, which is what a user would normally expect
1466 from a volume control. See QAudio::convertVolume() for more details.
1467*/
1468
1469/*!
1470 \property QMediaPlayer::muted
1471 \brief the muted state of the current media.
1472
1473 The value will be true if the playback volume is muted; otherwise false.
1474*/
1475
1476/*!
1477 \property QMediaPlayer::bufferStatus
1478 \brief the percentage of the temporary buffer filled before playback begins or resumes, from
1479 \c 0 (empty) to \c 100 (full).
1480
1481 When the player object is buffering; this property holds the percentage of
1482 the temporary buffer that is filled. The buffer will need to reach 100%
1483 filled before playback can start or resume, at which time mediaStatus() will return
1484 BufferedMedia or BufferingMedia. If the value is anything lower than \c 100, mediaStatus() will
1485 return StalledMedia.
1486
1487 \sa mediaStatus()
1488*/
1489
1490/*!
1491 \property QMediaPlayer::audioAvailable
1492 \brief the audio availabilty status for the current media.
1493
1494 As the life time of QMediaPlayer can be longer than the playback of one
1495 QMediaContent, this property may change over time, the
1496 audioAvailableChanged signal can be used to monitor it's status.
1497*/
1498
1499/*!
1500 \property QMediaPlayer::videoAvailable
1501 \brief the video availability status for the current media.
1502
1503 If available, the QVideoWidget class can be used to view the video. As the
1504 life time of QMediaPlayer can be longer than the playback of one
1505 QMediaContent, this property may change over time, the
1506 videoAvailableChanged signal can be used to monitor it's status.
1507
1508 \sa QVideoWidget, QMediaContent
1509*/
1510
1511/*!
1512 \property QMediaPlayer::seekable
1513 \brief the seek-able status of the current media
1514
1515 If seeking is supported this property will be true; false otherwise. The
1516 status of this property may change across the life time of the QMediaPlayer
1517 object, use the seekableChanged signal to monitor changes.
1518*/
1519
1520/*!
1521 \property QMediaPlayer::playbackRate
1522 \brief the playback rate of the current media.
1523
1524 This value is a multiplier applied to the media's standard play rate. By
1525 default this value is 1.0, indicating that the media is playing at the
1526 standard pace. Values higher than 1.0 will increase the rate of play.
1527 Values less than zero can be set and indicate the media will rewind at the
1528 multiplier of the standard pace.
1529
1530 Not all playback services support change of the playback rate. It is
1531 framework defined as to the status and quality of audio and video
1532 while fast forwarding or rewinding.
1533*/
1534
1535/*!
1536 \property QMediaPlayer::audioRole
1537 \brief the role of the audio stream played by the media player.
1538
1539 It can be set to specify the type of audio being played, allowing the system to make
1540 appropriate decisions when it comes to volume, routing or post-processing.
1541
1542 The audio role must be set before calling setMedia().
1543
1544 customAudioRole is cleared when this property is set to anything other than
1545 QAudio::CustomRole.
1546
1547 \since 5.6
1548 \sa supportedAudioRoles()
1549*/
1550
1551/*!
1552 \property QMediaPlayer::customAudioRole
1553 \brief the role of the audio stream played by the media player.
1554
1555 It can be set to specify the type of audio being played when the backend supports
1556 audio roles unknown to Qt. Specifying a role allows the system to make appropriate
1557 decisions when it comes to volume, routing or post-processing.
1558
1559 The audio role must be set before calling setMedia().
1560
1561 audioRole is set to QAudio::CustomRole when this property is set.
1562
1563 \since 5.11
1564 \sa supportedCustomAudioRoles()
1565*/
1566
1567/*!
1568 \fn void QMediaPlayer::durationChanged(qint64 duration)
1569
1570 Signal the duration of the content has changed to \a duration, expressed in milliseconds.
1571*/
1572
1573/*!
1574 \fn void QMediaPlayer::positionChanged(qint64 position)
1575
1576 Signal the position of the content has changed to \a position, expressed in
1577 milliseconds.
1578*/
1579
1580/*!
1581 \fn void QMediaPlayer::volumeChanged(int volume)
1582
1583 Signal the playback volume has changed to \a volume.
1584*/
1585
1586/*!
1587 \fn void QMediaPlayer::mutedChanged(bool muted)
1588
1589 Signal the mute state has changed to \a muted.
1590*/
1591
1592/*!
1593 \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable)
1594
1595 Signal the availability of visual content has changed to \a videoAvailable.
1596*/
1597
1598/*!
1599 \fn void QMediaPlayer::audioAvailableChanged(bool available)
1600
1601 Signals the availability of audio content has changed to \a available.
1602*/
1603
1604/*!
1605 \fn void QMediaPlayer::bufferStatusChanged(int percentFilled)
1606
1607 Signal the amount of the local buffer filled as a percentage by \a percentFilled.
1608*/
1609
1610/*!
1611 \fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration)
1612
1613 Signal that the active in use network access point has been changed to \a configuration and all subsequent network access will use this \a configuration.
1614*/
1615
1616/*!
1617 \enum QMediaPlayer::Flag
1618
1619 \value LowLatency The player is expected to be used with simple audio formats,
1620 but playback should start without significant delay.
1621 Such playback service can be used for beeps, ringtones, etc.
1622
1623 \value StreamPlayback The player is expected to play QIODevice based streams.
1624 If passed to QMediaPlayer constructor, the service supporting
1625 streams playback will be chosen.
1626
1627 \value VideoSurface The player is expected to be able to render to a
1628 QAbstractVideoSurface \l {setVideoOutput()}{output}.
1629*/
1630
1631#include "moc_qmediaplayer.cpp"
1632QT_END_NAMESPACE
1633
1634