]> Some of my projects - aniplayer.git/commitdiff
Make InstanceManager manage Player instances
authorAPTX <marek321@gmail.com>
Sun, 26 Feb 2017 21:01:11 +0000 (22:01 +0100)
committerAPTX <marek321@gmail.com>
Sun, 26 Feb 2017 21:01:11 +0000 (22:01 +0100)
InstanceManager's job is to control the
configuration of Player instances. Player no
longer handles loading backend plugins.

core/instancemanager.cpp
core/instancemanager.h
core/main.cpp
core/player.cpp
core/player.h
core/pluginmanager.h

index 3935346afd46dfd9b5dde1bfea078d21bbc5522b..1cb2df3b6b36956081a96eaaa0691d19e626decf 100644 (file)
@@ -6,39 +6,54 @@
 #include <QQmlContext>
 
 #include "player.h"
+#include "pluginmanager.h"
 #include "timeformatter.h"
 
 Q_LOGGING_CATEGORY(imCategory, "InstanceManager")
 
-InstanceManager::InstanceManager(QObject *parent) : QObject(parent) {
-  parser.addHelpOption();
-  parser.addVersionOption();
-  parser.addPositionalArgument("files", "Files to play", "[files...]");
-  parser.addOption(backendOption);
-  parser.addOption(uiOption);
-  parser.addOption(positionOption);
+InstanceManager::InstanceManager(QObject *parent)
+    : QObject(parent), m_backendPluginManager{new PluginManager} {
+  m_parser.addHelpOption();
+  m_parser.addVersionOption();
+  m_parser.addPositionalArgument("files", "Files to play", "[files...]");
+  m_parser.addOption(backendOption);
+  m_parser.addOption(uiOption);
+  m_parser.addOption(positionOption);
 }
 
-int InstanceManager::runInstance(const QCoreApplication &app) {
-  parser.process(app);
+void InstanceManager::startFirstInstance() {
+  m_parser.process(*qApp);
 
-  const auto positionalArgs = parser.positionalArguments();
+  const auto positionalArgs = m_parser.positionalArguments();
 
-  QQmlApplicationEngine engine;
+  QQmlApplicationEngine *engine = new QQmlApplicationEngine{this};
+  Q_CHECK_PTR(engine);
 
-  player = new Player{this};
-  Q_CHECK_PTR(player);
+  auto player = createInstance();
   qCDebug(imCategory, "Player Created");
 
+  m_instances.insert(player);
+
   if (!positionalArgs.empty())
     player->setNextSource(QUrl::fromUserInput(positionalArgs[0]));
   TimeFormatter timeFormatter;
-  engine.rootContext()->setContextProperty("player", player);
-  engine.rootContext()->setContextProperty("timeFormatter", &timeFormatter);
+  engine->rootContext()->setContextProperty("player", player);
+  engine->rootContext()->setContextProperty("timeFormatter", &timeFormatter);
   qCDebug(imCategory, "Player Added");
-  engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
+  engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
   qCDebug(imCategory, "QML engine loaded");
-  return app.exec();
+}
+
+void InstanceManager::startInstance() {}
+
+QString InstanceManager::encodeCommandLine() const {
+  QByteArray arr;
+  {
+    QDataStream stream{&arr, QIODevice::WriteOnly};
+    stream << qApp->arguments();
+  }
+  const auto base64 = arr.toBase64();
+  return QString::fromLatin1(base64);
 }
 
 void InstanceManager::handleSingleInstanceMessage(const QString &message) {
@@ -53,17 +68,44 @@ void InstanceManager::handleSingleInstanceMessage(const QString &message) {
         << "Failed to read serialized single instance message";
     return;
   }
-  if (!parser.parse(args)) {
+  if (!m_parser.parse(args)) {
     qCWarning(imCategory)
         << "Failed to parse arguments from single instance message";
     return;
   }
 
-  const auto positionalArgs = parser.positionalArguments();
+  const auto positionalArgs = m_parser.positionalArguments();
   if (positionalArgs.empty()) {
     qCInfo(imCategory()) << "No new file to open";
     return;
   }
-  Q_ASSERT(player);
+
+  const auto it = m_instances.cbegin();
+
+  Q_ASSERT(it != m_instances.cend());
+
+  auto player = *it;
+
   player->loadAndPlay(QUrl::fromUserInput(positionalArgs[0]));
 }
+
+Player *InstanceManager::createInstance() {
+#ifdef Q_OS_WIN
+  static QStringList pluginPaths{"backendplugins"};
+#else
+  static QStringList pluginPaths{"backendplugins",
+                                 "/usr/lib/aniplayer/backendplugins"};
+#endif
+  m_backendPluginManager->setPluginDirectories(pluginPaths);
+  m_backendPluginManager->setPluginPrefix("backend");
+  m_backendPluginManager->setPreferredPlugins({"mpv"});
+  m_backendPluginManager->loadBestPlugin();
+  auto instance = m_backendPluginManager->bestInstance<BackendPluginBase>();
+  if (!instance)
+    throw std::runtime_error{std::string("Failed to load backend: ") +
+                             qPrintable(m_backendPluginManager->errorString())};
+
+  auto player = new Player{instance, this};
+  Q_CHECK_PTR(player);
+  return player;
+}
index c1ae55b4b8c89d2e10cf14961d1f3d703aa07843..ab6838229baeba616d177e950fb49259dee11f62 100644 (file)
@@ -3,30 +3,39 @@
 
 #include <QObject>
 
-#include <QCoreApplication>
 #include <QCommandLineOption>
 #include <QCommandLineParser>
+#include <QCoreApplication>
+#include <QSet>
 
 class Player;
+class PluginManager;
 
 class InstanceManager : public QObject {
   Q_OBJECT
 public:
   explicit InstanceManager(QObject *parent = 0);
 
-  int runInstance(const QCoreApplication &app);
+  void startFirstInstance();
+  void startInstance();
+
 public slots:
+  QString encodeCommandLine() const;
   void handleSingleInstanceMessage(const QString &message);
 
 private:
+  Player *createInstance();
   const QCommandLineOption backendOption{"backend", "Use backend",
                                          "name of backend plugin", "default"};
   const QCommandLineOption uiOption{"ui", "Use ui", "name of ui", "default"};
   const QCommandLineOption positionOption{"position",
                                           "Start playback specific position",
                                           "position in seconds", "0"};
-  QCommandLineParser parser;
-  Player *player = nullptr;
+  const QCommandLineOption multiInstanceOption{
+      QStringList{"m", "multi-instance"}, "Open more than one player instance"};
+  QCommandLineParser m_parser;
+  QSet<Player *> m_instances;
+  PluginManager *m_backendPluginManager;
 };
 
 #endif // INSTANCEMANAGER_H
index 0ee70f9e35528619e6faf083c2e08b3b92138c5b..e626ae79670e4e28f47c7c9fe3074a19b6cc263d 100644 (file)
@@ -21,13 +21,8 @@ int main(int argc, char *argv[]) {
                    SLOT(handleSingleInstanceMessage(QString)));
 
   if (app.isRunning()) {
-    QByteArray arr;
-    {
-      QDataStream stream{&arr, QIODevice::WriteOnly};
-      stream << app.arguments();
-    }
-    const auto base64 = arr.toBase64();
-    if (app.sendMessage(QString::fromUtf8(base64)))
+
+    if (app.sendMessage(im.encodeCommandLine()))
       return 0;
     return 1;
   }
@@ -36,7 +31,8 @@ int main(int argc, char *argv[]) {
   Player::reqisterQmlTypes();
 
   try {
-    return im.runInstance(app);
+    im.startFirstInstance();
+    return app.exec();
   } catch (const std::exception &ex) {
     qDebug("Exception: %s", ex.what());
   }
index b20b42ceb4453ed89a170140ce8b64eb981b0d55..0be95be021734f79bb5fd169eb2b3b16a183ded3 100644 (file)
@@ -5,15 +5,19 @@
 
 Q_LOGGING_CATEGORY(playerCategory, "Player")
 
-Player::Player(QObject *parent) : QObject(parent) {
+Player::Player(BackendPluginBase *backendPlugin, QObject *parent)
+    : QObject(parent) {
+  if (!backendPlugin) {
+    qCCritical(playerCategory)
+        << "Trying to create a player without a backendPlugin";
+    return;
+  }
   qCDebug(playerCategory) << "Creating player" << this;
-  loadBackend();
+  m_backend = backendPlugin->createInstance(this);
+  Q_CHECK_PTR(m_backend);
 }
 
-Player::~Player()
-{
-  qCDebug(playerCategory) << "Destroying player" << this;
-}
+Player::~Player() { qCDebug(playerCategory) << "Destroying player" << this; }
 
 BackendInstance *Player::backend() const { return m_backend; }
 
@@ -203,26 +207,6 @@ void Player::reqisterQmlTypes() {
   qmlRegisterType<Player>("org.aptx.aniplayer", 1, 0, "Player");
 }
 
-void Player::loadBackend() {
-#ifdef Q_OS_WIN
-  QStringList pluginPaths{"backendplugins"};
-#else
-  QStringList pluginPaths{"backendplugins",
-                          "/usr/lib/aniplayer/backendplugins"};
-#endif
-  m_pluginManager.setPluginDirectories(pluginPaths);
-  m_pluginManager.setPluginPrefix("backend");
-  m_pluginManager.setPreferredPlugins({"mpv"});
-  m_pluginManager.loadBestPlugin();
-  m_plugin = m_pluginManager.bestInstance<BackendPluginBase>();
-  if (!m_plugin)
-    throw std::runtime_error{std::string("Failed to load backend: ") +
-                             qPrintable(m_pluginManager.errorString())};
-  m_backend = m_plugin->createInstance(this);
-  Q_CHECK_PTR(m_backend);
-  qCDebug(playerCategory) << "Loaded backend" << m_backend;
-}
-
 bool Player::canLoadVideoNow() const {
   return m_backendInstanceReady && m_renderer && m_rendererReady;
 }
index ab28b702ddedc8ba4351fff62a263f4f248d408b..c96d582900993cde87b322cb1922b2e69c0621c3 100644 (file)
@@ -52,7 +52,9 @@ public:
 
   static const constexpr Volume MAX_VOLUME = Volume{1.0};
 
-  explicit Player(QObject *parent = 0);
+  // BackendPluginBase * allowed to be null because this is exposed to QML
+  // for the enums/types. Player should never be created in QML.
+  explicit Player(BackendPluginBase * = nullptr, QObject *parent = nullptr);
   ~Player() override;
 
   enum class PlayState {
@@ -144,14 +146,12 @@ public:
   static void reqisterQmlTypes();
 
 private:
-  void loadBackend();
   bool canLoadVideoNow() const;
   void loadNextFile();
 
-  PluginManager m_pluginManager;
-  BackendPluginBase *m_plugin = nullptr;
   BackendInstance *m_backend = nullptr;
   QUrl m_currentSource;
+  QUrl m_nextSource;
   PlayState m_state = PlayState::Stopped;
   Volume m_volume = MAX_VOLUME;
   AudioStreams m_availableAudioStreams;
@@ -162,7 +162,6 @@ private:
   SubtitleStreams m_availableSubtitleStreams;
   Player::TimeStamp m_duration = 0;
   Player::TimeStamp m_position = 0;
-  QUrl m_nextSource;
   VideoUpdateInterface *m_renderer = nullptr;
   bool m_muted = false;
   bool m_backendInstanceReady = false;
index 5ba288ce4073643d927112531b695d2608dcf476..5ae839178e3b503b20b58eaa617d5e19d452cac1 100644 (file)
@@ -46,7 +46,6 @@ public slots:
 signals:
   void pluginDirectoriesChanged(QStringList pluginDirectories);
   void pluginPrefixChanged(QString pluginPrefix);
-
   void preferredPluginsChanged(QStringList preferredPlugins);
 
 private: