mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 11:00:48 +03:00
VoIP v1 implementation (#1161)
* Initial commit for VoIP v1 implementation * Added draft of event handlers for voip methods * Added event handlers for VoIP events, added rejectCall, added version tracking for call version for V0 and V1 compatibility * Added call events to the general message pipeline. Modified Call Reject mechanism * Added message delegates for new events. Modified hidden events. Updated handle events. * Updated implementation to keep track of calls on other devices * Fixed linting * Fixed code warnings * Fixed minor bugs * fixed ci * Added acceptNegotiation method definition when missing gstreamer * Fixed warnings * Fixed linting
This commit is contained in:
parent
8a4bb32b4a
commit
ac48c33286
19 changed files with 583 additions and 79 deletions
|
@ -46,14 +46,14 @@ Rectangle {
|
||||||
|
|
||||||
ImageButton {
|
ImageButton {
|
||||||
visible: CallManager.callsSupported && showAllButtons
|
visible: CallManager.callsSupported && showAllButtons
|
||||||
opacity: CallManager.haveCallInvite ? 0.3 : 1
|
opacity: (CallManager.haveCallInvite || CallManager.isOnCallOnOtherDevice) ? 0.3 : 1
|
||||||
Layout.alignment: Qt.AlignBottom
|
Layout.alignment: Qt.AlignBottom
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
width: 22
|
width: 22
|
||||||
height: 22
|
height: 22
|
||||||
image: CallManager.isOnCall ? ":/icons/icons/ui/end-call.svg" : ":/icons/icons/ui/place-call.svg"
|
image: CallManager.isOnCall ? ":/icons/icons/ui/end-call.svg" : ":/icons/icons/ui/place-call.svg"
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call")
|
ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : (CallManager.isOnCallOnOtherDevice ? qsTr("Already on a call") : qsTr("Place a call"))
|
||||||
Layout.margins: 8
|
Layout.margins: 8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (room) {
|
if (room) {
|
||||||
|
@ -61,7 +61,11 @@ Rectangle {
|
||||||
return ;
|
return ;
|
||||||
} else if (CallManager.isOnCall) {
|
} else if (CallManager.isOnCall) {
|
||||||
CallManager.hangUp();
|
CallManager.hangUp();
|
||||||
} else {
|
}
|
||||||
|
else if(CallManager.isOnCallOnOtherDevice) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
var dialog = placeCallDialog.createObject(timelineRoot);
|
var dialog = placeCallDialog.createObject(timelineRoot);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
timelineRoot.destroyOnClose(dialog);
|
timelineRoot.destroyOnClose(dialog);
|
||||||
|
|
|
@ -378,6 +378,34 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.CallReject
|
||||||
|
|
||||||
|
NoticeMessage {
|
||||||
|
body: formatted
|
||||||
|
isOnlyEmoji: false
|
||||||
|
isReply: d.isReply
|
||||||
|
keepFullText: d.keepFullText
|
||||||
|
isStateEvent: d.isStateEvent
|
||||||
|
formatted: qsTr("%1 rejected the call.").arg(d.userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.CallSelectAnswer
|
||||||
|
|
||||||
|
NoticeMessage {
|
||||||
|
body: formatted
|
||||||
|
isOnlyEmoji: false
|
||||||
|
isReply: d.isReply
|
||||||
|
keepFullText: d.keepFullText
|
||||||
|
isStateEvent: d.isStateEvent
|
||||||
|
formatted: qsTr("%1 select answer").arg(d.userName)
|
||||||
|
// formatted: qsTr("Call answered elsewhere")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: MtxEvent.CallHangUp
|
roleValue: MtxEvent.CallHangUp
|
||||||
|
|
||||||
|
@ -406,6 +434,20 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.CallNegotiate
|
||||||
|
|
||||||
|
NoticeMessage {
|
||||||
|
body: formatted
|
||||||
|
isOnlyEmoji: false
|
||||||
|
isReply: d.isReply
|
||||||
|
keepFullText: d.keepFullText
|
||||||
|
isStateEvent: d.isStateEvent
|
||||||
|
formatted: qsTr("%1 is negotiating the call...").arg(d.userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: MtxEvent.PowerLevels
|
roleValue: MtxEvent.PowerLevels
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Qt.labs.platform 1.1 as P
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
|
import "../voip"
|
||||||
|
|
||||||
P.MessageDialog {
|
P.MessageDialog {
|
||||||
id: leaveRoomRoot
|
id: leaveRoomRoot
|
||||||
|
@ -18,5 +19,14 @@ P.MessageDialog {
|
||||||
text: qsTr("Are you sure you want to leave?")
|
text: qsTr("Are you sure you want to leave?")
|
||||||
modality: Qt.ApplicationModal
|
modality: Qt.ApplicationModal
|
||||||
buttons: P.MessageDialog.Ok | P.MessageDialog.Cancel
|
buttons: P.MessageDialog.Ok | P.MessageDialog.Cancel
|
||||||
onAccepted: Rooms.leave(roomId, reason)
|
onAccepted: {
|
||||||
|
|
||||||
|
if (CallManager.haveCallInvite) {
|
||||||
|
callManager.rejectInvite();
|
||||||
|
} else if (CallManager.isOnCall) {
|
||||||
|
CallManager.hangUp();
|
||||||
|
}
|
||||||
|
Rooms.leave(roomId, reason)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ Popup {
|
||||||
implicitWidth: buttonLayout.buttonSize
|
implicitWidth: buttonLayout.buttonSize
|
||||||
implicitHeight: buttonLayout.buttonSize
|
implicitHeight: buttonLayout.buttonSize
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CallManager.hangUp();
|
CallManager.rejectInvite();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ Rectangle {
|
||||||
text: qsTr("Decline")
|
text: qsTr("Decline")
|
||||||
palette: Nheko.colors
|
palette: Nheko.colors
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CallManager.hangUp();
|
CallManager.rejectInvite();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,8 +184,18 @@ Cache::isHiddenEvent(lmdb::txn &txn,
|
||||||
hiddenEvents.hidden_event_types = std::vector{
|
hiddenEvents.hidden_event_types = std::vector{
|
||||||
EventType::Reaction,
|
EventType::Reaction,
|
||||||
EventType::CallCandidates,
|
EventType::CallCandidates,
|
||||||
|
EventType::CallNegotiate,
|
||||||
EventType::Unsupported,
|
EventType::Unsupported,
|
||||||
};
|
};
|
||||||
|
// check if selected answer is from to local user
|
||||||
|
/*
|
||||||
|
* localUser accepts/rejects the call and it is selected by caller - No message
|
||||||
|
* Another User accepts/rejects the call and it is selected by caller - "Call answered/rejected
|
||||||
|
* elsewhere"
|
||||||
|
*/
|
||||||
|
bool callLocalUser_ = true;
|
||||||
|
if (callLocalUser_)
|
||||||
|
hiddenEvents.hidden_event_types->push_back(EventType::CallSelectAnswer);
|
||||||
|
|
||||||
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) {
|
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) {
|
||||||
auto h = std::get<
|
auto h = std::get<
|
||||||
|
@ -1661,11 +1671,18 @@ isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallAnswer> &)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto
|
auto
|
||||||
isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallHangUp> &)
|
isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallHangUp> &)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auto
|
||||||
|
// isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallReject> &)
|
||||||
|
// {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -363,6 +363,9 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
||||||
connectCallMessage<mtx::events::voip::CallCandidates>();
|
connectCallMessage<mtx::events::voip::CallCandidates>();
|
||||||
connectCallMessage<mtx::events::voip::CallAnswer>();
|
connectCallMessage<mtx::events::voip::CallAnswer>();
|
||||||
connectCallMessage<mtx::events::voip::CallHangUp>();
|
connectCallMessage<mtx::events::voip::CallHangUp>();
|
||||||
|
connectCallMessage<mtx::events::voip::CallSelectAnswer>();
|
||||||
|
connectCallMessage<mtx::events::voip::CallReject>();
|
||||||
|
connectCallMessage<mtx::events::voip::CallNegotiate>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -222,6 +222,8 @@ PowerlevelsTypeListModel::data(const QModelIndex &index, int role) const
|
||||||
return tr("Answer a call");
|
return tr("Answer a call");
|
||||||
else if (type.type == "m.call.hangup")
|
else if (type.type == "m.call.hangup")
|
||||||
return tr("Hang up a call");
|
return tr("Hang up a call");
|
||||||
|
else if (type.type == "m.call.reject")
|
||||||
|
return tr("Reject a call");
|
||||||
else if (type.type == "im.ponies.room_emotes")
|
else if (type.type == "im.ponies.room_emotes")
|
||||||
return tr("Change the room emotes");
|
return tr("Change the room emotes");
|
||||||
return QString::fromStdString(type.type);
|
return QString::fromStdString(type.type);
|
||||||
|
|
|
@ -219,6 +219,7 @@ utils::getMessageDescription(const TimelineEvent &event,
|
||||||
using CallInvite = mtx::events::RoomEvent<mtx::events::voip::CallInvite>;
|
using CallInvite = mtx::events::RoomEvent<mtx::events::voip::CallInvite>;
|
||||||
using CallAnswer = mtx::events::RoomEvent<mtx::events::voip::CallAnswer>;
|
using CallAnswer = mtx::events::RoomEvent<mtx::events::voip::CallAnswer>;
|
||||||
using CallHangUp = mtx::events::RoomEvent<mtx::events::voip::CallHangUp>;
|
using CallHangUp = mtx::events::RoomEvent<mtx::events::voip::CallHangUp>;
|
||||||
|
using CallReject = mtx::events::RoomEvent<mtx::events::voip::CallReject>;
|
||||||
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
|
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
|
||||||
|
|
||||||
if (std::holds_alternative<Audio>(event)) {
|
if (std::holds_alternative<Audio>(event)) {
|
||||||
|
@ -241,6 +242,8 @@ utils::getMessageDescription(const TimelineEvent &event,
|
||||||
return createDescriptionInfo<CallAnswer>(event, localUser, displayName);
|
return createDescriptionInfo<CallAnswer>(event, localUser, displayName);
|
||||||
} else if (std::holds_alternative<CallHangUp>(event)) {
|
} else if (std::holds_alternative<CallHangUp>(event)) {
|
||||||
return createDescriptionInfo<CallHangUp>(event, localUser, displayName);
|
return createDescriptionInfo<CallHangUp>(event, localUser, displayName);
|
||||||
|
} else if (std::holds_alternative<CallReject>(event)) {
|
||||||
|
return createDescriptionInfo<CallReject>(event, localUser, displayName);
|
||||||
} else if (std::holds_alternative<mtx::events::Sticker>(event)) {
|
} else if (std::holds_alternative<mtx::events::Sticker>(event)) {
|
||||||
return createDescriptionInfo<mtx::events::Sticker>(event, localUser, displayName);
|
return createDescriptionInfo<mtx::events::Sticker>(event, localUser, displayName);
|
||||||
} else if (auto msg = std::get_if<Encrypted>(&event); msg != nullptr) {
|
} else if (auto msg = std::get_if<Encrypted>(&event); msg != nullptr) {
|
||||||
|
|
|
@ -110,6 +110,7 @@ messageDescription(const QString &username = QString(),
|
||||||
using CallInvite = mtx::events::RoomEvent<mtx::events::voip::CallInvite>;
|
using CallInvite = mtx::events::RoomEvent<mtx::events::voip::CallInvite>;
|
||||||
using CallAnswer = mtx::events::RoomEvent<mtx::events::voip::CallAnswer>;
|
using CallAnswer = mtx::events::RoomEvent<mtx::events::voip::CallAnswer>;
|
||||||
using CallHangUp = mtx::events::RoomEvent<mtx::events::voip::CallHangUp>;
|
using CallHangUp = mtx::events::RoomEvent<mtx::events::voip::CallHangUp>;
|
||||||
|
using CallReject = mtx::events::RoomEvent<mtx::events::voip::CallReject>;
|
||||||
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
|
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
|
||||||
|
|
||||||
if (std::is_same<T, Audio>::value) {
|
if (std::is_same<T, Audio>::value) {
|
||||||
|
@ -185,6 +186,12 @@ messageDescription(const QString &username = QString(),
|
||||||
else
|
else
|
||||||
return QCoreApplication::translate("message-description sent:", "%1 ended a call")
|
return QCoreApplication::translate("message-description sent:", "%1 ended a call")
|
||||||
.arg(username);
|
.arg(username);
|
||||||
|
} else if (std::is_same<T, CallReject>::value) {
|
||||||
|
if (isLocal)
|
||||||
|
return QCoreApplication::translate("message-description sent:", "You rejected a call");
|
||||||
|
else
|
||||||
|
return QCoreApplication::translate("message-description sent:", "%1 rejected a call")
|
||||||
|
.arg(username);
|
||||||
} else {
|
} else {
|
||||||
return QCoreApplication::translate("utils", "Unknown Message Type");
|
return QCoreApplication::translate("utils", "Unknown Message Type");
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,20 @@ struct RoomEventType
|
||||||
{
|
{
|
||||||
return qml_mtx_events::EventType::CallCandidates;
|
return qml_mtx_events::EventType::CallCandidates;
|
||||||
}
|
}
|
||||||
|
qml_mtx_events::EventType
|
||||||
|
operator()(const mtx::events::Event<mtx::events::voip::CallSelectAnswer> &)
|
||||||
|
{
|
||||||
|
return qml_mtx_events::EventType::CallSelectAnswer;
|
||||||
|
}
|
||||||
|
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::voip::CallReject> &)
|
||||||
|
{
|
||||||
|
return qml_mtx_events::EventType::CallReject;
|
||||||
|
}
|
||||||
|
qml_mtx_events::EventType
|
||||||
|
operator()(const mtx::events::Event<mtx::events::voip::CallNegotiate> &)
|
||||||
|
{
|
||||||
|
return qml_mtx_events::EventType::CallNegotiate;
|
||||||
|
}
|
||||||
// ::EventType::Type operator()(const Event<mtx::events::msg::Location> &e) { return
|
// ::EventType::Type operator()(const Event<mtx::events::msg::Location> &e) { return
|
||||||
// ::EventType::LocationMessage; }
|
// ::EventType::LocationMessage; }
|
||||||
};
|
};
|
||||||
|
@ -258,6 +272,15 @@ qml_mtx_events::fromRoomEventType(qml_mtx_events::EventType t)
|
||||||
/// m.call.candidates
|
/// m.call.candidates
|
||||||
case qml_mtx_events::CallCandidates:
|
case qml_mtx_events::CallCandidates:
|
||||||
return mtx::events::EventType::CallCandidates;
|
return mtx::events::EventType::CallCandidates;
|
||||||
|
/// m.call.select_answer
|
||||||
|
case qml_mtx_events::CallSelectAnswer:
|
||||||
|
return mtx::events::EventType::CallSelectAnswer;
|
||||||
|
/// m.call.reject
|
||||||
|
case qml_mtx_events::CallReject:
|
||||||
|
return mtx::events::EventType::CallReject;
|
||||||
|
/// m.call.negotiate
|
||||||
|
case qml_mtx_events::CallNegotiate:
|
||||||
|
return mtx::events::EventType::CallNegotiate;
|
||||||
/// m.room.canonical_alias
|
/// m.room.canonical_alias
|
||||||
case qml_mtx_events::CanonicalAlias:
|
case qml_mtx_events::CanonicalAlias:
|
||||||
return mtx::events::EventType::RoomCanonicalAlias;
|
return mtx::events::EventType::RoomCanonicalAlias;
|
||||||
|
@ -922,16 +945,22 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::holds_alternative<RoomEvent<voip::CallCandidates>>(e) ||
|
if (std::holds_alternative<RoomEvent<voip::CallCandidates>>(e) ||
|
||||||
|
std::holds_alternative<RoomEvent<voip::CallNegotiate>>(e) ||
|
||||||
std::holds_alternative<RoomEvent<voip::CallInvite>>(e) ||
|
std::holds_alternative<RoomEvent<voip::CallInvite>>(e) ||
|
||||||
std::holds_alternative<RoomEvent<voip::CallAnswer>>(e) ||
|
std::holds_alternative<RoomEvent<voip::CallAnswer>>(e) ||
|
||||||
|
std::holds_alternative<RoomEvent<voip::CallSelectAnswer>>(e) ||
|
||||||
|
std::holds_alternative<RoomEvent<voip::CallReject>>(e) ||
|
||||||
std::holds_alternative<RoomEvent<voip::CallHangUp>>(e))
|
std::holds_alternative<RoomEvent<voip::CallHangUp>>(e))
|
||||||
std::visit(
|
std::visit(
|
||||||
[this](auto &event) {
|
[this](auto &event) {
|
||||||
event.room_id = room_id_.toStdString();
|
event.room_id = room_id_.toStdString();
|
||||||
if constexpr (std::is_same_v<std::decay_t<decltype(event)>,
|
if constexpr (
|
||||||
RoomEvent<voip::CallAnswer>> ||
|
std::is_same_v<std::decay_t<decltype(event)>, RoomEvent<voip::CallAnswer>> ||
|
||||||
std::is_same_v<std::decay_t<decltype(event)>,
|
std::is_same_v<std::decay_t<decltype(event)>, RoomEvent<voip::CallInvite>> ||
|
||||||
RoomEvent<voip::CallHangUp>>)
|
std::is_same_v<std::decay_t<decltype(event)>,
|
||||||
|
RoomEvent<voip::CallSelectAnswer>> ||
|
||||||
|
std::is_same_v<std::decay_t<decltype(event)>, RoomEvent<voip::CallReject>> ||
|
||||||
|
std::is_same_v<std::decay_t<decltype(event)>, RoomEvent<voip::CallHangUp>>)
|
||||||
emit newCallEvent(event);
|
emit newCallEvent(event);
|
||||||
else {
|
else {
|
||||||
if (event.sender != http::client()->user_id().to_string())
|
if (event.sender != http::client()->user_id().to_string())
|
||||||
|
@ -1007,6 +1036,17 @@ isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallHangUp> &)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallReject> &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto
|
||||||
|
isMessage(const mtx::events::RoomEvent<mtx::events::voip::CallSelectAnswer> &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Workaround. We also want to see a room at the top, if we just joined it
|
// Workaround. We also want to see a room at the top, if we just joined it
|
||||||
auto
|
auto
|
||||||
isYourJoin(const mtx::events::StateEvent<mtx::events::state::Member> &e)
|
isYourJoin(const mtx::events::StateEvent<mtx::events::state::Member> &e)
|
||||||
|
@ -1503,6 +1543,23 @@ struct SendMessageVisitor
|
||||||
sendRoomEvent<mtx::events::voip::CallHangUp, mtx::events::EventType::CallHangUp>(event);
|
sendRoomEvent<mtx::events::voip::CallHangUp, mtx::events::EventType::CallHangUp>(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator()(const mtx::events::RoomEvent<mtx::events::voip::CallSelectAnswer> &event)
|
||||||
|
{
|
||||||
|
sendRoomEvent<mtx::events::voip::CallSelectAnswer,
|
||||||
|
mtx::events::EventType::CallSelectAnswer>(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const mtx::events::RoomEvent<mtx::events::voip::CallReject> &event)
|
||||||
|
{
|
||||||
|
sendRoomEvent<mtx::events::voip::CallReject, mtx::events::EventType::CallReject>(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const mtx::events::RoomEvent<mtx::events::voip::CallNegotiate> &event)
|
||||||
|
{
|
||||||
|
sendRoomEvent<mtx::events::voip::CallNegotiate, mtx::events::EventType::CallNegotiate>(
|
||||||
|
event);
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &msg)
|
void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &msg)
|
||||||
{
|
{
|
||||||
sendRoomEvent<mtx::events::msg::KeyVerificationRequest,
|
sendRoomEvent<mtx::events::msg::KeyVerificationRequest,
|
||||||
|
|
|
@ -58,6 +58,12 @@ enum EventType
|
||||||
CallHangUp,
|
CallHangUp,
|
||||||
/// m.call.candidates
|
/// m.call.candidates
|
||||||
CallCandidates,
|
CallCandidates,
|
||||||
|
/// m.call.select_answer
|
||||||
|
CallSelectAnswer,
|
||||||
|
/// m.call.reject
|
||||||
|
CallReject,
|
||||||
|
/// m.call.negotiate
|
||||||
|
CallNegotiate,
|
||||||
/// m.room.canonical_alias
|
/// m.room.canonical_alias
|
||||||
CanonicalAlias,
|
CanonicalAlias,
|
||||||
/// m.room.create
|
/// m.room.create
|
||||||
|
|
|
@ -377,6 +377,28 @@ TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
|
const mtx::events::voip::CallSelectAnswer &callSelectAnswer)
|
||||||
|
{
|
||||||
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callSelectAnswer, mtx::events::EventType::CallSelectAnswer);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
|
const mtx::events::voip::CallReject &callReject)
|
||||||
|
{
|
||||||
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callReject, mtx::events::EventType::CallReject);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
|
const mtx::events::voip::CallNegotiate &callNegotiate)
|
||||||
|
{
|
||||||
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callNegotiate, mtx::events::EventType::CallNegotiate);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::focusMessageInput()
|
TimelineViewManager::focusMessageInput()
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,6 +109,9 @@ public slots:
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallCandidates &);
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallCandidates &);
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallAnswer &);
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallAnswer &);
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallHangUp &);
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallHangUp &);
|
||||||
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallSelectAnswer &);
|
||||||
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallReject &);
|
||||||
|
void queueCallMessage(const QString &roomid, const mtx::events::voip::CallNegotiate &);
|
||||||
|
|
||||||
void setVideoCallItem();
|
void setVideoCallItem();
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,20 @@ HiddenEvents::load()
|
||||||
hiddenEvents.hidden_event_types = std::vector{
|
hiddenEvents.hidden_event_types = std::vector{
|
||||||
EventType::Reaction,
|
EventType::Reaction,
|
||||||
EventType::CallCandidates,
|
EventType::CallCandidates,
|
||||||
|
EventType::CallNegotiate,
|
||||||
EventType::Unsupported,
|
EventType::Unsupported,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// check if selected answer is from to local user
|
||||||
|
/*
|
||||||
|
* localUser accepts/rejects the call and it is selected by caller - No message
|
||||||
|
* Another User accepts/rejects the call and it is selected by caller - "Call answered/rejected
|
||||||
|
* elsewhere"
|
||||||
|
*/
|
||||||
|
bool callLocalUser_ = true;
|
||||||
|
if (callLocalUser_)
|
||||||
|
hiddenEvents.hidden_event_types->push_back(EventType::CallSelectAnswer);
|
||||||
|
|
||||||
if (auto temp =
|
if (auto temp =
|
||||||
cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents, "")) {
|
cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents, "")) {
|
||||||
auto h = std::get<
|
auto h = std::get<
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
|
|
||||||
#include "mtx/responses/turn_server.hpp"
|
#include "mtx/responses/turn_server.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select Answer when one instance of the client supports v0
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef XCB_AVAILABLE
|
#ifdef XCB_AVAILABLE
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_ewmh.h>
|
#include <xcb/xcb_ewmh.h>
|
||||||
|
@ -67,10 +71,15 @@ CallManager::CallManager(QObject *parent)
|
||||||
this,
|
this,
|
||||||
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
|
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - sending offer", callid_);
|
nhlog::ui()->debug("WebRTC: call id: {} - sending offer", callid_);
|
||||||
emit newMessage(
|
emit newMessage(roomid_,
|
||||||
roomid_,
|
CallInvite{callid_,
|
||||||
CallInvite{callid_, partyid_, SDO{sdp, SDO::Type::Offer}, "0", timeoutms_, invitee_});
|
partyid_,
|
||||||
emit newMessage(roomid_, CallCandidates{callid_, partyid_, candidates, "0"});
|
SDO{sdp, SDO::Type::Offer},
|
||||||
|
callPartyVersion_,
|
||||||
|
timeoutms_,
|
||||||
|
invitee_});
|
||||||
|
emit newMessage(roomid_,
|
||||||
|
CallCandidates{callid_, partyid_, candidates, callPartyVersion_});
|
||||||
std::string callid(callid_);
|
std::string callid(callid_);
|
||||||
QTimer::singleShot(timeoutms_, this, [this, callid]() {
|
QTimer::singleShot(timeoutms_, this, [this, callid]() {
|
||||||
if (session_.state() == webrtc::State::OFFERSENT && callid == callid_) {
|
if (session_.state() == webrtc::State::OFFERSENT && callid == callid_) {
|
||||||
|
@ -87,8 +96,10 @@ CallManager::CallManager(QObject *parent)
|
||||||
this,
|
this,
|
||||||
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
|
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - sending answer", callid_);
|
nhlog::ui()->debug("WebRTC: call id: {} - sending answer", callid_);
|
||||||
emit newMessage(roomid_, CallAnswer{callid_, partyid_, "0", SDO{sdp, SDO::Type::Answer}});
|
emit newMessage(
|
||||||
emit newMessage(roomid_, CallCandidates{callid_, partyid_, candidates, "0"});
|
roomid_, CallAnswer{callid_, partyid_, callPartyVersion_, SDO{sdp, SDO::Type::Answer}});
|
||||||
|
emit newMessage(roomid_,
|
||||||
|
CallCandidates{callid_, partyid_, candidates, callPartyVersion_});
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&session_,
|
connect(&session_,
|
||||||
|
@ -96,7 +107,8 @@ CallManager::CallManager(QObject *parent)
|
||||||
this,
|
this,
|
||||||
[this](const CallCandidates::Candidate &candidate) {
|
[this](const CallCandidates::Candidate &candidate) {
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - sending ice candidate", callid_);
|
nhlog::ui()->debug("WebRTC: call id: {} - sending ice candidate", callid_);
|
||||||
emit newMessage(roomid_, CallCandidates{callid_, partyid_, {candidate}, "0"});
|
emit newMessage(roomid_,
|
||||||
|
CallCandidates{callid_, partyid_, {candidate}, callPartyVersion_});
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&turnServerTimer_, &QTimer::timeout, this, &CallManager::retrieveTurnServer);
|
connect(&turnServerTimer_, &QTimer::timeout, this, &CallManager::retrieveTurnServer);
|
||||||
|
@ -170,23 +182,14 @@ CallManager::CallManager(QObject *parent)
|
||||||
void
|
void
|
||||||
CallManager::sendInvite(const QString &roomid, CallType callType, unsigned int windowIndex)
|
CallManager::sendInvite(const QString &roomid, CallType callType, unsigned int windowIndex)
|
||||||
{
|
{
|
||||||
if (isOnCall())
|
if (isOnCall() || isOnCallOnOtherDevice()) {
|
||||||
|
if (isOnCallOnOtherDevice_ != "")
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
QStringLiteral("User is already in a call"));
|
||||||
return;
|
return;
|
||||||
if (callType == CallType::SCREEN) {
|
|
||||||
if (!screenShareSupported())
|
|
||||||
return;
|
|
||||||
if (windows_.empty() || windowIndex >= windows_.size()) {
|
|
||||||
nhlog::ui()->error("WebRTC: window index out of range");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto roomInfo = cache::singleRoomInfo(roomid.toStdString());
|
auto roomInfo = cache::singleRoomInfo(roomid.toStdString());
|
||||||
if (roomInfo.member_count != 2) {
|
|
||||||
emit ChatPage::instance()->showNotification(
|
|
||||||
QStringLiteral("Calls are limited to 1:1 rooms."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string errorMessage;
|
std::string errorMessage;
|
||||||
if (!session_.havePlugins(false, &errorMessage) ||
|
if (!session_.havePlugins(false, &errorMessage) ||
|
||||||
|
@ -198,17 +201,60 @@ CallManager::sendInvite(const QString &roomid, CallType callType, unsigned int w
|
||||||
|
|
||||||
callType_ = callType;
|
callType_ = callType;
|
||||||
roomid_ = roomid;
|
roomid_ = roomid;
|
||||||
session_.setTurnServers(turnURIs_);
|
|
||||||
generateCallID();
|
generateCallID();
|
||||||
|
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
|
||||||
|
const RoomMember *callee;
|
||||||
|
if (roomInfo.member_count == 1)
|
||||||
|
callee = &members.front();
|
||||||
|
else if (roomInfo.member_count == 2)
|
||||||
|
callee = members.front().user_id == utils::localUser() ? &members.back() : &members.front();
|
||||||
|
else {
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
QStringLiteral("Calls are limited to rooms with less than two members"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callType == CallType::SCREEN) {
|
||||||
|
if (!screenShareSupported())
|
||||||
|
return;
|
||||||
|
if (windows_.empty() || windowIndex >= windows_.size()) {
|
||||||
|
nhlog::ui()->error("WebRTC: window index out of range");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveCallInvite_) {
|
||||||
|
nhlog::ui()->debug(
|
||||||
|
"WebRTC: Discarding outbound call for inbound call. localUser is polite party");
|
||||||
|
if (callParty_ == callee->user_id) {
|
||||||
|
if (callType == callType_)
|
||||||
|
acceptInvite();
|
||||||
|
else {
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
QStringLiteral("Can't place call. Call types do not match"));
|
||||||
|
emit newMessage(
|
||||||
|
roomid_,
|
||||||
|
CallHangUp{callid_, partyid_, callPartyVersion_, CallHangUp::Reason::UserBusy});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
QStringLiteral("Already on a call with a different user"));
|
||||||
|
emit newMessage(
|
||||||
|
roomid_,
|
||||||
|
CallHangUp{callid_, partyid_, callPartyVersion_, CallHangUp::Reason::UserBusy});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_.setTurnServers(turnURIs_);
|
||||||
std::string strCallType =
|
std::string strCallType =
|
||||||
callType_ == CallType::VOICE ? "voice" : (callType_ == CallType::VIDEO ? "video" : "screen");
|
callType_ == CallType::VOICE ? "voice" : (callType_ == CallType::VIDEO ? "video" : "screen");
|
||||||
|
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - creating {} invite", callid_, strCallType);
|
nhlog::ui()->debug("WebRTC: call id: {} - creating {} invite", callid_, strCallType);
|
||||||
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
|
callParty_ = callee->user_id;
|
||||||
const RoomMember &callee =
|
callPartyDisplayName_ = callee->display_name.isEmpty() ? callee->user_id : callee->display_name;
|
||||||
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
|
||||||
callParty_ = callee.user_id;
|
|
||||||
callPartyDisplayName_ = callee.display_name.isEmpty() ? callee.user_id : callee.display_name;
|
|
||||||
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
||||||
|
invitee_ = callParty_.toStdString();
|
||||||
emit newInviteState();
|
emit newInviteState();
|
||||||
playRingtone(QUrl(QStringLiteral("qrc:/media/media/ringback.ogg")), true);
|
playRingtone(QUrl(QStringLiteral("qrc:/media/media/ringback.ogg")), true);
|
||||||
if (!session_.createOffer(callType,
|
if (!session_.createOffer(callType,
|
||||||
|
@ -249,7 +295,7 @@ CallManager::hangUp(CallHangUp::Reason reason)
|
||||||
if (!callid_.empty()) {
|
if (!callid_.empty()) {
|
||||||
nhlog::ui()->debug(
|
nhlog::ui()->debug(
|
||||||
"WebRTC: call id: {} - hanging up ({})", callid_, callHangUpReasonString(reason));
|
"WebRTC: call id: {} - hanging up ({})", callid_, callHangUpReasonString(reason));
|
||||||
emit newMessage(roomid_, CallHangUp{callid_, partyid_, "0", reason});
|
emit newMessage(roomid_, CallHangUp{callid_, partyid_, callPartyVersion_, reason});
|
||||||
endCall();
|
endCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +305,9 @@ CallManager::syncEvent(const mtx::events::collections::TimelineEvents &event)
|
||||||
{
|
{
|
||||||
#ifdef GSTREAMER_AVAILABLE
|
#ifdef GSTREAMER_AVAILABLE
|
||||||
if (handleEvent<CallInvite>(event) || handleEvent<CallCandidates>(event) ||
|
if (handleEvent<CallInvite>(event) || handleEvent<CallCandidates>(event) ||
|
||||||
handleEvent<CallAnswer>(event) || handleEvent<CallHangUp>(event))
|
handleEvent<CallNegotiate>(event) || handleEvent<CallSelectAnswer>(event) ||
|
||||||
|
handleEvent<CallAnswer>(event) || handleEvent<CallReject>(event) ||
|
||||||
|
handleEvent<CallHangUp>(event))
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
(void)event;
|
(void)event;
|
||||||
|
@ -289,41 +337,121 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
|
||||||
[](unsigned char c1, unsigned char c2) {
|
[](unsigned char c1, unsigned char c2) {
|
||||||
return std::tolower(c1) == std::tolower(c2);
|
return std::tolower(c1) == std::tolower(c2);
|
||||||
}) != sdp.cend();
|
}) != sdp.cend();
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming {} CallInvite from ({},{}) ",
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - incoming {} CallInvite from {}",
|
|
||||||
callInviteEvent.content.call_id,
|
callInviteEvent.content.call_id,
|
||||||
(isVideo ? "video" : "voice"),
|
(isVideo ? "video" : "voice"),
|
||||||
callInviteEvent.sender);
|
callInviteEvent.sender,
|
||||||
|
callInviteEvent.content.party_id);
|
||||||
|
|
||||||
if (callInviteEvent.content.call_id.empty())
|
if (callInviteEvent.content.call_id.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto roomInfo = cache::singleRoomInfo(callInviteEvent.room_id);
|
if (callInviteEvent.sender == utils::localUser().toStdString()) {
|
||||||
if (isOnCall() || roomInfo.member_count != 2) {
|
if (callInviteEvent.content.party_id == partyid_)
|
||||||
emit newMessage(
|
return;
|
||||||
QString::fromStdString(callInviteEvent.room_id),
|
else {
|
||||||
CallHangUp{
|
if (callInviteEvent.content.invitee != utils::localUser().toStdString()) {
|
||||||
callInviteEvent.content.call_id, partyid_, "0", CallHangUp::Reason::InviteTimeOut});
|
isOnCallOnOtherDevice_ = callInviteEvent.content.call_id;
|
||||||
return;
|
emit newCallDeviceState();
|
||||||
|
nhlog::ui()->debug("WebRTC: User is on call on other device.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto roomInfo = cache::singleRoomInfo(callInviteEvent.room_id);
|
||||||
|
callPartyVersion_ = callInviteEvent.content.version;
|
||||||
|
|
||||||
const QString &ringtone = UserSettings::instance()->ringtone();
|
const QString &ringtone = UserSettings::instance()->ringtone();
|
||||||
if (ringtone != QLatin1String("Mute"))
|
bool sharesRoom = true;
|
||||||
|
|
||||||
|
std::vector<RoomMember> members(cache::getMembers(callInviteEvent.room_id));
|
||||||
|
const RoomMember &caller =
|
||||||
|
*std::find_if(members.begin(), members.end(), [&](RoomMember member) {
|
||||||
|
return member.user_id.toStdString() == callInviteEvent.sender;
|
||||||
|
});
|
||||||
|
if (isOnCall() || isOnCallOnOtherDevice()) {
|
||||||
|
if (isOnCallOnOtherDevice_ != "")
|
||||||
|
return;
|
||||||
|
if (callParty_.toStdString() == callInviteEvent.sender) {
|
||||||
|
if (session_.state() == webrtc::State::OFFERSENT) {
|
||||||
|
if (callid_ > callInviteEvent.content.call_id) {
|
||||||
|
endCall();
|
||||||
|
callParty_ = caller.user_id;
|
||||||
|
callPartyDisplayName_ =
|
||||||
|
caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
|
||||||
|
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
||||||
|
|
||||||
|
roomid_ = QString::fromStdString(callInviteEvent.room_id);
|
||||||
|
callid_ = callInviteEvent.content.call_id;
|
||||||
|
remoteICECandidates_.clear();
|
||||||
|
haveCallInvite_ = true;
|
||||||
|
callType_ = isVideo ? CallType::VIDEO : CallType::VOICE;
|
||||||
|
inviteSDP_ = callInviteEvent.content.offer.sdp;
|
||||||
|
emit newInviteState();
|
||||||
|
acceptInvite();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (session_.state() < webrtc::State::OFFERSENT)
|
||||||
|
endCall();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callPartyVersion_ == "0") {
|
||||||
|
if (roomInfo.member_count != 2) {
|
||||||
|
emit newMessage(QString::fromStdString(callInviteEvent.room_id),
|
||||||
|
CallHangUp{callInviteEvent.content.call_id,
|
||||||
|
partyid_,
|
||||||
|
callPartyVersion_,
|
||||||
|
CallHangUp::Reason::InviteTimeOut});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (caller.user_id == utils::localUser() &&
|
||||||
|
callInviteEvent.content.party_id == partyid_) // remote echo
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (roomInfo.member_count == 2 || // general call in room with two members
|
||||||
|
(roomInfo.member_count == 1 &&
|
||||||
|
partyid_ !=
|
||||||
|
callInviteEvent.content.party_id) || // self call, ring if not the same party_id
|
||||||
|
callInviteEvent.content.invitee == "" || // empty, meant for everyone
|
||||||
|
callInviteEvent.content.invitee ==
|
||||||
|
utils::localUser().toStdString()) // meant specifically for local user
|
||||||
|
{
|
||||||
|
if (roomInfo.member_count > 2) {
|
||||||
|
// check if shares room
|
||||||
|
sharesRoom = checkSharesRoom(QString::fromStdString(callInviteEvent.room_id),
|
||||||
|
callInviteEvent.content.invitee);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit newMessage(QString::fromStdString(callInviteEvent.room_id),
|
||||||
|
CallHangUp{callInviteEvent.content.call_id,
|
||||||
|
partyid_,
|
||||||
|
callPartyVersion_,
|
||||||
|
CallHangUp::Reason::InviteTimeOut});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ring if not mute or does not have direct message room
|
||||||
|
if (ringtone != QLatin1String("Mute") && sharesRoom)
|
||||||
playRingtone(ringtone == QLatin1String("Default")
|
playRingtone(ringtone == QLatin1String("Default")
|
||||||
? QUrl(QStringLiteral("qrc:/media/media/ring.ogg"))
|
? QUrl(QStringLiteral("qrc:/media/media/ring.ogg"))
|
||||||
: QUrl::fromLocalFile(ringtone),
|
: QUrl::fromLocalFile(ringtone),
|
||||||
true);
|
true);
|
||||||
roomid_ = QString::fromStdString(callInviteEvent.room_id);
|
|
||||||
callid_ = callInviteEvent.content.call_id;
|
|
||||||
remoteICECandidates_.clear();
|
|
||||||
|
|
||||||
std::vector<RoomMember> members(cache::getMembers(callInviteEvent.room_id));
|
|
||||||
const RoomMember &caller =
|
|
||||||
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
|
||||||
callParty_ = caller.user_id;
|
callParty_ = caller.user_id;
|
||||||
callPartyDisplayName_ = caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
|
callPartyDisplayName_ = caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
|
||||||
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
||||||
|
|
||||||
|
roomid_ = QString::fromStdString(callInviteEvent.room_id);
|
||||||
|
callid_ = callInviteEvent.content.call_id;
|
||||||
|
remoteICECandidates_.clear();
|
||||||
|
|
||||||
haveCallInvite_ = true;
|
haveCallInvite_ = true;
|
||||||
callType_ = isVideo ? CallType::VIDEO : CallType::VOICE;
|
callType_ = isVideo ? CallType::VIDEO : CallType::VOICE;
|
||||||
inviteSDP_ = callInviteEvent.content.offer.sdp;
|
inviteSDP_ = callInviteEvent.content.offer.sdp;
|
||||||
|
@ -333,6 +461,8 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
|
||||||
void
|
void
|
||||||
CallManager::acceptInvite()
|
CallManager::acceptInvite()
|
||||||
{
|
{
|
||||||
|
// if call was accepted/rejected elsewhere and m.call.select_answer is received
|
||||||
|
// before acceptInvite
|
||||||
if (!haveCallInvite_)
|
if (!haveCallInvite_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -341,7 +471,7 @@ CallManager::acceptInvite()
|
||||||
if (!session_.havePlugins(false, &errorMessage) ||
|
if (!session_.havePlugins(false, &errorMessage) ||
|
||||||
(callType_ == CallType::VIDEO && !session_.havePlugins(true, &errorMessage))) {
|
(callType_ == CallType::VIDEO && !session_.havePlugins(true, &errorMessage))) {
|
||||||
emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
|
emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
|
||||||
hangUp();
|
hangUp(CallHangUp::Reason::UserMediaFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,15 +487,31 @@ CallManager::acceptInvite()
|
||||||
emit newInviteState();
|
emit newInviteState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CallManager::rejectInvite()
|
||||||
|
{
|
||||||
|
if (callPartyVersion_ == "0") {
|
||||||
|
hangUp();
|
||||||
|
// send m.call.reject after sending hangup as mentioned in MSC2746
|
||||||
|
emit newMessage(roomid_, CallReject{callid_, partyid_, callPartyVersion_});
|
||||||
|
}
|
||||||
|
if (!callid_.empty()) {
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - rejecting call", callid_);
|
||||||
|
emit newMessage(roomid_, CallReject{callid_, partyid_, callPartyVersion_});
|
||||||
|
endCall(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallManager::handleEvent(const RoomEvent<CallCandidates> &callCandidatesEvent)
|
CallManager::handleEvent(const RoomEvent<CallCandidates> &callCandidatesEvent)
|
||||||
{
|
{
|
||||||
if (callCandidatesEvent.sender == utils::localUser().toStdString())
|
if (callCandidatesEvent.sender == utils::localUser().toStdString() &&
|
||||||
|
callCandidatesEvent.content.party_id == partyid_)
|
||||||
return;
|
return;
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallCandidates from ({}, {})",
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallCandidates from {}",
|
|
||||||
callCandidatesEvent.content.call_id,
|
callCandidatesEvent.content.call_id,
|
||||||
callCandidatesEvent.sender);
|
callCandidatesEvent.sender,
|
||||||
|
callCandidatesEvent.content.party_id);
|
||||||
|
|
||||||
if (callid_ == callCandidatesEvent.content.call_id) {
|
if (callid_ == callCandidatesEvent.content.call_id) {
|
||||||
if (isOnCall())
|
if (isOnCall())
|
||||||
|
@ -382,20 +528,31 @@ CallManager::handleEvent(const RoomEvent<CallCandidates> &callCandidatesEvent)
|
||||||
void
|
void
|
||||||
CallManager::handleEvent(const RoomEvent<CallAnswer> &callAnswerEvent)
|
CallManager::handleEvent(const RoomEvent<CallAnswer> &callAnswerEvent)
|
||||||
{
|
{
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallAnswer from {}",
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallAnswer from ({}, {})",
|
||||||
callAnswerEvent.content.call_id,
|
callAnswerEvent.content.call_id,
|
||||||
callAnswerEvent.sender);
|
callAnswerEvent.sender,
|
||||||
|
callAnswerEvent.content.party_id);
|
||||||
|
if (answerSelected_)
|
||||||
|
return;
|
||||||
|
|
||||||
if (callAnswerEvent.sender == utils::localUser().toStdString() &&
|
if (callAnswerEvent.sender == utils::localUser().toStdString() &&
|
||||||
callid_ == callAnswerEvent.content.call_id) {
|
callid_ == callAnswerEvent.content.call_id) {
|
||||||
|
if (partyid_ == callAnswerEvent.content.party_id)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!isOnCall()) {
|
if (!isOnCall()) {
|
||||||
emit ChatPage::instance()->showNotification(
|
emit ChatPage::instance()->showNotification(
|
||||||
QStringLiteral("Call answered on another device."));
|
QStringLiteral("Call answered on another device."));
|
||||||
stopRingtone();
|
stopRingtone();
|
||||||
haveCallInvite_ = false;
|
haveCallInvite_ = false;
|
||||||
|
if (callPartyVersion_ != "1") {
|
||||||
|
isOnCallOnOtherDevice_ = callid_;
|
||||||
|
emit newCallDeviceState();
|
||||||
|
}
|
||||||
emit newInviteState();
|
emit newInviteState();
|
||||||
}
|
}
|
||||||
return;
|
if (callParty_ != utils::localUser())
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOnCall() && callid_ == callAnswerEvent.content.call_id) {
|
if (isOnCall() && callid_ == callAnswerEvent.content.call_id) {
|
||||||
|
@ -405,20 +562,141 @@ CallManager::handleEvent(const RoomEvent<CallAnswer> &callAnswerEvent)
|
||||||
hangUp();
|
hangUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
emit newMessage(
|
||||||
|
roomid_,
|
||||||
|
CallSelectAnswer{callid_, partyid_, callPartyVersion_, callAnswerEvent.content.party_id});
|
||||||
|
selectedpartyid_ = callAnswerEvent.content.party_id;
|
||||||
|
answerSelected_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallManager::handleEvent(const RoomEvent<CallHangUp> &callHangUpEvent)
|
CallManager::handleEvent(const RoomEvent<CallHangUp> &callHangUpEvent)
|
||||||
{
|
{
|
||||||
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallHangUp ({}) from {}",
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallHangUp ({}) from ({}, {})",
|
||||||
callHangUpEvent.content.call_id,
|
callHangUpEvent.content.call_id,
|
||||||
callHangUpReasonString(callHangUpEvent.content.reason),
|
callHangUpReasonString(callHangUpEvent.content.reason),
|
||||||
callHangUpEvent.sender);
|
callHangUpEvent.sender,
|
||||||
|
callHangUpEvent.content.party_id);
|
||||||
|
|
||||||
if (callid_ == callHangUpEvent.content.call_id)
|
if (callid_ == callHangUpEvent.content.call_id ||
|
||||||
|
isOnCallOnOtherDevice_ == callHangUpEvent.content.call_id)
|
||||||
endCall();
|
endCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CallManager::handleEvent(const RoomEvent<CallSelectAnswer> &callSelectAnswerEvent)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallSelectAnswer from ({}, {})",
|
||||||
|
callSelectAnswerEvent.content.call_id,
|
||||||
|
callSelectAnswerEvent.sender,
|
||||||
|
callSelectAnswerEvent.content.party_id);
|
||||||
|
if (callSelectAnswerEvent.sender == utils::localUser().toStdString()) {
|
||||||
|
if (callSelectAnswerEvent.content.party_id != partyid_) {
|
||||||
|
if (std::find(rejectCallPartyIDs_.begin(),
|
||||||
|
rejectCallPartyIDs_.begin(),
|
||||||
|
callSelectAnswerEvent.content.selected_party_id) !=
|
||||||
|
rejectCallPartyIDs_.end())
|
||||||
|
endCall();
|
||||||
|
else {
|
||||||
|
if (callSelectAnswerEvent.content.selected_party_id == partyid_)
|
||||||
|
return;
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - user is on call with this user!",
|
||||||
|
callSelectAnswerEvent.content.call_id);
|
||||||
|
isOnCallOnOtherDevice_ = callSelectAnswerEvent.content.call_id;
|
||||||
|
emit newCallDeviceState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (callid_ == callSelectAnswerEvent.content.call_id) {
|
||||||
|
if (callSelectAnswerEvent.content.selected_party_id != partyid_) {
|
||||||
|
bool endAllCalls = false;
|
||||||
|
if (std::find(rejectCallPartyIDs_.begin(),
|
||||||
|
rejectCallPartyIDs_.begin(),
|
||||||
|
callSelectAnswerEvent.content.selected_party_id) !=
|
||||||
|
rejectCallPartyIDs_.end())
|
||||||
|
endAllCalls = true;
|
||||||
|
else {
|
||||||
|
isOnCallOnOtherDevice_ = callid_;
|
||||||
|
emit newCallDeviceState();
|
||||||
|
}
|
||||||
|
endCall(endAllCalls);
|
||||||
|
} else if (session_.state() == webrtc::State::DISCONNECTED)
|
||||||
|
endCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CallManager::handleEvent(const RoomEvent<CallReject> &callRejectEvent)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallReject from ({}, {})",
|
||||||
|
callRejectEvent.content.call_id,
|
||||||
|
callRejectEvent.sender,
|
||||||
|
callRejectEvent.content.party_id);
|
||||||
|
if (answerSelected_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rejectCallPartyIDs_.push_back(callRejectEvent.content.party_id);
|
||||||
|
// check remote echo
|
||||||
|
if (callRejectEvent.sender == utils::localUser().toStdString()) {
|
||||||
|
if (callRejectEvent.content.party_id != partyid_ && callParty_ != utils::localUser())
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
QStringLiteral("Call rejected on another device."));
|
||||||
|
endCall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callRejectEvent.content.call_id == callid_) {
|
||||||
|
if (session_.state() == webrtc::State::OFFERSENT) {
|
||||||
|
// only accept reject if webrtc is in OFFERSENT state, else call has been accepted
|
||||||
|
emit newMessage(
|
||||||
|
roomid_,
|
||||||
|
CallSelectAnswer{
|
||||||
|
callid_, partyid_, callPartyVersion_, callRejectEvent.content.party_id});
|
||||||
|
endCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CallManager::handleEvent(const RoomEvent<CallNegotiate> &callNegotiateEvent)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("WebRTC: call id: {} - incoming CallNegotiate from ({}, {})",
|
||||||
|
callNegotiateEvent.content.call_id,
|
||||||
|
callNegotiateEvent.sender,
|
||||||
|
callNegotiateEvent.content.party_id);
|
||||||
|
|
||||||
|
std::string negotiationSDP_ = callNegotiateEvent.content.description.sdp;
|
||||||
|
if (!session_.acceptNegotiation(negotiationSDP_)) {
|
||||||
|
emit ChatPage::instance()->showNotification(QStringLiteral("Problem accepting new SDP"));
|
||||||
|
hangUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session_.acceptICECandidates(remoteICECandidates_);
|
||||||
|
remoteICECandidates_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CallManager::checkSharesRoom(QString roomid, std::string invitee) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
IMPLEMENTATION REQUIRED
|
||||||
|
Check if room is shared to determine whether to ring or not.
|
||||||
|
Called from handle callInvite event
|
||||||
|
*/
|
||||||
|
if (roomid.toStdString() != "") {
|
||||||
|
if (invitee == "") {
|
||||||
|
// check all members
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
// check if invitee shares a direct room with local user
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallManager::toggleMicMute()
|
CallManager::toggleMicMute()
|
||||||
{
|
{
|
||||||
|
@ -467,7 +745,7 @@ CallManager::generateCallID()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallManager::clear()
|
CallManager::clear(bool endAllCalls)
|
||||||
{
|
{
|
||||||
roomid_.clear();
|
roomid_.clear();
|
||||||
callParty_.clear();
|
callParty_.clear();
|
||||||
|
@ -476,17 +754,23 @@ CallManager::clear()
|
||||||
callid_.clear();
|
callid_.clear();
|
||||||
callType_ = CallType::VOICE;
|
callType_ = CallType::VOICE;
|
||||||
haveCallInvite_ = false;
|
haveCallInvite_ = false;
|
||||||
|
answerSelected_ = false;
|
||||||
|
if (endAllCalls) {
|
||||||
|
isOnCallOnOtherDevice_ = "";
|
||||||
|
rejectCallPartyIDs_.clear();
|
||||||
|
emit newCallDeviceState();
|
||||||
|
}
|
||||||
emit newInviteState();
|
emit newInviteState();
|
||||||
inviteSDP_.clear();
|
inviteSDP_.clear();
|
||||||
remoteICECandidates_.clear();
|
remoteICECandidates_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallManager::endCall()
|
CallManager::endCall(bool endAllCalls)
|
||||||
{
|
{
|
||||||
stopRingtone();
|
stopRingtone();
|
||||||
session_.end();
|
session_.end();
|
||||||
clear();
|
clear(endAllCalls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "WebRTCSession.h"
|
#include "WebRTCSession.h"
|
||||||
#include "mtx/events/collections.hpp"
|
#include "mtx/events/collections.hpp"
|
||||||
#include "mtx/events/voip.hpp"
|
#include "mtx/events/voip.hpp"
|
||||||
|
#include <mtxclient/utils.hpp>
|
||||||
|
|
||||||
namespace mtx::responses {
|
namespace mtx::responses {
|
||||||
struct TurnServer;
|
struct TurnServer;
|
||||||
|
@ -30,6 +31,7 @@ class CallManager final : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
|
Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
|
||||||
Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
|
Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
|
||||||
|
Q_PROPERTY(bool isOnCallOnOtherDevice READ isOnCallOnOtherDevice NOTIFY newCallDeviceState)
|
||||||
Q_PROPERTY(webrtc::CallType callType READ callType NOTIFY newInviteState)
|
Q_PROPERTY(webrtc::CallType callType READ callType NOTIFY newInviteState)
|
||||||
Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
|
Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
|
||||||
Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
|
Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
|
||||||
|
@ -46,7 +48,9 @@ public:
|
||||||
CallManager(QObject *);
|
CallManager(QObject *);
|
||||||
|
|
||||||
bool haveCallInvite() const { return haveCallInvite_; }
|
bool haveCallInvite() const { return haveCallInvite_; }
|
||||||
bool isOnCall() const { return session_.state() != webrtc::State::DISCONNECTED; }
|
bool isOnCall() const { return (session_.state() != webrtc::State::DISCONNECTED); }
|
||||||
|
bool isOnCallOnOtherDevice() const { return (isOnCallOnOtherDevice_ != ""); }
|
||||||
|
bool checkSharesRoom(QString roomid_, std::string invitee) const;
|
||||||
webrtc::CallType callType() const { return callType_; }
|
webrtc::CallType callType() const { return callType_; }
|
||||||
webrtc::State callState() const { return session_.state(); }
|
webrtc::State callState() const { return session_.state(); }
|
||||||
QString callParty() const { return callParty_; }
|
QString callParty() const { return callParty_; }
|
||||||
|
@ -67,8 +71,9 @@ public slots:
|
||||||
void toggleMicMute();
|
void toggleMicMute();
|
||||||
void toggleLocalPiP() { session_.toggleLocalPiP(); }
|
void toggleLocalPiP() { session_.toggleLocalPiP(); }
|
||||||
void acceptInvite();
|
void acceptInvite();
|
||||||
void
|
void hangUp(
|
||||||
hangUp(mtx::events::voip::CallHangUp::Reason = mtx::events::voip::CallHangUp::Reason::User);
|
mtx::events::voip::CallHangUp::Reason = mtx::events::voip::CallHangUp::Reason::UserHangUp);
|
||||||
|
void rejectInvite();
|
||||||
QStringList windowList();
|
QStringList windowList();
|
||||||
void previewWindow(unsigned int windowIndex) const;
|
void previewWindow(unsigned int windowIndex) const;
|
||||||
|
|
||||||
|
@ -77,8 +82,12 @@ signals:
|
||||||
void newMessage(const QString &roomid, const mtx::events::voip::CallCandidates &);
|
void newMessage(const QString &roomid, const mtx::events::voip::CallCandidates &);
|
||||||
void newMessage(const QString &roomid, const mtx::events::voip::CallAnswer &);
|
void newMessage(const QString &roomid, const mtx::events::voip::CallAnswer &);
|
||||||
void newMessage(const QString &roomid, const mtx::events::voip::CallHangUp &);
|
void newMessage(const QString &roomid, const mtx::events::voip::CallHangUp &);
|
||||||
|
void newMessage(const QString &roomid, const mtx::events::voip::CallSelectAnswer &);
|
||||||
|
void newMessage(const QString &roomid, const mtx::events::voip::CallReject &);
|
||||||
|
void newMessage(const QString &roomid, const mtx::events::voip::CallNegotiate &);
|
||||||
void newInviteState();
|
void newInviteState();
|
||||||
void newCallState();
|
void newCallState();
|
||||||
|
void newCallDeviceState();
|
||||||
void micMuteChanged();
|
void micMuteChanged();
|
||||||
void devicesChanged();
|
void devicesChanged();
|
||||||
void turnServerRetrieved(const mtx::responses::TurnServer &);
|
void turnServerRetrieved(const mtx::responses::TurnServer &);
|
||||||
|
@ -92,18 +101,23 @@ private:
|
||||||
QString callParty_;
|
QString callParty_;
|
||||||
QString callPartyDisplayName_;
|
QString callPartyDisplayName_;
|
||||||
QString callPartyAvatarUrl_;
|
QString callPartyAvatarUrl_;
|
||||||
|
std::string callPartyVersion_ = "1";
|
||||||
std::string callid_;
|
std::string callid_;
|
||||||
std::string partyid_ = "";
|
std::string partyid_ = mtx::client::utils::random_token(8, false);
|
||||||
std::string invitee_ = "";
|
std::string selectedpartyid_ = "";
|
||||||
const uint32_t timeoutms_ = 120000;
|
std::string invitee_ = "";
|
||||||
webrtc::CallType callType_ = webrtc::CallType::VOICE;
|
const uint32_t timeoutms_ = 120000;
|
||||||
bool haveCallInvite_ = false;
|
webrtc::CallType callType_ = webrtc::CallType::VOICE;
|
||||||
|
bool haveCallInvite_ = false;
|
||||||
|
bool answerSelected_ = false;
|
||||||
|
std::string isOnCallOnOtherDevice_ = "";
|
||||||
std::string inviteSDP_;
|
std::string inviteSDP_;
|
||||||
std::vector<mtx::events::voip::CallCandidates::Candidate> remoteICECandidates_;
|
std::vector<mtx::events::voip::CallCandidates::Candidate> remoteICECandidates_;
|
||||||
std::vector<std::string> turnURIs_;
|
std::vector<std::string> turnURIs_;
|
||||||
QTimer turnServerTimer_;
|
QTimer turnServerTimer_;
|
||||||
QMediaPlayer player_;
|
QMediaPlayer player_;
|
||||||
std::vector<std::pair<QString, uint32_t>> windows_;
|
std::vector<std::pair<QString, uint32_t>> windows_;
|
||||||
|
std::vector<std::string> rejectCallPartyIDs_;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool handleEvent(const mtx::events::collections::TimelineEvents &event);
|
bool handleEvent(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
@ -111,11 +125,14 @@ private:
|
||||||
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallCandidates> &);
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallCandidates> &);
|
||||||
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallAnswer> &);
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallAnswer> &);
|
||||||
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallHangUp> &);
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallHangUp> &);
|
||||||
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallSelectAnswer> &);
|
||||||
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallReject> &);
|
||||||
|
void handleEvent(const mtx::events::RoomEvent<mtx::events::voip::CallNegotiate> &);
|
||||||
void answerInvite(const mtx::events::voip::CallInvite &, bool isVideo);
|
void answerInvite(const mtx::events::voip::CallInvite &, bool isVideo);
|
||||||
void generateCallID();
|
void generateCallID();
|
||||||
QStringList devices(bool isVideo) const;
|
QStringList devices(bool isVideo) const;
|
||||||
void clear();
|
void clear(bool endAllCalls = true);
|
||||||
void endCall();
|
void endCall(bool endAllCalls = true);
|
||||||
void playRingtone(const QUrl &ringtone, bool repeat);
|
void playRingtone(const QUrl &ringtone, bool repeat);
|
||||||
void stopRingtone();
|
void stopRingtone();
|
||||||
};
|
};
|
||||||
|
|
|
@ -699,6 +699,15 @@ WebRTCSession::acceptOffer(const std::string &sdp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WebRTCSession::acceptNegotiation(const std::string &sdp)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("WebRTC: received negotiation offer:\n{}", sdp);
|
||||||
|
if (state_ == State::DISCONNECTED)
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebRTCSession::acceptAnswer(const std::string &sdp)
|
WebRTCSession::acceptAnswer(const std::string &sdp)
|
||||||
{
|
{
|
||||||
|
@ -1138,6 +1147,12 @@ WebRTCSession::createOffer(webrtc::CallType, uint32_t)
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
bool
|
||||||
|
WebRTCSession::acceptNegotiation(const std::string &)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebRTCSession::acceptOffer(const std::string &)
|
WebRTCSession::acceptOffer(const std::string &)
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
bool createOffer(webrtc::CallType, uint32_t shareWindowId);
|
bool createOffer(webrtc::CallType, uint32_t shareWindowId);
|
||||||
bool acceptOffer(const std::string &sdp);
|
bool acceptOffer(const std::string &sdp);
|
||||||
bool acceptAnswer(const std::string &sdp);
|
bool acceptAnswer(const std::string &sdp);
|
||||||
|
bool acceptNegotiation(const std::string &sdp);
|
||||||
void acceptICECandidates(const std::vector<mtx::events::voip::CallCandidates::Candidate> &);
|
void acceptICECandidates(const std::vector<mtx::events::voip::CallCandidates::Candidate> &);
|
||||||
|
|
||||||
bool isMicMuted() const;
|
bool isMicMuted() const;
|
||||||
|
|
Loading…
Reference in a new issue