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(nullptr)
113 , control(nullptr)
114 , audioRoleControl(nullptr)
115 , customAudioRoleControl(nullptr)
116 , playlist(nullptr)
117 , networkAccessControl(nullptr)
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 = nullptr);
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 nullptr;
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, nullptr);
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 = nullptr;
333 setMedia(QMediaContent(), nullptr);
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(), nullptr);
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())), nullptr);
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(), nullptr);
451 if (isSameMedia) {
452 emit q->currentMediaChanged(q->currentMedia());
453 }
454 }
455 } else {
456 setMedia(QMediaContent(), nullptr);
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(), nullptr);
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 == nullptr) {
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 != nullptr) {
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 != nullptr) {
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 // Disconnect everything to prevent notifying
652 // when a receiver is already destroyed.
653 disconnect();
654
655 if (d->service) {
656 if (d->control)
657 d->service->releaseControl(d->control);
658 if (d->audioRoleControl)
659 d->service->releaseControl(d->audioRoleControl);
660 if (d->customAudioRoleControl)
661 d->service->releaseControl(d->customAudioRoleControl);
662
663 d->provider->releaseService(d->service);
664 }
665}
666
667QMediaContent QMediaPlayer::media() const
668{
669 Q_D(const QMediaPlayer);
670
671 return d->rootMedia;
672}
673
674/*!
675 Returns the stream source of media data.
676
677 This is only valid if a stream was passed to setMedia().
678
679 \sa setMedia()
680*/
681
682const QIODevice *QMediaPlayer::mediaStream() const
683{
684 Q_D(const QMediaPlayer);
685
686 // When playing a resource file, we might have passed a QFile to the backend. Hide it from
687 // the user.
688 if (d->control && d->qrcMedia.isNull())
689 return d->control->mediaStream();
690
691 return nullptr;
692}
693
694QMediaPlaylist *QMediaPlayer::playlist() const
695{
696 Q_D(const QMediaPlayer);
697
698 return d->rootMedia.playlist();
699}
700
701QMediaContent QMediaPlayer::currentMedia() const
702{
703 Q_D(const QMediaPlayer);
704
705 // When playing a resource file, don't return the backend's current media, which
706 // can be a temporary file.
707 if (!d->qrcMedia.isNull())
708 return d->qrcMedia;
709
710 if (d->control)
711 return d->control->media();
712
713 return QMediaContent();
714}
715
716void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
717{
718 QMediaContent m(playlist, QUrl(), false);
719 setMedia(m);
720}
721
722/*!
723 Sets the network access points for remote media playback.
724 \a configurations contains, in ascending preferential order, a list of
725 configuration that can be used for network access.
726
727 This will invalidate the choice of previous configurations.
728*/
729void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations)
730{
731 Q_D(QMediaPlayer);
732
733 if (d->networkAccessControl)
734 d->networkAccessControl->setConfigurations(configurations);
735}
736
737QMediaPlayer::State QMediaPlayer::state() const
738{
739 Q_D(const QMediaPlayer);
740
741 // In case if EndOfMedia status is already received
742 // but state is not.
743 if (d->control != nullptr
744 && d->status == QMediaPlayer::EndOfMedia
745 && d->state != d->control->state()) {
746 return d->control->state();
747 }
748
749 return d->state;
750}
751
752QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const
753{
754 return d_func()->status;
755}
756
757qint64 QMediaPlayer::duration() const
758{
759 Q_D(const QMediaPlayer);
760
761 if (d->control != nullptr)
762 return d->control->duration();
763
764 return -1;
765}
766
767qint64 QMediaPlayer::position() const
768{
769 Q_D(const QMediaPlayer);
770
771 if (d->control != nullptr)
772 return d->control->position();
773
774 return 0;
775}
776
777int QMediaPlayer::volume() const
778{
779 Q_D(const QMediaPlayer);
780
781 if (d->control != nullptr)
782 return d->control->volume();
783
784 return 0;
785}
786
787bool QMediaPlayer::isMuted() const
788{
789 Q_D(const QMediaPlayer);
790
791 if (d->control != nullptr)
792 return d->control->isMuted();
793
794 return false;
795}
796
797int QMediaPlayer::bufferStatus() const
798{
799 Q_D(const QMediaPlayer);
800
801 if (d->control != nullptr)
802 return d->control->bufferStatus();
803
804 return 0;
805}
806
807bool QMediaPlayer::isAudioAvailable() const
808{
809 Q_D(const QMediaPlayer);
810
811 if (d->control != nullptr)
812 return d->control->isAudioAvailable();
813
814 return false;
815}
816
817bool QMediaPlayer::isVideoAvailable() const
818{
819 Q_D(const QMediaPlayer);
820
821 if (d->control != nullptr)
822 return d->control->isVideoAvailable();
823
824 return false;
825}
826
827bool QMediaPlayer::isSeekable() const
828{
829 Q_D(const QMediaPlayer);
830
831 if (d->control != nullptr)
832 return d->control->isSeekable();
833
834 return false;
835}
836
837qreal QMediaPlayer::playbackRate() const
838{
839 Q_D(const QMediaPlayer);
840
841 if (d->control != nullptr)
842 return d->control->playbackRate();
843
844 return 0.0;
845}
846
847/*!
848 Returns the current error state.
849*/
850
851QMediaPlayer::Error QMediaPlayer::error() const
852{
853 return d_func()->error;
854}
855
856QString QMediaPlayer::errorString() const
857{
858 return d_func()->errorString;
859}
860
861/*!
862 Returns the current network access point in use.
863 If a default contructed QNetworkConfiguration is returned
864 this feature is not available or that none of the
865 current supplied configurations are in use.
866*/
867QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const
868{
869 Q_D(const QMediaPlayer);
870
871 if (d->networkAccessControl)
872 return d_func()->networkAccessControl->currentConfiguration();
873
874 return QNetworkConfiguration();
875}
876
877//public Q_SLOTS:
878/*!
879 Start or resume playing the current source.
880*/
881
882void QMediaPlayer::play()
883{
884 Q_D(QMediaPlayer);
885
886 if (d->control == nullptr) {
887 QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection,
888 Q_ARG(int, QMediaPlayer::ServiceMissingError),
889 Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")));
890 return;
891 }
892
893 //if playlist control is available, the service should advance itself
894 if (d->rootMedia.playlist() && !d->rootMedia.playlist()->isEmpty()) {
895 // switch to playing state
896 if (d->state != QMediaPlayer::PlayingState)
897 d->_q_stateChanged(QMediaPlayer::PlayingState);
898
899 if (d->rootMedia.playlist()->currentIndex() == -1) {
900 if (d->playlist != d->rootMedia.playlist())
901 d->setPlaylist(d->rootMedia.playlist());
902 Q_ASSERT(d->playlist == d->rootMedia.playlist());
903
904 emit currentMediaChanged(d->rootMedia);
905 d->playlist->setCurrentIndex(0);
906 }
907 }
908
909 // Reset error conditions
910 d->error = NoError;
911 d->errorString = QString();
912
913 d->control->play();
914}
915
916/*!
917 Pause playing the current source.
918*/
919
920void QMediaPlayer::pause()
921{
922 Q_D(QMediaPlayer);
923
924 if (d->control != nullptr)
925 d->control->pause();
926}
927
928/*!
929 Stop playing, and reset the play position to the beginning.
930*/
931
932void QMediaPlayer::stop()
933{
934 Q_D(QMediaPlayer);
935
936 if (d->control != nullptr)
937 d->control->stop();
938
939 // If media player didn't stop in response to control.
940 // This happens if we have an active playlist and control
941 // media status is
942 // QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
943 // see QMediaPlayerPrivate::_q_stateChanged()
944 if (d->playlist && d->state != QMediaPlayer::StoppedState) {
945 d->state = QMediaPlayer::StoppedState;
946 removePropertyWatch("position");
947 emit stateChanged(QMediaPlayer::StoppedState);
948 }
949}
950
951void QMediaPlayer::setPosition(qint64 position)
952{
953 Q_D(QMediaPlayer);
954
955 if (d->control == nullptr)
956 return;
957
958 d->control->setPosition(qMax(position, 0ll));
959}
960
961void QMediaPlayer::setVolume(int v)
962{
963 Q_D(QMediaPlayer);
964
965 if (d->control == nullptr)
966 return;
967
968 int clamped = qBound(0, v, 100);
969 if (clamped == volume())
970 return;
971
972 d->control->setVolume(clamped);
973}
974
975void QMediaPlayer::setMuted(bool muted)
976{
977 Q_D(QMediaPlayer);
978
979 if (d->control == nullptr || muted == isMuted())
980 return;
981
982 d->control->setMuted(muted);
983}
984
985void QMediaPlayer::setPlaybackRate(qreal rate)
986{
987 Q_D(QMediaPlayer);
988
989 if (d->control != nullptr)
990 d->control->setPlaybackRate(rate);
991}
992
993/*!
994 Sets the current \a media source.
995
996 If a \a stream is supplied; media data will be read from it instead of resolving the media
997 source. In this case the media source may still be used to resolve additional information
998 about the media such as mime type. The \a stream must be open and readable.
999
1000 Setting the media to a null QMediaContent will cause the player to discard all
1001 information relating to the current media source and to cease all I/O operations related
1002 to that media.
1003
1004 \note This function returns immediately after recording the specified source of the media.
1005 It does not wait for the media to finish loading and does not check for errors. Listen for
1006 the mediaStatusChanged() and error() signals to be notified when the media is loaded and
1007 when an error occurs during loading.
1008*/
1009
1010void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
1011{
1012 Q_D(QMediaPlayer);
1013 stop();
1014
1015 QMediaContent oldMedia = d->rootMedia;
1016 d->disconnectPlaylist();
1017 d->playlist = nullptr;
1018 d->rootMedia = media;
1019 d->nestedPlaylists = 0;
1020
1021 if (oldMedia != media)
1022 emit mediaChanged(d->rootMedia);
1023
1024 if (media.playlist()) {
1025 // reset playlist to the 1st item
1026 media.playlist()->setCurrentIndex(0);
1027 d->setPlaylist(media.playlist());
1028 } else {
1029 d->setMedia(media, stream);
1030 }
1031}
1032
1033/*!
1034 \internal
1035*/
1036
1037bool QMediaPlayer::bind(QObject *obj)
1038{
1039 return QMediaObject::bind(obj);
1040}
1041
1042/*!
1043 \internal
1044*/
1045
1046void QMediaPlayer::unbind(QObject *obj)
1047{
1048 QMediaObject::unbind(obj);
1049}
1050
1051/*!
1052 Returns the level of support a media player has for a \a mimeType and a set of \a codecs.
1053
1054 The \a flags argument allows additional requirements such as performance indicators to be
1055 specified.
1056*/
1057QMultimedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType,
1058 const QStringList& codecs,
1059 Flags flags)
1060{
1061 return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1062 mimeType,
1063 codecs,
1064 flags);
1065}
1066
1067/*!
1068 \deprecated
1069 Returns a list of MIME types supported by the media player.
1070
1071 The \a flags argument causes the resultant list to be restricted to MIME types which can be supported
1072 given additional requirements, such as performance indicators.
1073
1074 This function may not return useful results on some platforms, and support for a specific file of a
1075 given mime type is not guaranteed even if the mime type is in general supported. In addition, in some
1076 cases this function will need to load all available media plugins and query them for their support, which
1077 may take some time.
1078*/
1079QStringList QMediaPlayer::supportedMimeTypes(Flags flags)
1080{
1081 return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER),
1082 flags);
1083}
1084
1085/*!
1086 \fn void QMediaPlayer::setVideoOutput(QVideoWidget* output)
1087
1088 Attach a QVideoWidget video \a output to the media player.
1089
1090 If the media player has already video output attached,
1091 it will be replaced with a new one.
1092*/
1093void QMediaPlayer::setVideoOutput(QVideoWidget *output)
1094{
1095 Q_D(QMediaPlayer);
1096
1097 if (d->videoOutput)
1098 unbind(d->videoOutput);
1099
1100 // We don't know (in this library) that QVideoWidget inherits QObject
1101 QObject *outputObject = reinterpret_cast<QObject*>(output);
1102
1103 d->videoOutput = outputObject && bind(outputObject) ? outputObject : nullptr;
1104}
1105
1106/*!
1107 \fn void QMediaPlayer::setVideoOutput(QGraphicsVideoItem* output)
1108
1109 Attach a QGraphicsVideoItem video \a output to the media player.
1110
1111 If the media player has already video output attached,
1112 it will be replaced with a new one.
1113*/
1114void QMediaPlayer::setVideoOutput(QGraphicsVideoItem *output)
1115{
1116 Q_D(QMediaPlayer);
1117
1118 if (d->videoOutput)
1119 unbind(d->videoOutput);
1120
1121 // We don't know (in this library) that QGraphicsVideoItem (multiply) inherits QObject
1122 // but QObject inheritance depends on QObject coming first, so try this out.
1123 QObject *outputObject = reinterpret_cast<QObject*>(output);
1124
1125 d->videoOutput = outputObject && bind(outputObject) ? outputObject : nullptr;
1126}
1127
1128/*!
1129 Sets a video \a surface as the video output of a media player.
1130
1131 If a video output has already been set on the media player the new surface
1132 will replace it.
1133*/
1134
1135void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
1136{
1137 Q_D(QMediaPlayer);
1138
1139 d->surfaceOutput.setVideoSurface(surface);
1140
1141 if (d->videoOutput != &d->surfaceOutput) {
1142 if (d->videoOutput)
1143 unbind(d->videoOutput);
1144
1145 d->videoOutput = nullptr;
1146
1147 if (surface && bind(&d->surfaceOutput))
1148 d->videoOutput = &d->surfaceOutput;
1149 } else if (!surface) {
1150 //unbind the surfaceOutput if null surface is set
1151 unbind(&d->surfaceOutput);
1152 d->videoOutput = nullptr;
1153 }
1154}
1155
1156/*! \reimp */
1157QMultimedia::AvailabilityStatus QMediaPlayer::availability() const
1158{
1159 Q_D(const QMediaPlayer);
1160
1161 if (!d->control)
1162 return QMultimedia::ServiceMissing;
1163
1164 return QMediaObject::availability();
1165}
1166
1167QAudio::Role QMediaPlayer::audioRole() const
1168{
1169 Q_D(const QMediaPlayer);
1170
1171 if (d->audioRoleControl != nullptr)
1172 return d->audioRoleControl->audioRole();
1173
1174 return QAudio::UnknownRole;
1175}
1176
1177void QMediaPlayer::setAudioRole(QAudio::Role audioRole)
1178{
1179 Q_D(QMediaPlayer);
1180
1181 if (d->audioRoleControl) {
1182 if (d->customAudioRoleControl != nullptr && d->audioRoleControl->audioRole() != audioRole) {
1183 d->customAudioRoleControl->setCustomAudioRole(QString());
1184 }
1185
1186 d->audioRoleControl->setAudioRole(audioRole);
1187 }
1188}
1189
1190/*!
1191 Returns a list of supported audio roles.
1192
1193 If setting the audio role is not supported, an empty list is returned.
1194
1195 \since 5.6
1196 \sa audioRole
1197*/
1198QList<QAudio::Role> QMediaPlayer::supportedAudioRoles() const
1199{
1200 Q_D(const QMediaPlayer);
1201
1202 if (d->audioRoleControl)
1203 return d->audioRoleControl->supportedAudioRoles();
1204
1205 return QList<QAudio::Role>();
1206}
1207
1208QString QMediaPlayer::customAudioRole() const
1209{
1210 Q_D(const QMediaPlayer);
1211
1212 if (audioRole() != QAudio::CustomRole)
1213 return QString();
1214
1215 if (d->customAudioRoleControl != nullptr)
1216 return d->customAudioRoleControl->customAudioRole();
1217
1218 return QString();
1219}
1220
1221void QMediaPlayer::setCustomAudioRole(const QString &audioRole)
1222{
1223 Q_D(QMediaPlayer);
1224
1225 if (d->customAudioRoleControl) {
1226 Q_ASSERT(d->audioRoleControl);
1227 setAudioRole(QAudio::CustomRole);
1228 d->customAudioRoleControl->setCustomAudioRole(audioRole);
1229 }
1230}
1231
1232/*!
1233 Returns a list of supported custom audio roles. An empty list may
1234 indicate that the supported custom audio roles aren't known. The
1235 list may not be complete.
1236
1237 \since 5.11
1238 \sa customAudioRole
1239*/
1240QStringList QMediaPlayer::supportedCustomAudioRoles() const
1241{
1242 Q_D(const QMediaPlayer);
1243
1244 if (d->customAudioRoleControl)
1245 return d->customAudioRoleControl->supportedCustomAudioRoles();
1246
1247 return QStringList();
1248}
1249
1250// Enums
1251/*!
1252 \enum QMediaPlayer::State
1253
1254 Defines the current state of a media player.
1255
1256 \value StoppedState The media player is not playing content, playback will begin from the start
1257 of the current track.
1258 \value PlayingState The media player is currently playing content.
1259 \value PausedState The media player has paused playback, playback of the current track will
1260 resume from the position the player was paused at.
1261*/
1262
1263/*!
1264 \enum QMediaPlayer::MediaStatus
1265
1266 Defines the status of a media player's current media.
1267
1268 \value UnknownMediaStatus The status of the media cannot be determined.
1269 \value NoMedia The is no current media. The player is in the StoppedState.
1270 \value LoadingMedia The current media is being loaded. The player may be in any state.
1271 \value LoadedMedia The current media has been loaded. The player is in the StoppedState.
1272 \value StalledMedia Playback of the current media has stalled due to insufficient buffering or
1273 some other temporary interruption. The player is in the PlayingState or PausedState.
1274 \value BufferingMedia The player is buffering data but has enough data buffered for playback to
1275 continue for the immediate future. The player is in the PlayingState or PausedState.
1276 \value BufferedMedia The player has fully buffered the current media. The player is in the
1277 PlayingState or PausedState.
1278 \value EndOfMedia Playback has reached the end of the current media. The player is in the
1279 StoppedState.
1280 \value InvalidMedia The current media cannot be played. The player is in the StoppedState.
1281*/
1282
1283/*!
1284 \enum QMediaPlayer::Error
1285
1286 Defines a media player error condition.
1287
1288 \value NoError No error has occurred.
1289 \value ResourceError A media resource couldn't be resolved.
1290 \value FormatError The format of a media resource isn't (fully) supported. Playback may still
1291 be possible, but without an audio or video component.
1292 \value NetworkError A network error occurred.
1293 \value AccessDeniedError There are not the appropriate permissions to play a media resource.
1294 \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
1295 \omitvalue MediaIsPlaylist
1296*/
1297
1298// Signals
1299/*!
1300 \fn QMediaPlayer::error(QMediaPlayer::Error error)
1301
1302 Signals that an \a error condition has occurred.
1303
1304 \sa errorString()
1305*/
1306
1307/*!
1308 \fn void QMediaPlayer::stateChanged(State state)
1309
1310 Signal the \a state of the Player object has changed.
1311*/
1312
1313/*!
1314 \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status)
1315
1316 Signals that the \a status of the current media has changed.
1317
1318 \sa mediaStatus()
1319*/
1320
1321/*!
1322 \fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
1323
1324 Signals that the media source has been changed to \a media.
1325
1326 \sa media(), currentMediaChanged()
1327*/
1328
1329/*!
1330 \fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
1331
1332 Signals that the current playing content has been changed to \a media.
1333
1334 \sa currentMedia(), mediaChanged()
1335*/
1336
1337/*!
1338 \fn void QMediaPlayer::playbackRateChanged(qreal rate);
1339
1340 Signals the playbackRate has changed to \a rate.
1341*/
1342
1343/*!
1344 \fn void QMediaPlayer::seekableChanged(bool seekable);
1345
1346 Signals the \a seekable status of the player object has changed.
1347*/
1348
1349/*!
1350 \fn void QMediaPlayer::audioRoleChanged(QAudio::Role role)
1351
1352 Signals that the audio \a role of the media player has changed.
1353
1354 \since 5.6
1355*/
1356
1357/*!
1358 \fn void QMediaPlayer::customAudioRoleChanged(const QString &role)
1359
1360 Signals that the audio \a role of the media player has changed.
1361
1362 \since 5.11
1363*/
1364
1365// Properties
1366/*!
1367 \property QMediaPlayer::state
1368 \brief the media player's playback state.
1369
1370 By default this property is QMediaPlayer::Stopped
1371
1372 \sa mediaStatus(), play(), pause(), stop()
1373*/
1374
1375/*!
1376 \property QMediaPlayer::error
1377 \brief a string describing the last error condition.
1378
1379 \sa error()
1380*/
1381
1382/*!
1383 \property QMediaPlayer::media
1384 \brief the active media source being used by the player object.
1385
1386 The player object will use the QMediaContent for selection of the content to
1387 be played.
1388
1389 By default this property has a null QMediaContent.
1390
1391 Setting this property to a null QMediaContent will cause the player to discard all
1392 information relating to the current media source and to cease all I/O operations related
1393 to that media.
1394
1395 \sa QMediaContent, currentMedia()
1396*/
1397
1398/*!
1399 \property QMediaPlayer::currentMedia
1400 \brief the current active media content being played by the player object.
1401 This value could be different from QMediaPlayer::media property if a playlist is used.
1402 In this case currentMedia indicates the current media content being processed
1403 by the player, while QMediaPlayer::media property contains the original playlist.
1404
1405 \sa QMediaContent, media()
1406*/
1407
1408/*!
1409 \property QMediaPlayer::playlist
1410 \brief the media playlist being used by the player object.
1411
1412 The player object will use the current playlist item for selection of the content to
1413 be played.
1414
1415 By default this property is set to null.
1416
1417 If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
1418 a current playlist item. The current source should be selected with
1419 QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
1420 otherwise the current playlist will be discarded.
1421
1422 \sa QMediaContent
1423*/
1424
1425
1426/*!
1427 \property QMediaPlayer::mediaStatus
1428 \brief the status of the current media stream.
1429
1430 The stream status describes how the playback of the current stream is
1431 progressing.
1432
1433 By default this property is QMediaPlayer::NoMedia
1434
1435 \sa state
1436*/
1437
1438/*!
1439 \property QMediaPlayer::duration
1440 \brief the duration of the current media.
1441
1442 The value is the total playback time in milliseconds of the current media.
1443 The value may change across the life time of the QMediaPlayer object and
1444 may not be available when initial playback begins, connect to the
1445 durationChanged() signal to receive status notifications.
1446*/
1447
1448/*!
1449 \property QMediaPlayer::position
1450 \brief the playback position of the current media.
1451
1452 The value is the current playback position, expressed in milliseconds since
1453 the beginning of the media. Periodically changes in the position will be
1454 indicated with the signal positionChanged(), the interval between updates
1455 can be set with QMediaObject's method setNotifyInterval().
1456*/
1457
1458/*!
1459 \property QMediaPlayer::volume
1460 \brief the current playback volume.
1461
1462 The playback volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume).
1463 Values outside this range will be clamped.
1464
1465 By default the volume is \c 100.
1466
1467 UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale
1468 will produce linear changes in perceived loudness, which is what a user would normally expect
1469 from a volume control. See QAudio::convertVolume() for more details.
1470*/
1471
1472/*!
1473 \property QMediaPlayer::muted
1474 \brief the muted state of the current media.
1475
1476 The value will be true if the playback volume is muted; otherwise false.
1477*/
1478
1479/*!
1480 \property QMediaPlayer::bufferStatus
1481 \brief the percentage of the temporary buffer filled before playback begins or resumes, from
1482 \c 0 (empty) to \c 100 (full).
1483
1484 When the player object is buffering; this property holds the percentage of
1485 the temporary buffer that is filled. The buffer will need to reach 100%
1486 filled before playback can start or resume, at which time mediaStatus() will return
1487 BufferedMedia or BufferingMedia. If the value is anything lower than \c 100, mediaStatus() will
1488 return StalledMedia.
1489
1490 \sa mediaStatus()
1491*/
1492
1493/*!
1494 \property QMediaPlayer::audioAvailable
1495 \brief the audio availabilty status for the current media.
1496
1497 As the life time of QMediaPlayer can be longer than the playback of one
1498 QMediaContent, this property may change over time, the
1499 audioAvailableChanged signal can be used to monitor it's status.
1500*/
1501
1502/*!
1503 \property QMediaPlayer::videoAvailable
1504 \brief the video availability status for the current media.
1505
1506 If available, the QVideoWidget class can be used to view the video. As the
1507 life time of QMediaPlayer can be longer than the playback of one
1508 QMediaContent, this property may change over time, the
1509 videoAvailableChanged signal can be used to monitor it's status.
1510
1511 \sa QVideoWidget, QMediaContent
1512*/
1513
1514/*!
1515 \property QMediaPlayer::seekable
1516 \brief the seek-able status of the current media
1517
1518 If seeking is supported this property will be true; false otherwise. The
1519 status of this property may change across the life time of the QMediaPlayer
1520 object, use the seekableChanged signal to monitor changes.
1521*/
1522
1523/*!
1524 \property QMediaPlayer::playbackRate
1525 \brief the playback rate of the current media.
1526
1527 This value is a multiplier applied to the media's standard play rate. By
1528 default this value is 1.0, indicating that the media is playing at the
1529 standard pace. Values higher than 1.0 will increase the rate of play.
1530 Values less than zero can be set and indicate the media will rewind at the
1531 multiplier of the standard pace.
1532
1533 Not all playback services support change of the playback rate. It is
1534 framework defined as to the status and quality of audio and video
1535 while fast forwarding or rewinding.
1536*/
1537
1538/*!
1539 \property QMediaPlayer::audioRole
1540 \brief the role of the audio stream played by the media player.
1541
1542 It can be set to specify the type of audio being played, allowing the system to make
1543 appropriate decisions when it comes to volume, routing or post-processing.
1544
1545 The audio role must be set before calling setMedia().
1546
1547 customAudioRole is cleared when this property is set to anything other than
1548 QAudio::CustomRole.
1549
1550 \since 5.6
1551 \sa supportedAudioRoles()
1552*/
1553
1554/*!
1555 \property QMediaPlayer::customAudioRole
1556 \brief the role of the audio stream played by the media player.
1557
1558 It can be set to specify the type of audio being played when the backend supports
1559 audio roles unknown to Qt. Specifying a role allows the system to make appropriate
1560 decisions when it comes to volume, routing or post-processing.
1561
1562 The audio role must be set before calling setMedia().
1563
1564 audioRole is set to QAudio::CustomRole when this property is set.
1565
1566 \since 5.11
1567 \sa supportedCustomAudioRoles()
1568*/
1569
1570/*!
1571 \fn void QMediaPlayer::durationChanged(qint64 duration)
1572
1573 Signal the duration of the content has changed to \a duration, expressed in milliseconds.
1574*/
1575
1576/*!
1577 \fn void QMediaPlayer::positionChanged(qint64 position)
1578
1579 Signal the position of the content has changed to \a position, expressed in
1580 milliseconds.
1581*/
1582
1583/*!
1584 \fn void QMediaPlayer::volumeChanged(int volume)
1585
1586 Signal the playback volume has changed to \a volume.
1587*/
1588
1589/*!
1590 \fn void QMediaPlayer::mutedChanged(bool muted)
1591
1592 Signal the mute state has changed to \a muted.
1593*/
1594
1595/*!
1596 \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable)
1597
1598 Signal the availability of visual content has changed to \a videoAvailable.
1599*/
1600
1601/*!
1602 \fn void QMediaPlayer::audioAvailableChanged(bool available)
1603
1604 Signals the availability of audio content has changed to \a available.
1605*/
1606
1607/*!
1608 \fn void QMediaPlayer::bufferStatusChanged(int percentFilled)
1609
1610 Signal the amount of the local buffer filled as a percentage by \a percentFilled.
1611*/
1612
1613/*!
1614 \fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration)
1615
1616 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.
1617*/
1618
1619/*!
1620 \enum QMediaPlayer::Flag
1621
1622 \value LowLatency The player is expected to be used with simple audio formats,
1623 but playback should start without significant delay.
1624 Such playback service can be used for beeps, ringtones, etc.
1625
1626 \value StreamPlayback The player is expected to play QIODevice based streams.
1627 If passed to QMediaPlayer constructor, the service supporting
1628 streams playback will be chosen.
1629
1630 \value VideoSurface The player is expected to be able to render to a
1631 QAbstractVideoSurface \l {setVideoOutput()}{output}.
1632*/
1633
1634#include "moc_qmediaplayer.cpp"
1635QT_END_NAMESPACE
1636
1637