From 8dcbbc3873ef97d166976e6ccccf7bdaf4e35b62 Mon Sep 17 00:00:00 2001 From: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com> Date: Mon, 6 Sep 2021 16:59:44 -0400 Subject: [PATCH] audio layer: prevent a deadlock A deadlock is caused by a lock-order-inversion of the private mutex from pulse-audio thread loop, and the callMutex_ mutex from the Call class. It occurs when concurrently calling writeToSpeaker() and onNegoDone() callbacks. The deadlock is prevented by avoid to a access Call data from the pulse-audio thread. Gitlab: #623 Change-Id: I91d936b37528db3de24e93b0d49d686f5ca11813 --- src/manager.cpp | 5 +++++ src/media/audio/audiolayer.cpp | 8 ++------ src/media/audio/audiolayer.h | 17 ++++++++++++++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/manager.cpp b/src/manager.cpp index 73ef2833c2..7589759b91 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -615,6 +615,9 @@ void Manager::ManagerPimpl::addWaitingCall(const std::string& id) { std::lock_guard<std::mutex> m(waitingCallsMutex_); + // Enable incoming call beep if needed. + if (audiodriver_ and waitingCalls_.empty() and not currentCall_.empty()) + audiodriver_->playIncomingCallNotification(true); waitingCalls_.insert(id); } @@ -623,6 +626,8 @@ Manager::ManagerPimpl::removeWaitingCall(const std::string& id) { std::lock_guard<std::mutex> m(waitingCallsMutex_); waitingCalls_.erase(id); + if (audiodriver_ and waitingCalls_.empty()) + audiodriver_->playIncomingCallNotification(false); } void diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp index 3f7e3f874b..dd86480235 100644 --- a/src/media/audio/audiolayer.cpp +++ b/src/media/audio/audiolayer.cpp @@ -164,21 +164,17 @@ AudioLayer::putUrgent(AudioBuffer& buffer) void AudioLayer::notifyIncomingCall() { - if (!Manager::instance().incomingCallsWaiting()) + if (not playIncomingCallBeep_) return; auto now = std::chrono::system_clock::now(); // Notify maximum once every 5 seconds - if ((now - lastNotificationTime_) < std::chrono::seconds(5)) + if (now < lastNotificationTime_ + std::chrono::seconds(5)) return; lastNotificationTime_ = now; - // Enable notification only if more than one call - if (!Manager::instance().hasCurrentCall()) - return; - Tone tone("440/160", getSampleRate()); size_t nbSample = tone.getSize(); AudioBuffer buf(nbSample, AudioFormat::MONO()); diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 79ad74d36b..86562bee8c 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -53,7 +53,7 @@ typedef struct SpeexEchoState_ SpeexEchoState; #define COREAUDIO_API_STR "coreaudio" #define PORTAUDIO_API_STR "portaudio" -#define PCM_DEFAULT "default" // Default ALSA plugin +#define PCM_DEFAULT "default" // Default ALSA plugin #define PCM_DSNOOP "plug:dsnoop" // Alsa plugin for microphone sharing #define PCM_DMIX_DSNOOP "dmix/dsnoop" // Audio profile using Alsa dmix/dsnoop @@ -117,6 +117,12 @@ public: */ void putUrgent(AudioBuffer& buffer); + /** + * Start/Stop playing the incoming call notification sound (beep) + * while playing back audio (typically during an ongoing call). + */ + void playIncomingCallNotification(bool play) { playIncomingCallBeep_.exchange(play); } + /** * Flush main buffer */ @@ -179,7 +185,7 @@ public: AudioFormat getFormat() const { return audioFormat_; } /** - * Emit an audio notification on incoming calls + * Emit an audio notification (beep) on incoming calls */ void notifyIncomingCall(); @@ -295,10 +301,15 @@ protected: private: void checkAEC(); + // Set to "true" to play the incoming call notification (beep) + // when the playback is on (typically when there is already an + // active call). + std::atomic_bool playIncomingCallBeep_ {false}; /** * Time of the last incoming call notification */ - std::chrono::system_clock::time_point lastNotificationTime_; + std::chrono::system_clock::time_point lastNotificationTime_ { + std::chrono::system_clock::time_point::min()}; }; } // namespace jami -- GitLab