summaryrefslogtreecommitdiffstats
path: root/pica-client/audiovideocallcontroller.cpp
diff options
context:
space:
mode:
authorAnton <anton@picapica.im>2026-08-13 00:19:12 +0400
committerAnton <anton@picapica.im>2026-08-13 00:19:12 +0400
commitf65bda4889e67dac8df0d972f3adade837a2fa79 (patch)
treeb7a162cf7b3406442f1367d45f4352afd9cd3f55 /pica-client/audiovideocallcontroller.cpp
parentc05b724cfc95ec56827ebb744998aa42f8c00ee8 (diff)
downloadpica-pica-f65bda4889e67dac8df0d972f3adade837a2fa79.tar.gz
pica-pica-f65bda4889e67dac8df0d972f3adade837a2fa79.zip
pica-client: fix locking bug in audio queues
Diffstat (limited to 'pica-client/audiovideocallcontroller.cpp')
-rw-r--r--pica-client/audiovideocallcontroller.cpp20
1 files changed, 17 insertions, 3 deletions
diff --git a/pica-client/audiovideocallcontroller.cpp b/pica-client/audiovideocallcontroller.cpp
index 1a4d8ae..964b15c 100644
--- a/pica-client/audiovideocallcontroller.cpp
+++ b/pica-client/audiovideocallcontroller.cpp
@@ -137,8 +137,17 @@ void AudioVideoCallController::startAudioPipeline()
void AudioVideoCallController::stopAudioPipeline()
{
- QMetaObject::invokeMethod(microphone, "Close", Qt::QueuedConnection);
- QMetaObject::invokeMethod(output, "Close", Qt::QueuedConnection);
+ // Close() only touches a QAtomicInt and wakes a QWaitCondition, both
+ // safe to reach from any thread - it must be called directly rather
+ // than via invokeMethod()/QueuedConnection: microphone/output's own
+ // thread is blocked inside Capture()/Play() for the call's duration,
+ // so its event loop cannot deliver a queued call back to itself until
+ // that blocking call returns - which is exactly what Close() is
+ // supposed to make happen. Routing it through the event queue would
+ // deadlock (the thread would never quit, and the app would hang on
+ // exit after a call).
+ microphone->Close();
+ output->Close();
}
void AudioVideoCallController::call_failed(QByteArray peer_id, QString reason)
@@ -303,6 +312,11 @@ void AudioVideoCallController::incoming_audio_packet(QByteArray peer_id, quint16
if (!is_active || peer_id != m_peer_id)
return;
- QMetaObject::invokeMethod(output, "enqueuePacket", Qt::QueuedConnection, Q_ARG(QByteArray, data));
+ // Direct call, not invokeMethod()/QueuedConnection - see the comment in
+ // stopAudioPipeline(). enqueuePacket() is mutex-protected and safe to
+ // call from any thread; queuing it behind output's own blocking Play()
+ // call would mean it's never delivered, and Play() would sit forever
+ // pulling from an empty jitter buffer.
+ output->enqueuePacket(data);
}