call: две фазы исходящего вызова — индикация + разные гудки (desktop/Android)

This commit is contained in:
evgeny committed 2026-09-23 19:16:53 +03:00
1 parent 7198154106
commit b90dc752d2
21 files changed
+170 -21

No files matched your search

+7 -2
View File
@@ -229,6 +229,10 @@ void CallWindow::setState(State s) {
m_state = s;
switch (s) {
case Outgoing:
m_statusLabel->setText(QStringLiteral("Пытаемся связаться…"));
m_durationLabel->hide();
break;
case Ringing:
m_statusLabel->setText(QStringLiteral("Звоним…"));
m_durationLabel->hide();
break;
@@ -273,7 +277,7 @@ void CallWindow::populateDeviceCombo() {
void CallWindow::updateButtons() {
m_acceptCell->setVisible(m_state == Incoming);
m_declineCell->setVisible(m_state == Incoming);
m_hangupCell->setVisible(m_state == Outgoing || m_state == Active);
m_hangupCell->setVisible(m_state == Outgoing || m_state == Ringing || m_state == Active);
m_muteCell->setVisible(m_state == Active);
m_deviceCombo->setVisible(m_state == Active);
}
@@ -314,7 +318,8 @@ void CallWindow::onDeviceChanged(int index) {
}
void CallWindow::closeEvent(QCloseEvent* event) {
if (m_state == Active) postCallFn(call_hangup_trampoline, m_callId);
if (m_state == Outgoing || m_state == Ringing || m_state == Active)
postCallFn(call_hangup_trampoline, m_callId);
emit closed(m_callId);
event->accept();
}
+3 -3
View File
@@ -8,12 +8,12 @@ class QPushButton;
class QComboBox;
class QTimer;
/* Окно звонка: состояния Outgoing (звоним), Incoming (принять/отклонить),
* Active (идёт разговор, таймер), Ended (завершён). */
/* Окно звонка: состояния Outgoing (пытаемся связаться), Ringing (звоним),
* Incoming (принять/отклонить), Active (идёт разговор, таймер), Ended (завершён). */
class CallWindow : public QWidget {
Q_OBJECT
public:
enum State { Outgoing, Incoming, Active, Ended };
enum State { Outgoing, Ringing, Incoming, Active, Ended };
explicit CallWindow(QWidget* parent = nullptr);
~CallWindow() override;
+24 -5
View File
@@ -328,16 +328,20 @@ void MainWindow::setupSoundFromConfig() {
else
sm->loadSound("call_incoming", resolvePath(callInFile));
sm->loadSound("call_connecting", ":/sounds/call_connecting.mp3");
sm->loadSound("call_ringing", ":/sounds/call_ringing.mp3");
if (!msgOutFile.isEmpty()) sm->loadSound("msg_outgoing", resolvePath(msgOutFile));
if (!connectFile.isEmpty()) sm->loadSound("connect", resolvePath(connectFile));
if (!disconnectFile.isEmpty()) sm->loadSound("disconnect", resolvePath(disconnectFile));
if (m_db && m_db->isOpen()) {
sm->setEnabled(m_db->getUiStateInt("sound_enabled", 1));
sm->setVolume(m_db->getUiStateInt("sound_volume", 80) / 100.0f);
QString se[] = {"msg_incoming", "msg_outgoing", "connect", "disconnect", "call_incoming"};
for (int i = 0; i < 5; i++) {
QString se[] = {"msg_incoming", "msg_outgoing", "connect", "disconnect",
"call_incoming", "call_connecting", "call_ringing"};
for (int i = 0; i < 7; i++) {
const QString& ek = se[i];
sm->setEvent(ek, m_db->getUiStateInt(QStringLiteral("sound_%1_on").arg(ek), (i == 0 || i == 4) ? 1 : 0),
sm->setEvent(ek, m_db->getUiStateInt(QStringLiteral("sound_%1_on").arg(ek), (i == 0 || i >= 4) ? 1 : 0),
m_db->getUiStateInt(QStringLiteral("sound_%1_vol").arg(ek), 80) / 100.0f);
}
}
@@ -448,6 +452,10 @@ void MainWindow::setupBridgeCallbacks() {
gui_bridge_set_call_declined_cb([](uint64_t call_id, uint8_t reason) {
if (s_mainWindow) s_mainWindow->onCallEnded(call_id, reason);
});
gui_bridge_set_call_error_cb([](uint64_t call_id, uint8_t err, const char* text, int len) {
Q_UNUSED(text); Q_UNUSED(len);
if (s_mainWindow) s_mainWindow->onCallError(call_id, err);
});
gui_bridge_set_call_path_cb([](uint64_t call_id, const char* text, int len) {
if (s_mainWindow) s_mainWindow->onCallPath(call_id, QString::fromUtf8(text, len));
});
@@ -537,6 +545,8 @@ void MainWindow::onCallRequested(const QString& chId, quint64 nodeId, const QStr
connect(w, &CallWindow::closed, this, &MainWindow::closeCallWindow);
m_activeCalls.insert(callId, w);
w->show();
SoundManager::instance()->playLoop("call_connecting");
}
void MainWindow::onCallIncoming(const QString& chId, quint64 caller, quint64 callId) {
@@ -563,8 +573,11 @@ void MainWindow::onCallIncoming(const QString& chId, quint64 caller, quint64 cal
}
void MainWindow::onCallRinging(quint64 callId) {
/* caller слышит гудок — окно уже показано в Outgoing */
Q_UNUSED(callId);
/* caller: INVITE доставлен, у пира идёт вызов — фаза 2 (гудки) */
CallWindow* w = m_activeCalls.value(callId, nullptr);
if (w && w->state() == CallWindow::Outgoing)
w->setState(CallWindow::Ringing);
SoundManager::instance()->playLoop("call_ringing");
}
void MainWindow::onCallAccepted(quint64 callId) {
@@ -584,6 +597,12 @@ void MainWindow::onCallEnded(quint64 callId, uint8_t reason) {
closeCallWindow(callId);
}
void MainWindow::onCallError(quint64 callId, uint8_t err) {
/* пир офлайн / нет маршрута — звонок не состоялся */
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "MainWindow: call error id=%016llx err=%u", (unsigned long long)callId, (unsigned)err);
closeCallWindow(callId);
}
void MainWindow::onCallPath(quint64 callId, const QString& path) {
CallWindow* w = m_activeCalls.value(callId, nullptr);
if (w) w->setBgpPath(path);
+1
View File
@@ -72,6 +72,7 @@ public:
void onCallRinging(quint64 callId);
void onCallAccepted(quint64 callId);
void onCallEnded(quint64 callId, uint8_t reason);
void onCallError(quint64 callId, uint8_t err);
void onCallPath(quint64 callId, const QString& path);
void closeCallWindow(quint64 callId);
+3
View File
@@ -164,6 +164,9 @@ void SoundManager::playLoop(const QString& name) {
if (!m_enabled) return;
if (!m_initialized) { DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "SoundManager::playLoop: not initialized"); return; }
/* остановить предыдущий цикл (иначе call_connecting + call_ringing звучат вместе) */
stopLoop();
EventSettings es = m_eventSettings.value(name);
if (!es.enabled) return;
+6 -4
View File
@@ -60,8 +60,10 @@ SoundSettingsPage::SoundSettingsPage(DbManager* db, QWidget* parent)
m_events[2] = {"connect", "Peer connected", nullptr, nullptr, nullptr};
m_events[3] = {"disconnect", "Peer disconnected", nullptr, nullptr, nullptr};
m_events[4] = {"call_incoming", "Incoming call", nullptr, nullptr, nullptr};
m_events[5] = {"call_connecting", "Call: connecting", nullptr, nullptr, nullptr};
m_events[6] = {"call_ringing", "Call: ringback", nullptr, nullptr, nullptr};
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 7; i++) {
auto& e = m_events[i];
auto* row = new QHBoxLayout();
row->setSpacing(8);
@@ -119,11 +121,11 @@ void SoundSettingsPage::loadFromDb() {
m_volumeLabel->setEnabled(enabled);
m_volumeLabel->setText(QString::number(vol) + "%");
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 7; i++) {
auto& e = m_events[i];
QString onKey = QStringLiteral("sound_%1_on").arg(e.key);
QString volKey = QStringLiteral("sound_%1_vol").arg(e.key);
bool on = m_db->getUiStateInt(onKey, (i == 0 || i == 4) ? 1 : 0); // msg_incoming и call_incoming on by default
bool on = m_db->getUiStateInt(onKey, (i == 0 || i >= 4) ? 1 : 0); // msg_incoming и звонковые on by default
int ev = m_db->getUiStateInt(volKey, 80);
e.check->setChecked(on);
e.slider->setValue(ev);
@@ -139,7 +141,7 @@ void SoundSettingsPage::applyAndSave() {
sm->setEnabled(enabled);
sm->setVolume(masterVol);
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 7; i++) {
auto& e = m_events[i];
bool on = e.check->isChecked();
float ev = e.slider->value() / 100.0f;
+1 -1
View File
@@ -28,5 +28,5 @@ private:
QCheckBox* m_enabledCheck;
QSlider* m_volumeSlider;
QLabel* m_volumeLabel;
EventRow m_events[5];
EventRow m_events[7];
};