diff --git a/linphone-desktop/assets/languages/en.ts b/linphone-desktop/assets/languages/en.ts
index d28e5bb8a..d95f0da50 100644
--- a/linphone-desktop/assets/languages/en.ts
+++ b/linphone-desktop/assets/languages/en.ts
@@ -357,6 +357,17 @@ Server url not configured.
Status
+
+ Conference
+
+ conferenceTitle
+ CONFERENCE
+
+
+ pendingRequestLabel
+ Please to wait, a request is pending.
+
+
ConferenceManager
diff --git a/linphone-desktop/assets/languages/fr.ts b/linphone-desktop/assets/languages/fr.ts
index 4e9643974..3e93740b9 100644
--- a/linphone-desktop/assets/languages/fr.ts
+++ b/linphone-desktop/assets/languages/fr.ts
@@ -357,6 +357,17 @@ Url du serveur non configurée.
Status
+
+ Conference
+
+ conferenceTitle
+ CONFÉRENCE
+
+
+ pendingRequestLabel
+ Merci de patienter, une requête est en attente.
+
+
ConferenceManager
diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc
index 5be4da53f..8cb03098b 100644
--- a/linphone-desktop/resources.qrc
+++ b/linphone-desktop/resources.qrc
@@ -355,6 +355,7 @@
ui/views/App/Calls/CallsWindow.js
ui/views/App/Calls/CallsWindow.qml
ui/views/App/Calls/ConferenceManager.qml
+ ui/views/App/Calls/Conference.qml
ui/views/App/Calls/EndedCall.qml
ui/views/App/Calls/IncallFullscreenWindow.qml
ui/views/App/Calls/Incall.js
diff --git a/linphone-desktop/src/components/call/CallModel.cpp b/linphone-desktop/src/components/call/CallModel.cpp
index e170a02aa..d5f6fcdd7 100644
--- a/linphone-desktop/src/components/call/CallModel.cpp
+++ b/linphone-desktop/src/components/call/CallModel.cpp
@@ -79,9 +79,10 @@ QString CallModel::getSipAddress () const {
void CallModel::setRecordFile (shared_ptr &callParams) {
callParams->setRecordFile(
::Utils::qStringToLinphoneString(
- CoreManager::getInstance()->getSettingsModel()->getSavedVideosFolder() +
- QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss")
- ) + ".mkv"
+ QStringLiteral("%1%2.mkv")
+ .arg(CoreManager::getInstance()->getSettingsModel()->getSavedVideosFolder())
+ .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss"))
+ )
);
}
@@ -183,14 +184,15 @@ void CallModel::startRecording () {
}
void CallModel::stopRecording () {
- if (mRecording) {
- qInfo() << QStringLiteral("Stop recording call:") << this;
+ if (!mRecording)
+ return;
- mRecording = false;
- mCall->stopRecording();
+ qInfo() << QStringLiteral("Stop recording call:") << this;
- emit recordingChanged(false);
- }
+ mRecording = false;
+ mCall->stopRecording();
+
+ emit recordingChanged(false);
}
// -----------------------------------------------------------------------------
diff --git a/linphone-desktop/src/components/conference/ConferenceModel.cpp b/linphone-desktop/src/components/conference/ConferenceModel.cpp
index 5bdbefb38..8ecd9cb1a 100644
--- a/linphone-desktop/src/components/conference/ConferenceModel.cpp
+++ b/linphone-desktop/src/components/conference/ConferenceModel.cpp
@@ -20,8 +20,15 @@
* Author: Ronan Abhamon
*/
+#include
+
+#include "../../Utils.hpp"
+#include "../core/CoreManager.hpp"
+
#include "ConferenceModel.hpp"
+using namespace std;
+
// =============================================================================
ConferenceModel::ConferenceModel (QObject *parent) : QAbstractListModel(parent) {}
@@ -47,3 +54,57 @@ QVariant ConferenceModel::data (const QModelIndex &index, int role) const {
return QVariant();
}
+
+// -----------------------------------------------------------------------------
+
+void ConferenceModel::startRecording () {
+ if (mRecording)
+ return;
+
+ qInfo() << QStringLiteral("Start recording conference:") << this;
+
+ CoreManager *coreManager = CoreManager::getInstance();
+ coreManager->getCore()->startConferenceRecording(
+ ::Utils::qStringToLinphoneString(
+ QStringLiteral("%1%2.mkv")
+ .arg(coreManager->getSettingsModel()->getSavedVideosFolder())
+ .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss"))
+ )
+ );
+ mRecording = true;
+
+ emit recordingChanged(true);
+}
+
+void ConferenceModel::stopRecording () {
+ if (!mRecording)
+ return;
+
+ qInfo() << QStringLiteral("Stop recording conference:") << this;
+
+ mRecording = false;
+ CoreManager::getInstance()->getCore()->stopConferenceRecording();
+
+ emit recordingChanged(false);
+}
+
+// -----------------------------------------------------------------------------
+
+bool ConferenceModel::getMicroMuted () const {
+ return !CoreManager::getInstance()->getCore()->micEnabled();
+}
+
+void ConferenceModel::setMicroMuted (bool status) {
+ shared_ptr core = CoreManager::getInstance()->getCore();
+
+ if (status == core->micEnabled()) {
+ core->enableMic(!status);
+ emit microMutedChanged(status);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool ConferenceModel::getRecording () const {
+ return mRecording;
+}
diff --git a/linphone-desktop/src/components/conference/ConferenceModel.hpp b/linphone-desktop/src/components/conference/ConferenceModel.hpp
index 72e930d35..ab06e3bd1 100644
--- a/linphone-desktop/src/components/conference/ConferenceModel.hpp
+++ b/linphone-desktop/src/components/conference/ConferenceModel.hpp
@@ -28,6 +28,12 @@
// =============================================================================
class ConferenceModel : public QAbstractListModel {
+ Q_OBJECT;
+
+ Q_PROPERTY(bool microMuted READ getMicroMuted WRITE setMicroMuted NOTIFY microMutedChanged);
+
+ Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged);
+
public:
ConferenceModel (QObject *parent = Q_NULLPTR);
~ConferenceModel () = default;
@@ -37,7 +43,21 @@ public:
QHash roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ Q_INVOKABLE void startRecording ();
+ Q_INVOKABLE void stopRecording ();
+
+signals:
+ void microMutedChanged (bool status);
+ void recordingChanged (bool status);
+
private:
+ bool getMicroMuted () const;
+ void setMicroMuted (bool status);
+
+ bool getRecording () const;
+
+ bool mRecording = false;
+
QStringList mSipAddresses;
};
diff --git a/linphone-desktop/ui/views/App/Calls/Conference.qml b/linphone-desktop/ui/views/App/Calls/Conference.qml
new file mode 100644
index 000000000..22e5b55fc
--- /dev/null
+++ b/linphone-desktop/ui/views/App/Calls/Conference.qml
@@ -0,0 +1,216 @@
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+import Common 1.0
+import Linphone 1.0
+import LinphoneUtils 1.0
+import Utils 1.0
+
+import App.Styles 1.0
+
+//import 'Conference.js' as Logic
+
+// =============================================================================
+
+Rectangle {
+ property var call: null // TODO: Remove me
+
+ color: CallStyle.backgroundColor
+
+ // ---------------------------------------------------------------------------
+
+ ConferenceModel {
+ id: conference
+ }
+
+ ColumnLayout {
+ anchors {
+ fill: parent
+ topMargin: CallStyle.header.topMargin
+ }
+
+ spacing: 0
+
+ // -------------------------------------------------------------------------
+ // Call info.
+ // -------------------------------------------------------------------------
+
+ Item {
+ id: info
+
+ Layout.fillWidth: true
+ Layout.leftMargin: CallStyle.header.leftMargin
+ Layout.rightMargin: CallStyle.header.rightMargin
+ Layout.preferredHeight: CallStyle.header.conferenceDescription.height
+
+ ActionBar {
+ id: leftActions
+
+ anchors.left: parent.left
+ iconSize: CallStyle.header.iconSize
+ }
+
+ Text {
+ id: conferenceDescription
+
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: qsTr('conferenceTitle')
+
+ height: parent.height
+ width: parent.width - rightActions.width - leftActions.width - CallStyle.header.conferenceDescription.width
+ }
+
+ // -----------------------------------------------------------------------
+ // Video actions.
+ // -----------------------------------------------------------------------
+
+ ActionBar {
+ id: rightActions
+
+ anchors.right: parent.right
+ iconSize: CallStyle.header.iconSize
+
+ ActionSwitch {
+ enabled: conference.recording
+ icon: 'record'
+ useStates: false
+
+ onClicked: !enabled
+ ? conference.startRecording()
+ : conference.stopRecording()
+ }
+ }
+ }
+
+ Text {
+ id: elapsedTime
+
+ Layout.fillWidth: true
+ color: CallStyle.header.elapsedTime.color
+ font.pointSize: CallStyle.header.elapsedTime.fontSize
+ horizontalAlignment: Text.AlignHCenter
+
+ Timer {
+ interval: 1000
+ repeat: true
+ running: true
+ triggeredOnStart: true
+
+ onTriggered: elapsedTime.text = Utils.formatElapsedTime(conference.duration)
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Contacts visual.
+ // -------------------------------------------------------------------------
+
+ Item {
+ id: container
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: CallStyle.container.margins
+ }
+
+ // -------------------------------------------------------------------------
+ // Action Buttons.
+ // -------------------------------------------------------------------------
+
+ Item {
+ Layout.fillWidth: true
+ Layout.preferredHeight: CallStyle.actionArea.height
+
+ RowLayout {
+ anchors {
+ left: parent.left
+ leftMargin: CallStyle.actionArea.leftButtonsGroupMargin
+ verticalCenter: parent.verticalCenter
+ }
+
+ spacing: ActionBarStyle.spacing
+
+ Row {
+ spacing: CallStyle.actionArea.vu.spacing
+
+ VuMeter {
+ Timer {
+ interval: 50
+ repeat: true
+ running: micro.enabled
+
+ onTriggered: parent.value = conference.microVu
+ }
+
+ enabled: micro.enabled
+ }
+
+ ActionSwitch {
+ id: micro
+
+ enabled: !conference.microMuted
+ icon: 'micro'
+ iconSize: CallStyle.actionArea.iconSize
+
+ onClicked: conference.microMuted = enabled
+ }
+ }
+
+ Row {
+ spacing: CallStyle.actionArea.vu.spacing
+
+ VuMeter {
+ Timer {
+ interval: 50
+ repeat: true
+ running: speaker.enabled
+
+ onTriggered: parent.value = conference.speakerVu
+ }
+
+ enabled: speaker.enabled
+ }
+
+ ActionSwitch {
+ id: speaker
+
+ enabled: true
+ icon: 'speaker'
+ iconSize: CallStyle.actionArea.iconSize
+
+ onClicked: console.log('TODO')
+ }
+ }
+ }
+
+ ActionBar {
+ anchors {
+ right: parent.right
+ rightMargin: CallStyle.actionArea.rightButtonsGroupMargin
+ verticalCenter: parent.verticalCenter
+ }
+ iconSize: CallStyle.actionArea.iconSize
+
+ ActionSwitch {
+ enabled: !conference.pausedByUser
+ icon: 'pause'
+ updating: conference.updating
+
+ onClicked: conference.pausedByUser = enabled
+
+ TooltipArea {
+ text: qsTr('pendingRequestLabel')
+ visible: parent.updating
+ }
+ }
+
+ ActionButton {
+ icon: 'hangup'
+
+ onClicked: conference.terminate()
+ }
+ }
+ }
+ }
+}