diff --git a/src/CallManager.cpp b/src/CallManager.cpp
index 89cfeaf9..f725d49f 100644
--- a/src/CallManager.cpp
+++ b/src/CallManager.cpp
@@ -10,11 +10,9 @@
#include "CallManager.h"
#include "ChatPage.h"
#include "Logging.h"
-#include "MainWindow.h"
#include "MatrixClient.h"
+#include "UserSettingsPage.h"
#include "Utils.h"
-#include "WebRTCSession.h"
-#include "dialogs/AcceptCall.h"
#include "mtx/responses/turn_server.hpp"
@@ -112,6 +110,23 @@ CallManager::CallManager(QObject *parent)
default:
break;
}
+ emit newCallState();
+ });
+
+ connect(&session_, &WebRTCSession::devicesChanged, this, [this]() {
+ if (ChatPage::instance()->userSettings()->microphone().isEmpty()) {
+ auto mics = session_.getDeviceNames(false, std::string());
+ if (!mics.empty())
+ ChatPage::instance()->userSettings()->setMicrophone(
+ QString::fromStdString(mics.front()));
+ }
+ if (ChatPage::instance()->userSettings()->camera().isEmpty()) {
+ auto cameras = session_.getDeviceNames(true, std::string());
+ if (!cameras.empty())
+ ChatPage::instance()->userSettings()->setCamera(
+ QString::fromStdString(cameras.front()));
+ }
+ emit devicesChanged();
});
connect(&player_,
@@ -144,7 +159,7 @@ CallManager::CallManager(QObject *parent)
void
CallManager::sendInvite(const QString &roomid, bool isVideo)
{
- if (onActiveCall())
+ if (isOnCall())
return;
auto roomInfo = cache::singleRoomInfo(roomid.toStdString());
@@ -160,7 +175,8 @@ CallManager::sendInvite(const QString &roomid, bool isVideo)
return;
}
- roomid_ = roomid;
+ isVideo_ = isVideo;
+ roomid_ = roomid;
session_.setTurnServers(turnURIs_);
generateCallID();
nhlog::ui()->debug(
@@ -168,16 +184,14 @@ CallManager::sendInvite(const QString &roomid, bool isVideo)
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
const RoomMember &callee =
members.front().user_id == utils::localUser() ? members.back() : members.front();
- callPartyName_ = callee.display_name.isEmpty() ? callee.user_id : callee.display_name;
+ callParty_ = callee.display_name.isEmpty() ? callee.user_id : callee.display_name;
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
- emit newCallParty();
+ emit newInviteState();
playRingtone(QUrl("qrc:/media/media/ringback.ogg"), true);
if (!session_.createOffer(isVideo)) {
emit ChatPage::instance()->showNotification("Problem setting up call.");
endCall();
}
- if (isVideo)
- emit newVideoCallState();
}
namespace {
@@ -206,12 +220,6 @@ CallManager::hangUp(CallHangUp::Reason reason)
}
}
-bool
-CallManager::onActiveCall() const
-{
- return session_.state() != webrtc::State::DISCONNECTED;
-}
-
void
CallManager::syncEvent(const mtx::events::collections::TimelineEvents &event)
{
@@ -257,7 +265,7 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
return;
auto roomInfo = cache::singleRoomInfo(callInviteEvent.room_id);
- if (onActiveCall() || roomInfo.member_count != 2) {
+ if (isOnCall() || roomInfo.member_count != 2) {
emit newMessage(QString::fromStdString(callInviteEvent.room_id),
CallHangUp{callInviteEvent.content.call_id,
0,
@@ -277,48 +285,41 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
std::vector<RoomMember> members(cache::getMembers(callInviteEvent.room_id));
const RoomMember &caller =
members.front().user_id == utils::localUser() ? members.back() : members.front();
- callPartyName_ = caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
+ callParty_ = caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
- emit newCallParty();
- auto dialog = new dialogs::AcceptCall(caller.user_id,
- caller.display_name,
- QString::fromStdString(roomInfo.name),
- QString::fromStdString(roomInfo.avatar_url),
- isVideo,
- MainWindow::instance());
- connect(dialog, &dialogs::AcceptCall::accept, this, [this, callInviteEvent, isVideo]() {
- MainWindow::instance()->hideOverlay();
- answerInvite(callInviteEvent.content, isVideo);
- });
- connect(dialog, &dialogs::AcceptCall::reject, this, [this]() {
- MainWindow::instance()->hideOverlay();
- hangUp();
- });
- MainWindow::instance()->showSolidOverlayModal(dialog);
+
+ haveCallInvite_ = true;
+ isVideo_ = isVideo;
+ inviteSDP_ = callInviteEvent.content.sdp;
+ session_.refreshDevices();
+ emit newInviteState();
}
void
-CallManager::answerInvite(const CallInvite &invite, bool isVideo)
+CallManager::acceptInvite()
{
+ if (!haveCallInvite_)
+ return;
+
stopRingtone();
std::string errorMessage;
if (!session_.havePlugins(false, &errorMessage) ||
- (isVideo && !session_.havePlugins(true, &errorMessage))) {
+ (isVideo_ && !session_.havePlugins(true, &errorMessage))) {
emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
hangUp();
return;
}
session_.setTurnServers(turnURIs_);
- if (!session_.acceptOffer(invite.sdp)) {
+ if (!session_.acceptOffer(inviteSDP_)) {
emit ChatPage::instance()->showNotification("Problem setting up call.");
hangUp();
return;
}
session_.acceptICECandidates(remoteICECandidates_);
remoteICECandidates_.clear();
- if (isVideo)
- emit newVideoCallState();
+ haveCallInvite_ = false;
+ emit newInviteState();
}
void
@@ -332,7 +333,7 @@ CallManager::handleEvent(const RoomEvent<CallCandidates> &callCandidatesEvent)
callCandidatesEvent.sender);
if (callid_ == callCandidatesEvent.content.call_id) {
- if (onActiveCall())
+ if (isOnCall())
session_.acceptICECandidates(callCandidatesEvent.content.candidates);
else {
// CallInvite has been received and we're awaiting localUser to accept or
@@ -350,15 +351,19 @@ CallManager::handleEvent(const RoomEvent<CallAnswer> &callAnswerEvent)
callAnswerEvent.content.call_id,
callAnswerEvent.sender);
- if (!onActiveCall() && callAnswerEvent.sender == utils::localUser().toStdString() &&
+ if (callAnswerEvent.sender == utils::localUser().toStdString() &&
callid_ == callAnswerEvent.content.call_id) {
- emit ChatPage::instance()->showNotification("Call answered on another device.");
- stopRingtone();
- MainWindow::instance()->hideOverlay();
+ if (!isOnCall()) {
+ emit ChatPage::instance()->showNotification(
+ "Call answered on another device.");
+ stopRingtone();
+ haveCallInvite_ = false;
+ emit newInviteState();
+ }
return;
}
- if (onActiveCall() && callid_ == callAnswerEvent.content.call_id) {
+ if (isOnCall() && callid_ == callAnswerEvent.content.call_id) {
stopRingtone();
if (!session_.acceptAnswer(callAnswerEvent.content.sdp)) {
emit ChatPage::instance()->showNotification("Problem setting up call.");
@@ -375,10 +380,42 @@ CallManager::handleEvent(const RoomEvent<CallHangUp> &callHangUpEvent)
callHangUpReasonString(callHangUpEvent.content.reason),
callHangUpEvent.sender);
- if (callid_ == callHangUpEvent.content.call_id) {
- MainWindow::instance()->hideOverlay();
+ if (callid_ == callHangUpEvent.content.call_id)
endCall();
- }
+}
+
+void
+CallManager::toggleMicMute()
+{
+ session_.toggleMicMute();
+ emit micMuteChanged();
+}
+
+bool
+CallManager::callsSupported() const
+{
+#ifdef GSTREAMER_AVAILABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+QStringList
+CallManager::devices(bool isVideo) const
+{
+ QStringList ret;
+ const QString &defaultDevice = isVideo ? ChatPage::instance()->userSettings()->camera()
+ : ChatPage::instance()->userSettings()->microphone();
+ std::vector<std::string> devices =
+ session_.getDeviceNames(isVideo, defaultDevice.toStdString());
+ ret.reserve(devices.size());
+ std::transform(devices.cbegin(),
+ devices.cend(),
+ std::back_inserter(ret),
+ [](const auto &d) { return QString::fromStdString(d); });
+
+ return ret;
}
void
@@ -393,9 +430,13 @@ void
CallManager::clear()
{
roomid_.clear();
- callPartyName_.clear();
+ callParty_.clear();
callPartyAvatarUrl_.clear();
callid_.clear();
+ isVideo_ = false;
+ haveCallInvite_ = false;
+ emit newInviteState();
+ inviteSDP_.clear();
remoteICECandidates_.clear();
}
@@ -403,11 +444,8 @@ void
CallManager::endCall()
{
stopRingtone();
- clear();
- bool isVideo = session_.isVideo();
session_.end();
- if (isVideo)
- emit newVideoCallState();
+ clear();
}
void
diff --git a/src/CallManager.h b/src/CallManager.h
index 8004e838..7d388efd 100644
--- a/src/CallManager.h
+++ b/src/CallManager.h
@@ -8,6 +8,7 @@
#include <QString>
#include <QTimer>
+#include "WebRTCSession.h"
#include "mtx/events/collections.hpp"
#include "mtx/events/voip.hpp"
@@ -15,34 +16,59 @@ namespace mtx::responses {
struct TurnServer;
}
+class QStringList;
class QUrl;
-class WebRTCSession;
class CallManager : public QObject
{
Q_OBJECT
+ Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
+ Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
+ Q_PROPERTY(bool isVideo READ isVideo NOTIFY newInviteState)
+ Q_PROPERTY(bool haveLocalVideo READ haveLocalVideo NOTIFY newCallState)
+ Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
+ Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
+ Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY newInviteState)
+ Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged)
+ Q_PROPERTY(bool callsSupported READ callsSupported CONSTANT)
+ Q_PROPERTY(QStringList mics READ mics NOTIFY devicesChanged)
+ Q_PROPERTY(QStringList cameras READ cameras NOTIFY devicesChanged)
public:
CallManager(QObject *);
- void sendInvite(const QString &roomid, bool isVideo);
- void hangUp(
- mtx::events::msg::CallHangUp::Reason = mtx::events::msg::CallHangUp::Reason::User);
- bool onActiveCall() const;
- QString callPartyName() const { return callPartyName_; }
+ bool haveCallInvite() const { return haveCallInvite_; }
+ bool isOnCall() const { return session_.state() != webrtc::State::DISCONNECTED; }
+ bool isVideo() const { return isVideo_; }
+ bool haveLocalVideo() const { return session_.haveLocalVideo(); }
+ webrtc::State callState() const { return session_.state(); }
+ QString callParty() const { return callParty_; }
QString callPartyAvatarUrl() const { return callPartyAvatarUrl_; }
+ bool isMicMuted() const { return session_.isMicMuted(); }
+ bool callsSupported() const;
+ QStringList mics() const { return devices(false); }
+ QStringList cameras() const { return devices(true); }
void refreshTurnServer();
public slots:
+ void sendInvite(const QString &roomid, bool isVideo);
void syncEvent(const mtx::events::collections::TimelineEvents &event);
+ void refreshDevices() { session_.refreshDevices(); }
+ void toggleMicMute();
+ void toggleCameraView() { session_.toggleCameraView(); }
+ void acceptInvite();
+ void hangUp(
+ mtx::events::msg::CallHangUp::Reason = mtx::events::msg::CallHangUp::Reason::User);
signals:
void newMessage(const QString &roomid, const mtx::events::msg::CallInvite &);
void newMessage(const QString &roomid, const mtx::events::msg::CallCandidates &);
void newMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
void newMessage(const QString &roomid, const mtx::events::msg::CallHangUp &);
- void newCallParty();
- void newVideoCallState();
+ void newInviteState();
+ void newCallState();
+ void micMuteChanged();
+ void devicesChanged();
void turnServerRetrieved(const mtx::responses::TurnServer &);
private slots:
@@ -51,10 +77,13 @@ private slots:
private:
WebRTCSession &session_;
QString roomid_;
- QString callPartyName_;
+ QString callParty_;
QString callPartyAvatarUrl_;
std::string callid_;
const uint32_t timeoutms_ = 120000;
+ bool isVideo_ = false;
+ bool haveCallInvite_ = false;
+ std::string inviteSDP_;
std::vector<mtx::events::msg::CallCandidates::Candidate> remoteICECandidates_;
std::vector<std::string> turnURIs_;
QTimer turnServerTimer_;
@@ -68,6 +97,7 @@ private:
void handleEvent(const mtx::events::RoomEvent<mtx::events::msg::CallHangUp> &);
void answerInvite(const mtx::events::msg::CallInvite &, bool isVideo);
void generateCallID();
+ QStringList devices(bool isVideo) const;
void clear();
void endCall();
void playRingtone(const QUrl &ringtone, bool repeat);
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 4e87349a..238c9362 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -47,7 +47,6 @@
#include "notifications/Manager.h"
-#include "dialogs/PlaceCall.h"
#include "dialogs/ReadReceipts.h"
#include "popups/UserMentions.h"
#include "timeline/TimelineViewManager.h"
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 7c7ef9ab..f133c87d 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -464,7 +464,7 @@ UserSettings::applyTheme()
stylefile.setFileName(":/styles/styles/nheko.qss");
QPalette lightActive(
/*windowText*/ QColor("#333"),
- /*button*/ QColor("#333"),
+ /*button*/ QColor("white"),
/*light*/ QColor(0xef, 0xef, 0xef),
/*dark*/ QColor(110, 110, 110),
/*mid*/ QColor(220, 220, 220),
@@ -477,7 +477,7 @@ UserSettings::applyTheme()
lightActive.setColor(QPalette::ToolTipBase, lightActive.base().color());
lightActive.setColor(QPalette::ToolTipText, lightActive.text().color());
lightActive.setColor(QPalette::Link, QColor("#0077b5"));
- lightActive.setColor(QPalette::ButtonText, QColor("#495057"));
+ lightActive.setColor(QPalette::ButtonText, QColor("#333"));
QApplication::setPalette(lightActive);
} else if (this->theme() == "dark") {
stylefile.setFileName(":/styles/styles/nheko-dark.qss");
diff --git a/src/WebRTCSession.cpp b/src/WebRTCSession.cpp
index 0770a439..094a2906 100644
--- a/src/WebRTCSession.cpp
+++ b/src/WebRTCSession.cpp
@@ -242,12 +242,14 @@ newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data)
GstDevice *device;
gst_message_parse_device_added(msg, &device);
addDevice(device);
+ emit WebRTCSession::instance().devicesChanged();
break;
}
case GST_MESSAGE_DEVICE_REMOVED: {
GstDevice *device;
gst_message_parse_device_removed(msg, &device);
removeDevice(device, false);
+ emit WebRTCSession::instance().devicesChanged();
break;
}
case GST_MESSAGE_DEVICE_CHANGED: {
@@ -553,7 +555,10 @@ getResolution(GstPad *pad)
void
addCameraView(GstElement *pipe, const std::pair<int, int> &videoCallSize)
{
- GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe), "videosrctee");
+ GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe), "videosrctee");
+ if (!tee)
+ return;
+
GstElement *queue = gst_element_factory_make("queue", nullptr);
GstElement *videorate = gst_element_factory_make("videorate", nullptr);
gst_bin_add_many(GST_BIN(pipe), queue, videorate, nullptr);
@@ -1151,6 +1156,19 @@ WebRTCSession::addVideoPipeline(int vp8PayloadType)
}
bool
+WebRTCSession::haveLocalVideo() const
+{
+ if (isVideo_ && state_ >= State::INITIATED) {
+ GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe_), "videosrctee");
+ if (tee) {
+ gst_object_unref(tee);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
WebRTCSession::isMicMuted() const
{
if (state_ < State::INITIATED)
@@ -1274,6 +1292,7 @@ WebRTCSession::refreshDevices()
addDevice(GST_DEVICE_CAST(l->data));
g_list_free(devices);
}
+ emit devicesChanged();
#endif
}
@@ -1325,6 +1344,12 @@ WebRTCSession::havePlugins(bool, std::string *)
}
bool
+WebRTCSession::haveLocalVideo() const
+{
+ return false;
+}
+
+bool
WebRTCSession::createOffer(bool)
{
return false;
diff --git a/src/WebRTCSession.h b/src/WebRTCSession.h
index 57002f8f..2f0fb70e 100644
--- a/src/WebRTCSession.h
+++ b/src/WebRTCSession.h
@@ -43,6 +43,7 @@ public:
bool havePlugins(bool isVideo, std::string *errorMessage = nullptr);
webrtc::State state() const { return state_; }
bool isVideo() const { return isVideo_; }
+ bool haveLocalVideo() const;
bool isOffering() const { return isOffering_; }
bool isRemoteVideoRecvOnly() const { return isRemoteVideoRecvOnly_; }
@@ -75,6 +76,7 @@ signals:
const std::vector<mtx::events::msg::CallCandidates::Candidate> &);
void newICECandidate(const mtx::events::msg::CallCandidates::Candidate &);
void stateChanged(webrtc::State);
+ void devicesChanged();
private slots:
void setState(webrtc::State state) { state_ = state; }
diff --git a/src/dialogs/AcceptCall.cpp b/src/dialogs/AcceptCall.cpp
deleted file mode 100644
index 3d25ad82..00000000
--- a/src/dialogs/AcceptCall.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#include <QComboBox>
-#include <QLabel>
-#include <QPushButton>
-#include <QString>
-#include <QVBoxLayout>
-
-#include "ChatPage.h"
-#include "Config.h"
-#include "UserSettingsPage.h"
-#include "Utils.h"
-#include "WebRTCSession.h"
-#include "dialogs/AcceptCall.h"
-#include "ui/Avatar.h"
-
-namespace dialogs {
-
-AcceptCall::AcceptCall(const QString &caller,
- const QString &displayName,
- const QString &roomName,
- const QString &avatarUrl,
- bool isVideo,
- QWidget *parent)
- : QWidget(parent)
-{
- std::string errorMessage;
- WebRTCSession *session = &WebRTCSession::instance();
- if (!session->havePlugins(false, &errorMessage)) {
- emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
- emit close();
- return;
- }
- if (isVideo && !session->havePlugins(true, &errorMessage)) {
- emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
- emit close();
- return;
- }
-
- session->refreshDevices();
- microphones_ = session->getDeviceNames(
- false, ChatPage::instance()->userSettings()->microphone().toStdString());
- if (microphones_.empty()) {
- emit ChatPage::instance()->showNotification(
- tr("Incoming call: No microphone found."));
- emit close();
- return;
- }
- if (isVideo)
- cameras_ = session->getDeviceNames(
- true, ChatPage::instance()->userSettings()->camera().toStdString());
-
- setAutoFillBackground(true);
- setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
- setWindowModality(Qt::WindowModal);
- setAttribute(Qt::WA_DeleteOnClose, true);
-
- setMinimumWidth(conf::modals::MIN_WIDGET_WIDTH);
- setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
-
- auto layout = new QVBoxLayout(this);
- layout->setSpacing(conf::modals::WIDGET_SPACING);
- layout->setMargin(conf::modals::WIDGET_MARGIN);
-
- QFont f;
- f.setPointSizeF(f.pointSizeF());
-
- QFont labelFont;
- labelFont.setWeight(QFont::Medium);
-
- QLabel *displayNameLabel = nullptr;
- if (!displayName.isEmpty() && displayName != caller) {
- displayNameLabel = new QLabel(displayName, this);
- labelFont.setPointSizeF(f.pointSizeF() * 2);
- displayNameLabel->setFont(labelFont);
- displayNameLabel->setAlignment(Qt::AlignCenter);
- }
-
- QLabel *callerLabel = new QLabel(caller, this);
- labelFont.setPointSizeF(f.pointSizeF() * 1.2);
- callerLabel->setFont(labelFont);
- callerLabel->setAlignment(Qt::AlignCenter);
-
- auto avatar = new Avatar(this, QFontMetrics(f).height() * 6);
- if (!avatarUrl.isEmpty())
- avatar->setImage(avatarUrl);
- else
- avatar->setLetter(utils::firstChar(roomName));
-
- const int iconSize = 22;
- QLabel *callTypeIndicator = new QLabel(this);
- callTypeIndicator->setPixmap(
- QIcon(isVideo ? ":/icons/icons/ui/video-call.png" : ":/icons/icons/ui/place-call.png")
- .pixmap(QSize(iconSize * 2, iconSize * 2)));
-
- QLabel *callTypeLabel = new QLabel(isVideo ? tr("Video Call") : tr("Voice Call"), this);
- labelFont.setPointSizeF(f.pointSizeF() * 1.1);
- callTypeLabel->setFont(labelFont);
- callTypeLabel->setAlignment(Qt::AlignCenter);
-
- auto buttonLayout = new QHBoxLayout;
- buttonLayout->setSpacing(18);
- acceptBtn_ = new QPushButton(tr("Accept"), this);
- acceptBtn_->setDefault(true);
- acceptBtn_->setIcon(
- QIcon(isVideo ? ":/icons/icons/ui/video-call.png" : ":/icons/icons/ui/place-call.png"));
- acceptBtn_->setIconSize(QSize(iconSize, iconSize));
-
- rejectBtn_ = new QPushButton(tr("Reject"), this);
- rejectBtn_->setIcon(QIcon(":/icons/icons/ui/end-call.png"));
- rejectBtn_->setIconSize(QSize(iconSize, iconSize));
- buttonLayout->addWidget(acceptBtn_);
- buttonLayout->addWidget(rejectBtn_);
-
- microphoneCombo_ = new QComboBox(this);
- for (const auto &m : microphones_)
- microphoneCombo_->addItem(QIcon(":/icons/icons/ui/microphone-unmute.png"),
- QString::fromStdString(m));
-
- if (!cameras_.empty()) {
- cameraCombo_ = new QComboBox(this);
- for (const auto &c : cameras_)
- cameraCombo_->addItem(QIcon(":/icons/icons/ui/video-call.png"),
- QString::fromStdString(c));
- }
-
- if (displayNameLabel)
- layout->addWidget(displayNameLabel, 0, Qt::AlignCenter);
- layout->addWidget(callerLabel, 0, Qt::AlignCenter);
- layout->addWidget(avatar, 0, Qt::AlignCenter);
- layout->addWidget(callTypeIndicator, 0, Qt::AlignCenter);
- layout->addWidget(callTypeLabel, 0, Qt::AlignCenter);
- layout->addLayout(buttonLayout);
- layout->addWidget(microphoneCombo_);
- if (cameraCombo_)
- layout->addWidget(cameraCombo_);
-
- connect(acceptBtn_, &QPushButton::clicked, this, [this]() {
- ChatPage::instance()->userSettings()->setMicrophone(
- QString::fromStdString(microphones_[microphoneCombo_->currentIndex()]));
- if (cameraCombo_) {
- ChatPage::instance()->userSettings()->setCamera(
- QString::fromStdString(cameras_[cameraCombo_->currentIndex()]));
- }
- emit accept();
- emit close();
- });
- connect(rejectBtn_, &QPushButton::clicked, this, [this]() {
- emit reject();
- emit close();
- });
-}
-
-}
diff --git a/src/dialogs/AcceptCall.h b/src/dialogs/AcceptCall.h
deleted file mode 100644
index 76ca7ae1..00000000
--- a/src/dialogs/AcceptCall.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include <QWidget>
-
-class QComboBox;
-class QPushButton;
-class QString;
-
-namespace dialogs {
-
-class AcceptCall : public QWidget
-{
- Q_OBJECT
-
-public:
- AcceptCall(const QString &caller,
- const QString &displayName,
- const QString &roomName,
- const QString &avatarUrl,
- bool isVideo,
- QWidget *parent = nullptr);
-
-signals:
- void accept();
- void reject();
-
-private:
- QPushButton *acceptBtn_ = nullptr;
- QPushButton *rejectBtn_ = nullptr;
- QComboBox *microphoneCombo_ = nullptr;
- QComboBox *cameraCombo_ = nullptr;
- std::vector<std::string> microphones_;
- std::vector<std::string> cameras_;
-};
-
-}
diff --git a/src/dialogs/PlaceCall.cpp b/src/dialogs/PlaceCall.cpp
deleted file mode 100644
index 85a398a2..00000000
--- a/src/dialogs/PlaceCall.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-#include <QComboBox>
-#include <QLabel>
-#include <QPushButton>
-#include <QString>
-#include <QVBoxLayout>
-
-#include "ChatPage.h"
-#include "Config.h"
-#include "UserSettingsPage.h"
-#include "Utils.h"
-#include "WebRTCSession.h"
-#include "dialogs/PlaceCall.h"
-#include "ui/Avatar.h"
-
-namespace dialogs {
-
-PlaceCall::PlaceCall(const QString &callee,
- const QString &displayName,
- const QString &roomName,
- const QString &avatarUrl,
- QSharedPointer<UserSettings> settings,
- QWidget *parent)
- : QWidget(parent)
-{
- std::string errorMessage;
- WebRTCSession *session = &WebRTCSession::instance();
- if (!session->havePlugins(false, &errorMessage)) {
- emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
- emit close();
- return;
- }
- session->refreshDevices();
- microphones_ = session->getDeviceNames(false, settings->microphone().toStdString());
- if (microphones_.empty()) {
- emit ChatPage::instance()->showNotification(tr("No microphone found."));
- emit close();
- return;
- }
- cameras_ = session->getDeviceNames(true, settings->camera().toStdString());
-
- setAutoFillBackground(true);
- setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
- setWindowModality(Qt::WindowModal);
- setAttribute(Qt::WA_DeleteOnClose, true);
-
- auto layout = new QVBoxLayout(this);
- layout->setSpacing(conf::modals::WIDGET_SPACING);
- layout->setMargin(conf::modals::WIDGET_MARGIN);
-
- auto buttonLayout = new QHBoxLayout;
- buttonLayout->setSpacing(15);
- buttonLayout->setMargin(0);
-
- QFont f;
- f.setPointSizeF(f.pointSizeF());
- auto avatar = new Avatar(this, QFontMetrics(f).height() * 3);
- if (!avatarUrl.isEmpty())
- avatar->setImage(avatarUrl);
- else
- avatar->setLetter(utils::firstChar(roomName));
-
- voiceBtn_ = new QPushButton(tr("Voice"), this);
- voiceBtn_->setIcon(QIcon(":/icons/icons/ui/place-call.png"));
- voiceBtn_->setIconSize(QSize(iconSize_, iconSize_));
- voiceBtn_->setDefault(true);
-
- if (!cameras_.empty()) {
- videoBtn_ = new QPushButton(tr("Video"), this);
- videoBtn_->setIcon(QIcon(":/icons/icons/ui/video-call.png"));
- videoBtn_->setIconSize(QSize(iconSize_, iconSize_));
- }
- cancelBtn_ = new QPushButton(tr("Cancel"), this);
-
- buttonLayout->addWidget(avatar);
- buttonLayout->addStretch();
- buttonLayout->addWidget(voiceBtn_);
- if (videoBtn_)
- buttonLayout->addWidget(videoBtn_);
- buttonLayout->addWidget(cancelBtn_);
-
- QString name = displayName.isEmpty() ? callee : displayName;
- QLabel *label = new QLabel(tr("Place a call to ") + name + "?", this);
-
- microphoneCombo_ = new QComboBox(this);
- for (const auto &m : microphones_)
- microphoneCombo_->addItem(QIcon(":/icons/icons/ui/microphone-unmute.png"),
- QString::fromStdString(m));
-
- if (videoBtn_) {
- cameraCombo_ = new QComboBox(this);
- for (const auto &c : cameras_)
- cameraCombo_->addItem(QIcon(":/icons/icons/ui/video-call.png"),
- QString::fromStdString(c));
- }
-
- layout->addWidget(label);
- layout->addLayout(buttonLayout);
- layout->addStretch();
- layout->addWidget(microphoneCombo_);
- if (videoBtn_)
- layout->addWidget(cameraCombo_);
-
- connect(voiceBtn_, &QPushButton::clicked, this, [this, settings]() {
- settings->setMicrophone(
- QString::fromStdString(microphones_[microphoneCombo_->currentIndex()]));
- emit voice();
- emit close();
- });
- if (videoBtn_)
- connect(videoBtn_, &QPushButton::clicked, this, [this, settings, session]() {
- std::string error;
- if (!session->havePlugins(true, &error)) {
- emit ChatPage::instance()->showNotification(
- QString::fromStdString(error));
- emit close();
- return;
- }
- settings->setMicrophone(
- QString::fromStdString(microphones_[microphoneCombo_->currentIndex()]));
- settings->setCamera(
- QString::fromStdString(cameras_[cameraCombo_->currentIndex()]));
- emit video();
- emit close();
- });
- connect(cancelBtn_, &QPushButton::clicked, this, [this]() {
- emit cancel();
- emit close();
- });
-}
-
-}
diff --git a/src/dialogs/PlaceCall.h b/src/dialogs/PlaceCall.h
deleted file mode 100644
index e042258f..00000000
--- a/src/dialogs/PlaceCall.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include <QSharedPointer>
-#include <QWidget>
-
-class QComboBox;
-class QPushButton;
-class QString;
-class UserSettings;
-
-namespace dialogs {
-
-class PlaceCall : public QWidget
-{
- Q_OBJECT
-
-public:
- PlaceCall(const QString &callee,
- const QString &displayName,
- const QString &roomName,
- const QString &avatarUrl,
- QSharedPointer<UserSettings> settings,
- QWidget *parent = nullptr);
-
-signals:
- void voice();
- void video();
- void cancel();
-
-private:
- const int iconSize_ = 18;
- QPushButton *voiceBtn_ = nullptr;
- QPushButton *videoBtn_ = nullptr;
- QPushButton *cancelBtn_ = nullptr;
- QComboBox *microphoneCombo_ = nullptr;
- QComboBox *cameraCombo_ = nullptr;
- std::vector<std::string> microphones_;
- std::vector<std::string> cameras_;
-};
-
-}
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index 5cbc33e0..3cddd613 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -13,7 +13,6 @@
#include <mtx/responses/media.hpp>
#include "Cache.h"
-#include "CallManager.h"
#include "ChatPage.h"
#include "CompletionProxyModel.h"
#include "Logging.h"
@@ -25,7 +24,6 @@
#include "UserSettingsPage.h"
#include "UsersModel.h"
#include "Utils.h"
-#include "dialogs/PlaceCall.h"
#include "dialogs/PreviewUploadOverlay.h"
#include "emoji/EmojiModel.h"
@@ -594,48 +592,6 @@ InputBar::showPreview(const QMimeData &source, QString path, const QStringList &
}
void
-InputBar::callButton()
-{
- auto callManager_ = ChatPage::instance()->callManager();
- if (callManager_->onActiveCall()) {
- callManager_->hangUp();
- } else {
- auto current_room_ = room->roomId();
- if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString());
- roomInfo.member_count != 2) {
- ChatPage::instance()->showNotification("Calls are limited to 1:1 rooms.");
- } else {
- std::vector<RoomMember> members(
- cache::getMembers(current_room_.toStdString()));
- const RoomMember &callee = members.front().user_id == utils::localUser()
- ? members.back()
- : members.front();
- auto dialog =
- new dialogs::PlaceCall(callee.user_id,
- callee.display_name,
- QString::fromStdString(roomInfo.name),
- QString::fromStdString(roomInfo.avatar_url),
- ChatPage::instance()->userSettings(),
- MainWindow::instance());
- connect(dialog,
- &dialogs::PlaceCall::voice,
- callManager_,
- [callManager_, current_room_]() {
- callManager_->sendInvite(current_room_, false);
- });
- connect(dialog,
- &dialogs::PlaceCall::video,
- callManager_,
- [callManager_, current_room_]() {
- callManager_->sendInvite(current_room_, true);
- });
- utils::centerWidget(dialog, MainWindow::instance());
- dialog->show();
- }
- }
-}
-
-void
InputBar::startTyping()
{
if (!typingRefresh_.isActive()) {
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index 89ca34fe..c729a6fc 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -41,7 +41,6 @@ public slots:
void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text);
void openFileSelection();
bool uploading() const { return uploading_; }
- void callButton();
void message(QString body);
QObject *completerFor(QString completerName);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index adef886d..2b5b5794 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -613,8 +613,13 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
std::visit(
[this](auto &event) {
event.room_id = room_id_.toStdString();
- if (event.sender != http::client()->user_id().to_string())
+ if constexpr (std::is_same_v<std::decay_t<decltype(event)>,
+ RoomEvent<msg::CallAnswer>>)
emit newCallEvent(event);
+ else {
+ if (event.sender != http::client()->user_id().to_string())
+ emit newCallEvent(event);
+ }
},
e);
else if (std::holds_alternative<StateEvent<state::Avatar>>(e))
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index f10c2c0d..97af0065 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -136,6 +136,10 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
return ChatPage::instance()->userSettings().data();
});
+ qmlRegisterSingletonType<CallManager>(
+ "im.nheko", 1, 0, "CallManager", [](QQmlEngine *, QJSEngine *) -> QObject * {
+ return ChatPage::instance()->callManager();
+ });
qRegisterMetaType<mtx::events::collections::TimelineEvents>();
qRegisterMetaType<std::vector<DeviceInfo>>();
@@ -237,36 +241,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
isInitialSync_ = true;
emit initialSyncChanged(true);
});
- connect(&WebRTCSession::instance(),
- &WebRTCSession::stateChanged,
- this,
- &TimelineViewManager::callStateChanged);
- connect(
- callManager_, &CallManager::newCallParty, this, &TimelineViewManager::callPartyChanged);
- connect(callManager_,
- &CallManager::newVideoCallState,
- this,
- &TimelineViewManager::videoCallChanged);
-
- connect(&WebRTCSession::instance(),
- &WebRTCSession::stateChanged,
- this,
- &TimelineViewManager::onCallChanged);
-}
-
-bool
-TimelineViewManager::isOnCall() const
-{
- return callManager_->onActiveCall();
-}
-bool
-TimelineViewManager::callsSupported() const
-{
-#ifdef GSTREAMER_AVAILABLE
- return true;
-#else
- return false;
-#endif
}
void
@@ -355,19 +329,6 @@ TimelineViewManager::escapeEmoji(QString str) const
}
void
-TimelineViewManager::toggleMicMute()
-{
- WebRTCSession::instance().toggleMicMute();
- emit micMuteChanged();
-}
-
-void
-TimelineViewManager::toggleCameraView()
-{
- WebRTCSession::instance().toggleCameraView();
-}
-
-void
TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const
{
if (mxcUrl.isEmpty()) {
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 1cec0939..23a960b8 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -36,13 +36,6 @@ class TimelineViewManager : public QObject
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(
bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
- Q_PROPERTY(webrtc::State callState READ callState NOTIFY callStateChanged)
- Q_PROPERTY(bool onVideoCall READ onVideoCall NOTIFY videoCallChanged)
- Q_PROPERTY(QString callPartyName READ callPartyName NOTIFY callPartyChanged)
- Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY callPartyChanged)
- Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged)
- Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY onCallChanged)
- Q_PROPERTY(bool callsSupported READ callsSupported CONSTANT)
public:
TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr);
@@ -61,14 +54,6 @@ public:
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
bool isNarrowView() const { return isNarrowView_; }
- webrtc::State callState() const { return WebRTCSession::instance().state(); }
- bool onVideoCall() const { return WebRTCSession::instance().isVideo(); }
- Q_INVOKABLE void setVideoCallItem();
- QString callPartyName() const { return callManager_->callPartyName(); }
- QString callPartyAvatarUrl() const { return callManager_->callPartyAvatarUrl(); }
- bool isMicMuted() const { return WebRTCSession::instance().isMicMuted(); }
- Q_INVOKABLE void toggleMicMute();
- Q_INVOKABLE void toggleCameraView();
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
Q_INVOKABLE QColor userColor(QString id, QColor background);
Q_INVOKABLE QString escapeEmoji(QString str) const;
@@ -98,11 +83,6 @@ signals:
void inviteUsers(QStringList users);
void showRoomList();
void narrowViewChanged();
- void callStateChanged(webrtc::State);
- void videoCallChanged();
- void callPartyChanged();
- void micMuteChanged();
- void onCallChanged();
public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
@@ -130,8 +110,7 @@ public slots:
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallHangUp &);
void updateEncryptedDescriptions();
- bool isOnCall() const;
- bool callsSupported() const;
+ void setVideoCallItem();
void enableBackButton()
{
|