diff --git a/src/CallManager.cpp b/src/CallManager.cpp index ac0636e0..89cfeaf9 100644 --- a/src/CallManager.cpp +++ b/src/CallManager.cpp @@ -98,7 +98,7 @@ CallManager::CallManager(QObject *parent) connect(&session_, &WebRTCSession::stateChanged, this, [this](webrtc::State state) { switch (state) { case webrtc::State::DISCONNECTED: - playRingtone("qrc:/media/media/callend.ogg", false); + playRingtone(QUrl("qrc:/media/media/callend.ogg"), false); clear(); break; case webrtc::State::ICEFAILED: { @@ -121,6 +121,24 @@ CallManager::CallManager(QObject *parent) if (status == QMediaPlayer::LoadedMedia) player_.play(); }); + + connect(&player_, + QOverload::of(&QMediaPlayer::error), + [this](QMediaPlayer::Error error) { + stopRingtone(); + switch (error) { + case QMediaPlayer::FormatError: + case QMediaPlayer::ResourceError: + nhlog::ui()->error("WebRTC: valid ringtone file not found"); + break; + case QMediaPlayer::AccessDeniedError: + nhlog::ui()->error("WebRTC: access to ringtone file denied"); + break; + default: + nhlog::ui()->error("WebRTC: unable to play ringtone"); + break; + } + }); } void @@ -153,7 +171,7 @@ CallManager::sendInvite(const QString &roomid, bool isVideo) callPartyName_ = callee.display_name.isEmpty() ? callee.user_id : callee.display_name; callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url); emit newCallParty(); - playRingtone("qrc:/media/media/ringback.ogg", true); + playRingtone(QUrl("qrc:/media/media/ringback.ogg"), true); if (!session_.createOffer(isVideo)) { emit ChatPage::instance()->showNotification("Problem setting up call."); endCall(); @@ -247,7 +265,11 @@ CallManager::handleEvent(const RoomEvent &callInviteEvent) return; } - playRingtone("qrc:/media/media/ring.ogg", true); + const QString &ringtone = ChatPage::instance()->userSettings()->ringtone(); + if (ringtone != "Mute") + playRingtone(ringtone == "Default" ? QUrl("qrc:/media/media/ring.ogg") + : QUrl::fromLocalFile(ringtone), + true); roomid_ = QString::fromStdString(callInviteEvent.room_id); callid_ = callInviteEvent.content.call_id; remoteICECandidates_.clear(); @@ -409,13 +431,13 @@ CallManager::retrieveTurnServer() } void -CallManager::playRingtone(const QString &ringtone, bool repeat) +CallManager::playRingtone(const QUrl &ringtone, bool repeat) { static QMediaPlaylist playlist; playlist.clear(); playlist.setPlaybackMode(repeat ? QMediaPlaylist::CurrentItemInLoop : QMediaPlaylist::CurrentItemOnce); - playlist.addMedia(QUrl(ringtone)); + playlist.addMedia(ringtone); player_.setVolume(100); player_.setPlaylist(&playlist); } diff --git a/src/CallManager.h b/src/CallManager.h index da7569e2..8004e838 100644 --- a/src/CallManager.h +++ b/src/CallManager.h @@ -15,6 +15,7 @@ namespace mtx::responses { struct TurnServer; } +class QUrl; class WebRTCSession; class CallManager : public QObject @@ -69,6 +70,6 @@ private: void generateCallID(); void clear(); void endCall(); - void playRingtone(const QString &ringtone, bool repeat); + void playRingtone(const QUrl &ringtone, bool repeat); void stopRingtone(); }; diff --git a/src/Olm.cpp b/src/Olm.cpp index cdafabf3..af8bb512 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -435,8 +435,8 @@ send_key_request_for(mtx::events::EncryptedEvent e, e.content.session_id); mtx::events::msg::KeyRequest request; - request.action = !cancel ? mtx::events::msg::RequestAction::Request - : mtx::events::msg::RequestAction::Cancellation; + request.action = !cancel ? mtx::events::msg::RequestAction::Request + : mtx::events::msg::RequestAction::Cancellation; request.algorithm = MEGOLM_ALGO; request.room_id = e.room_id; request.sender_key = e.content.sender_key; diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index f75358c8..454353fd 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -453,8 +453,8 @@ FilteredTextEdit::completerRect() auto item_height = completer_->popup()->sizeHintForRow(0); auto max_height = item_height * completer_->maxVisibleItems(); auto height = (completer_->completionCount() > completer_->maxVisibleItems()) - ? max_height - : completer_->completionCount() * item_height; + ? max_height + : completer_->completionCount() * item_height; rect.setWidth(completer_->popup()->sizeHintForColumn(0)); rect.moveBottom(-height); return rect; diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index df75ee7f..c26faed2 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -83,6 +83,7 @@ UserSettings::load() presence_ = settings.value("user/presence", QVariant::fromValue(Presence::AutomaticPresence)) .value(); + ringtone_ = settings.value("user/ringtone", "Default").toString(); microphone_ = settings.value("user/microphone", QString()).toString(); camera_ = settings.value("user/camera", QString()).toString(); cameraResolution_ = settings.value("user/camera_resolution", QString()).toString(); @@ -321,6 +322,16 @@ UserSettings::setShareKeysWithTrustedUsers(bool shareKeys) save(); } +void +UserSettings::setRingtone(QString ringtone) +{ + if (ringtone == ringtone_) + return; + ringtone_ = ringtone; + emit ringtoneChanged(ringtone); + save(); +} + void UserSettings::setMicrophone(QString microphone) { @@ -450,6 +461,7 @@ UserSettings::save() settings.setValue("font_family", font_); settings.setValue("emoji_font_family", emojiFont_); settings.setValue("presence", QVariant::fromValue(presence_)); + settings.setValue("ringtone", ringtone_); settings.setValue("microphone", microphone_); settings.setValue("camera", camera_); settings.setValue("camera_resolution", cameraResolution_); @@ -530,6 +542,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge fontSizeCombo_ = new QComboBox{this}; fontSelectionCombo_ = new QFontComboBox{this}; emojiFontSelectionCombo_ = new QComboBox{this}; + ringtoneCombo_ = new QComboBox{this}; microphoneCombo_ = new QComboBox{this}; cameraCombo_ = new QComboBox{this}; cameraResolutionCombo_ = new QComboBox{this}; @@ -720,14 +733,26 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge formLayout_->addRow(callsLabel); formLayout_->addRow(new HorizontalLine{this}); + boxWrap(tr("Ringtone"), + ringtoneCombo_, + tr("Set the notification sound to play when a call invite arrives")); boxWrap(tr("Microphone"), microphoneCombo_); boxWrap(tr("Camera"), cameraCombo_); boxWrap(tr("Camera resolution"), cameraResolutionCombo_); boxWrap(tr("Camera frame rate"), cameraFrameRateCombo_); + + ringtoneCombo_->setSizeAdjustPolicy(QComboBox::AdjustToContents); + ringtoneCombo_->addItem("Mute"); + ringtoneCombo_->addItem("Default"); + ringtoneCombo_->addItem("Other..."); + const QString &ringtone = settings_->ringtone(); + if (!ringtone.isEmpty() && ringtone != "Mute" && ringtone != "Default") + ringtoneCombo_->addItem(ringtone); microphoneCombo_->setSizeAdjustPolicy(QComboBox::AdjustToContents); cameraCombo_->setSizeAdjustPolicy(QComboBox::AdjustToContents); cameraResolutionCombo_->setSizeAdjustPolicy(QComboBox::AdjustToContents); cameraFrameRateCombo_->setSizeAdjustPolicy(QComboBox::AdjustToContents); + boxWrap(tr("Allow fallback call assist server"), useStunServer_, tr("Will use turn.matrix.org as assist when your home server does not offer one.")); @@ -786,6 +811,34 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge static_cast(&QComboBox::currentTextChanged), [this](const QString &family) { settings_->setEmojiFontFamily(family.trimmed()); }); + connect(ringtoneCombo_, + static_cast(&QComboBox::currentTextChanged), + [this](const QString &ringtone) { + if (ringtone == "Other...") { + QString homeFolder = + QStandardPaths::writableLocation(QStandardPaths::HomeLocation); + auto filepath = QFileDialog::getOpenFileName( + this, tr("Select a file"), homeFolder, tr("All Files (*)")); + if (!filepath.isEmpty()) { + const auto &oldSetting = settings_->ringtone(); + if (oldSetting != "Mute" && oldSetting != "Default") + ringtoneCombo_->removeItem( + ringtoneCombo_->findText(oldSetting)); + settings_->setRingtone(filepath); + ringtoneCombo_->addItem(filepath); + ringtoneCombo_->setCurrentText(filepath); + } else { + ringtoneCombo_->setCurrentText(settings_->ringtone()); + } + } else if (ringtone == "Mute" || ringtone == "Default") { + const auto &oldSetting = settings_->ringtone(); + if (oldSetting != "Mute" && oldSetting != "Default") + ringtoneCombo_->removeItem( + ringtoneCombo_->findText(oldSetting)); + settings_->setRingtone(ringtone); + } + }); + connect(microphoneCombo_, static_cast(&QComboBox::currentTextChanged), [this](const QString µphone) { settings_->setMicrophone(microphone); }); @@ -916,6 +969,7 @@ UserSettingsPage::showEvent(QShowEvent *) utils::restoreCombobox(fontSizeCombo_, QString::number(settings_->fontSize()) + " "); utils::restoreCombobox(scaleFactorCombo_, QString::number(utils::scaleFactor())); utils::restoreCombobox(themeCombo_, settings_->theme()); + utils::restoreCombobox(ringtoneCombo_, settings_->ringtone()); // FIXME: Toggle treats true as "off" trayToggle_->setState(!settings_->tray()); diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h index 0bd0ac84..d1ae93f0 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h @@ -73,6 +73,7 @@ class UserSettings : public QObject Q_PROPERTY( QString emojiFont READ emojiFont WRITE setEmojiFontFamily NOTIFY emojiFontChanged) Q_PROPERTY(Presence presence READ presence WRITE setPresence NOTIFY presenceChanged) + Q_PROPERTY(QString ringtone READ ringtone WRITE setRingtone NOTIFY ringtoneChanged) Q_PROPERTY(QString microphone READ microphone WRITE setMicrophone NOTIFY microphoneChanged) Q_PROPERTY(QString camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(QString cameraResolution READ cameraResolution WRITE setCameraResolution NOTIFY @@ -120,6 +121,7 @@ public: void setAvatarCircles(bool state); void setDecryptSidebar(bool state); void setPresence(Presence state); + void setRingtone(QString ringtone); void setMicrophone(QString microphone); void setCamera(QString camera); void setCameraResolution(QString resolution); @@ -152,6 +154,7 @@ public: QString font() const { return font_; } QString emojiFont() const { return emojiFont_; } Presence presence() const { return presence_; } + QString ringtone() const { return ringtone_; } QString microphone() const { return microphone_; } QString camera() const { return camera_; } QString cameraResolution() const { return cameraResolution_; } @@ -181,6 +184,7 @@ signals: void fontChanged(QString state); void emojiFontChanged(QString state); void presenceChanged(Presence state); + void ringtoneChanged(QString ringtone); void microphoneChanged(QString microphone); void cameraChanged(QString camera); void cameraResolutionChanged(QString resolution); @@ -216,6 +220,7 @@ private: QString font_; QString emojiFont_; Presence presence_; + QString ringtone_; QString microphone_; QString camera_; QString cameraResolution_; @@ -286,6 +291,7 @@ private: QComboBox *fontSizeCombo_; QFontComboBox *fontSelectionCombo_; QComboBox *emojiFontSelectionCombo_; + QComboBox *ringtoneCombo_; QComboBox *microphoneCombo_; QComboBox *cameraCombo_; QComboBox *cameraResolutionCombo_; diff --git a/src/Utils.cpp b/src/Utils.cpp index 0bfc82c3..38dbba22 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -638,7 +638,7 @@ utils::luminance(const QColor &col) qreal lumRgb[3]; for (int i = 0; i < 3; i++) { - qreal v = colRgb[i] / 255.0; + qreal v = colRgb[i] / 255.0; v <= 0.03928 ? lumRgb[i] = v / 12.92 : lumRgb[i] = qPow((v + 0.055) / 1.055, 2.4); }