Video management

This commit is contained in:
Julien Wadel 2024-04-09 16:36:22 +02:00
parent b6bddabcce
commit cba34e82c0
21 changed files with 129 additions and 53 deletions

View file

@ -53,7 +53,10 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
mDuration = call->getDuration();
mMicrophoneMuted = call->getMicrophoneMuted();
mSpeakerMuted = call->getSpeakerMuted();
mCameraEnabled = call->cameraEnabled();
// mCameraEnabled = call->cameraEnabled();
auto videoDirection = call->getCurrentParams()->getVideoDirection();
mCameraEnabled =
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
mState = LinphoneEnums::fromLinphone(call->getState());
mPeerAddress = Utils::coreStringToAppString(call->getRemoteAddress()->asStringUriOnly());
mStatus = LinphoneEnums::fromLinphone(call->getCallLog()->getStatus());
@ -355,6 +358,7 @@ bool CallCore::getCameraEnabled() const {
void CallCore::setCameraEnabled(bool enabled) {
if (mCameraEnabled != enabled) {
mCameraEnabled = enabled;
qWarning() << "CameraEnabled: " << mCameraEnabled;
emit cameraEnabledChanged();
}
}

View file

@ -62,7 +62,7 @@ class CallCore : public QObject, public AbstractObject {
Q_PROPERTY(LinphoneEnums::CallState transferState READ getTransferState NOTIFY transferStateChanged)
Q_PROPERTY(ConferenceGui *conference READ getConferenceGui NOTIFY conferenceChanged)
Q_PROPERTY(LinphoneEnums::ConferenceLayout conferenceVideoLayout READ getConferenceVideoLayout WRITE
lSetConferenceVideoLayout NOTIFY conferenceVideoLayoutChanged)
lSetConferenceVideoLayout NOTIFY conferenceVideoLayoutChanged)
public:
// Should be call from model Thread. Will be automatically in App thread after initialization
@ -180,6 +180,7 @@ signals:
void lSetSpeakerMuted(bool muted);
void lSetMicrophoneMuted(bool isMuted);
void lSetCameraEnabled(bool enabled);
void lSetVideoEnabled(bool enabled);
void lSetPaused(bool paused);
void lTransferCall(QString &est);
void lStartRecording();
@ -226,7 +227,8 @@ private:
int mDuration = 0;
bool mSpeakerMuted;
bool mMicrophoneMuted;
bool mCameraEnabled;
bool mCameraEnabled = false;
bool mVideoEnabled = false;
bool mPaused = false;
bool mRemoteVideoEnabled = false;
bool mRecording = false;

View file

@ -197,7 +197,7 @@ void CameraGui::setWindowIdLocation(const WindowIdLocation &location) {
if (mWindowIdLocation != location) {
lDebug() << log().arg("Update Window Id location from %2 to %3").arg(mWindowIdLocation).arg(location);
if (mWindowIdLocation == CorePreview) PreviewManager::getInstance()->unsubscribe(this);
else resetWindowId(); // Location change: Reset old window ID.
else if (mWindowIdLocation != None) resetWindowId(); // Location change: Reset old window ID.
mWindowIdLocation = location;
if (mWindowIdLocation == CorePreview) PreviewManager::getInstance()->subscribe(this);
update();

View file

@ -75,7 +75,7 @@ QQuickFramebufferObject::Renderer *PreviewManager::subscribe(const CameraGui *ca
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId();
}
if (isFirst) {
lDebug() << "[PreviewManager] " << name << " Set Native Preview Id";
lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer;
CoreModel::getInstance()->getCore()->setNativePreviewWindowId(renderer);
}
});
@ -118,9 +118,17 @@ void PreviewManager::unsubscribe(QObject *sender) {
}
void PreviewManager::activate() {
App::postModelBlock([]() { CoreModel::getInstance()->getCore()->enableVideoPreview(true); });
App::postModelBlock([]() {
qDebug() << "[PreviewManager] Activation";
CoreModel::getInstance()->getCore()->enableVideoPreview(true);
CoreModel::getInstance()->getCore()->iterate();
});
}
void PreviewManager::deactivate() {
App::postModelBlock([]() { CoreModel::getInstance()->getCore()->enableVideoPreview(false); });
App::postModelBlock([]() {
qDebug() << "[PreviewManager] Deactivation";
CoreModel::getInstance()->getCore()->enableVideoPreview(false);
CoreModel::getInstance()->getCore()->iterate();
});
}

View file

@ -34,6 +34,11 @@
<section name="sip">
<entry name="rls_uri" overwrite="true">sips:rls@sip.linphone.org</entry>
</section>
<section name="video">
<entry name="automatically_accept" overwrite="true">1</entry>
<entry name="automatically_initiate" overwrite="true">0</entry>
<entry name="automatically_accept_direction" overwrite="true">2</entry>
</section>
<section name="assistant">
<entry name="domain" overwrite="true">sip.linphone.org</entry>
<entry name="algorithm" overwrite="true">SHA-256</entry>

View file

@ -34,6 +34,11 @@
<section name="sip">
<entry name="rls_uri" overwrite="true">sips:rls@sip.linphone.org</entry>
</section>
<section name="video">
<entry name="automatically_accept" overwrite="true">1</entry>
<entry name="automatically_initiate" overwrite="true">0</entry>
<entry name="automatically_accept_direction" overwrite="true">2</entry>
</section>
<section name="assistant">
<entry name="domain" overwrite="true">sip.linphone.org</entry>
<entry name="algorithm" overwrite="true">SHA-256</entry>

View file

@ -30,6 +30,11 @@
<entry name="use_rls_presence" overwrite="true"></entry>
<entry name="rls_uri" overwrite="true"></entry>
</section>
<section name="video">
<entry name="automatically_accept" overwrite="true">1</entry>
<entry name="automatically_initiate" overwrite="true">0</entry>
<entry name="automatically_accept_direction" overwrite="true">2</entry>
</section>
<section name="assistant">
<entry name="domain" overwrite="true"></entry>
<entry name="algorithm" overwrite="true">MD5</entry>

View file

@ -124,11 +124,51 @@ void CallModel::setSpeakerMuted(bool isMuted) {
void CallModel::setCameraEnabled(bool enabled) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->enableCamera(enabled);
auto core = CoreModel::getInstance()->getCore();
auto params = core->createCallParams(mMonitor);
params->enableVideo(enabled);
emit cameraEnabledChanged(enabled);
// mMonitor->enableCamera(enabled);
auto params = CoreModel::getInstance()->getCore()->createCallParams(mMonitor);
params->enableVideo(true);
auto direction = mMonitor->getCurrentParams()->getVideoDirection();
auto videoDirection = linphone::MediaDirection::RecvOnly;
if (enabled) { // +Send
switch (direction) {
case linphone::MediaDirection::RecvOnly:
videoDirection = linphone::MediaDirection::SendRecv;
break;
case linphone::MediaDirection::SendOnly:
videoDirection = linphone::MediaDirection::SendOnly;
break;
case linphone::MediaDirection::SendRecv:
videoDirection = linphone::MediaDirection::SendRecv;
break;
default:
videoDirection = linphone::MediaDirection::SendOnly;
}
} else { // -Send
switch (direction) {
case linphone::MediaDirection::RecvOnly:
videoDirection = linphone::MediaDirection::RecvOnly;
break;
case linphone::MediaDirection::SendOnly:
videoDirection = linphone::MediaDirection::Inactive;
break;
case linphone::MediaDirection::SendRecv:
videoDirection = linphone::MediaDirection::RecvOnly;
break;
default:
videoDirection = linphone::MediaDirection::Inactive;
}
}
/*
auto videoDirection =
!enabled ? linphone::MediaDirection::RecvOnly
: direction == linphone::MediaDirection::RecvOnly //
? linphone::MediaDirection::SendRecv
: direction == linphone::MediaDirection::SendRecv || direction == linphone::MediaDirection::SendOnly
? linphone::MediaDirection::RecvOnly
: linphone::MediaDirection::SendOnly;
*/
params->setVideoDirection(videoDirection);
mMonitor->update(params);
}
void CallModel::startRecording() {
@ -319,7 +359,11 @@ void CallModel::onStateChanged(const std::shared_ptr<linphone::Call> &call,
// After UpdatedByRemote, video direction could be changed.
auto params = call->getRemoteParams();
emit remoteVideoEnabledChanged(params && params->videoEnabled());
emit cameraEnabledChanged(call->cameraEnabled());
qWarning() << "CallCameraEnabled:" << call->cameraEnabled();
auto videoDirection = call->getCurrentParams()->getVideoDirection();
emit cameraEnabledChanged(videoDirection == linphone::MediaDirection::SendOnly ||
videoDirection == linphone::MediaDirection::SendRecv);
// emit cameraEnabledChanged(call->cameraEnabled());
setConference(call->getConference());
updateConferenceVideoLayout();
}

View file

@ -157,7 +157,7 @@ signals:
void cameraNotWorking(const std::shared_ptr<linphone::Call> &call, const std::string &cameraName);
void videoDisplayErrorOccurred(const std::shared_ptr<linphone::Call> &call, int errorCode);
void audioDeviceChanged(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::AudioDevice> &audioDevice);
const std::shared_ptr<linphone::AudioDevice> &audioDevice);
void remoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording);
};

View file

@ -94,12 +94,13 @@ QString ToolModel::getDisplayName(QString address) {
}
QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
bool withVideo,
const QVariantMap &options,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers,
linphone::MediaEncryption mediaEncryption) {
bool waitRegistrationForCall = true; // getSettingsModel()->getWaitRegistrationForCall()
std::shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
bool cameraEnabled = options.contains("cameraEnabled") ? options["cameraEnabled"].toBool() : false;
std::shared_ptr<linphone::Address> address = interpretUrl(sipAddress);
if (!address) {
@ -109,7 +110,9 @@ QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
}
std::shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(withVideo);
params->enableVideo(true);
params->setVideoDirection(cameraEnabled ? linphone::MediaDirection::SendRecv : linphone::MediaDirection::Inactive);
params->setMediaEncryption(mediaEncryption);
if (Utils::coreStringToAppString(params->getRecordFile()).isEmpty()) {
@ -129,7 +132,7 @@ QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
auto call = core->inviteAddressWithParams(address, params);
call->enableCamera(withVideo);
call->enableCamera(cameraEnabled);
return call ? CallCore::create(call) : nullptr;
/* TODO transfer

View file

@ -47,7 +47,7 @@ public:
static QString getDisplayName(QString address);
static QSharedPointer<CallCore> createCall(const QString &sipAddress,
bool withVideo = false,
const QVariantMap &options = {},
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {},
linphone::MediaEncryption = linphone::MediaEncryption::None);

View file

@ -94,14 +94,14 @@ QString Utils::getInitials(const QString &username) {
return QLocale().toUpper(initials.join(""));
}
VariantObject *Utils::createCall(const QString &sipAddress,
bool withVideo,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) {
VariantObject *Utils::createCall(QString sipAddress,
QVariantMap options,
QString prepareTransfertAddress,
QHash<QString, QString> headers) {
VariantObject *data = new VariantObject(QVariant()); // Scope : GUI
if (!data) return nullptr;
data->makeRequest([sipAddress, withVideo, prepareTransfertAddress, headers]() {
auto call = ToolModel::createCall(sipAddress, withVideo, prepareTransfertAddress, headers);
data->makeRequest([sipAddress, options, prepareTransfertAddress, headers]() {
auto call = ToolModel::createCall(sipAddress, options, prepareTransfertAddress, headers);
if (call) {
auto callGui = QVariant::fromValue(new CallGui(call));
App::postCoreSync([callGui]() {

View file

@ -58,10 +58,10 @@ public:
Q_INVOKABLE static QString getFamilyNameFromFullName(const QString &fullName);
Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32
Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress,
bool withVideo = false,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
Q_INVOKABLE static VariantObject *createCall(QString sipAddress,
QVariantMap options = {},
QString prepareTransfertAddress = "",
QHash<QString, QString> headers = {});
Q_INVOKABLE static void openCallsWindow(CallGui *call);
Q_INVOKABLE static void setupConference(ConferenceInfoGui *confGui);
Q_INVOKABLE static void setCallsWindowCall(CallGui *call);

View file

@ -34,10 +34,10 @@ Window {
}
property var callObj
function joinConference(withVideo) {
function joinConference(options) {
if (!conferenceInfo || conferenceInfo.core.uri.length === 0) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence n'a pas pu démarrer en raison d'une erreur d'uri."), mainWindow)
else {
callObj = UtilsCpp.createCall(conferenceInfo.core.uri, withVideo)
callObj = UtilsCpp.createCall(conferenceInfo.core.uri, options)
}
}
@ -789,14 +789,7 @@ Window {
target: rightPanel
onVisibleChanged: if (!visible) waitingRoomIn.settingsButtonChecked = false
}
Connections {
target: mainWindow
onCallChanged: if (mainWindow.conferenceInfo && mainWindow.call) {
mainWindow.call.core.lSetCameraEnabled(waitingRoomIn.cameraEnabled)
mainWindow.call.core.lSetMicrophoneMuted(!waitingRoomIn.microEnabled)
}
}
onJoinConfRequested: mainWindow.joinConference(cameraEnabled)
onJoinConfRequested: mainWindow.joinConference({'microEnabled':microEnabled, 'cameraEnabled':cameraEnabled})
}
}
Component {

View file

@ -245,7 +245,7 @@ Item {
height: 24 * DefaultStyle.dp
source: AppIcons.videoCamera
}
onClicked: mainItem.callObj = UtilsCpp.createCall(sipAddr.text, true)
onClicked: mainItem.callObj = UtilsCpp.createCall(sipAddr.text, {'cameraEnabled':true})
}
}
Button {

View file

@ -22,6 +22,7 @@ RowLayout {
// Layout.leftMargin: 97 * DefaultStyle.dp
Sticker {
id: preview
previewEnabled: true
Layout.preferredHeight: 330 * DefaultStyle.dp
Layout.preferredWidth: 558 * DefaultStyle.dp
qmlName: "WP"
@ -29,7 +30,6 @@ RowLayout {
id: accounts
}
account: accounts.defaultAccount
previewEnabled: true
}
RowLayout {
Layout.alignment: Qt.AlignHCenter

View file

@ -169,7 +169,7 @@ ListView {
height: 24 * DefaultStyle.dp
source: AppIcons.videoCamera
}
onClicked: callObj = UtilsCpp.createCall(modelData.core.defaultAddress, true)
onClicked: callObj = UtilsCpp.createCall(modelData.core.defaultAddress, {'cameraEnabled':true})
}
}
PopupButton {

View file

@ -14,19 +14,23 @@ Item {
id: mainItem
height: 300
width: 200
required property bool previewEnabled
property CallGui call: null
property AccountGui account: null
property ParticipantDeviceGui participantDevice: null
property bool previewEnabled: false
property bool displayBorder : participantDevice && participantDevice.core.isSpeaking || false
property color color: DefaultStyle.grey_600
property int radius: 15 * DefaultStyle.dp
property var peerAddressObj: participantDevice && participantDevice.core
? UtilsCpp.getDisplayName(participantDevice.core.address)
: !previewEnabled && call && call.core
? UtilsCpp.getDisplayName(call.core.peerAddress)
: null
property var peerAddressObj: previewEnabled
? UtilsCpp.getDisplayName(account.core.identityAddress)
: participantDevice && participantDevice.core
? UtilsCpp.getDisplayName(participantDevice.core.address)
: !previewEnabled && call && call.core
? UtilsCpp.getDisplayName(call.core.peerAddress)
: null
property string peerAddress:peerAddressObj ? peerAddressObj.value : ""
onPeerAddressChanged: console.log("TOTO " +qmlName + " => " +peerAddress)
property var identityAddress: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : null
property bool cameraEnabled: previewEnabled || participantDevice && participantDevice.core.videoEnabled
property string qmlName
@ -97,9 +101,10 @@ Item {
anchors.fill: parent
visible: false
qmlName: mainItem.qmlName
isPreview: mainItem.previewEnabled
call: mainItem.call
participantDevice: mainItem.participantDevice
isPreview: mainItem.previewEnabled
onRequestNewRenderer: {
console.log("Request new renderer for " +mainItem.qmlName)
resetTimer.restart()

View file

@ -31,6 +31,7 @@ Item{
Sticker {
id: activeSpeakerSticker
previewEnabled: false
Layout.fillWidth: true
Layout.fillHeight: true
call: mainItem.call
@ -88,14 +89,14 @@ Item{
clip: true
delegate:
Sticker {
visible: mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released
previewEnabled: index == 0
visible: modelData && mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released
&& modelData.core.address != activeSpeakerSticker.address
height: visible ? 180 * DefaultStyle.dp : 0
width: 300 * DefaultStyle.dp
qmlName: 'S_'+index
participantDevice: modelData
previewEnabled: index == 0
Component.onCompleted: console.log(qmlName + " is " +modelData.core.address)
}
}
@ -115,7 +116,8 @@ Item{
//participantDevice: allDevices.me
cameraEnabled: preview.visible && mainItem.call && mainItem.call.core.cameraEnabled
onCameraEnabledChanged: console.log("P : " +cameraEnabled + " / " +visible +" / " +mainItem.call)
property AccountProxy accounts: AccountProxy{id: accountProxy}
account: accountProxy.defaultAccount
call: mainItem.call
MovableMouseArea {

View file

@ -33,12 +33,12 @@ Mosaic {
width: grid.cellWidth - 10
Sticker {
id: cameraView
previewEnabled: index == 0
visible: mainItem.callState != LinphoneEnums.CallState.End && mainItem.callState != LinphoneEnums.CallState.Released
anchors.fill: parent
qmlName: 'G_'+index
participantDevice: avatarCell.currentDevice
previewEnabled: index == 0
Component.onCompleted: console.log(qmlName + " is " +modelData.core.address)
}
/*

@ -1 +1 @@
Subproject commit 0dda330ac9ccd7f5b495ac147e88ff7dbb620762
Subproject commit 1f9db257fe224ea6d9b067e69ee6b9f72102e129