diff --git a/linphone-desktop/CMakeLists.txt b/linphone-desktop/CMakeLists.txt index 7e4be0a21..8a7ee997c 100644 --- a/linphone-desktop/CMakeLists.txt +++ b/linphone-desktop/CMakeLists.txt @@ -93,6 +93,7 @@ set(SOURCES src/components/call/CallModel.cpp src/components/calls/CallsListModel.cpp src/components/camera/Camera.cpp + src/components/camera/CameraPreview.cpp src/components/camera/MSFunctions.cpp src/components/chat/ChatModel.cpp src/components/chat/ChatProxyModel.cpp @@ -131,6 +132,7 @@ set(HEADERS src/components/call/CallModel.hpp src/components/calls/CallsListModel.hpp src/components/camera/Camera.hpp + src/components/camera/CameraPreview.hpp src/components/camera/MSFunctions.hpp src/components/chat/ChatModel.hpp src/components/chat/ChatProxyModel.hpp diff --git a/linphone-desktop/src/app/App.cpp b/linphone-desktop/src/app/App.cpp index 6ed63778c..d0432ea15 100644 --- a/linphone-desktop/src/app/App.cpp +++ b/linphone-desktop/src/app/App.cpp @@ -278,6 +278,7 @@ void App::registerTypes () { qmlRegisterType("Linphone", 1, 0, "AssistantModel"); qmlRegisterType("Linphone", 1, 0, "Authentication"); qmlRegisterType("Linphone", 1, 0, "Camera"); + qmlRegisterType("Linphone", 1, 0, "CameraPreview"); qmlRegisterType("Linphone", 1, 0, "ChatModel"); qmlRegisterType("Linphone", 1, 0, "ChatProxyModel"); qmlRegisterType("Linphone", 1, 0, "ContactsListProxyModel"); diff --git a/linphone-desktop/src/components/Components.hpp b/linphone-desktop/src/components/Components.hpp index 0e245df2c..f4537e528 100644 --- a/linphone-desktop/src/components/Components.hpp +++ b/linphone-desktop/src/components/Components.hpp @@ -24,6 +24,7 @@ #include "authentication/Authentication.hpp" #include "calls/CallsListModel.hpp" #include "camera/Camera.hpp" +#include "camera/CameraPreview.hpp" #include "chat/ChatProxyModel.hpp" #include "codecs/AudioCodecsModel.hpp" #include "codecs/VideoCodecsModel.hpp" diff --git a/linphone-desktop/src/components/call/CallModel.cpp b/linphone-desktop/src/components/call/CallModel.cpp index 4f30cc964..37d5dd964 100644 --- a/linphone-desktop/src/components/call/CallModel.cpp +++ b/linphone-desktop/src/components/call/CallModel.cpp @@ -123,8 +123,8 @@ void CallModel::setRecordFile (shared_ptr &callParams) { ); } -void CallModel::updateStats (const linphone::CallStats &stats) { - switch (stats.getType()) { +void CallModel::updateStats (const shared_ptr &stats) { + switch (stats->getType()) { case linphone::StreamTypeAudio: updateStats(stats, mAudioStats); break; @@ -426,12 +426,12 @@ inline QVariantMap createStat (const QString &key, const QString &value) { return m; } -void CallModel::updateStats (const linphone::CallStats &callStats, QVariantList &stats) { +void CallModel::updateStats (const shared_ptr &callStats, QVariantList &stats) { QString family; shared_ptr params = mLinphoneCall->getCurrentParams(); shared_ptr payloadType; - switch (callStats.getType()) { + switch (callStats->getType()) { case linphone::StreamTypeAudio: payloadType = params->getUsedAudioPayloadType(); break; @@ -442,7 +442,7 @@ void CallModel::updateStats (const linphone::CallStats &callStats, QVariantList return; } - switch (callStats.getIpFamilyOfRemote()) { + switch (callStats->getIpFamilyOfRemote()) { case linphone::AddressFamilyInet: family = "IPv4"; break; @@ -459,16 +459,16 @@ void CallModel::updateStats (const linphone::CallStats &callStats, QVariantList stats << createStat(tr("callStatsCodec"), payloadType ? QString("%1 / %2kHz").arg(Utils::linphoneStringToQString(payloadType->getMimeType())).arg(payloadType->getClockRate() / 1000) : ""); - stats << createStat(tr("callStatsUploadBandwidth"), QString("%1 kbits/s").arg(int(callStats.getUploadBandwidth()))); - stats << createStat(tr("callStatsDownloadBandwidth"), QString("%1 kbits/s").arg(int(callStats.getDownloadBandwidth()))); - stats << createStat(tr("callStatsIceState"), iceStateToString(callStats.getIceState())); + stats << createStat(tr("callStatsUploadBandwidth"), QString("%1 kbits/s").arg(int(callStats->getUploadBandwidth()))); + stats << createStat(tr("callStatsDownloadBandwidth"), QString("%1 kbits/s").arg(int(callStats->getDownloadBandwidth()))); + stats << createStat(tr("callStatsIceState"), iceStateToString(callStats->getIceState())); stats << createStat(tr("callStatsIpFamily"), family); - stats << createStat(tr("callStatsSenderLossRate"), QString("%1 %").arg(callStats.getSenderLossRate())); - stats << createStat(tr("callStatsReceiverLossRate"), QString("%1 %").arg(callStats.getReceiverLossRate())); + stats << createStat(tr("callStatsSenderLossRate"), QString("%1 %").arg(callStats->getSenderLossRate())); + stats << createStat(tr("callStatsReceiverLossRate"), QString("%1 %").arg(callStats->getReceiverLossRate())); - switch (callStats.getType()) { + switch (callStats->getType()) { case linphone::StreamTypeAudio: - stats << createStat(tr("callStatsJitterBuffer"), QString("%1 ms").arg(callStats.getJitterBufferSizeMs())); + stats << createStat(tr("callStatsJitterBuffer"), QString("%1 ms").arg(callStats->getJitterBufferSizeMs())); break; case linphone::StreamTypeVideo: { QString sentVideoDefinitionName = Utils::linphoneStringToQString(params->getSentVideoDefinition()->getName()); diff --git a/linphone-desktop/src/components/call/CallModel.hpp b/linphone-desktop/src/components/call/CallModel.hpp index b399021d5..04dd0a066 100644 --- a/linphone-desktop/src/components/call/CallModel.hpp +++ b/linphone-desktop/src/components/call/CallModel.hpp @@ -72,7 +72,7 @@ public: } static void setRecordFile (std::shared_ptr &callParams); - void updateStats (const linphone::CallStats &stats); + void updateStats (const std::shared_ptr &stats); Q_INVOKABLE void accept (); Q_INVOKABLE void acceptWithVideo (); @@ -126,7 +126,7 @@ private: QVariantList getAudioStats () const; QVariantList getVideoStats () const; - void updateStats (const linphone::CallStats &callStats, QVariantList &stats); + void updateStats (const std::shared_ptr &callStats, QVariantList &stats); QString iceStateToString (linphone::IceState state) const; diff --git a/linphone-desktop/src/components/camera/Camera.cpp b/linphone-desktop/src/components/camera/Camera.cpp index 4e6a226fd..f75058d24 100644 --- a/linphone-desktop/src/components/camera/Camera.cpp +++ b/linphone-desktop/src/components/camera/Camera.cpp @@ -20,13 +20,11 @@ * Author: Ronan Abhamon */ -#include "../../Utils.hpp" #include "../core/CoreManager.hpp" #include "MSFunctions.hpp" #include "Camera.hpp" -#include #include #include #include @@ -91,9 +89,6 @@ QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize & } void CameraRenderer::render () { - if (!mLinphoneCall) - return; - // Draw with ms filter. { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); @@ -101,16 +96,19 @@ void CameraRenderer::render () { f->glClearColor(0.f, 0.f, 0.f, 0.f); f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - CoreManager *core = CoreManager::getInstance(); + CoreManager *coreManager = CoreManager::getInstance(); + + coreManager->lockVideoRender(); MSFunctions *msFunctions = MSFunctions::getInstance(); - - core->lockVideoRender(); - msFunctions->bind(f); - mLinphoneCall->oglRender(mIsPreview); - msFunctions->bind(nullptr); - core->unlockVideoRender(); + if (mIsPreview) + coreManager->getCore()->previewOglRender(); + else if (mLinphoneCall) + mLinphoneCall->oglRender(); + + msFunctions->bind(nullptr); + coreManager->unlockVideoRender(); } // Synchronize opengl calls with QML. diff --git a/linphone-desktop/src/components/camera/CameraPreview.cpp b/linphone-desktop/src/components/camera/CameraPreview.cpp new file mode 100644 index 000000000..4bc43b519 --- /dev/null +++ b/linphone-desktop/src/components/camera/CameraPreview.cpp @@ -0,0 +1,147 @@ +/* + * CameraPreview.cpp + * Copyright (C) 2017 Belledonne Communications, Grenoble, France + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Created on: April 19, 2017 + * Author: Ronan Abhamon + */ + +#include "../core/CoreManager.hpp" +#include "MSFunctions.hpp" + +#include "CameraPreview.hpp" + +#include +#include +#include + +#define MAX_FPS 30 + +using namespace std; + +// ============================================================================= + +struct ContextInfo { + GLuint width; + GLuint height; + + OpenGlFunctions *functions; +}; + +// ----------------------------------------------------------------------------- + +CameraPreviewRenderer::CameraPreviewRenderer () { + mContextInfo = new ContextInfo(); +} + +CameraPreviewRenderer::~CameraPreviewRenderer () { + qInfo() << QStringLiteral("Delete context info:") << mContextInfo; + + CoreManager *core = CoreManager::getInstance(); + + core->lockVideoRender(); + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(nullptr); + core->unlockVideoRender(); + + delete mContextInfo; +} + +QOpenGLFramebufferObject *CameraPreviewRenderer::createFramebufferObject (const QSize &size) { + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + format.setInternalTextureFormat(GL_RGBA8); + format.setSamples(4); + + CoreManager *core = CoreManager::getInstance(); + + // It's not the same thread as render. + core->lockVideoRender(); + + mContextInfo->width = size.width(); + mContextInfo->height = size.height(); + mContextInfo->functions = MSFunctions::getInstance()->getFunctions(); + mUpdateContextInfo = true; + + updateWindowId(); + + core->unlockVideoRender(); + + return new QOpenGLFramebufferObject(size, format); +} + +void CameraPreviewRenderer::render () { + // Draw with ms filter. + { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + + f->glClearColor(0.f, 0.f, 0.f, 0.f); + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + CoreManager *coreManager = CoreManager::getInstance(); + + coreManager->lockVideoRender(); + MSFunctions *msFunctions = MSFunctions::getInstance(); + msFunctions->bind(f); + + coreManager->getCore()->previewOglRender(); + + msFunctions->bind(nullptr); + coreManager->unlockVideoRender(); + } + + // Synchronize opengl calls with QML. + if (mWindow) + mWindow->resetOpenGLState(); +} + +void CameraPreviewRenderer::synchronize (QQuickFramebufferObject *item) { + mWindow = item->window(); +} + +void CameraPreviewRenderer::updateWindowId () { + if (!mUpdateContextInfo) + return; + + mUpdateContextInfo = false; + + qInfo() << "Thread" << QThread::currentThread() << QStringLiteral("Set context info (width: %1, height: %2):") + .arg(mContextInfo->width).arg(mContextInfo->height) << mContextInfo; + + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(mContextInfo); +} + +// ----------------------------------------------------------------------------- + +CameraPreview::CameraPreview (QQuickItem *parent) : QQuickFramebufferObject(parent) { + // The fbo content must be y-mirrored because the ms rendering is y-inverted. + setMirrorVertically(true); + + mRefreshTimer = new QTimer(this); + mRefreshTimer->setInterval(1 / MAX_FPS * 1000); + + QObject::connect( + mRefreshTimer, &QTimer::timeout, + this, &QQuickFramebufferObject::update, + Qt::DirectConnection + ); + + mRefreshTimer->start(); +} + +QQuickFramebufferObject::Renderer *CameraPreview::createRenderer () const { + return new CameraPreviewRenderer(); +} diff --git a/linphone-desktop/src/components/camera/CameraPreview.hpp b/linphone-desktop/src/components/camera/CameraPreview.hpp new file mode 100644 index 000000000..1b9d9ccc6 --- /dev/null +++ b/linphone-desktop/src/components/camera/CameraPreview.hpp @@ -0,0 +1,72 @@ +/* + * CameraPreview.hpp + * Copyright (C) 2017 Belledonne Communications, Grenoble, France + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Created on: April 19, 2017 + * Author: Ronan Abhamon + */ + +#ifndef CAMERA_PREVIEW_H_ +#define CAMERA_PREVIEW_H_ + +#include +#include + +// ============================================================================= + +class CameraPreview; +struct ContextInfo; + +class CameraPreviewRenderer : public QQuickFramebufferObject::Renderer { + friend class CameraPreview; + +public: + CameraPreviewRenderer (); + ~CameraPreviewRenderer (); + +protected: + QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override; + void render () override; + void synchronize (QQuickFramebufferObject *item) override; + +private: + void updateWindowId (); + + ContextInfo *mContextInfo; + bool mUpdateContextInfo = false; + + QQuickWindow *mWindow; +}; + +// ----------------------------------------------------------------------------- + +class CameraPreview : public QQuickFramebufferObject { + friend class CameraPreviewRenderer; + + Q_OBJECT; + +public: + CameraPreview (QQuickItem *parent = Q_NULLPTR); + ~CameraPreview () = default; + + QQuickFramebufferObject::Renderer *createRenderer () const override; + +private: + QTimer *mRefreshTimer; +}; + +#endif // CAMERA_PREVIEW_H_ diff --git a/linphone-desktop/src/components/core/CoreHandlers.cpp b/linphone-desktop/src/components/core/CoreHandlers.cpp index 1ca6ee15d..f35d17b26 100644 --- a/linphone-desktop/src/components/core/CoreHandlers.cpp +++ b/linphone-desktop/src/components/core/CoreHandlers.cpp @@ -55,7 +55,7 @@ void CoreHandlers::onCallStateChanged ( void CoreHandlers::onCallStatsUpdated ( const shared_ptr &, const shared_ptr &call, - const linphone::CallStats &stats + const shared_ptr &stats ) { call->getData("call-model").updateStats(stats); } diff --git a/linphone-desktop/src/components/core/CoreHandlers.hpp b/linphone-desktop/src/components/core/CoreHandlers.hpp index 8c945d200..a7e529d07 100644 --- a/linphone-desktop/src/components/core/CoreHandlers.hpp +++ b/linphone-desktop/src/components/core/CoreHandlers.hpp @@ -57,7 +57,7 @@ private: void onCallStatsUpdated ( const std::shared_ptr &core, const std::shared_ptr &call, - const linphone::CallStats &stats + const std::shared_ptr &stats ) override; void onMessageReceived ( diff --git a/submodules/linphone b/submodules/linphone index 1dcd17198..101adaeab 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 1dcd17198ee56ef54a5bb03b477575e83c29892d +Subproject commit 101adaeab8d0f39b5523a68d5d67ae594274ca89 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 36186e9ec..dc46e818f 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 36186e9ec9ee478eacaa53b8d9e1e154d31aad89 +Subproject commit dc46e818fe9b621eca3c132dfebbed39f2f232e3 diff --git a/submodules/ortp b/submodules/ortp index 100146d7c..9759554cd 160000 --- a/submodules/ortp +++ b/submodules/ortp @@ -1 +1 @@ -Subproject commit 100146d7c09aea0bddcc6a10926f1ee528d42738 +Subproject commit 9759554cd788dc8254086b6a63b4cc74609b8535