From d3b7e65d84daf3244f1e979812b64d90187af861 Mon Sep 17 00:00:00 2001 From: Cajus Pollmeier Date: Wed, 20 May 2026 14:31:48 +0200 Subject: [PATCH 1/5] Catch "device broken" issues --- src/media/AudioPort.cpp | 12 ++++++++++-- src/sip/SIPCall.cpp | 25 ++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/media/AudioPort.cpp b/src/media/AudioPort.cpp index 1a713bbd..c77079b5 100644 --- a/src/media/AudioPort.cpp +++ b/src/media/AudioPort.cpp @@ -35,7 +35,11 @@ bool AudioPort::initialize() createPort(m_device.id().toStdString(), m_pj_fmt); if (m_device.mode() == QAudioDevice::Mode::Input) { - adjustTxLevel(NORMAL_AUDIO_LEVEL); + try { + adjustTxLevel(NORMAL_AUDIO_LEVEL); + } catch(pj::Error &err) { + qCCritical(lcAudioPort) << "failed to adjust tx level: " << err.info(); + } } return true; @@ -45,7 +49,11 @@ void AudioPort::setMuted(bool value) { if (m_isMuted != value) { if (m_device.mode() == QAudioDevice::Mode::Input) { - adjustTxLevel(value ? 0.0f : NORMAL_AUDIO_LEVEL); + try { + adjustTxLevel(value ? 0.0f : NORMAL_AUDIO_LEVEL); + } catch(pj::Error &err) { + qCCritical(lcAudioPort) << "failed to adjust tx level: " << err.info(); + } } m_isMuted = value; diff --git a/src/sip/SIPCall.cpp b/src/sip/SIPCall.cpp index 8b30f53c..96a2d239 100644 --- a/src/sip/SIPCall.cpp +++ b/src/sip/SIPCall.cpp @@ -20,6 +20,7 @@ #include "NotificationManager.h" #include "AvatarManager.h" #include "GlobalCallState.h" +#include "ErrorBus.h" #include #include @@ -359,13 +360,31 @@ void SIPCall::onCallMediaState(pj::OnCallMediaStateParam &prm) qCInfo(lcSIPCall) << "Found media, index" << i << "of" << ci.media.size(); aud_med = getAudioMedia(i); - mic_media.startTransmit(aud_med); - aud_med.startTransmit(speaker_media); + + try { + mic_media.startTransmit(aud_med); + } catch(pj::Error &err) { + qCCritical(lcSIPCall) << "failed to start mic media transmission: " << err.info(); + ErrorBus::instance().addFatalError(tr("Failed to initialize microphone audio")); + } + + try { + aud_med.startTransmit(speaker_media); + } catch(pj::Error &err) { + qCCritical(lcSIPCall) << "failed to start aud media transmission: " << err.info(); + ErrorBus::instance().addFatalError(tr("Failed to initialize call audio")); + } if (!m_sniffer) { m_sniffer = new Sniffer(this); m_sniffer->initialize(); - aud_med.startTransmit(dynamic_cast(*m_sniffer)); + + try { + aud_med.startTransmit(dynamic_cast(*m_sniffer)); + } catch(pj::Error &err) { + qCCritical(lcSIPCall) << "failed to start audio level transmission: " << err.info(); + } + connect(m_sniffer, &Sniffer::audioLevelChanged, this, [this]() { Q_EMIT SIPCallManager::instance().audioLevelChanged( this, m_sniffer->audioLevel()); From fa8de12a4e51b87a6b316446dc1a76f9c78547cc Mon Sep 17 00:00:00 2001 From: Cajus Pollmeier Date: Wed, 20 May 2026 14:37:22 +0200 Subject: [PATCH 2/5] Also read missing configId --- src/contacts/Contact.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contacts/Contact.cpp b/src/contacts/Contact.cpp index 084e7f72..a53453b6 100644 --- a/src/contacts/Contact.cpp +++ b/src/contacts/Contact.cpp @@ -338,7 +338,7 @@ QDataStream &operator>>(QDataStream &in, Contact &contact) BlockInfo blockInfo; QList phoneNumbers; - in >> id >> dn >> sourceUid >> name >> prio >> displayName >> company >> mail >> lastModified + in >> id >> dn >> sourceUid >> name >> prio >> displayName >> configId >> company >> mail >> lastModified >> sipStatusSubscriptable >> phoneNumbers >> blockInfo; contact = Contact(id, dn, sourceUid, { prio, displayName, configId }, name, company, mail, lastModified, phoneNumbers, blockInfo); From fe9a3986f2bf56a6a2d40114f6100fc18662ea84 Mon Sep 17 00:00:00 2001 From: Cajus Pollmeier Date: Wed, 20 May 2026 14:56:17 +0200 Subject: [PATCH 3/5] Abort on potentially broken number of contacts --- .../carddav/CardDAVAddressBookFeeder.cpp | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/contacts/carddav/CardDAVAddressBookFeeder.cpp b/src/contacts/carddav/CardDAVAddressBookFeeder.cpp index 74635e92..ca595a65 100644 --- a/src/contacts/carddav/CardDAVAddressBookFeeder.cpp +++ b/src/contacts/carddav/CardDAVAddressBookFeeder.cpp @@ -219,18 +219,29 @@ void CardDAVAddressBookFeeder::loadCachedData(const size_t hash) QDataStream in(&cacheFile); - quint16 magic; - quint8 version; - qsizetype numberOfContacts; + quint16 magic = 0; + quint8 version = 0; in >> magic; in >> version; - in >> m_ignoredIds; - in >> numberOfContacts; - if (magic != CARDDAV_MAGIC || version != CARDDAV_VERSION) { + if (in.status() != QDataStream::Ok || magic != CARDDAV_MAGIC || version != CARDDAV_VERSION) { qCInfo(lcCardDAVAddressBookFeeder) << "CardDAV cache file at" << filePath << "is invalid and will therefore be removed."; + cacheFile.close(); + cacheFile.remove(); + return; + } + + qsizetype numberOfContacts = 0; + in >> m_ignoredIds; + in >> numberOfContacts; + + if (in.status() != QDataStream::Ok || numberOfContacts < 0 || numberOfContacts > 1000000) { + qCWarning(lcCardDAVAddressBookFeeder) << "CardDAV cache file at" << filePath + << "is corrupted and will therefore be removed."; + m_ignoredIds.clear(); + cacheFile.close(); cacheFile.remove(); return; } @@ -240,6 +251,19 @@ void CardDAVAddressBookFeeder::loadCachedData(const size_t hash) Contact *contact = new Contact(this); in >> key; in >> *contact; + + if (in.status() != QDataStream::Ok) { + delete contact; + qCWarning(lcCardDAVAddressBookFeeder) << "CardDAV cache file at" << filePath + << "is truncated or corrupted - aborting cache load."; + qDeleteAll(m_cachedContacts); + m_cachedContacts.clear(); + m_ignoredIds.clear(); + cacheFile.close(); + cacheFile.remove(); + return; + } + m_cachedContacts.insert(key, contact); } From 6c40227aa5f0547c48b38db33b15ec97c81322cc Mon Sep 17 00:00:00 2001 From: Cajus Pollmeier Date: Wed, 20 May 2026 15:08:05 +0200 Subject: [PATCH 4/5] chore: formatting --- src/contacts/Contact.cpp | 4 ++-- .../carddav/CardDAVAddressBookFeeder.cpp | 5 ++-- src/media/AudioPort.cpp | 12 +++++----- src/sip/SIPCall.cpp | 24 +++++++++++-------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/contacts/Contact.cpp b/src/contacts/Contact.cpp index a53453b6..e927b3e3 100644 --- a/src/contacts/Contact.cpp +++ b/src/contacts/Contact.cpp @@ -338,8 +338,8 @@ QDataStream &operator>>(QDataStream &in, Contact &contact) BlockInfo blockInfo; QList phoneNumbers; - in >> id >> dn >> sourceUid >> name >> prio >> displayName >> configId >> company >> mail >> lastModified - >> sipStatusSubscriptable >> phoneNumbers >> blockInfo; + in >> id >> dn >> sourceUid >> name >> prio >> displayName >> configId >> company >> mail + >> lastModified >> sipStatusSubscriptable >> phoneNumbers >> blockInfo; contact = Contact(id, dn, sourceUid, { prio, displayName, configId }, name, company, mail, lastModified, phoneNumbers, blockInfo); diff --git a/src/contacts/carddav/CardDAVAddressBookFeeder.cpp b/src/contacts/carddav/CardDAVAddressBookFeeder.cpp index ca595a65..dae8fa1d 100644 --- a/src/contacts/carddav/CardDAVAddressBookFeeder.cpp +++ b/src/contacts/carddav/CardDAVAddressBookFeeder.cpp @@ -254,8 +254,9 @@ void CardDAVAddressBookFeeder::loadCachedData(const size_t hash) if (in.status() != QDataStream::Ok) { delete contact; - qCWarning(lcCardDAVAddressBookFeeder) << "CardDAV cache file at" << filePath - << "is truncated or corrupted - aborting cache load."; + qCWarning(lcCardDAVAddressBookFeeder) + << "CardDAV cache file at" << filePath + << "is truncated or corrupted - aborting cache load."; qDeleteAll(m_cachedContacts); m_cachedContacts.clear(); m_ignoredIds.clear(); diff --git a/src/media/AudioPort.cpp b/src/media/AudioPort.cpp index c77079b5..e3e0049f 100644 --- a/src/media/AudioPort.cpp +++ b/src/media/AudioPort.cpp @@ -37,7 +37,7 @@ bool AudioPort::initialize() if (m_device.mode() == QAudioDevice::Mode::Input) { try { adjustTxLevel(NORMAL_AUDIO_LEVEL); - } catch(pj::Error &err) { + } catch (pj::Error &err) { qCCritical(lcAudioPort) << "failed to adjust tx level: " << err.info(); } } @@ -51,7 +51,7 @@ void AudioPort::setMuted(bool value) if (m_device.mode() == QAudioDevice::Mode::Input) { try { adjustTxLevel(value ? 0.0f : NORMAL_AUDIO_LEVEL); - } catch(pj::Error &err) { + } catch (pj::Error &err) { qCCritical(lcAudioPort) << "failed to adjust tx level: " << err.info(); } } @@ -174,8 +174,8 @@ void AudioPort::startSinkIO() qCInfo(lcAudioPort).noquote().nospace() << "Initialize sink of device_descr=\"" << m_device.description() << "\", device_id=\"" - << m_device.id() << "\", with settings:" - << "\nsampleRate=" << m_audioFormat.sampleRate() + << m_device.id() + << "\", with settings:" << "\nsampleRate=" << m_audioFormat.sampleRate() << "\nchannelCount=" << m_audioFormat.channelCount() << "\nbytesPerSample=" << m_audioFormat.bytesPerSample() << "\nsampleFormat=" << m_audioFormat.sampleFormat(); @@ -216,8 +216,8 @@ void AudioPort::startSourceIO() qCInfo(lcAudioPort).noquote().nospace() << "Initialize source of device_descr=\"" << m_device.description() - << "\", device_id=\"" << m_device.id() << "\", with settings:" - << "\nsampleRate=" << m_audioFormat.sampleRate() + << "\", device_id=\"" << m_device.id() + << "\", with settings:" << "\nsampleRate=" << m_audioFormat.sampleRate() << "\nchannelCount=" << m_audioFormat.channelCount() << "\nbytesPerSample=" << m_audioFormat.bytesPerSample() << "\nsampleFormat=" << m_audioFormat.sampleFormat(); diff --git a/src/sip/SIPCall.cpp b/src/sip/SIPCall.cpp index 96a2d239..4cea032f 100644 --- a/src/sip/SIPCall.cpp +++ b/src/sip/SIPCall.cpp @@ -160,8 +160,8 @@ void SIPCall::onCallState(pj::OnCallStateParam &prm) qCInfo(lcSIPCall).nospace() << "Call State: " << ci.stateText << " (" << remoteUri << ")" << " last status code: " << EnumTranslation::instance().sipStatusCode(statusCode) << " (" - << statusCode << ") " - << " last reason " << ci.lastReason << " contactId " << m_contactId; + << statusCode << ") " << " last reason " << ci.lastReason + << " contactId " << m_contactId; if (statusCode == PJSIP_SC_RINGING) { ringToneFactory.ringingTone()->start(); @@ -363,15 +363,18 @@ void SIPCall::onCallMediaState(pj::OnCallMediaStateParam &prm) try { mic_media.startTransmit(aud_med); - } catch(pj::Error &err) { - qCCritical(lcSIPCall) << "failed to start mic media transmission: " << err.info(); - ErrorBus::instance().addFatalError(tr("Failed to initialize microphone audio")); + } catch (pj::Error &err) { + qCCritical(lcSIPCall) + << "failed to start mic media transmission: " << err.info(); + ErrorBus::instance().addFatalError( + tr("Failed to initialize microphone audio")); } try { aud_med.startTransmit(speaker_media); - } catch(pj::Error &err) { - qCCritical(lcSIPCall) << "failed to start aud media transmission: " << err.info(); + } catch (pj::Error &err) { + qCCritical(lcSIPCall) + << "failed to start aud media transmission: " << err.info(); ErrorBus::instance().addFatalError(tr("Failed to initialize call audio")); } @@ -381,13 +384,14 @@ void SIPCall::onCallMediaState(pj::OnCallMediaStateParam &prm) try { aud_med.startTransmit(dynamic_cast(*m_sniffer)); - } catch(pj::Error &err) { - qCCritical(lcSIPCall) << "failed to start audio level transmission: " << err.info(); + } catch (pj::Error &err) { + qCCritical(lcSIPCall) + << "failed to start audio level transmission: " << err.info(); } connect(m_sniffer, &Sniffer::audioLevelChanged, this, [this]() { Q_EMIT SIPCallManager::instance().audioLevelChanged( - this, m_sniffer->audioLevel()); + this, m_sniffer -> audioLevel()); }); } } From f8b757ae3b7e8d3e6aa8b4dfc63eef8a71e94d90 Mon Sep 17 00:00:00 2001 From: Cajus Pollmeier Date: Wed, 20 May 2026 15:38:33 +0200 Subject: [PATCH 5/5] chore: remove spacing --- src/sip/SIPCall.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sip/SIPCall.cpp b/src/sip/SIPCall.cpp index 4cea032f..a4274e8e 100644 --- a/src/sip/SIPCall.cpp +++ b/src/sip/SIPCall.cpp @@ -391,7 +391,7 @@ void SIPCall::onCallMediaState(pj::OnCallMediaStateParam &prm) connect(m_sniffer, &Sniffer::audioLevelChanged, this, [this]() { Q_EMIT SIPCallManager::instance().audioLevelChanged( - this, m_sniffer -> audioLevel()); + this, m_sniffer->audioLevel()); }); } }