From 6aeafbd0fa2ebd48ef3da1d2fa779307ccbdc4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Tue, 15 Sep 2015 16:44:02 -0400 Subject: [PATCH] audiolayer: prevent double-init Issue: #80355 Change-Id: I8d0a1c0391aa33b9c01e3cd1f1ed315e1a68fe14 --- src/media/audio/alsa/alsalayer.cpp | 20 +++++++++--- src/media/audio/audiolayer.cpp | 3 -- src/media/audio/audiolayer.h | 21 ++++++++---- src/media/audio/coreaudio/corelayer.cpp | 32 ++++++++---------- src/media/audio/coreaudio/corelayer.h | 3 -- src/media/audio/jack/jacklayer.cpp | 34 +++++++++----------- src/media/audio/jack/jacklayer.h | 1 - src/media/audio/opensl/opensllayer.cpp | 30 ++++++++++------- src/media/audio/portaudio/portaudiolayer.cpp | 22 +++++++------ src/media/audio/portaudio/portaudiolayer.h | 2 -- src/media/audio/pulseaudio/pulselayer.cpp | 3 +- 11 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp index b2ddf9df32..c44d5ba1a0 100644 --- a/src/media/audio/alsa/alsalayer.cpp +++ b/src/media/audio/alsa/alsalayer.cpp @@ -136,9 +136,13 @@ void AlsaThread::initAudioLayer(void) void AlsaThread::run() { initAudioLayer(); - alsa_->isStarted_ = true; + { + std::lock_guard<std::mutex> lock(alsa_->mutex_); + alsa_->status_ = AudioLayer::Status::Started; + } + alsa_->startedCv_.notify_all(); - while (alsa_->isStarted_ and running_) { + while (alsa_->status_ == AudioLayer::Status::Started and running_) { alsa_->audioCallback(); } } @@ -168,7 +172,6 @@ AlsaLayer::AlsaLayer(const AudioPreference &pref) AlsaLayer::~AlsaLayer() { - isStarted_ = false; audioThread_.reset(); /* Then close the audio devices */ @@ -212,6 +215,13 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre void AlsaLayer::startStream() { + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Idle) + return; + status_ = Status::Starting; + } + dcblocker_.reset(); if (is_playback_running_ and is_capture_running_) @@ -228,8 +238,6 @@ AlsaLayer::startStream() void AlsaLayer::stopStream() { - isStarted_ = false; - audioThread_.reset(); closeCaptureStream(); @@ -242,6 +250,8 @@ AlsaLayer::stopStream() /* Flush the ring buffers */ flushUrgent(); flushMain(); + + status_ = Status::Idle; } /* diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp index fb38538dbe..0823ca3a16 100644 --- a/src/media/audio/audiolayer.cpp +++ b/src/media/audio/audiolayer.cpp @@ -45,12 +45,9 @@ AudioLayer::AudioLayer(const AudioPreference &pref) , isPlaybackMuted_(pref.getPlaybackMuted()) , captureGain_(pref.getVolumemic()) , playbackGain_(pref.getVolumespkr()) - , isStarted_(false) , audioFormat_(Manager::instance().getRingBufferPool().getInternalAudioFormat()) , audioInputFormat_(Manager::instance().getRingBufferPool().getInternalAudioFormat()) , urgentRingBuffer_("urgentRingBuffer_id", SIZEBUF, audioFormat_) - , mutex_() - , dcblocker_() , resampler_(new Resampler{audioFormat_.sample_rate}) , inputResampler_(new Resampler{audioInputFormat_.sample_rate}) , lastNotificationTime_(0) diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 310bf80a1a..611ddc77ef 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -77,6 +77,13 @@ class AudioLayer { private: NON_COPYABLE(AudioLayer); + protected: + enum class Status { + Idle, + Starting, + Started + }; + public: AudioLayer(const AudioPreference &); @@ -108,15 +115,15 @@ class AudioLayer { /** * Determine wether or not the audio layer is active (i.e. stream opened) */ - bool isStarted() const { - return isStarted_; + inline bool isStarted() const { + return status_ == Status::Started; } template< class Rep, class Period > bool waitForStart(const std::chrono::duration<Rep, Period>& rel_time) const { std::unique_lock<std::mutex> lk(mutex_); - startedCv_.wait_for(lk, rel_time, [&]{return isStarted_.load();}); - return isStarted_; + startedCv_.wait_for(lk, rel_time, [&]{return isStarted();}); + return isStarted(); } /** @@ -245,7 +252,7 @@ class AudioLayer { /** * Whether or not the audio layer stream is started */ - std::atomic_bool isStarted_; + Status status_ {Status::Idle}; mutable std::condition_variable startedCv_; /** @@ -266,12 +273,12 @@ class AudioLayer { /** * Lock for the entire audio layer */ - mutable std::mutex mutex_; + mutable std::mutex mutex_ {}; /** * Remove audio offset that can be introduced by certain cheap audio device */ - DcBlocker dcblocker_; + DcBlocker dcblocker_ {}; /** * Manage sampling rate conversion diff --git a/src/media/audio/coreaudio/corelayer.cpp b/src/media/audio/coreaudio/corelayer.cpp index beb40b7e72..2bbe088056 100644 --- a/src/media/audio/coreaudio/corelayer.cpp +++ b/src/media/audio/coreaudio/corelayer.cpp @@ -50,15 +50,11 @@ CoreLayer::CoreLayer(const AudioPreference &pref) , indexRing_(pref.getAlsaCardring()) , playbackBuff_(0, audioFormat_) , captureBuff_(0) - , is_playback_running_(false) - , is_capture_running_(false) , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) {} CoreLayer::~CoreLayer() { - isStarted_ = false; - if (captureBuff_) { for (UInt32 i = 0; i < captureBuff_->mNumberBuffers; ++i) free(captureBuff_->mBuffers[i].mData); @@ -166,11 +162,6 @@ void CoreLayer::initAudioLayerPlayback() // Initialize checkErr(AudioUnitInitialize(outputUnit_)); checkErr(AudioOutputUnitStart(outputUnit_)); - - is_playback_running_ = true; - is_capture_running_ = true; - - initAudioFormat(); } void CoreLayer::initAudioLayerCapture() @@ -304,10 +295,15 @@ void CoreLayer::initAudioLayerCapture() void CoreLayer::startStream() { RING_DBG("START STREAM"); - dcblocker_.reset(); - if (is_playback_running_ and is_capture_running_) - return; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Idle) + return; + status_ = Status::Started; + } + + dcblocker_.reset(); initAudioLayerPlayback(); initAudioLayerCapture(); @@ -328,7 +324,12 @@ void CoreLayer::stopStream() { RING_DBG("STOP STREAM"); - isStarted_ = is_playback_running_ = is_capture_running_ = false; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Started) + return; + status_ = Status::Idle; + } destroyAudioLayer(); @@ -341,11 +342,6 @@ void CoreLayer::stopStream() //// PRIVATE ///// -void CoreLayer::initAudioFormat() -{ -} - - OSStatus CoreLayer::outputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, diff --git a/src/media/audio/coreaudio/corelayer.h b/src/media/audio/coreaudio/corelayer.h index d5b39493b8..732348ba32 100644 --- a/src/media/audio/coreaudio/corelayer.h +++ b/src/media/audio/coreaudio/corelayer.h @@ -178,9 +178,6 @@ class CoreLayer : public AudioLayer { AudioUnit inputUnit_; std::shared_ptr<RingBuffer> mainRingBuffer_; - bool is_playback_running_; - bool is_capture_running_; - std::vector<AudioDevice> getDeviceList(bool getCapture) const; }; diff --git a/src/media/audio/jack/jacklayer.cpp b/src/media/audio/jack/jacklayer.cpp index 3ace332b5c..10ad67b86f 100644 --- a/src/media/audio/jack/jacklayer.cpp +++ b/src/media/audio/jack/jacklayer.cpp @@ -257,7 +257,7 @@ JackLayer::ringbuffer_worker() std::unique_lock<std::mutex> lock(ringbuffer_thread_mutex_); // may have changed, we don't want to wait for a notification we won't get - if (not workerAlive_) + if (status_ != Status::Started) return; // FIXME this is all kinds of evil @@ -273,7 +273,7 @@ JackLayer::ringbuffer_worker() data_ready_.wait(lock, [&] { // Note: lock is released while waiting, and held when woken // up, so this predicate is called while holding the lock - return not workerAlive_ + return status_ != Status::Started or ringbuffer_ready_for_read(in_ringbuffers_[0]); }); } @@ -320,7 +320,7 @@ JackLayer::JackLayer(const AudioPreference &p) : out_ringbuffers_(), in_ringbuffers_(), ringbuffer_thread_(), - workerAlive_(false), + //workerAlive_(false), ringbuffer_thread_mutex_(), data_ready_(), playbackBuffer_(0, audioFormat_), @@ -477,26 +477,22 @@ JackLayer::process_playback(jack_nframes_t frames, void *arg) void JackLayer::startStream() { - if (isStarted_) - return; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Idle) + return; + status_ = Status::Started; + } dcblocker_.reset(); const auto hardwareFormat = AudioFormat(playbackBuffer_.getSampleRate(), out_ports_.size()); hardwareFormatAvailable(hardwareFormat); - workerAlive_ = true; - assert(not ringbuffer_thread_.joinable()); - ringbuffer_thread_ = std::thread(&JackLayer::ringbuffer_worker, this); - if (jack_activate(playbackClient_) or jack_activate(captureClient_)) { RING_ERR("Could not activate JACK client"); - workerAlive_ = false; - ringbuffer_thread_.join(); - isStarted_ = false; return; - } else { - isStarted_ = true; } + ringbuffer_thread_ = std::thread(&JackLayer::ringbuffer_worker, this); connectPorts(playbackClient_, JackPortIsInput, out_ports_); connectPorts(captureClient_, JackPortIsOutput, in_ports_); @@ -516,17 +512,17 @@ void JackLayer::stopStream() { { - std::lock_guard<std::mutex> lock(ringbuffer_thread_mutex_); - workerAlive_ = false; - data_ready_.notify_one(); + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Started) + return; + status_ = Status::Idle; } + data_ready_.notify_one(); if (jack_deactivate(playbackClient_) or jack_deactivate(captureClient_)) { RING_ERR("JACK client could not deactivate"); } - isStarted_ = false; - if (ringbuffer_thread_.joinable()) ringbuffer_thread_.join(); diff --git a/src/media/audio/jack/jacklayer.h b/src/media/audio/jack/jacklayer.h index 8b18920735..1e2f1a5a3b 100644 --- a/src/media/audio/jack/jacklayer.h +++ b/src/media/audio/jack/jacklayer.h @@ -57,7 +57,6 @@ class JackLayer : public AudioLayer { std::vector<jack_ringbuffer_t *> out_ringbuffers_; std::vector<jack_ringbuffer_t *> in_ringbuffers_; std::thread ringbuffer_thread_; - bool workerAlive_; std::mutex ringbuffer_thread_mutex_; std::condition_variable data_ready_; AudioBuffer playbackBuffer_; diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp index 2fd1411e2c..f179bafba0 100644 --- a/src/media/audio/opensl/opensllayer.cpp +++ b/src/media/audio/opensl/opensllayer.cpp @@ -87,9 +87,6 @@ OpenSLLayer::OpenSLLayer(const AudioPreference &pref) // Destructor OpenSLLayer::~OpenSLLayer() { - isStarted_ = false; - - /* Then close the audio devices */ stopAudioPlayback(); stopAudioCapture(); } @@ -110,12 +107,17 @@ OpenSLLayer::startStream() { dcblocker_.reset(); - if (isStarted_) - return; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Idle) + return; + status_ = Status::Starting; + } RING_DBG("Start OpenSL audio layer"); std::vector<int32_t> hw_infos; + hw_infos.reserve(4); emitSignal<DRing::ConfigurationSignal::GetHardwareAudioFormat>(&hw_infos); hardwareFormat_ = AudioFormat(hw_infos[0], 1); // Mono on Android hardwareBuffSize_ = hw_infos[1]; @@ -131,7 +133,11 @@ OpenSLLayer::startStream() init(); startAudioPlayback(); startAudioCapture(); - isStarted_ = true; + RING_WARN("OpenSL audio layer started"); + { + std::lock_guard<std::mutex> lock(mutex_); + status_ = Status::Started; + } startedCv_.notify_all(); }); launcher.detach(); @@ -140,16 +146,18 @@ OpenSLLayer::startStream() void OpenSLLayer::stopStream() { - if (not isStarted_) - return; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Started) + return; + status_ = Status::Idle; + } - RING_DBG("Stop OpenSL audio layer"); + RING_WARN("Stop OpenSL audio layer"); stopAudioPlayback(); stopAudioCapture(); - isStarted_ = false; - flushMain(); flushUrgent(); } diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp index ed4a73de06..cb943ff1c7 100644 --- a/src/media/audio/portaudio/portaudiolayer.cpp +++ b/src/media/audio/portaudio/portaudiolayer.cpp @@ -45,13 +45,12 @@ PortAudioLayer::PortAudioLayer(const AudioPreference &pref) , playbackBuff_(0, audioFormat_) , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) { - isStarted_ = false; - this->init(); + init(); } PortAudioLayer::~PortAudioLayer() { - this->terminate(); + terminate(); } std::vector<std::string> @@ -118,17 +117,19 @@ PortAudioLayer::getIndexRingtone() const void PortAudioLayer::startStream() { - if (isRunning_) - return; + { + std::lock_guard<std::mutex> lock(mutex_); + if (status_ != Status::Idle) + return; + status_ = Status::Started; + } this->initStream(); - isRunning_ = isStarted_ = true; } void PortAudioLayer::stopStream() { - - if (!isRunning_) + if (status_ != Status::Started) return; RING_DBG("Stop PortAudio Streams"); @@ -143,7 +144,10 @@ PortAudioLayer::stopStream() this->handleError(err); } - isRunning_ = isStarted_ = false; + { + std::lock_guard<std::mutex> lock(mutex_); + status_ = Status::Idle; + } /* Flush the ring buffers */ flushUrgent(); diff --git a/src/media/audio/portaudio/portaudiolayer.h b/src/media/audio/portaudio/portaudiolayer.h index a982c378ee..c54e713fa7 100644 --- a/src/media/audio/portaudio/portaudiolayer.h +++ b/src/media/audio/portaudio/portaudiolayer.h @@ -84,8 +84,6 @@ public: std::shared_ptr<RingBuffer> mainRingBuffer_; - bool isRunning_; - enum Direction {Input=0, Output=1, End=2}; PaStream* streams[(int)Direction::End]; diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp index 06c62ae63b..a90d0f7bf2 100644 --- a/src/media/audio/pulseaudio/pulselayer.cpp +++ b/src/media/audio/pulseaudio/pulselayer.cpp @@ -137,7 +137,8 @@ PulseLayer::PulseLayer(AudioPreference &pref) pa_threaded_mainloop_wait(mainloop_); } - isStarted_ = true; + // No one had the opportunity to lock the mutex or listen on the CV yet. + status_ = Status::Started; } PulseLayer::~PulseLayer() -- GitLab