-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from heartfin/32-abstract-media-playback-imple…
…mentation-from-viewmodel-playbackmanager Abstract media playback implementation from ViewModel::PlaybackManager
- Loading branch information
Showing
20 changed files
with
1,894 additions
and
662 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
/* | ||
* Sailfin: a Jellyfin client written using Qt | ||
* Copyright (C) 2021-2022 Chris Josten and the Sailfin Contributors. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2.1 of the License, or (at your option) any later version. | ||
* | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
*/ | ||
#ifndef JELLYFIN_MODEL_PLAYBACKMANAGER_H | ||
#define JELLYFIN_MODEL_PLAYBACKMANAGER_H | ||
|
||
#include <QLoggingCategory> | ||
#include <QObject> | ||
#include <QSharedPointer> | ||
|
||
#include <JellyfinQt/dto/playmethod.h> | ||
#include <JellyfinQt/model/player.h> | ||
|
||
namespace Jellyfin { | ||
namespace Model { | ||
|
||
class Item; | ||
class Playlist; | ||
|
||
Q_DECLARE_LOGGING_CATEGORY(playbackManager); | ||
|
||
class PlaybackManagerErrorClass { | ||
Q_GADGET | ||
public: | ||
enum Value { | ||
NoError, | ||
PlaybackInfoError, | ||
RemoteClientNotReachable, | ||
PlayerGeneralError | ||
}; | ||
Q_ENUM(Value); | ||
}; | ||
|
||
using PlaybackManagerError = PlaybackManagerErrorClass::Value; | ||
|
||
class PlaybackManagerPrivate; | ||
/** | ||
* @brief Base class for a playback manager. | ||
* | ||
* Besides some glue code for the properties, | ||
* most of the actual playback logic is implemented in the two subclasses: {@link LocalPlaybackManager} | ||
* and {@link RemotePlaybackManager} | ||
*/ | ||
class PlaybackManager : public QObject { | ||
Q_OBJECT | ||
Q_DECLARE_PRIVATE(PlaybackManager); | ||
Q_PROPERTY(bool resumePlayback READ resumePlayback WRITE setResumePlayback NOTIFY resumePlaybackChanged) | ||
Q_PROPERTY(int audioIndex READ audioIndex WRITE setAudioIndex NOTIFY audioIndexChanged) | ||
Q_PROPERTY(int subtitleIndex READ subtitleIndex WRITE setSubtitleIndex NOTIFY subtitleIndexChanged) | ||
Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) | ||
Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) | ||
Q_PROPERTY(bool seekable READ seekable NOTIFY seekableChanged) | ||
Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged) | ||
Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) | ||
Q_PROPERTY(Jellyfin::Model::PlayerStateClass::Value playbackState READ playbackState NOTIFY playbackStateChanged) | ||
Q_PROPERTY(Jellyfin::Model::MediaStatusClass::Value mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) | ||
Q_PROPERTY(Jellyfin::Model::Playlist *queue READ queue NOTIFY queueChanged) | ||
Q_PROPERTY(int queueIndex READ queueIndex NOTIFY queueIndexChanged) | ||
public: | ||
explicit PlaybackManager(QObject *parent = nullptr); | ||
virtual ~PlaybackManager(); | ||
virtual void swap(PlaybackManager& other) = 0; | ||
|
||
ApiClient * apiClient() const; | ||
void setApiClient(ApiClient *apiClient); | ||
|
||
// Getters | ||
QSharedPointer<Item> currentItem() const; | ||
Playlist *queue() const; | ||
int queueIndex() const; | ||
|
||
bool resumePlayback() const; | ||
void setResumePlayback(bool newResumePlayback); | ||
int audioIndex() const; | ||
void setAudioIndex(int newAudioIndex); | ||
int subtitleIndex() const; | ||
void setSubtitleIndex(int newSubtitleIndex); | ||
|
||
virtual PlayerState playbackState() const = 0; | ||
virtual MediaStatus mediaStatus() const = 0; | ||
virtual bool hasNext() const = 0; | ||
virtual bool hasPrevious() const = 0; | ||
virtual PlaybackManagerError error() const = 0; | ||
|
||
virtual const QString &errorString() const = 0; | ||
virtual qint64 position() const = 0; | ||
virtual qint64 duration() const = 0; | ||
virtual bool seekable() const = 0; | ||
virtual bool hasAudio() const = 0; | ||
virtual bool hasVideo() const = 0; | ||
|
||
virtual void playItem(QSharedPointer<Model::Item> item) = 0; | ||
virtual void playItemInList(const QList<QSharedPointer<Model::Item>> &items, int index) = 0; | ||
|
||
signals: | ||
void playbackStateChanged(Jellyfin::Model::PlayerStateClass::Value newPlaybackState); | ||
void mediaStatusChanged(Jellyfin::Model::MediaStatusClass::Value newMediaStatus); | ||
void queueChanged(Jellyfin::Model::Playlist *newPlaylist); | ||
void hasNextChanged(bool newHasNext); | ||
void hasPreviousChanged(bool newHasPrevious); | ||
void itemChanged(); | ||
void queueIndexChanged(int index); | ||
void errorChanged(Jellyfin::Model::PlaybackManagerErrorClass::Value newError); | ||
void errorStringChanged(const QString &newErrorString); | ||
void positionChanged(qint64 newPosition); | ||
void durationChanged(qint64 newDuration); | ||
void seekableChanged(bool newSeekable); | ||
void hasAudioChanged(); | ||
void hasVideoChanged(); | ||
void resumePlaybackChanged(bool newPlaybackChanged); | ||
void audioIndexChanged(int newAudioIndex); | ||
void subtitleIndexChanged(int newSubtitleIndex); | ||
|
||
public slots: | ||
virtual void pause() = 0; | ||
virtual void play() = 0; | ||
virtual void playItemId(const QString &id) = 0; | ||
virtual void previous() = 0; | ||
virtual void next() = 0; | ||
/** | ||
* @brief Play the item at the index in the current playlist | ||
* @param index the item to go to; | ||
*/ | ||
virtual void goTo(int index) = 0; | ||
virtual void stop() = 0; | ||
virtual void seek(qint64 pos) = 0; | ||
protected: | ||
explicit PlaybackManager(PlaybackManagerPrivate *d, QObject *parent = nullptr); | ||
QScopedPointer<PlaybackManagerPrivate> d_ptr; | ||
}; | ||
|
||
class LocalPlaybackManagerPrivate; | ||
/** | ||
* @brief Controls playback whithin this app. | ||
* | ||
* This class mostly consists of bookkeeping between the actual media player implementation (which is | ||
* abstracted into yet another class) and the ViewModel. | ||
* | ||
* It does things like: | ||
* * Fetching the actual media URL of an item and deciding which playback method to use | ||
* * Managing the current playlist state and instructing the media player which item to play next | ||
* * Keeping track of the playback state that the user would expect from a media player, | ||
* instead of what the media player implementation reports. | ||
* | ||
*/ | ||
class LocalPlaybackManager : public PlaybackManager { | ||
Q_DECLARE_PRIVATE(LocalPlaybackManager); | ||
Q_OBJECT | ||
Q_PROPERTY(Jellyfin::Model::Player *player READ player NOTIFY playerChanged) | ||
Q_PROPERTY(Jellyfin::DTO::PlayMethodClass::Value playMethod READ playMethod NOTIFY playMethodChanged) | ||
Q_PROPERTY(QUrl streamUrl READ streamUrl NOTIFY streamUrlChanged) | ||
public: | ||
explicit LocalPlaybackManager(QObject *parent = nullptr); | ||
|
||
void swap(PlaybackManager& other) override; | ||
|
||
Player *player() const; | ||
QString sessionId() const; | ||
DTO::PlayMethod playMethod() const; | ||
const QUrl &streamUrl() const; | ||
|
||
PlayerState playbackState() const override; | ||
MediaStatus mediaStatus() const override; | ||
PlaybackManagerError error() const override; | ||
const QString& errorString() const override; | ||
qint64 position() const override; | ||
qint64 duration() const override; | ||
bool seekable() const override; | ||
bool hasAudio() const override; | ||
bool hasVideo() const override; | ||
|
||
bool hasNext() const override; | ||
bool hasPrevious() const override; | ||
|
||
void playItemInList(const QList<QSharedPointer<Model::Item>> &items, int index) override; | ||
|
||
public slots: | ||
void pause() override; | ||
void play() override; | ||
void playItem(QSharedPointer<Model::Item> item) override; | ||
void playItemId(const QString &itemId) override; | ||
void next() override; | ||
void previous() override; | ||
void stop() override; | ||
void seek(qint64 pos) override; | ||
void goTo(int index) override; | ||
signals: | ||
void playerChanged(Jellyfin::Model::Player *newPlayer); | ||
void playMethodChanged(Jellyfin::DTO::PlayMethodClass::Value newPlayMethod); | ||
void streamUrlChanged(const QUrl &newStreamUrl); | ||
}; | ||
|
||
/** | ||
* @brief Controls playback for remote devices, such as other Jellyfin clients, over the network. | ||
*/ | ||
class RemoteJellyfinPlaybackManager { | ||
|
||
}; | ||
|
||
} // NS Model | ||
} // NS Jellyfin | ||
|
||
#endif // JELLYFIN_MODEL_PLAYBACKMANAGER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Sailfin: a Jellyfin client written using Qt | ||
* Copyright (C) 2021-2022 Chris Josten and the Sailfin Contributors. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2.1 of the License, or (at your option) any later version. | ||
* | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
*/ | ||
#ifndef JELLYFIN_MODEL_PLAYBACKREPORTER_H | ||
#define JELLYFIN_MODEL_PLAYBACKREPORTER_H | ||
|
||
#include <QLoggingCategory> | ||
#include <QObject> | ||
#include <QScopedPointer> | ||
|
||
namespace Jellyfin { | ||
|
||
class ApiClient; | ||
|
||
namespace Model { | ||
|
||
Q_DECLARE_LOGGING_CATEGORY(playbackReporter); | ||
|
||
class LocalPlaybackManager; | ||
|
||
class PlaybackReporterPrivate; | ||
/** | ||
* @brief Reports the current playback state to the Jellyfin server | ||
* | ||
* Set a playbackManager using setPlaybackmanager() and this class | ||
* will do its job. | ||
*/ | ||
class PlaybackReporter : public QObject { | ||
Q_OBJECT | ||
Q_DECLARE_PRIVATE(PlaybackReporter); | ||
public: | ||
explicit PlaybackReporter(QObject *parent = nullptr); | ||
|
||
void setPlaybackManager(LocalPlaybackManager *playbackManager); | ||
private: | ||
PlaybackReporterPrivate *d_ptr; | ||
}; | ||
|
||
} | ||
} | ||
|
||
#endif //JELLYFIN_MODEL_PLAYBACKREPORTER_H | ||
|
Oops, something went wrong.