Commit 677712e8 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(ui/views/App/Calls/Incall): supports screenshots, video recording

parent 222f8810
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 41 (35326) - http://www.bohemiancoding.com/sketch -->
<title>record_over</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="record_over">
<path d="M20,40 C31.045695,40 40,31.045695 40,20 C40,8.954305 31.045695,0 20,0 C8.954305,0 0,8.954305 0,20 C0,31.045695 8.954305,40 20,40 Z" fill="#E8E8E8" opacity="0.85"></path>
<circle stroke="#FF5E00" cx="19.5" cy="15.5" r="5"></circle>
<circle fill="#FF5E00" cx="19.5" cy="15.5" r="3"></circle>
<text font-family="Arial-BoldMT, Arial" font-size="8" font-weight="bold" fill="#FF5E00">
<tspan x="11.5546875" y="29.5">REC</tspan>
</text>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -359,10 +359,6 @@ Server url not configured.</translation>
</context>
<context>
<name>Incall</name>
<message>
<source>saveScreenshotTitle</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>acceptVideoDescription</source>
<translation type="unfinished"></translation>
......
......@@ -347,10 +347,6 @@ Url du serveur non configurée.</translation>
</context>
<context>
<name>Incall</name>
<message>
<source>saveScreenshotTitle</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>acceptVideoDescription</source>
<translation type="unfinished"></translation>
......
......@@ -127,9 +127,8 @@
<file>assets/images/pause_on_normal.svg</file>
<file>assets/images/pause_on_pressed.svg</file>
<file>assets/images/pause_on_updating.svg</file>
<file>assets/images/record_hovered.svg</file>
<file>assets/images/record_normal.svg</file>
<file>assets/images/record_pressed.svg</file>
<file>assets/images/record_off.svg</file>
<file>assets/images/record_on.svg</file>
<file>assets/images/screenshot_hovered.svg</file>
<file>assets/images/screenshot_normal.svg</file>
<file>assets/images/screenshot_pressed.svg</file>
......
......@@ -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);
}
......@@ -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 ();
......
#include <QDateTime>
#include <QtDebug>
#include "../../app/Paths.hpp"
#include "../../utils.hpp"
#include "../core/CoreManager.hpp"
......@@ -61,6 +65,17 @@ CallModel::CallModel (shared_ptr<linphone::Call> linphone_call) {
// -----------------------------------------------------------------------------
void CallModel::setRecordFile (shared_ptr<linphone::CallParams> &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<linphone::CallParams> params = m_linphone_call->getCurrentParams()->copy();
shared_ptr<linphone::CallParams> 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;
}
......@@ -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<linphone::CallParams> &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<linphone::Call> m_linphone_call;
};
......
......@@ -70,6 +70,7 @@ void CallsListModel::launchAudioCall (const QString &sip_uri) const {
shared_ptr<linphone::CallParams> 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<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableEarlyMediaSending(true);
params->enableVideo(true);
CallModel::setRecordFile(params);
core->inviteAddressWithParams(address, params);
}
......
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment