QMediaPlayer frontend: changes to playlist support.

Allow to load playlists using setMedia().
Use QNetworkMediaPlaylistProvider for playlist parsing.
Updated unit tests.

Change-Id: If4dba07be8b2e8a9e9549d5bed58e552dfb958b7
Reviewed-by: Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
This commit is contained in:
Lev Zelenskiy
2012-03-09 09:53:21 +10:00
committed by Qt by Nokia
parent 2ebea05283
commit 2c034beab5
9 changed files with 407 additions and 443 deletions

View File

@@ -11,16 +11,18 @@ PRIVATE_HEADERS += \
playback/qmediaplaylist_p.h \ playback/qmediaplaylist_p.h \
playback/qmediaplaylistprovider_p.h \ playback/qmediaplaylistprovider_p.h \
playback/qmediaplaylistioplugin_p.h \ playback/qmediaplaylistioplugin_p.h \
playback/qlocalmediaplaylistprovider_p.h \ playback/qmediaplaylistnavigator_p.h \
playback/qmediaplaylistnavigator_p.h playback/qmedianetworkplaylistprovider_p.h \
playback/playlistfileparser_p.h
SOURCES += \ SOURCES += \
playback/qaudioendpointselector.cpp \ playback/qaudioendpointselector.cpp \
playback/qlocalmediaplaylistprovider.cpp \ playback/qmedianetworkplaylistprovider.cpp \
playback/qmediacontent.cpp \ playback/qmediacontent.cpp \
playback/qmediaplayer.cpp \ playback/qmediaplayer.cpp \
playback/qmediaplaylist.cpp \ playback/qmediaplaylist.cpp \
playback/qmediaplaylistioplugin.cpp \ playback/qmediaplaylistioplugin.cpp \
playback/qmediaplaylistnavigator.cpp \ playback/qmediaplaylistnavigator.cpp \
playback/qmediaplaylistprovider.cpp \ playback/qmediaplaylistprovider.cpp \
playback/qmediaresource.cpp playback/qmediaresource.cpp \
playback/playlistfileparser.cpp

View File

@@ -1,194 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qlocalmediaplaylistprovider_p.h"
#include "qmediaplaylistprovider_p.h"
#include "qmediacontent.h"
QT_BEGIN_NAMESPACE
class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate
{
public:
QList<QMediaContent> resources;
};
QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent)
:QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent)
{
}
QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider()
{
}
bool QLocalMediaPlaylistProvider::isReadOnly() const
{
return false;
}
int QLocalMediaPlaylistProvider::mediaCount() const
{
return d_func()->resources.size();
}
QMediaContent QLocalMediaPlaylistProvider::media(int pos) const
{
return d_func()->resources.value(pos);
}
bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content)
{
Q_D(QLocalMediaPlaylistProvider);
int pos = d->resources.count();
emit mediaAboutToBeInserted(pos, pos);
d->resources.append(content);
emit mediaInserted(pos, pos);
return true;
}
bool QLocalMediaPlaylistProvider::addMedia(const QList<QMediaContent> &items)
{
Q_D(QLocalMediaPlaylistProvider);
if (items.isEmpty())
return true;
int pos = d->resources.count();
int end = pos+items.count()-1;
emit mediaAboutToBeInserted(pos, end);
d->resources.append(items);
emit mediaInserted(pos, end);
return true;
}
bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content)
{
Q_D(QLocalMediaPlaylistProvider);
emit mediaAboutToBeInserted(pos, pos);
d->resources.insert(pos, content);
emit mediaInserted(pos,pos);
return true;
}
bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList<QMediaContent> &items)
{
Q_D(QLocalMediaPlaylistProvider);
if (items.isEmpty())
return true;
const int last = pos+items.count()-1;
emit mediaAboutToBeInserted(pos, last);
for (int i=0; i<items.count(); i++)
d->resources.insert(pos+i, items.at(i));
emit mediaInserted(pos, last);
return true;
}
bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos)
{
Q_D(QLocalMediaPlaylistProvider);
Q_ASSERT(fromPos >= 0);
Q_ASSERT(fromPos <= toPos);
Q_ASSERT(toPos < mediaCount());
emit mediaAboutToBeRemoved(fromPos, toPos);
d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1);
emit mediaRemoved(fromPos, toPos);
return true;
}
bool QLocalMediaPlaylistProvider::removeMedia(int pos)
{
Q_D(QLocalMediaPlaylistProvider);
emit mediaAboutToBeRemoved(pos, pos);
d->resources.removeAt(pos);
emit mediaRemoved(pos, pos);
return true;
}
bool QLocalMediaPlaylistProvider::clear()
{
Q_D(QLocalMediaPlaylistProvider);
if (!d->resources.isEmpty()) {
int lastPos = mediaCount()-1;
emit mediaAboutToBeRemoved(0, lastPos);
d->resources.clear();
emit mediaRemoved(0, lastPos);
}
return true;
}
void QLocalMediaPlaylistProvider::shuffle()
{
Q_D(QLocalMediaPlaylistProvider);
if (!d->resources.isEmpty()) {
QList<QMediaContent> resources;
while (!d->resources.isEmpty()) {
resources.append(d->resources.takeAt(qrand() % d->resources.size()));
}
d->resources = resources;
emit mediaChanged(0, mediaCount()-1);
}
}
#include "moc_qlocalmediaplaylistprovider_p.cpp"
QT_END_NAMESPACE

View File

@@ -1,98 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QLOCALMEDIAPAYLISTPROVIDER_P_H
#define QLOCALMEDIAPAYLISTPROVIDER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qmediaplaylistprovider_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Multimedia)
class QLocalMediaPlaylistProviderPrivate;
class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider
{
Q_OBJECT
public:
QLocalMediaPlaylistProvider(QObject *parent=0);
virtual ~QLocalMediaPlaylistProvider();
virtual int mediaCount() const;
virtual QMediaContent media(int pos) const;
virtual bool isReadOnly() const;
virtual bool addMedia(const QMediaContent &content);
virtual bool addMedia(const QList<QMediaContent> &items);
virtual bool insertMedia(int pos, const QMediaContent &content);
virtual bool insertMedia(int pos, const QList<QMediaContent> &items);
virtual bool removeMedia(int pos);
virtual bool removeMedia(int start, int end);
virtual bool clear();
public Q_SLOTS:
virtual void shuffle();
private:
Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider)
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QLOCALMEDIAPAYLISTSOURCE_P_H

View File

@@ -49,7 +49,6 @@
#include <qmediaplaylist.h> #include <qmediaplaylist.h>
#include <qmediaplaylistcontrol_p.h> #include <qmediaplaylistcontrol_p.h>
#include <qmediaplaylistsourcecontrol_p.h> #include <qmediaplaylistsourcecontrol_p.h>
#include <qmedianetworkaccesscontrol.h> #include <qmedianetworkaccesscontrol.h>
#include <QtCore/qcoreevent.h> #include <QtCore/qcoreevent.h>
@@ -97,6 +96,8 @@ public:
} _registerPlayerMetaTypes; } _registerPlayerMetaTypes;
} }
#define MAX_NESTED_PLAYLISTS 16
class QMediaPlayerPrivate : public QMediaObjectPrivate class QMediaPlayerPrivate : public QMediaObjectPrivate
{ {
Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer) Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer)
@@ -105,47 +106,86 @@ public:
QMediaPlayerPrivate() QMediaPlayerPrivate()
: provider(0) : provider(0)
, control(0) , control(0)
, playlistSourceControl(0)
, state(QMediaPlayer::StoppedState) , state(QMediaPlayer::StoppedState)
, error(QMediaPlayer::NoError) , error(QMediaPlayer::NoError)
, filterStates(false)
, playlist(0) , playlist(0)
, networkAccessControl(0) , networkAccessControl(0)
, nestedPlaylists(0)
{} {}
QMediaServiceProvider *provider; QMediaServiceProvider *provider;
QMediaPlayerControl* control; QMediaPlayerControl* control;
QMediaPlaylistSourceControl* playlistSourceControl;
QMediaPlayer::State state; QMediaPlayer::State state;
QMediaPlayer::Error error; QMediaPlayer::Error error;
QString errorString; QString errorString;
bool filterStates;
QPointer<QObject> videoOutput; QPointer<QObject> videoOutput;
QMediaPlaylist *playlist; QMediaPlaylist *playlist;
QMediaNetworkAccessControl *networkAccessControl; QMediaNetworkAccessControl *networkAccessControl;
QVideoSurfaceOutput surfaceOutput; QVideoSurfaceOutput surfaceOutput;
QMediaContent rootMedia;
QMediaContent pendingPlaylist;
QMediaPlaylist *parentPlaylist(QMediaPlaylist *pls);
bool isInChain(QUrl url);
int nestedPlaylists;
void setPlaylist(QMediaPlaylist *playlist);
void setPlaylistMedia();
void loadPlaylist();
void disconnectPlaylist();
void connectPlaylist();
void _q_stateChanged(QMediaPlayer::State state); void _q_stateChanged(QMediaPlayer::State state);
void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status);
void _q_error(int error, const QString &errorString); void _q_error(int error, const QString &errorString);
void _q_updateMedia(const QMediaContent&); void _q_updateMedia(const QMediaContent&);
void _q_playlistDestroyed(); void _q_playlistDestroyed();
void _q_handlePlaylistLoaded();
void _q_handlePlaylistLoadFailed();
}; };
QMediaPlaylist *QMediaPlayerPrivate::parentPlaylist(QMediaPlaylist *pls)
{
// This function finds a parent playlist for an item in the active chain of playlists.
// Every item in the chain comes from currentMedia() of its parent.
// We don't need to travers the whole tree of playlists,
// but only the subtree of active ones.
for (QMediaPlaylist *current = rootMedia.playlist(); current && current != pls; current = current->currentMedia().playlist())
if (current->currentMedia().playlist() == pls)
return current;
return 0;
}
bool QMediaPlayerPrivate::isInChain(QUrl url)
{
// Check whether a URL is already in the chain of playlists.
// Also see a comment in parentPlaylist().
for (QMediaPlaylist *current = rootMedia.playlist(); current && current != playlist; current = current->currentMedia().playlist())
if (current->currentMedia().canonicalUrl() == url) {
return true;
}
return false;
}
void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps)
{ {
Q_Q(QMediaPlayer); Q_Q(QMediaPlayer);
if (filterStates) // Backend switches into stopped state every time new media is about to be loaded.
return; // If media player has a playlist loaded make sure player doesn' stop.
if (playlist && playlist->currentIndex() != -1 && ps != state && ps == QMediaPlayer::StoppedState) {
if (playlist if (control->mediaStatus() == QMediaPlayer::EndOfMedia ||
&& ps != state && ps == QMediaPlayer::StoppedState control->mediaStatus() == QMediaPlayer::InvalidMedia) {
&& (control->mediaStatus() == QMediaPlayer::EndOfMedia || // if media player is not stopped, and
control->mediaStatus() == QMediaPlayer::InvalidMedia)) { // we have finished playback for the current media,
playlist->next(); // advance to the next item in the playlist
ps = control->state(); Q_ASSERT(state != QMediaPlayer::StoppedState);
playlist->next();
return;
} else if (control->mediaStatus() == QMediaPlayer::LoadingMedia) {
return;
}
} }
if (ps != state) { if (ps != state) {
@@ -182,10 +222,16 @@ void QMediaPlayerPrivate::_q_error(int error, const QString &errorString)
{ {
Q_Q(QMediaPlayer); Q_Q(QMediaPlayer);
this->error = QMediaPlayer::Error(error); if (error == int(QMediaPlayer::MediaIsPlaylist)) {
this->errorString = errorString; loadPlaylist();
} else {
this->error = QMediaPlayer::Error(error);
this->errorString = errorString;
emit q->error(this->error);
emit q->error(this->error); if (playlist)
playlist->next();
}
} }
void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
@@ -195,9 +241,45 @@ void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
if (!control) if (!control)
return; return;
// check if the current playlist is a top-level playlist
Q_ASSERT(playlist);
if (media.isNull() && playlist != rootMedia.playlist()) {
// switch back to parent playlist
QMediaPlaylist *pls = parentPlaylist(playlist);
Q_ASSERT(pls);
disconnectPlaylist();
playlist = pls;
connectPlaylist();
Q_ASSERT(!pendingPlaylist.playlist());
nestedPlaylists--;
Q_ASSERT(nestedPlaylists >= 0);
playlist->next();
return;
}
if (media.playlist()) {
if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
nestedPlaylists++;
Q_ASSERT(!pendingPlaylist.playlist());
// disconnect current playlist
disconnectPlaylist();
// new playlist signals are connected
// in the call to setPlaylist() in _q_handlePlaylistLoaded()
playlist = media.playlist();
emit q->currentMediaChanged(media);
_q_handlePlaylistLoaded();
return;
} else if (playlist) {
playlist->next();
}
return;
}
const QMediaPlayer::State currentState = state; const QMediaPlayer::State currentState = state;
filterStates = true;
control->setMedia(media, 0); control->setMedia(media, 0);
if (!media.isNull()) { if (!media.isNull()) {
@@ -212,18 +294,8 @@ void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media)
break; break;
} }
} }
filterStates = false;
state = control->state(); _q_stateChanged(control->state());
if (state != currentState) {
if (state == QMediaPlayer::PlayingState)
q->addPropertyWatch("position");
else
q->removePropertyWatch("position");
emit q->stateChanged(state);
}
} }
void QMediaPlayerPrivate::_q_playlistDestroyed() void QMediaPlayerPrivate::_q_playlistDestroyed()
@@ -233,12 +305,151 @@ void QMediaPlayerPrivate::_q_playlistDestroyed()
if (!control) if (!control)
return; return;
if (playlistSourceControl)
playlistSourceControl->setPlaylist(0);
control->setMedia(QMediaContent(), 0); control->setMedia(QMediaContent(), 0);
} }
void QMediaPlayerPrivate::setPlaylist(QMediaPlaylist *pls)
{
disconnectPlaylist();
playlist = pls;
setPlaylistMedia();
}
void QMediaPlayerPrivate::setPlaylistMedia()
{
// This function loads current playlist media into backend.
// If current media is a playlist, the function recursively
// loads media from the playlist.
// It also makes sure the correct playlist signals are connected.
Q_Q(QMediaPlayer);
if (playlist) {
connectPlaylist();
if (playlist->currentMedia().playlist()) {
if (nestedPlaylists < MAX_NESTED_PLAYLISTS) {
emit q->currentMediaChanged(playlist->currentMedia());
// rewind nested playlist to start
playlist->currentMedia().playlist()->setCurrentIndex(0);
nestedPlaylists++;
setPlaylist(playlist->currentMedia().playlist());
} else {
playlist->next();
}
return;
} else if (control != 0) {
// If we've just switched to a new playlist,
// then last emited currentMediaChanged was a playlist.
// Make sure we emit currentMediaChanged if new playlist has
// the same media as the previous one:
// sample.m3u
// test.wav -- processed by backend
// nested.m3u -- processed by frontend
// test.wav -- processed by backend,
// media is not changed,
// frontend needs to emit currentMediaChanged
bool isSameMedia = (control->media() == playlist->currentMedia());
control->setMedia(playlist->currentMedia(), 0);
if (isSameMedia) {
emit q->currentMediaChanged(control->media());
}
}
} else {
q->setMedia(QMediaContent(), 0);
}
}
void QMediaPlayerPrivate::loadPlaylist()
{
Q_Q(QMediaPlayer);
Q_ASSERT(pendingPlaylist.isNull());
// Do not load a playlist if there are more than MAX_NESTED_PLAYLISTS in the chain already,
// or if the playlist URL is already in the chain, i.e. do not allow recursive playlists and loops.
if (nestedPlaylists < MAX_NESTED_PLAYLISTS && !q->currentMedia().canonicalUrl().isEmpty() && !isInChain(q->currentMedia().canonicalUrl())) {
pendingPlaylist = QMediaContent(new QMediaPlaylist, q->currentMedia().canonicalUrl(), true);
QObject::connect(pendingPlaylist.playlist(), SIGNAL(loaded()), q, SLOT(_q_handlePlaylistLoaded()));
QObject::connect(pendingPlaylist.playlist(), SIGNAL(loadFailed()), q, SLOT(_q_handlePlaylistLoadFailed()));
pendingPlaylist.playlist()->load(pendingPlaylist.canonicalUrl());
} else if (playlist) {
playlist->next();
}
}
void QMediaPlayerPrivate::disconnectPlaylist()
{
Q_Q(QMediaPlayer);
if (playlist) {
QObject::disconnect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
q, SLOT(_q_updateMedia(QMediaContent)));
QObject::disconnect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
}
}
void QMediaPlayerPrivate::connectPlaylist()
{
Q_Q(QMediaPlayer);
if (playlist) {
QObject::connect(playlist, SIGNAL(currentMediaChanged(QMediaContent)),
q, SLOT(_q_updateMedia(QMediaContent)));
QObject::connect(playlist, SIGNAL(destroyed()), q, SLOT(_q_playlistDestroyed()));
}
}
void QMediaPlayerPrivate::_q_handlePlaylistLoaded()
{
Q_Q(QMediaPlayer);
QMediaPlaylist *oldPlaylist = 0;
if (pendingPlaylist.playlist()) {
Q_ASSERT(!q->currentMedia().playlist());
// if there is an active playlist
if (playlist) {
Q_ASSERT(playlist->currentIndex() >= 0);
oldPlaylist = playlist;
disconnectPlaylist();
playlist->insertMedia(playlist->currentIndex() + 1, pendingPlaylist);
playlist->removeMedia(playlist->currentIndex());
nestedPlaylists++;
} else {
Q_ASSERT(!rootMedia.playlist());
rootMedia = pendingPlaylist;
emit q->mediaChanged(rootMedia);
}
playlist = pendingPlaylist.playlist();
emit q->currentMediaChanged(pendingPlaylist);
}
pendingPlaylist = QMediaContent();
playlist->next();
setPlaylistMedia();
switch (state) {
case QMediaPlayer::PausedState:
control->pause();
break;
case QMediaPlayer::PlayingState:
control->play();
break;
case QMediaPlayer::StoppedState:
break;
}
}
void QMediaPlayerPrivate::_q_handlePlaylistLoadFailed()
{
pendingPlaylist = QMediaContent();
if (!control)
return;
if (playlist)
playlist->next();
else
control->setMedia(QMediaContent(), 0);
}
static QMediaService *playerService(QMediaPlayer::Flags flags) static QMediaService *playerService(QMediaPlayer::Flags flags)
{ {
QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider();
@@ -277,10 +488,9 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
d->error = ServiceMissingError; d->error = ServiceMissingError;
} else { } else {
d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid)); d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid));
d->playlistSourceControl = qobject_cast<QMediaPlaylistSourceControl*>(d->service->requestControl(QMediaPlaylistSourceControl_iid));
d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid)); d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid));
if (d->control != 0) { if (d->control != 0) {
connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent))); connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent)));
connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State))); connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus)));
@@ -330,10 +540,7 @@ QMediaContent QMediaPlayer::media() const
{ {
Q_D(const QMediaPlayer); Q_D(const QMediaPlayer);
if (d->control != 0) return d->rootMedia;
return d->control->media();
return QMediaContent();
} }
/*! /*!
@@ -356,44 +563,25 @@ const QIODevice *QMediaPlayer::mediaStream() const
QMediaPlaylist *QMediaPlayer::playlist() const QMediaPlaylist *QMediaPlayer::playlist() const
{ {
return d_func()->playlistSourceControl ? Q_D(const QMediaPlayer);
d_func()->playlistSourceControl->playlist() :
d_func()->playlist; return d->rootMedia.playlist();
}
QMediaContent QMediaPlayer::currentMedia() const
{
Q_D(const QMediaPlayer);
if (d->control != 0)
return d->control->media();
return QMediaContent();
} }
void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist) void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
{ {
Q_D(QMediaPlayer); QMediaContent m(playlist, QUrl(), false);
setMedia(m);
if (d->playlistSourceControl) {
if (d->playlistSourceControl->playlist())
disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
d->playlistSourceControl->setPlaylist(playlist);
if (playlist)
connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
} else {
if (d->playlist) {
disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)),
this, SLOT(_q_updateMedia(QMediaContent)));
disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
}
d->playlist = playlist;
if (d->playlist) {
connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)),
this, SLOT(_q_updateMedia(QMediaContent)));
connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed()));
if (d->control != 0)
d->control->setMedia(playlist->currentMedia(), 0);
} else {
setMedia(QMediaContent(), 0);
}
}
} }
/*! /*!
@@ -563,8 +751,18 @@ void QMediaPlayer::play()
} }
//if playlist control is available, the service should advance itself //if playlist control is available, the service should advance itself
if (d->playlist && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty()) if (d->rootMedia.playlist() && d->rootMedia.playlist()->currentIndex() == -1 && !d->rootMedia.playlist()->isEmpty()) {
// switch to playing state
if (d->state != QMediaPlayer::PlayingState)
d->_q_stateChanged(QMediaPlayer::PlayingState);
if (d->playlist != d->rootMedia.playlist())
d->setPlaylist(d->rootMedia.playlist());
Q_ASSERT(d->playlist == d->rootMedia.playlist());
emit currentMediaChanged(d->rootMedia);
d->playlist->setCurrentIndex(0); d->playlist->setCurrentIndex(0);
}
// Reset error conditions // Reset error conditions
d->error = NoError; d->error = NoError;
@@ -595,6 +793,17 @@ void QMediaPlayer::stop()
if (d->control != 0) if (d->control != 0)
d->control->stop(); d->control->stop();
// If media player didn't stop in response to control.
// This happens if we have an active playlist and control
// media status is
// QMediaPlayer::LoadingMedia, QMediaPlayer::InvalidMedia, or QMediaPlayer::EndOfMedia
// see QMediaPlayerPrivate::_q_stateChanged()
if (d->playlist && d->state != QMediaPlayer::StoppedState) {
d->state = QMediaPlayer::StoppedState;
removePropertyWatch("position");
emit stateChanged(QMediaPlayer::StoppedState);
}
} }
void QMediaPlayer::setPosition(qint64 position) void QMediaPlayer::setPosition(qint64 position)
@@ -654,12 +863,24 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream) void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream)
{ {
Q_D(QMediaPlayer); Q_D(QMediaPlayer);
stop();
if (playlist() && playlist()->currentMedia() != media) QMediaContent oldMedia = d->rootMedia;
setPlaylist(0); d->disconnectPlaylist();
d->playlist = 0;
d->rootMedia = media;
d->nestedPlaylists = 0;
if (d->control != 0) if (oldMedia != media)
d_func()->control->setMedia(media, stream); emit mediaChanged(d->rootMedia);
if (media.playlist()) {
// reset playlist to the 1st item
media.playlist()->setCurrentIndex(0);
d->setPlaylist(media.playlist());
} else if (d->control != 0) {
d->control->setMedia(media, stream);
}
} }
/*! /*!
@@ -796,6 +1017,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
return QMediaObject::availabilityError(); return QMediaObject::availabilityError();
} }
// Enums // Enums
/*! /*!
\enum QMediaPlayer::State \enum QMediaPlayer::State
@@ -841,6 +1063,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
\value NetworkError A network error occurred. \value NetworkError A network error occurred.
\value AccessDeniedError There are not the appropriate permissions to play a media resource. \value AccessDeniedError There are not the appropriate permissions to play a media resource.
\value ServiceMissingError A valid playback service was not found, playback cannot proceed. \value ServiceMissingError A valid playback service was not found, playback cannot proceed.
\omitvalue MediaIsPlaylist
*/ */
// Signals // Signals
@@ -869,9 +1092,17 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
/*! /*!
\fn void QMediaPlayer::mediaChanged(const QMediaContent &media); \fn void QMediaPlayer::mediaChanged(const QMediaContent &media);
Signals that the current playing content will be obtained from \a media. Signals that the media source has been changed to \a media.
\sa media() \sa media(), currentMediaChanged()
*/
/*!
\fn void QMediaPlayer::currentMediaChanged(const QMediaContent &media);
Signals that the current playing content has been changed to \a media.
\sa currentMedia(), mediaChanged()
*/ */
/*! /*!
@@ -916,7 +1147,17 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
information relating to the current media source and to cease all I/O operations related information relating to the current media source and to cease all I/O operations related
to that media. to that media.
\sa QMediaContent \sa QMediaContent, currentMedia()
*/
/*!
\property QMediaPlayer::currentMedia
\brief the current active media content being played by the player object.
This value could be different from QMediaPlayer::media property if a playlist is used.
In this case currentMedia indicates the current media content being processed
by the player, while QMediaPlayer::media property contains the original playlist.
\sa QMediaContent, media()
*/ */
/*! /*!
@@ -928,7 +1169,7 @@ QtMultimedia::AvailabilityError QMediaPlayer::availabilityError() const
By default this property is set to null. By default this property is set to null.
If the media playlist is used as a source, QMediaPlayer::media is updated with If the media playlist is used as a source, QMediaPlayer::currentMedia is updated with
a current playlist item. The current source should be selected with a current playlist item. The current source should be selected with
QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(), QMediaPlaylist::setCurrentIndex(int) instead of QMediaPlayer::setMedia(),
otherwise the current playlist will be discarded. otherwise the current playlist will be discarded.

View File

@@ -65,6 +65,7 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged)
Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged)
Q_PROPERTY(QMediaPlaylist * playlist READ playlist WRITE setPlaylist) Q_PROPERTY(QMediaPlaylist * playlist READ playlist WRITE setPlaylist)
Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged)
Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged)
@@ -118,7 +119,8 @@ public:
FormatError, FormatError,
NetworkError, NetworkError,
AccessDeniedError, AccessDeniedError,
ServiceMissingError ServiceMissingError,
MediaIsPlaylist
}; };
QMediaPlayer(QObject *parent = 0, Flags flags = 0); QMediaPlayer(QObject *parent = 0, Flags flags = 0);
@@ -136,6 +138,7 @@ public:
QMediaContent media() const; QMediaContent media() const;
const QIODevice *mediaStream() const; const QIODevice *mediaStream() const;
QMediaPlaylist *playlist() const; QMediaPlaylist *playlist() const;
QMediaContent currentMedia() const;
State state() const; State state() const;
MediaStatus mediaStatus() const; MediaStatus mediaStatus() const;
@@ -178,6 +181,7 @@ public Q_SLOTS:
Q_SIGNALS: Q_SIGNALS:
void mediaChanged(const QMediaContent &media); void mediaChanged(const QMediaContent &media);
void currentMediaChanged(const QMediaContent &media);
void stateChanged(QMediaPlayer::State newState); void stateChanged(QMediaPlayer::State newState);
void mediaStatusChanged(QMediaPlayer::MediaStatus status); void mediaStatusChanged(QMediaPlayer::MediaStatus status);
@@ -210,6 +214,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &))
Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&)) Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&))
Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed())
Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoaded())
Q_PRIVATE_SLOT(d_func(), void _q_handlePlaylistLoadFailed())
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -42,8 +42,8 @@
#include "qmediaplaylist.h" #include "qmediaplaylist.h"
#include "qmediaplaylist_p.h" #include "qmediaplaylist_p.h"
#include "qmediaplaylistprovider_p.h" #include "qmediaplaylistprovider_p.h"
#include "qlocalmediaplaylistprovider_p.h"
#include "qmediaplaylistioplugin_p.h" #include "qmediaplaylistioplugin_p.h"
#include "qmedianetworkplaylistprovider_p.h"
#include "qmediaservice.h" #include "qmediaservice.h"
#include "qmediaplaylistcontrol_p.h" #include "qmediaplaylistcontrol_p.h"
#include "qmediaplayercontrol.h" #include "qmediaplayercontrol.h"
@@ -129,7 +129,7 @@ QMediaPlaylist::QMediaPlaylist(QObject *parent)
Q_D(QMediaPlaylist); Q_D(QMediaPlaylist);
d->q_ptr = this; d->q_ptr = this;
d->localPlaylistControl = new QLocalMediaPlaylistControl(this); d->networkPlaylistControl = new QMediaNetworkPlaylistControl(this);
setMediaObject(0); setMediaObject(0);
} }
@@ -178,7 +178,7 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject)
newControl = qobject_cast<QMediaPlaylistControl*>(service->requestControl(QMediaPlaylistControl_iid)); newControl = qobject_cast<QMediaPlaylistControl*>(service->requestControl(QMediaPlaylistControl_iid));
if (!newControl) if (!newControl)
newControl = d->localPlaylistControl; newControl = d->networkPlaylistControl;
if (d->control != newControl) { if (d->control != newControl) {
int oldSize = 0; int oldSize = 0;

View File

@@ -57,7 +57,7 @@
#include "qmediaplaylistcontrol_p.h" #include "qmediaplaylistcontrol_p.h"
#include "qmediaplayer.h" #include "qmediaplayer.h"
#include "qmediaplayercontrol.h" #include "qmediaplayercontrol.h"
#include "qlocalmediaplaylistprovider_p.h" #include "qmedianetworkplaylistprovider_p.h"
#include "qmediaobject_p.h" #include "qmediaobject_p.h"
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
@@ -86,7 +86,7 @@ public:
QMediaPlaylistPrivate() QMediaPlaylistPrivate()
:mediaObject(0), :mediaObject(0),
control(0), control(0),
localPlaylistControl(0), networkPlaylistControl(0),
error(QMediaPlaylist::NoError) error(QMediaPlaylist::NoError)
{ {
} }
@@ -105,7 +105,7 @@ public:
{ {
Q_Q(QMediaPlaylist); Q_Q(QMediaPlaylist);
mediaObject = 0; mediaObject = 0;
if (control != localPlaylistControl) if (control != networkPlaylistControl)
control = 0; control = 0;
q->setMediaObject(0); q->setMediaObject(0);
} }
@@ -115,7 +115,7 @@ public:
QMediaPlaylistControl *control; QMediaPlaylistControl *control;
QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); } QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); }
QMediaPlaylistControl *localPlaylistControl; QMediaPlaylistControl *networkPlaylistControl;
bool readItems(QMediaPlaylistReader *reader); bool readItems(QMediaPlaylistReader *reader);
bool writeItems(QMediaPlaylistWriter *writer); bool writeItems(QMediaPlaylistWriter *writer);
@@ -127,14 +127,14 @@ public:
}; };
class QLocalMediaPlaylistControl : public QMediaPlaylistControl class QMediaNetworkPlaylistControl : public QMediaPlaylistControl
{ {
Q_OBJECT Q_OBJECT
public: public:
QLocalMediaPlaylistControl(QObject *parent) QMediaNetworkPlaylistControl(QObject *parent)
:QMediaPlaylistControl(parent) :QMediaPlaylistControl(parent)
{ {
QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this); QMediaPlaylistProvider *playlist = new QMediaNetworkPlaylistProvider(this);
m_navigator = new QMediaPlaylistNavigator(playlist,this); m_navigator = new QMediaPlaylistNavigator(playlist,this);
m_navigator->setPlaybackMode(QMediaPlaylist::Sequential); m_navigator->setPlaybackMode(QMediaPlaylist::Sequential);
@@ -143,7 +143,7 @@ public:
connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); connect(m_navigator, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)));
} }
virtual ~QLocalMediaPlaylistControl() {}; virtual ~QMediaNetworkPlaylistControl() {};
QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); }
bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist)

View File

@@ -227,11 +227,12 @@ void tst_QMediaPlayer::testNullService()
{ {
QFETCH_GLOBAL(QMediaContent, mediaContent); QFETCH_GLOBAL(QMediaContent, mediaContent);
QSignalSpy spy(&player, SIGNAL(mediaChanged(QMediaContent))); QSignalSpy spy(&player, SIGNAL(currentMediaChanged(QMediaContent)));
QFile file; QFile file;
player.setMedia(mediaContent, &file); player.setMedia(mediaContent, &file);
QCOMPARE(player.media(), QMediaContent()); QCOMPARE(player.currentMedia(), QMediaContent());
QCOMPARE(player.media(), mediaContent);
QCOMPARE(player.mediaStream(), nullDevice); QCOMPARE(player.mediaStream(), nullDevice);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
} { } {
@@ -297,13 +298,15 @@ void tst_QMediaPlayer::testNullService()
playlist.setCurrentIndex(0); playlist.setCurrentIndex(0);
QCOMPARE(playlist.currentIndex(), 0); QCOMPARE(playlist.currentIndex(), 0);
QCOMPARE(player.media(), QMediaContent()); QCOMPARE(player.currentMedia(), QMediaContent());
QCOMPARE(player.media().playlist(), &playlist);
QCOMPARE(mediaSpy.count(), 0); QCOMPARE(mediaSpy.count(), 0);
QCOMPARE(statusSpy.count(), 0); QCOMPARE(statusSpy.count(), 0);
playlist.next(); playlist.next();
QCOMPARE(playlist.currentIndex(), 1); QCOMPARE(playlist.currentIndex(), 1);
QCOMPARE(player.media(), QMediaContent()); QCOMPARE(player.currentMedia(), QMediaContent());
QCOMPARE(player.media().playlist(), &playlist);
QCOMPARE(mediaSpy.count(), 0); QCOMPARE(mediaSpy.count(), 0);
QCOMPARE(statusSpy.count(), 0); QCOMPARE(statusSpy.count(), 0);
} }
@@ -324,11 +327,11 @@ void tst_QMediaPlayer::testMedia()
QFETCH_GLOBAL(QMediaContent, mediaContent); QFETCH_GLOBAL(QMediaContent, mediaContent);
mockService->setMedia(mediaContent); mockService->setMedia(mediaContent);
QCOMPARE(player->media(), mediaContent); QCOMPARE(player->currentMedia(), mediaContent);
QBuffer stream; QBuffer stream;
player->setMedia(mediaContent, &stream); player->setMedia(mediaContent, &stream);
QCOMPARE(player->media(), mediaContent); QCOMPARE(player->currentMedia(), mediaContent);
QCOMPARE((QBuffer*)player->mediaStream(), &stream); QCOMPARE((QBuffer*)player->mediaStream(), &stream);
} }
@@ -525,7 +528,7 @@ void tst_QMediaPlayer::testPlay()
mockService->setState(state); mockService->setState(state);
mockService->setMedia(mediaContent); mockService->setMedia(mediaContent);
QVERIFY(player->state() == state); QVERIFY(player->state() == state);
QVERIFY(player->media() == mediaContent); QVERIFY(player->currentMedia() == mediaContent);
QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State)));
@@ -551,7 +554,7 @@ void tst_QMediaPlayer::testPause()
mockService->setState(state); mockService->setState(state);
mockService->setMedia(mediaContent); mockService->setMedia(mediaContent);
QVERIFY(player->state() == state); QVERIFY(player->state() == state);
QVERIFY(player->media() == mediaContent); QVERIFY(player->currentMedia() == mediaContent);
QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State)));
@@ -575,7 +578,7 @@ void tst_QMediaPlayer::testStop()
mockService->setState(state); mockService->setState(state);
mockService->setMedia(mediaContent); mockService->setMedia(mediaContent);
QVERIFY(player->state() == state); QVERIFY(player->state() == state);
QVERIFY(player->media() == mediaContent); QVERIFY(player->currentMedia() == mediaContent);
QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State)));
@@ -686,14 +689,15 @@ void tst_QMediaPlayer::testPlaylist()
QMediaPlaylist *playlist = new QMediaPlaylist; QMediaPlaylist *playlist = new QMediaPlaylist;
player->setPlaylist(playlist); player->setPlaylist(playlist);
QCOMPARE(player->media().playlist(), playlist);
QSignalSpy stateSpy(player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy stateSpy(player, SIGNAL(stateChanged(QMediaPlayer::State)));
QSignalSpy mediaSpy(player, SIGNAL(mediaChanged(QMediaContent))); QSignalSpy mediaSpy(player, SIGNAL(currentMediaChanged(QMediaContent)));
// Test the player does nothing with an empty playlist attached. // Test the player does nothing with an empty playlist attached.
player->play(); player->play();
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
QCOMPARE(stateSpy.count(), 0); QCOMPARE(stateSpy.count(), 0);
QCOMPARE(mediaSpy.count(), 0); QCOMPARE(mediaSpy.count(), 0);
@@ -704,28 +708,28 @@ void tst_QMediaPlayer::testPlaylist()
// Test changing the playlist position, changes the current media, but not the playing state. // Test changing the playlist position, changes the current media, but not the playing state.
playlist->setCurrentIndex(1); playlist->setCurrentIndex(1);
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 0); QCOMPARE(stateSpy.count(), 0);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
// Test playing starts with the current media. // Test playing starts with the current media.
player->play(); player->play();
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 1); QCOMPARE(stateSpy.count(), 1);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
// Test pausing doesn't change the current media. // Test pausing doesn't change the current media.
player->pause(); player->pause();
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::PausedState); QCOMPARE(player->state(), QMediaPlayer::PausedState);
QCOMPARE(stateSpy.count(), 2); QCOMPARE(stateSpy.count(), 2);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
// Test stopping doesn't change the current media. // Test stopping doesn't change the current media.
player->stop(); player->stop();
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 3); QCOMPARE(stateSpy.count(), 3);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
@@ -733,20 +737,20 @@ void tst_QMediaPlayer::testPlaylist()
// Test when the player service reaches the end of the current media, the player moves onto // Test when the player service reaches the end of the current media, the player moves onto
// the next item without stopping. // the next item without stopping.
player->play(); player->play();
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 4); QCOMPARE(stateSpy.count(), 4);
QCOMPARE(mediaSpy.count(), 1); QCOMPARE(mediaSpy.count(), 1);
mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia);
QCOMPARE(player->media(), content2); QCOMPARE(player->currentMedia(), content2);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 4); QCOMPARE(stateSpy.count(), 4);
QCOMPARE(mediaSpy.count(), 2); QCOMPARE(mediaSpy.count(), 2);
// Test skipping the current media doesn't change the state. // Test skipping the current media doesn't change the state.
playlist->next(); playlist->next();
QCOMPARE(player->media(), content3); QCOMPARE(player->currentMedia(), content3);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 4); QCOMPARE(stateSpy.count(), 4);
QCOMPARE(mediaSpy.count(), 3); QCOMPARE(mediaSpy.count(), 3);
@@ -754,13 +758,13 @@ void tst_QMediaPlayer::testPlaylist()
// Test changing the current media while paused doesn't change the state. // Test changing the current media while paused doesn't change the state.
player->pause(); player->pause();
mockService->setMediaStatus(QMediaPlayer::BufferedMedia); mockService->setMediaStatus(QMediaPlayer::BufferedMedia);
QCOMPARE(player->media(), content3); QCOMPARE(player->currentMedia(), content3);
QCOMPARE(player->state(), QMediaPlayer::PausedState); QCOMPARE(player->state(), QMediaPlayer::PausedState);
QCOMPARE(stateSpy.count(), 5); QCOMPARE(stateSpy.count(), 5);
QCOMPARE(mediaSpy.count(), 3); QCOMPARE(mediaSpy.count(), 3);
playlist->previous(); playlist->previous();
QCOMPARE(player->media(), content2); QCOMPARE(player->currentMedia(), content2);
QCOMPARE(player->state(), QMediaPlayer::PausedState); QCOMPARE(player->state(), QMediaPlayer::PausedState);
QCOMPARE(stateSpy.count(), 5); QCOMPARE(stateSpy.count(), 5);
QCOMPARE(mediaSpy.count(), 4); QCOMPARE(mediaSpy.count(), 4);
@@ -768,13 +772,13 @@ void tst_QMediaPlayer::testPlaylist()
// Test changing the current media while stopped doesn't change the state. // Test changing the current media while stopped doesn't change the state.
player->stop(); player->stop();
mockService->setMediaStatus(QMediaPlayer::LoadedMedia); mockService->setMediaStatus(QMediaPlayer::LoadedMedia);
QCOMPARE(player->media(), content2); QCOMPARE(player->currentMedia(), content2);
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 6); QCOMPARE(stateSpy.count(), 6);
QCOMPARE(mediaSpy.count(), 4); QCOMPARE(mediaSpy.count(), 4);
playlist->next(); playlist->next();
QCOMPARE(player->media(), content3); QCOMPARE(player->currentMedia(), content3);
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 6); QCOMPARE(stateSpy.count(), 6);
QCOMPARE(mediaSpy.count(), 5); QCOMPARE(mediaSpy.count(), 5);
@@ -782,7 +786,7 @@ void tst_QMediaPlayer::testPlaylist()
// Test the player is stopped and the current media cleared when it reaches the end of the last // Test the player is stopped and the current media cleared when it reaches the end of the last
// item in the playlist. // item in the playlist.
player->play(); player->play();
QCOMPARE(player->media(), content3); QCOMPARE(player->currentMedia(), content3);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 7); QCOMPARE(stateSpy.count(), 7);
QCOMPARE(mediaSpy.count(), 5); QCOMPARE(mediaSpy.count(), 5);
@@ -790,45 +794,46 @@ void tst_QMediaPlayer::testPlaylist()
// Double up the signals to ensure some noise doesn't destabalize things. // Double up the signals to ensure some noise doesn't destabalize things.
mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia);
mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia);
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 8); QCOMPARE(stateSpy.count(), 8);
QCOMPARE(mediaSpy.count(), 6); QCOMPARE(mediaSpy.count(), 6);
// Test starts playing from the start of the playlist if there is no current media selected. // Test starts playing from the start of the playlist if there is no current media selected.
player->play(); player->play();
QCOMPARE(player->media(), content0); QCOMPARE(player->currentMedia(), content0);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 9); QCOMPARE(stateSpy.count(), 9);
QCOMPARE(mediaSpy.count(), 7); // one notification is for playlist and another is for the first media in the playlist
QCOMPARE(mediaSpy.count(), 8);
// Test deleting the playlist stops the player and clears the media it set. // Test deleting the playlist stops the player and clears the media it set.
delete playlist; delete playlist;
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 10); QCOMPARE(stateSpy.count(), 10);
QCOMPARE(mediaSpy.count(), 8); QCOMPARE(mediaSpy.count(), 9);
// Test the player works as normal with the playlist removed. // Test the player works as normal with the playlist removed.
player->play(); player->play();
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
QCOMPARE(stateSpy.count(), 10); QCOMPARE(stateSpy.count(), 10);
QCOMPARE(mediaSpy.count(), 8); QCOMPARE(mediaSpy.count(), 9);
player->setMedia(content1); player->setMedia(content1);
player->play(); player->play();
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::PlayingState); QCOMPARE(player->state(), QMediaPlayer::PlayingState);
QCOMPARE(stateSpy.count(), 11); QCOMPARE(stateSpy.count(), 11);
QCOMPARE(mediaSpy.count(), 9); QCOMPARE(mediaSpy.count(), 10);
// Test the player can bind to playlist again // Test the player can bind to playlist again
playlist = new QMediaPlaylist; playlist = new QMediaPlaylist;
player->setPlaylist(playlist); player->setPlaylist(playlist);
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
playlist->addMedia(content0); playlist->addMedia(content0);
@@ -837,7 +842,7 @@ void tst_QMediaPlayer::testPlaylist()
playlist->addMedia(content3); playlist->addMedia(content3);
playlist->setCurrentIndex(1); playlist->setCurrentIndex(1);
QCOMPARE(player->media(), content1); QCOMPARE(player->currentMedia(), content1);
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
// Test attaching the new playlist, // Test attaching the new playlist,
@@ -850,11 +855,11 @@ void tst_QMediaPlayer::testPlaylist()
player->play(); player->play();
player->setPlaylist(playlist2); player->setPlaylist(playlist2);
QCOMPARE(player->media(), playlist2->currentMedia()); QCOMPARE(player->currentMedia(), playlist2->currentMedia());
QCOMPARE(player->state(), QMediaPlayer::StoppedState); QCOMPARE(player->state(), QMediaPlayer::StoppedState);
playlist2->setCurrentIndex(1); playlist2->setCurrentIndex(1);
QCOMPARE(player->media(), playlist2->currentMedia()); QCOMPARE(player->currentMedia(), playlist2->currentMedia());
{ {
QMediaPlaylist playlist; QMediaPlaylist playlist;
@@ -863,13 +868,14 @@ void tst_QMediaPlayer::testPlaylist()
playlist.addMedia(content3); playlist.addMedia(content3);
playlist.setCurrentIndex(1); playlist.setCurrentIndex(1);
// playlist resets to the first item
player->setPlaylist(&playlist); player->setPlaylist(&playlist);
QCOMPARE(player->playlist(), &playlist); QCOMPARE(player->playlist(), &playlist);
QCOMPARE(player->media(), content2); QCOMPARE(player->currentMedia(), content1);
} //playlist should be detached now } //playlist should be detached now
QVERIFY(player->playlist() == 0); QVERIFY(player->playlist() == 0);
QCOMPARE(player->media(), QMediaContent()); QCOMPARE(player->currentMedia(), QMediaContent());
// Test when the player service encounters an invalid media, the player moves onto // Test when the player service encounters an invalid media, the player moves onto
// the next item without stopping // the next item without stopping
@@ -877,6 +883,7 @@ void tst_QMediaPlayer::testPlaylist()
QSignalSpy ss(player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy ss(player, SIGNAL(stateChanged(QMediaPlayer::State)));
QSignalSpy ms(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); QSignalSpy ms(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)));
// playlist index is set to 0 when it is loaded into media player
player->setPlaylist(playlist); player->setPlaylist(playlist);
player->play(); player->play();
QCOMPARE(ss.count(), 1); QCOMPARE(ss.count(), 1);
@@ -888,7 +895,7 @@ void tst_QMediaPlayer::testPlaylist()
QCOMPARE(ms.count(), 1); QCOMPARE(ms.count(), 1);
// NOTE: status should begin transitioning through to BufferedMedia. // NOTE: status should begin transitioning through to BufferedMedia.
QCOMPARE(player->media(), content2); QCOMPARE(player->currentMedia(), content1);
} }
delete playlist; delete playlist;

View File

@@ -43,7 +43,7 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <QDebug> #include <QDebug>
#include <private/qlocalmediaplaylistprovider_p.h> #include <private/qmedianetworkplaylistprovider_p.h>
#include <private/qmediaplaylistnavigator_p.h> #include <private/qmediaplaylistnavigator_p.h>
QT_USE_NAMESPACE QT_USE_NAMESPACE
@@ -84,7 +84,7 @@ void tst_QMediaPlaylistNavigator::cleanup()
void tst_QMediaPlaylistNavigator::construction() void tst_QMediaPlaylistNavigator::construction()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QCOMPARE(playlist.mediaCount(), 0); QCOMPARE(playlist.mediaCount(), 0);
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
@@ -100,7 +100,7 @@ void tst_QMediaPlaylistNavigator::setPlaylist()
QCOMPARE(navigator.playlist()->media(0), QMediaContent()); QCOMPARE(navigator.playlist()->media(0), QMediaContent());
QVERIFY(navigator.playlist()->isReadOnly() ); QVERIFY(navigator.playlist()->isReadOnly() );
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QCOMPARE(playlist.mediaCount(), 0); QCOMPARE(playlist.mediaCount(), 0);
navigator.setPlaylist(&playlist); navigator.setPlaylist(&playlist);
@@ -111,7 +111,7 @@ void tst_QMediaPlaylistNavigator::setPlaylist()
void tst_QMediaPlaylistNavigator::linearPlayback() void tst_QMediaPlaylistNavigator::linearPlayback()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Sequential); navigator.setPlaybackMode(QMediaPlaylist::Sequential);
@@ -165,7 +165,7 @@ void tst_QMediaPlaylistNavigator::linearPlayback()
void tst_QMediaPlaylistNavigator::loopPlayback() void tst_QMediaPlaylistNavigator::loopPlayback()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Loop); navigator.setPlaybackMode(QMediaPlaylist::Loop);
@@ -216,7 +216,7 @@ void tst_QMediaPlaylistNavigator::loopPlayback()
void tst_QMediaPlaylistNavigator::currentItemOnce() void tst_QMediaPlaylistNavigator::currentItemOnce()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::CurrentItemOnce); navigator.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
@@ -247,7 +247,7 @@ void tst_QMediaPlaylistNavigator::currentItemOnce()
void tst_QMediaPlaylistNavigator::currentItemInLoop() void tst_QMediaPlaylistNavigator::currentItemInLoop()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop); navigator.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
@@ -275,7 +275,7 @@ void tst_QMediaPlaylistNavigator::currentItemInLoop()
void tst_QMediaPlaylistNavigator::randomPlayback() void tst_QMediaPlaylistNavigator::randomPlayback()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
@@ -326,7 +326,7 @@ void tst_QMediaPlaylistNavigator::randomPlayback()
void tst_QMediaPlaylistNavigator::testItemAt() void tst_QMediaPlaylistNavigator::testItemAt()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -348,7 +348,7 @@ void tst_QMediaPlaylistNavigator::testItemAt()
void tst_QMediaPlaylistNavigator::testNextIndex() void tst_QMediaPlaylistNavigator::testNextIndex()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -383,7 +383,7 @@ void tst_QMediaPlaylistNavigator::testNextIndex()
void tst_QMediaPlaylistNavigator::testPreviousIndex() void tst_QMediaPlaylistNavigator::testPreviousIndex()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -413,7 +413,7 @@ void tst_QMediaPlaylistNavigator::testPreviousIndex()
void tst_QMediaPlaylistNavigator::testCurrentIndexChangedSignal() void tst_QMediaPlaylistNavigator::testCurrentIndexChangedSignal()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -441,7 +441,7 @@ void tst_QMediaPlaylistNavigator::testCurrentIndexChangedSignal()
void tst_QMediaPlaylistNavigator::testPlaybackModeChangedSignal() void tst_QMediaPlaylistNavigator::testPlaybackModeChangedSignal()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -467,7 +467,7 @@ void tst_QMediaPlaylistNavigator::testPlaybackModeChangedSignal()
void tst_QMediaPlaylistNavigator::testSurroundingItemsChangedSignal() void tst_QMediaPlaylistNavigator::testSurroundingItemsChangedSignal()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);
@@ -493,7 +493,7 @@ void tst_QMediaPlaylistNavigator::testSurroundingItemsChangedSignal()
void tst_QMediaPlaylistNavigator::testActivatedSignal() void tst_QMediaPlaylistNavigator::testActivatedSignal()
{ {
QLocalMediaPlaylistProvider playlist; QMediaNetworkPlaylistProvider playlist;
QMediaPlaylistNavigator navigator(&playlist); QMediaPlaylistNavigator navigator(&playlist);
navigator.setPlaybackMode(QMediaPlaylist::Random); navigator.setPlaybackMode(QMediaPlaylist::Random);
QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random);