diff --git a/linphone-desktop/assets/images/record_normal.svg b/linphone-desktop/assets/images/record_off.svg similarity index 100% rename from linphone-desktop/assets/images/record_normal.svg rename to linphone-desktop/assets/images/record_off.svg diff --git a/linphone-desktop/assets/images/record_hovered.svg b/linphone-desktop/assets/images/record_on.svg similarity index 100% rename from linphone-desktop/assets/images/record_hovered.svg rename to linphone-desktop/assets/images/record_on.svg diff --git a/linphone-desktop/assets/images/record_pressed.svg b/linphone-desktop/assets/images/record_pressed.svg deleted file mode 100644 index ed4de9499..000000000 --- a/linphone-desktop/assets/images/record_pressed.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - record_over - Created with Sketch. - - - - - - - - REC - - - - \ No newline at end of file diff --git a/linphone-desktop/assets/languages/en.ts b/linphone-desktop/assets/languages/en.ts index 79e1678ff..c2bbcbd13 100644 --- a/linphone-desktop/assets/languages/en.ts +++ b/linphone-desktop/assets/languages/en.ts @@ -359,10 +359,6 @@ Server url not configured. Incall - - saveScreenshotTitle - - acceptVideoDescription diff --git a/linphone-desktop/assets/languages/fr.ts b/linphone-desktop/assets/languages/fr.ts index 13d702994..feb66dabf 100644 --- a/linphone-desktop/assets/languages/fr.ts +++ b/linphone-desktop/assets/languages/fr.ts @@ -347,10 +347,6 @@ Url du serveur non configurée. Incall - - saveScreenshotTitle - - acceptVideoDescription diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc index 68f22694d..4da6187d2 100644 --- a/linphone-desktop/resources.qrc +++ b/linphone-desktop/resources.qrc @@ -127,9 +127,8 @@ assets/images/pause_on_normal.svg assets/images/pause_on_pressed.svg assets/images/pause_on_updating.svg - assets/images/record_hovered.svg - assets/images/record_normal.svg - assets/images/record_pressed.svg + assets/images/record_off.svg + assets/images/record_on.svg assets/images/screenshot_hovered.svg assets/images/screenshot_normal.svg assets/images/screenshot_pressed.svg diff --git a/linphone-desktop/src/app/Paths.cpp b/linphone-desktop/src/app/Paths.cpp index e50033a8e..3b52efa32 100644 --- a/linphone-desktop/src/app/Paths.cpp +++ b/linphone-desktop/src/app/Paths.cpp @@ -27,6 +27,7 @@ #endif // ifdef _WIN32 #define PATH_AVATARS (LINPHONE_FOLDER "avatars/") +#define PATH_CAPTURES (LINPHONE_FOLDER "captures/") #define PATH_LOGS (LINPHONE_FOLDER "logs/") #define PATH_THUMBNAILS (LINPHONE_FOLDER "thumbnails/") @@ -92,3 +93,7 @@ string Paths::getMessageHistoryFilepath () { string Paths::getThumbnailsDirPath () { return getDirectoryPath(MAIN_PATH + PATH_THUMBNAILS); } + +string Paths::getCapturesDirPath () { + return getDirectoryPath(MAIN_PATH + PATH_CAPTURES); +} diff --git a/linphone-desktop/src/app/Paths.hpp b/linphone-desktop/src/app/Paths.hpp index 555341d72..3621f1cfc 100644 --- a/linphone-desktop/src/app/Paths.hpp +++ b/linphone-desktop/src/app/Paths.hpp @@ -10,6 +10,7 @@ namespace Paths { std::string getCallHistoryFilepath (); std::string getConfigFilepath (); std::string getFriendsListFilepath (); + std::string getCapturesDirPath (); std::string getLogsDirpath (); std::string getMessageHistoryFilepath (); std::string getThumbnailsDirPath (); diff --git a/linphone-desktop/src/components/call/CallModel.cpp b/linphone-desktop/src/components/call/CallModel.cpp index 344080f1e..f56414955 100644 --- a/linphone-desktop/src/components/call/CallModel.cpp +++ b/linphone-desktop/src/components/call/CallModel.cpp @@ -1,3 +1,7 @@ +#include +#include + +#include "../../app/Paths.hpp" #include "../../utils.hpp" #include "../core/CoreManager.hpp" @@ -61,6 +65,17 @@ CallModel::CallModel (shared_ptr linphone_call) { // ----------------------------------------------------------------------------- +void CallModel::setRecordFile (shared_ptr &call_params) { + call_params->setRecordFile( + Paths::getCapturesDirPath() + + ::Utils::qStringToLinphoneString( + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss") + ) + ".mkv" + ); +} + +// ----------------------------------------------------------------------------- + void CallModel::accept () { CoreManager::getInstance()->getCore()->acceptCall(m_linphone_call); } @@ -78,8 +93,9 @@ void CallModel::transfer () { } void CallModel::acceptVideoRequest () { - shared_ptr params = m_linphone_call->getCurrentParams()->copy(); + shared_ptr params = CoreManager::getInstance()->getCore()->createCallParams(m_linphone_call); params->enableVideo(true); + CoreManager::getInstance()->getCore()->acceptCallUpdate(m_linphone_call, params); } @@ -87,6 +103,47 @@ void CallModel::rejectVideoRequest () { CoreManager::getInstance()->getCore()->acceptCallUpdate(m_linphone_call, m_linphone_call->getCurrentParams()); } +void CallModel::takeSnapshot () { + static QString old_name; + QString new_name = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss") + ".jpg"; + + if (new_name == old_name) { + qWarning() << "Unable to take snapshot. Wait one second."; + return; + } + + old_name = new_name; + + qInfo() << "Take snapshot of call:" << &m_linphone_call; + + m_linphone_call->takeVideoSnapshot( + Paths::getCapturesDirPath() + ::Utils::qStringToLinphoneString(new_name) + ); +} + +void CallModel::startRecording () { + if (m_recording) + return; + + qInfo() << "Start recording call:" << &m_linphone_call; + + m_linphone_call->startRecording(); + m_recording = true; + + emit recordingChanged(true); +} + +void CallModel::stopRecording () { + if (m_recording) { + qInfo() << "Stop recording call:" << &m_linphone_call; + + m_recording = false; + m_linphone_call->stopRecording(); + + emit recordingChanged(false); + } +} + // ----------------------------------------------------------------------------- QString CallModel::getSipAddress () const { @@ -215,3 +272,7 @@ bool CallModel::getUpdating () const { return true; } + +bool CallModel::getRecording () const { + return m_recording; +} diff --git a/linphone-desktop/src/components/call/CallModel.hpp b/linphone-desktop/src/components/call/CallModel.hpp index 056c584db..f2103b37f 100644 --- a/linphone-desktop/src/components/call/CallModel.hpp +++ b/linphone-desktop/src/components/call/CallModel.hpp @@ -21,6 +21,8 @@ class CallModel : public QObject { Q_PROPERTY(bool videoEnabled READ getVideoEnabled WRITE setVideoEnabled NOTIFY statusChanged); Q_PROPERTY(bool updating READ getUpdating NOTIFY statusChanged) + Q_PROPERTY(bool recording READ getRecording NOTIFY recordingChanged); + public: enum CallStatus { CallStatusConnected, @@ -40,6 +42,8 @@ public: return m_linphone_call; } + static void setRecordFile (shared_ptr &call_params); + Q_INVOKABLE void accept (); Q_INVOKABLE void acceptWithVideo (); Q_INVOKABLE void terminate (); @@ -48,10 +52,16 @@ public: Q_INVOKABLE void acceptVideoRequest (); Q_INVOKABLE void rejectVideoRequest (); + Q_INVOKABLE void takeSnapshot (); + + Q_INVOKABLE void startRecording (); + Q_INVOKABLE void stopRecording (); + signals: void statusChanged (CallStatus status); void microMutedChanged (bool status); void videoRequested (); + void recordingChanged (bool status); private: QString getSipAddress () const; @@ -75,9 +85,12 @@ private: bool getUpdating () const; + bool getRecording () const; + bool m_micro_muted = false; bool m_paused_by_remote = false; bool m_paused_by_user = false; + bool m_recording = false; std::shared_ptr m_linphone_call; }; diff --git a/linphone-desktop/src/components/calls/CallsListModel.cpp b/linphone-desktop/src/components/calls/CallsListModel.cpp index 23cebb2b5..6527212eb 100644 --- a/linphone-desktop/src/components/calls/CallsListModel.cpp +++ b/linphone-desktop/src/components/calls/CallsListModel.cpp @@ -70,6 +70,7 @@ void CallsListModel::launchAudioCall (const QString &sip_uri) const { shared_ptr params = core->createCallParams(nullptr); params->enableVideo(false); + CallModel::setRecordFile(params); core->inviteAddressWithParams(address, params); } @@ -84,6 +85,7 @@ void CallsListModel::launchVideoCall (const QString &sip_uri) const { shared_ptr params = core->createCallParams(nullptr); params->enableEarlyMediaSending(true); params->enableVideo(true); + CallModel::setRecordFile(params); core->inviteAddressWithParams(address, params); } diff --git a/linphone-desktop/ui/views/App/Calls/Incall.qml b/linphone-desktop/ui/views/App/Calls/Incall.qml index 3d905c4c6..2804cf1f2 100644 --- a/linphone-desktop/ui/views/App/Calls/Incall.qml +++ b/linphone-desktop/ui/views/App/Calls/Incall.qml @@ -33,11 +33,19 @@ Rectangle { Component.onCompleted: this.connect(call, 'videoRequested', function () { var dialog - // Close window if call is ended. + // Close dialog after 10s. + var timeout = Utils.setTimeout(incall, 10000, function () { + call.statusChanged.disconnect(endedHandler) + dialog.close() + call.rejectVideoRequest() + }) + + // Close dialog if call is ended. var endedHandler = function (status) { if (status === CallModel.CallStatusEnded) { - dialog.close() + Utils.clearTimeout(timeout) call.statusChanged.disconnect(endedHandler) + dialog.close() } } @@ -46,6 +54,7 @@ Rectangle { dialog = Utils.openConfirmDialog(window, { descriptionText: qsTr('acceptVideoDescription'), exitHandler: function (status) { + Utils.clearTimeout(timeout) call.statusChanged.disconnect(endedHandler) if (status) { @@ -118,43 +127,37 @@ Rectangle { width: parent.width - cameraActions.width - callQuality.width - CallStyle.header.contactDescription.width } + // ----------------------------------------------------------------------- + // Video actions. + // ----------------------------------------------------------------------- + Loader { id: cameraActions anchors.right: parent.right - active: call.videoEnabled && call.status !== CallModel.CallStatusEnded + active: call.status !== CallModel.CallStatusEnded sourceComponent: ActionBar { iconSize: CallStyle.header.iconSize ActionButton { icon: 'screenshot' + visible: call.videoEnabled - FileDialog { - id: fileDialog - - folder: shortcuts.home - selectExisting: false - title: qsTr('saveScreenshotTitle') - - onAccepted: cameraLoader.item.saveScreenshot(fileUrl) - } - - onClicked: { - // TODO: At this moment, FileDialog does not support default filename, use this name in the future: - //'linphone ' + ((new Date()).toLocaleString(Qt.locale(), 'yyyy-MM-dd hh:mm:ss')) + '.jpg' - - cameraLoader.item.takeScreenshot() - fileDialog.open() - } + onClicked: call.takeSnapshot() } - ActionButton { + ActionSwitch { + enabled: call.recording icon: 'record' + useStates: false + + onClicked: !enabled ? call.startRecording() : call.stopRecording() } ActionButton { icon: 'fullscreen' + visible: call.videoEnabled } } } @@ -242,15 +245,13 @@ Rectangle { } Loader { - id: cameraLoader - anchors.centerIn: parent sourceComponent: call.videoEnabled ? camera : avatar } } // ------------------------------------------------------------------------- - // Buttons. + // Action Buttons. // ------------------------------------------------------------------------- Item {