From 088c367485edca9b638f62ea4816cac573df4eec Mon Sep 17 00:00:00 2001
From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
Date: Tue, 3 Oct 2023 07:18:55 -0300
Subject: [PATCH] filesharing: integrate mediaplayer API

GitLab: https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/485
Change-Id: I148f19eb76a526a5ab38c5f4a83f45ea66e348e4
---
 src/app/avadapter.cpp                         | 24 ++++++++-
 src/libclient/api/avmodel.h                   | 15 ++++++
 src/libclient/avmodel.cpp                     | 51 +++++++++++++++++++
 src/libclient/callbackshandler.cpp            |  5 ++
 src/libclient/callbackshandler.h              |  6 ++-
 src/libclient/qtwrapper/instancemanager.cpp   |  1 +
 src/libclient/qtwrapper/videomanager_wrap.cpp |  6 +++
 src/libclient/qtwrapper/videomanager_wrap.h   | 41 +++++++++++++++
 8 files changed, 146 insertions(+), 3 deletions(-)

diff --git a/src/app/avadapter.cpp b/src/app/avadapter.cpp
index c2c6a9021..53bbf71e7 100644
--- a/src/app/avadapter.cpp
+++ b/src/app/avadapter.cpp
@@ -195,8 +195,28 @@ AvAdapter::shareFile(const QString& filePath)
     auto callId = lrcInstance_->getCurrentCallId();
     if (!callId.isEmpty()) {
         muteCamera_ = !isCapturing();
-        lrcInstance_->getCurrentCallModel()
-            ->addMedia(callId, filePath, lrc::api::CallModel::MediaRequestType::FILESHARING);
+        auto resource = QString("%1%2%3")
+                            .arg(libjami::Media::VideoProtocolPrefix::FILE)
+                            .arg(libjami::Media::VideoProtocolPrefix::SEPARATOR)
+                            .arg(QUrl(filePath).toLocalFile());
+
+        Utils::oneShotConnect(&lrcInstance_->avModel(),
+                              &lrc::api::AVModel::fileOpened,
+                              this,
+                              [this, callId, filePath, resource](bool hasAudio, bool hasVideo) {
+                                  // TODO: add videos's audio while adding file sharing
+                                  if (hasVideo) {
+                                      lrcInstance_->avModel().pausePlayer(resource, false);
+                                      lrcInstance_->avModel().setAutoRestart(resource, true);
+                                      lrcInstance_->getCurrentCallModel()
+                                          ->addMedia(callId, filePath, lrc::api::CallModel::MediaRequestType::FILESHARING);
+                                  } else {
+                                      // Close media player because we are not going to start sharing
+                                      lrcInstance_->avModel().closeMediaPlayer(resource);
+                                  }
+                              });
+
+        lrcInstance_->avModel().createMediaPlayer(resource);
     }
 }
 
diff --git a/src/libclient/api/avmodel.h b/src/libclient/api/avmodel.h
index 8f76d1deb..d6296ea5b 100644
--- a/src/libclient/api/avmodel.h
+++ b/src/libclient/api/avmodel.h
@@ -286,6 +286,15 @@ public:
      */
     Q_SLOT void updateRenderersFPSInfo(QString rendererId);
 
+    QString createMediaPlayer(const QString& resource);
+    void closeMediaPlayer(const QString& resource);
+    Q_INVOKABLE bool pausePlayer(const QString& id, bool pause);
+    Q_INVOKABLE bool mutePlayerAudio(const QString& id, bool mute);
+    Q_INVOKABLE bool playerSeekToTime(const QString& id, int time);
+    Q_INVOKABLE qint64 getPlayerPosition(const QString& id);
+    Q_INVOKABLE qint64 getPlayerDuration(const QString& id);
+    Q_INVOKABLE void setAutoRestart(const QString& id, bool restart);
+
 Q_SIGNALS:
     /**
      * Emitted after an update of renderer's fps
@@ -332,6 +341,12 @@ Q_SIGNALS:
      * @param filePath
      */
     void recordPlaybackStopped(const QString& filePath);
+    /**
+     * returns if Media Player has audio and/or video
+     * @param hasAudio
+     * @param hasVideo
+     */
+    void fileOpened(bool hasAudio, bool hasVideo);
 
 private:
     std::unique_ptr<AVModelPimpl> pimpl_;
diff --git a/src/libclient/avmodel.cpp b/src/libclient/avmodel.cpp
index aa477673f..f6ac8c47e 100644
--- a/src/libclient/avmodel.cpp
+++ b/src/libclient/avmodel.cpp
@@ -795,6 +795,46 @@ AVModel::useDirectRenderer() const
 #endif
 }
 
+QString AVModel::createMediaPlayer(const QString& resource)
+{
+    return VideoManager::instance().createMediaPlayer(resource);
+}
+
+void AVModel::closeMediaPlayer(const QString& resource)
+{
+    VideoManager::instance().closeMediaPlayer(resource);
+}
+
+bool AVModel::pausePlayer(const QString& id, bool pause)
+{
+    return VideoManager::instance().pausePlayer(id, pause);
+}
+
+bool AVModel::mutePlayerAudio(const QString& id, bool mute)
+{
+    return VideoManager::instance().mutePlayerAudio(id, mute);
+}
+
+bool AVModel::playerSeekToTime(const QString& id, int time)
+{
+    return VideoManager::instance().playerSeekToTime(id, time);
+}
+
+qint64 AVModel::getPlayerPosition(const QString& id)
+{
+    return VideoManager::instance().getPlayerPosition(id);
+}
+
+qint64 AVModel::getPlayerDuration(const QString& id)
+{
+    return VideoManager::instance().getPlayerDuration(id);
+}
+
+void AVModel::setAutoRestart(const QString& id, bool restart)
+{
+    VideoManager::instance().setAutoRestart(id, restart);
+}
+
 AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHandler)
     : callbacksHandler(callbacksHandler)
     , linked_(linked)
@@ -826,6 +866,17 @@ AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHan
             &AVModelPimpl::onDecodingStopped,
             Qt::DirectConnection);
 
+    // Media player connection
+    connect(&callbacksHandler,
+            &CallbacksHandler::fileOpened,
+            this,
+            [this](const QString& path, MapStringString info) {
+                Q_UNUSED(path);
+                bool hasAudio = info["audio_stream"].toInt() >= 0;
+                bool hasVideo = info["video_stream"].toInt() >= 0;
+                Q_EMIT linked_.fileOpened(hasAudio, hasVideo);
+            });
+
     auto startedPreview = false;
     auto restartRenderers = [&](const QStringList& callList) {
         for (const auto& callId : callList) {
diff --git a/src/libclient/callbackshandler.cpp b/src/libclient/callbackshandler.cpp
index 254b361fa..b594ebddb 100644
--- a/src/libclient/callbackshandler.cpp
+++ b/src/libclient/callbackshandler.cpp
@@ -284,6 +284,11 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
             this,
             &CallbacksHandler::deviceEvent,
             Qt::QueuedConnection);
+    connect(&VideoManager::instance(),
+            &VideoManagerInterface::fileOpened,
+            this,
+            &CallbacksHandler::fileOpened,
+            Qt::DirectConnection);
 
     connect(&ConfigurationManager::instance(),
             &ConfigurationManagerInterface::audioDeviceEvent,
diff --git a/src/libclient/callbackshandler.h b/src/libclient/callbackshandler.h
index 4d62fdca0..ea7033a47 100644
--- a/src/libclient/callbackshandler.h
+++ b/src/libclient/callbackshandler.h
@@ -295,6 +295,11 @@ Q_SIGNALS:
      */
     void deviceEvent();
 
+    /**
+     * Emitted when a media player is opened
+     */
+    void fileOpened(const QString& path, const MapStringString& info);
+
     /**
      * Emitted when an audio level is plugged or unplugged
      */
@@ -365,7 +370,6 @@ Q_SIGNALS:
                                         const QString& conversationId,
                                         const MapStringString& preferences);
     void recordingStateChanged(const QString& callId, bool state);
-
     /**
      * Emitted when a conversation receives a new position
      */
diff --git a/src/libclient/qtwrapper/instancemanager.cpp b/src/libclient/qtwrapper/instancemanager.cpp
index bb18c0b09..e53649c09 100644
--- a/src/libclient/qtwrapper/instancemanager.cpp
+++ b/src/libclient/qtwrapper/instancemanager.cpp
@@ -41,6 +41,7 @@ InstanceManagerInterface::InstanceManagerInterface(bool muteDaemon)
 
 #ifdef ENABLE_VIDEO
     using libjami::VideoSignal;
+    using libjami::MediaPlayerSignal;
 #endif
 
 #ifndef MUTE_LIBJAMI
diff --git a/src/libclient/qtwrapper/videomanager_wrap.cpp b/src/libclient/qtwrapper/videomanager_wrap.cpp
index 70bd98f36..214d23716 100644
--- a/src/libclient/qtwrapper/videomanager_wrap.cpp
+++ b/src/libclient/qtwrapper/videomanager_wrap.cpp
@@ -23,6 +23,7 @@ VideoManagerInterface::VideoManagerInterface()
 #ifdef ENABLE_VIDEO
     using libjami::exportable_callback;
     using libjami::VideoSignal;
+    using libjami::MediaPlayerSignal;
     videoHandlers
         = {exportable_callback<VideoSignal::DeviceEvent>([this]() { Q_EMIT deviceEvent(); }),
            exportable_callback<VideoSignal::DecodingStarted>([this](const std::string& id,
@@ -41,6 +42,11 @@ VideoManagerInterface::VideoManagerInterface()
                    Q_EMIT decodingStopped(QString(id.c_str()),
                                           QString(shmPath.c_str()),
                                           isMixer);
+               }),
+           exportable_callback<MediaPlayerSignal::FileOpened>(
+               [this](const std::string& path, const std::map<std::string, std::string>& info) {
+                   Q_EMIT fileOpened(QString(path.c_str()),
+                                     convertMap(info));
                })};
 #endif
 }
diff --git a/src/libclient/qtwrapper/videomanager_wrap.h b/src/libclient/qtwrapper/videomanager_wrap.h
index 62e6662ed..cb4a52874 100644
--- a/src/libclient/qtwrapper/videomanager_wrap.h
+++ b/src/libclient/qtwrapper/videomanager_wrap.h
@@ -194,11 +194,52 @@ public Q_SLOTS: // METHODS
         return convertMap(libjami::getRenderer(id.toStdString()));
     }
 
+    QString createMediaPlayer(const QString& path)
+    {
+        return QString::fromStdString(libjami::createMediaPlayer(path.toStdString()));
+    }
+
+    bool closeMediaPlayer(const QString& id)
+    {
+        return libjami::closeMediaPlayer(id.toStdString());
+    }
+
+    bool pausePlayer(const QString& id, bool pause)
+    {
+        return libjami::pausePlayer(id.toStdString(), pause);
+    }
+
+    bool mutePlayerAudio(const QString& id, bool mute)
+    {
+        return libjami::mutePlayerAudio(id.toStdString(), mute);
+    }
+
+    bool playerSeekToTime(const QString& id, int time)
+    {
+        return libjami::playerSeekToTime(id.toStdString(), time);
+    }
+
+    qint64 getPlayerPosition(const QString& id)
+    {
+        return libjami::getPlayerPosition(id.toStdString());
+    }
+
+    qint64 getPlayerDuration(const QString& id)
+    {
+        return libjami::getPlayerDuration(id.toStdString());
+    }
+
+    void setAutoRestart(const QString& id, bool restart)
+    {
+        libjami::setAutoRestart(id.toStdString(), restart);
+    }
+
 Q_SIGNALS: // SIGNALS
     void deviceEvent();
     void decodingStarted(
         const QString& id, const QString& shmPath, int width, int height, bool isMixer);
     void decodingStopped(const QString& id, const QString& shmPath, bool isMixer);
+    void fileOpened(const QString& path, const MapStringString& info);
 };
 
 namespace org {
-- 
GitLab