Linux ADMs: fix recursive mutex locks.

This change fixes recursive locking going on in the Linux Pulse and ALSA audio device managers.

Bug: webrtc:11866
Change-Id: Ia7b7b82e7f1f2a92c2f99e07a7079632499354ca
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/182020
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Markus Handell <handellm@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31968}
This commit is contained in:
Markus Handell
2020-08-20 11:38:21 +02:00
committed by Commit Bot
parent 767ba0b384
commit 957318ceaf
5 changed files with 103 additions and 73 deletions

View File

@ -217,7 +217,10 @@ bool AudioDeviceLinuxALSA::Initialized() const {
int32_t AudioDeviceLinuxALSA::InitSpeaker() { int32_t AudioDeviceLinuxALSA::InitSpeaker() {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return InitSpeakerLocked();
}
int32_t AudioDeviceLinuxALSA::InitSpeakerLocked() {
if (_playing) { if (_playing) {
return -1; return -1;
} }
@ -229,7 +232,10 @@ int32_t AudioDeviceLinuxALSA::InitSpeaker() {
int32_t AudioDeviceLinuxALSA::InitMicrophone() { int32_t AudioDeviceLinuxALSA::InitMicrophone() {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return InitMicrophoneLocked();
}
int32_t AudioDeviceLinuxALSA::InitMicrophoneLocked() {
if (_recording) { if (_recording) {
return -1; return -1;
} }
@ -421,22 +427,22 @@ int32_t AudioDeviceLinuxALSA::StereoRecordingIsAvailable(bool& available) {
// Stop/uninitialize recording if initialized (and possibly started) // Stop/uninitialize recording if initialized (and possibly started)
if (_recIsInitialized) { if (_recIsInitialized) {
StopRecording(); StopRecordingLocked();
} }
// Try init in stereo; // Try init in stereo;
_recChannels = 2; _recChannels = 2;
if (InitRecording() == 0) { if (InitRecordingLocked() == 0) {
available = true; available = true;
} }
// Stop/uninitialize recording // Stop/uninitialize recording
StopRecording(); StopRecordingLocked();
// Recover previous states // Recover previous states
_recChannels = recChannels; _recChannels = recChannels;
if (recIsInitialized) { if (recIsInitialized) {
InitRecording(); InitRecordingLocked();
} }
if (recording) { if (recording) {
StartRecording(); StartRecording();
@ -481,22 +487,22 @@ int32_t AudioDeviceLinuxALSA::StereoPlayoutIsAvailable(bool& available) {
// Stop/uninitialize recording if initialized (and possibly started) // Stop/uninitialize recording if initialized (and possibly started)
if (_playIsInitialized) { if (_playIsInitialized) {
StopPlayout(); StopPlayoutLocked();
} }
// Try init in stereo; // Try init in stereo;
_playChannels = 2; _playChannels = 2;
if (InitPlayout() == 0) { if (InitPlayoutLocked() == 0) {
available = true; available = true;
} }
// Stop/uninitialize recording // Stop/uninitialize recording
StopPlayout(); StopPlayoutLocked();
// Recover previous states // Recover previous states
_playChannels = playChannels; _playChannels = playChannels;
if (playIsInitialized) { if (playIsInitialized) {
InitPlayout(); InitPlayoutLocked();
} }
if (playing) { if (playing) {
StartPlayout(); StartPlayout();
@ -745,9 +751,13 @@ int32_t AudioDeviceLinuxALSA::RecordingIsAvailable(bool& available) {
} }
int32_t AudioDeviceLinuxALSA::InitPlayout() { int32_t AudioDeviceLinuxALSA::InitPlayout() {
MutexLock lock(&mutex_);
return InitPlayoutLocked();
}
int32_t AudioDeviceLinuxALSA::InitPlayoutLocked() {
int errVal = 0; int errVal = 0;
MutexLock lock(&mutex_);
if (_playing) { if (_playing) {
return -1; return -1;
} }
@ -760,7 +770,7 @@ int32_t AudioDeviceLinuxALSA::InitPlayout() {
return 0; return 0;
} }
// Initialize the speaker (devices might have been added or removed) // Initialize the speaker (devices might have been added or removed)
if (InitSpeaker() == -1) { if (InitSpeakerLocked() == -1) {
RTC_LOG(LS_WARNING) << "InitSpeaker() failed"; RTC_LOG(LS_WARNING) << "InitSpeaker() failed";
} }
@ -864,9 +874,12 @@ int32_t AudioDeviceLinuxALSA::InitPlayout() {
} }
int32_t AudioDeviceLinuxALSA::InitRecording() { int32_t AudioDeviceLinuxALSA::InitRecording() {
int errVal = 0;
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return InitRecordingLocked();
}
int32_t AudioDeviceLinuxALSA::InitRecordingLocked() {
int errVal = 0;
if (_recording) { if (_recording) {
return -1; return -1;
@ -881,7 +894,7 @@ int32_t AudioDeviceLinuxALSA::InitRecording() {
} }
// Initialize the microphone (devices might have been added or removed) // Initialize the microphone (devices might have been added or removed)
if (InitMicrophone() == -1) { if (InitMicrophoneLocked() == -1) {
RTC_LOG(LS_WARNING) << "InitMicrophone() failed"; RTC_LOG(LS_WARNING) << "InitMicrophone() failed";
} }
@ -1058,9 +1071,11 @@ int32_t AudioDeviceLinuxALSA::StartRecording() {
} }
int32_t AudioDeviceLinuxALSA::StopRecording() { int32_t AudioDeviceLinuxALSA::StopRecording() {
{
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return StopRecordingLocked();
}
int32_t AudioDeviceLinuxALSA::StopRecordingLocked() {
if (!_recIsInitialized) { if (!_recIsInitialized) {
return 0; return 0;
} }
@ -1072,14 +1087,12 @@ int32_t AudioDeviceLinuxALSA::StopRecording() {
// Make sure we don't start recording (it's asynchronous). // Make sure we don't start recording (it's asynchronous).
_recIsInitialized = false; _recIsInitialized = false;
_recording = false; _recording = false;
}
if (_ptrThreadRec) { if (_ptrThreadRec) {
_ptrThreadRec->Stop(); _ptrThreadRec->Stop();
_ptrThreadRec.reset(); _ptrThreadRec.reset();
} }
MutexLock lock(&mutex_);
_recordingFramesLeft = 0; _recordingFramesLeft = 0;
if (_recordingBuffer) { if (_recordingBuffer) {
delete[] _recordingBuffer; delete[] _recordingBuffer;
@ -1162,9 +1175,11 @@ int32_t AudioDeviceLinuxALSA::StartPlayout() {
} }
int32_t AudioDeviceLinuxALSA::StopPlayout() { int32_t AudioDeviceLinuxALSA::StopPlayout() {
{
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return StopPlayoutLocked();
}
int32_t AudioDeviceLinuxALSA::StopPlayoutLocked() {
if (!_playIsInitialized) { if (!_playIsInitialized) {
return 0; return 0;
} }
@ -1174,7 +1189,6 @@ int32_t AudioDeviceLinuxALSA::StopPlayout() {
} }
_playing = false; _playing = false;
}
// stop playout thread first // stop playout thread first
if (_ptrThreadPlay) { if (_ptrThreadPlay) {
@ -1182,8 +1196,6 @@ int32_t AudioDeviceLinuxALSA::StopPlayout() {
_ptrThreadPlay.reset(); _ptrThreadPlay.reset();
} }
MutexLock lock(&mutex_);
_playoutFramesLeft = 0; _playoutFramesLeft = 0;
delete[] _playoutBuffer; delete[] _playoutBuffer;
_playoutBuffer = NULL; _playoutBuffer = NULL;

View File

@ -40,8 +40,8 @@ class AudioDeviceLinuxALSA : public AudioDeviceGeneric {
AudioDeviceModule::AudioLayer& audioLayer) const override; AudioDeviceModule::AudioLayer& audioLayer) const override;
// Main initializaton and termination // Main initializaton and termination
InitStatus Init() override; InitStatus Init() RTC_LOCKS_EXCLUDED(mutex_) override;
int32_t Terminate() override; int32_t Terminate() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Initialized() const override; bool Initialized() const override;
// Device enumeration // Device enumeration
@ -64,24 +64,24 @@ class AudioDeviceLinuxALSA : public AudioDeviceGeneric {
// Audio transport initialization // Audio transport initialization
int32_t PlayoutIsAvailable(bool& available) override; int32_t PlayoutIsAvailable(bool& available) override;
int32_t InitPlayout() override; int32_t InitPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
bool PlayoutIsInitialized() const override; bool PlayoutIsInitialized() const override;
int32_t RecordingIsAvailable(bool& available) override; int32_t RecordingIsAvailable(bool& available) override;
int32_t InitRecording() override; int32_t InitRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
bool RecordingIsInitialized() const override; bool RecordingIsInitialized() const override;
// Audio transport control // Audio transport control
int32_t StartPlayout() override; int32_t StartPlayout() override;
int32_t StopPlayout() override; int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Playing() const override; bool Playing() const override;
int32_t StartRecording() override; int32_t StartRecording() override;
int32_t StopRecording() override; int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Recording() const override; bool Recording() const override;
// Audio mixer initialization // Audio mixer initialization
int32_t InitSpeaker() override; int32_t InitSpeaker() RTC_LOCKS_EXCLUDED(mutex_) override;
bool SpeakerIsInitialized() const override; bool SpeakerIsInitialized() const override;
int32_t InitMicrophone() override; int32_t InitMicrophone() RTC_LOCKS_EXCLUDED(mutex_) override;
bool MicrophoneIsInitialized() const override; bool MicrophoneIsInitialized() const override;
// Speaker volume controls // Speaker volume controls
@ -109,19 +109,28 @@ class AudioDeviceLinuxALSA : public AudioDeviceGeneric {
int32_t MicrophoneMute(bool& enabled) const override; int32_t MicrophoneMute(bool& enabled) const override;
// Stereo support // Stereo support
int32_t StereoPlayoutIsAvailable(bool& available) override; int32_t StereoPlayoutIsAvailable(bool& available)
RTC_LOCKS_EXCLUDED(mutex_) override;
int32_t SetStereoPlayout(bool enable) override; int32_t SetStereoPlayout(bool enable) override;
int32_t StereoPlayout(bool& enabled) const override; int32_t StereoPlayout(bool& enabled) const override;
int32_t StereoRecordingIsAvailable(bool& available) override; int32_t StereoRecordingIsAvailable(bool& available)
RTC_LOCKS_EXCLUDED(mutex_) override;
int32_t SetStereoRecording(bool enable) override; int32_t SetStereoRecording(bool enable) override;
int32_t StereoRecording(bool& enabled) const override; int32_t StereoRecording(bool& enabled) const override;
// Delay information and control // Delay information and control
int32_t PlayoutDelay(uint16_t& delayMS) const override; int32_t PlayoutDelay(uint16_t& delayMS) const override;
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
RTC_LOCKS_EXCLUDED(mutex_) override;
private: private:
int32_t InitRecordingLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t StopRecordingLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t StopPlayoutLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t InitPlayoutLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t InitSpeakerLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t InitMicrophoneLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t GetDevicesInfo(const int32_t function, int32_t GetDevicesInfo(const int32_t function,
const bool playback, const bool playback,
const int32_t enumDeviceNo = 0, const int32_t enumDeviceNo = 0,

View File

@ -116,7 +116,7 @@ class AudioDeviceLinuxPulse : public AudioDeviceGeneric {
// Main initializaton and termination // Main initializaton and termination
InitStatus Init() override; InitStatus Init() override;
int32_t Terminate() override; int32_t Terminate() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Initialized() const override; bool Initialized() const override;
// Device enumeration // Device enumeration
@ -139,18 +139,18 @@ class AudioDeviceLinuxPulse : public AudioDeviceGeneric {
// Audio transport initialization // Audio transport initialization
int32_t PlayoutIsAvailable(bool& available) override; int32_t PlayoutIsAvailable(bool& available) override;
int32_t InitPlayout() override; int32_t InitPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
bool PlayoutIsInitialized() const override; bool PlayoutIsInitialized() const override;
int32_t RecordingIsAvailable(bool& available) override; int32_t RecordingIsAvailable(bool& available) override;
int32_t InitRecording() override; int32_t InitRecording() override;
bool RecordingIsInitialized() const override; bool RecordingIsInitialized() const override;
// Audio transport control // Audio transport control
int32_t StartPlayout() override; int32_t StartPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
int32_t StopPlayout() override; int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Playing() const override; bool Playing() const override;
int32_t StartRecording() override; int32_t StartRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
int32_t StopRecording() override; int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_) override;
bool Recording() const override; bool Recording() const override;
// Audio mixer initialization // Audio mixer initialization
@ -192,7 +192,8 @@ class AudioDeviceLinuxPulse : public AudioDeviceGeneric {
int32_t StereoRecording(bool& enabled) const override; int32_t StereoRecording(bool& enabled) const override;
// Delay information and control // Delay information and control
int32_t PlayoutDelay(uint16_t& delayMS) const override; int32_t PlayoutDelay(uint16_t& delayMS) const
RTC_LOCKS_EXCLUDED(mutex_) override;
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
@ -256,8 +257,8 @@ class AudioDeviceLinuxPulse : public AudioDeviceGeneric {
static void RecThreadFunc(void*); static void RecThreadFunc(void*);
static void PlayThreadFunc(void*); static void PlayThreadFunc(void*);
bool RecThreadProcess(); bool RecThreadProcess() RTC_LOCKS_EXCLUDED(mutex_);
bool PlayThreadProcess(); bool PlayThreadProcess() RTC_LOCKS_EXCLUDED(mutex_);
AudioDeviceBuffer* _ptrAudioBuffer; AudioDeviceBuffer* _ptrAudioBuffer;

View File

@ -47,16 +47,19 @@ int32_t AudioMixerManagerLinuxALSA::Close() {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
CloseSpeaker(); CloseSpeakerLocked();
CloseMicrophone(); CloseMicrophoneLocked();
return 0; return 0;
} }
int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() { int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() {
RTC_LOG(LS_VERBOSE) << __FUNCTION__;
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return CloseSpeakerLocked();
}
int32_t AudioMixerManagerLinuxALSA::CloseSpeakerLocked() {
RTC_LOG(LS_VERBOSE) << __FUNCTION__;
int errVal = 0; int errVal = 0;
@ -86,9 +89,12 @@ int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() {
} }
int32_t AudioMixerManagerLinuxALSA::CloseMicrophone() { int32_t AudioMixerManagerLinuxALSA::CloseMicrophone() {
RTC_LOG(LS_VERBOSE) << __FUNCTION__;
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
return CloseMicrophoneLocked();
}
int32_t AudioMixerManagerLinuxALSA::CloseMicrophoneLocked() {
RTC_LOG(LS_VERBOSE) << __FUNCTION__;
int errVal = 0; int errVal = 0;

View File

@ -21,27 +21,27 @@ namespace webrtc {
class AudioMixerManagerLinuxALSA { class AudioMixerManagerLinuxALSA {
public: public:
int32_t OpenSpeaker(char* deviceName); int32_t OpenSpeaker(char* deviceName) RTC_LOCKS_EXCLUDED(mutex_);
int32_t OpenMicrophone(char* deviceName); int32_t OpenMicrophone(char* deviceName) RTC_LOCKS_EXCLUDED(mutex_);
int32_t SetSpeakerVolume(uint32_t volume); int32_t SetSpeakerVolume(uint32_t volume) RTC_LOCKS_EXCLUDED(mutex_);
int32_t SpeakerVolume(uint32_t& volume) const; int32_t SpeakerVolume(uint32_t& volume) const;
int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; int32_t MaxSpeakerVolume(uint32_t& maxVolume) const;
int32_t MinSpeakerVolume(uint32_t& minVolume) const; int32_t MinSpeakerVolume(uint32_t& minVolume) const;
int32_t SpeakerVolumeIsAvailable(bool& available); int32_t SpeakerVolumeIsAvailable(bool& available);
int32_t SpeakerMuteIsAvailable(bool& available); int32_t SpeakerMuteIsAvailable(bool& available);
int32_t SetSpeakerMute(bool enable); int32_t SetSpeakerMute(bool enable) RTC_LOCKS_EXCLUDED(mutex_);
int32_t SpeakerMute(bool& enabled) const; int32_t SpeakerMute(bool& enabled) const;
int32_t MicrophoneMuteIsAvailable(bool& available); int32_t MicrophoneMuteIsAvailable(bool& available);
int32_t SetMicrophoneMute(bool enable); int32_t SetMicrophoneMute(bool enable) RTC_LOCKS_EXCLUDED(mutex_);
int32_t MicrophoneMute(bool& enabled) const; int32_t MicrophoneMute(bool& enabled) const;
int32_t MicrophoneVolumeIsAvailable(bool& available); int32_t MicrophoneVolumeIsAvailable(bool& available);
int32_t SetMicrophoneVolume(uint32_t volume); int32_t SetMicrophoneVolume(uint32_t volume) RTC_LOCKS_EXCLUDED(mutex_);
int32_t MicrophoneVolume(uint32_t& volume) const; int32_t MicrophoneVolume(uint32_t& volume) const;
int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const;
int32_t MinMicrophoneVolume(uint32_t& minVolume) const; int32_t MinMicrophoneVolume(uint32_t& minVolume) const;
int32_t Close(); int32_t Close() RTC_LOCKS_EXCLUDED(mutex_);
int32_t CloseSpeaker(); int32_t CloseSpeaker() RTC_LOCKS_EXCLUDED(mutex_);
int32_t CloseMicrophone(); int32_t CloseMicrophone() RTC_LOCKS_EXCLUDED(mutex_);
bool SpeakerIsInitialized() const; bool SpeakerIsInitialized() const;
bool MicrophoneIsInitialized() const; bool MicrophoneIsInitialized() const;
@ -50,6 +50,8 @@ class AudioMixerManagerLinuxALSA {
~AudioMixerManagerLinuxALSA(); ~AudioMixerManagerLinuxALSA();
private: private:
int32_t CloseSpeakerLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t CloseMicrophoneLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
int32_t LoadMicMixerElement() const; int32_t LoadMicMixerElement() const;
int32_t LoadSpeakerMixerElement() const; int32_t LoadSpeakerMixerElement() const;
void GetControlName(char* controlName, char* deviceName) const; void GetControlName(char* controlName, char* deviceName) const;