diff --git a/src/call.h b/src/call.h
index 10c897c947f25e9ce558753db129dc74077e1645..a306144933fd462af808210c28daf9f4bb40be91 100644
--- a/src/call.h
+++ b/src/call.h
@@ -49,6 +49,7 @@ namespace jami {
 class VoIPLink;
 class Account;
 struct AccountVideoCodecInfo;
+class AudioDeviceGuard;
 
 template<class T>
 using CallMap = std::map<std::string, std::shared_ptr<T>>;
@@ -331,6 +332,8 @@ public: // media management
         return confInfo_.toVectorMapStringString();
     }
 
+    std::unique_ptr<AudioDeviceGuard> audioGuard;
+
 protected:
     virtual void merge(Call& scall);
 
diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp
index 20faedc73088a301b149281a6846597b8e538329..b9155df1b5457b189627b71eb62c79910d4ef9d0 100644
--- a/src/client/configurationmanager.cpp
+++ b/src/client/configurationmanager.cpp
@@ -70,7 +70,7 @@ using jami::SIPAccount;
 using jami::JamiAccount;
 using jami::tls::TlsValidator;
 using jami::tls::CertificateStore;
-using jami::DeviceType;
+using jami::AudioDeviceType;
 using jami::HookPreference;
 
 void
@@ -641,25 +641,25 @@ getAudioInputDeviceList()
 void
 setAudioOutputDevice(int32_t index)
 {
-    return jami::Manager::instance().setAudioDevice(index, DeviceType::PLAYBACK);
+    return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::PLAYBACK);
 }
 
 void
 setAudioInputDevice(int32_t index)
 {
-    return jami::Manager::instance().setAudioDevice(index, DeviceType::CAPTURE);
+    return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::CAPTURE);
 }
 
 void
 startAudio()
 {
-    jami::Manager::instance().restartAudioDriverStream();
+    jami::Manager::instance().startAudio();
 }
 
 void
 setAudioRingtoneDevice(int32_t index)
 {
-    return jami::Manager::instance().setAudioDevice(index, DeviceType::RINGTONE);
+    return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::RINGTONE);
 }
 
 std::vector<std::string>
diff --git a/src/client/videomanager.cpp b/src/client/videomanager.cpp
index 881a6cd07fcaefebd5769615c68041b5a8476c28..55dd4c6ddce7c685133474f594ee8e732578de09 100644
--- a/src/client/videomanager.cpp
+++ b/src/client/videomanager.cpp
@@ -465,12 +465,6 @@ stopCamera()
 void
 startAudioDevice()
 {
-    // Don't start audio layer if already done
-    auto audioLayer = jami::Manager::instance().getAudioDriver();
-    if (!audioLayer)
-        jami::Manager::instance().initAudioDriver();
-    if (!audioLayer->isStarted())
-        jami::Manager::instance().startAudioDriverStream();
     jami::Manager::instance().getVideoManager().audioPreview = jami::getAudioInput(
         jami::RingBufferPool::DEFAULT_ID);
 }
@@ -479,7 +473,6 @@ void
 stopAudioDevice()
 {
     jami::Manager::instance().getVideoManager().audioPreview.reset();
-    jami::Manager::instance().checkAudio(); // stops audio layer if no calls
 }
 
 std::string
@@ -787,21 +780,19 @@ getMediaPlayer(const std::string& id)
 std::string
 createMediaPlayer(const std::string& path)
 {
-    auto& vmgr = Manager::instance().getVideoManager();
     auto player = std::make_shared<MediaPlayer>(path);
     if (!player->isInputValid()) {
         return "";
     }
     auto playerId = player.get()->getId();
-    vmgr.mediaPlayers[playerId] = player;
+    Manager::instance().getVideoManager().mediaPlayers[playerId] = player;
     return playerId;
 }
 
 bool
 pausePlayer(const std::string& id, bool pause)
 {
-    auto player = getMediaPlayer(id);
-    if (player) {
+    if (auto player = getMediaPlayer(id)) {
         player->pause(pause);
         return true;
     }
@@ -811,24 +802,13 @@ pausePlayer(const std::string& id, bool pause)
 bool
 closePlayer(const std::string& id)
 {
-    auto& vmgr = Manager::instance().getVideoManager();
-    auto player = getMediaPlayer(id);
-    if (player) {
-        vmgr.mediaPlayers.erase(id);
-        if (vmgr.mediaPlayers.empty()) {
-            jami::Manager::instance().checkAudio();
-        }
-        return true;
-    }
-    return false;
+    return Manager::instance().getVideoManager().mediaPlayers.erase(id) > 0;
 }
 
 bool
 mutePlayerAudio(const std::string& id, bool mute)
 {
-    auto& vmgr = Manager::instance().getVideoManager();
-    auto player = getMediaPlayer(id);
-    if (player) {
+    if (auto player = getMediaPlayer(id)) {
         player->muteAudio(mute);
         return true;
     }
@@ -838,22 +818,16 @@ mutePlayerAudio(const std::string& id, bool mute)
 bool
 playerSeekToTime(const std::string& id, int time)
 {
-    auto& vmgr = Manager::instance().getVideoManager();
-    auto player = getMediaPlayer(id);
-    if (player) {
+    if (auto player = getMediaPlayer(id))
         return player->seekToTime(time);
-    }
     return false;
 }
 
 int64_t
 getPlayerPosition(const std::string& id)
 {
-    auto& vmgr = Manager::instance().getVideoManager();
-    auto player = getMediaPlayer(id);
-    if (player) {
+    if (auto player = getMediaPlayer(id))
         return player->getPlayerPosition();
-    }
     return -1;
 }
 
diff --git a/src/manager.cpp b/src/manager.cpp
index d456e07572fcbc4a64f4ec183a6d38d4a3627fc8..0f90d65c3de09b3e1eb0440916f085f6d2be570e 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -300,7 +300,7 @@ struct Manager::ManagerPimpl
      */
     void playATone(Tone::ToneId toneId);
 
-    int getCurrentDeviceIndex(DeviceType type);
+    int getCurrentDeviceIndex(AudioDeviceType type);
 
     /**
      * Process remaining participant given a conference and the current call id.
@@ -345,6 +345,8 @@ struct Manager::ManagerPimpl
     template<class T>
     std::shared_ptr<T> findAccount(const std::function<bool(const std::shared_ptr<T>&)>&);
 
+    void initAudioDriver();
+
     Manager& base_; // pimpl back-pointer
 
     std::shared_ptr<asio::io_context> ioContext_;
@@ -357,6 +359,7 @@ struct Manager::ManagerPimpl
 
     /** Application wide tone controller */
     ToneControl toneCtrl_;
+    std::unique_ptr<AudioDeviceGuard> toneDeviceGuard_;
 
     /** Current Call ID */
     std::string currentCall_;
@@ -366,6 +369,7 @@ struct Manager::ManagerPimpl
 
     /** Audio layer */
     std::shared_ptr<AudioLayer> audiodriver_ {nullptr};
+    std::array<std::atomic_uint, 3> audioStreamUsers_ {};
 
     // Main thread
     std::unique_ptr<DTMF> dtmfKey_;
@@ -487,32 +491,29 @@ Manager::ManagerPimpl::playATone(Tone::ToneId toneId)
     if (not base_.voipPreferences.getPlayTones())
         return;
 
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (not audiodriver_) {
-            JAMI_ERR("Audio layer not initialized");
-            return;
-        }
-
-        audiodriver_->flushUrgent();
-        audiodriver_->startStream();
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    if (not audiodriver_) {
+        JAMI_ERR("Audio layer not initialized");
+        return;
     }
 
+    auto oldGuard = std::move(toneDeviceGuard_);
+    toneDeviceGuard_ = base_.startAudioStream(AudioDeviceType::PLAYBACK);
+    audiodriver_->flushUrgent();
     toneCtrl_.play(toneId);
 }
 
 int
-Manager::ManagerPimpl::getCurrentDeviceIndex(DeviceType type)
+Manager::ManagerPimpl::getCurrentDeviceIndex(AudioDeviceType type)
 {
     if (not audiodriver_)
         return -1;
     switch (type) {
-    case DeviceType::PLAYBACK:
+    case AudioDeviceType::PLAYBACK:
         return audiodriver_->getIndexPlayback();
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::RINGTONE:
         return audiodriver_->getIndexRingtone();
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         return audiodriver_->getIndexCapture();
     default:
         return -1;
@@ -817,17 +818,14 @@ Manager::init(const std::string& config_file)
         }
     }
 
-    initAudioDriver();
-
     {
         std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-
+        pimpl_->initAudioDriver();
         if (pimpl_->audiodriver_) {
             pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate());
             pimpl_->dtmfKey_.reset(new DTMF(getRingBufferPool().getInternalSamplingRate()));
         }
     }
-
     registerAccounts();
 }
 
@@ -861,7 +859,6 @@ Manager::finish() noexcept
 
         {
             std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-
             pimpl_->audiodriver_.reset();
         }
 
@@ -1025,22 +1022,6 @@ Manager::answerCall(const std::string& call_id)
     return result;
 }
 
-void
-Manager::checkAudio()
-{
-    // FIXME dirty, the manager should not need to be aware of local recorders
-    if (getCallList().empty()
-#ifdef ENABLE_VIDEO
-        and not getVideoManager().audioPreview
-#endif
-        and not getVideoManager().hasRunningPlayers()
-        and not jami::LocalRecorderManager::instance().hasRunningRecorders()) {
-        std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-        if (pimpl_->audiodriver_)
-            pimpl_->audiodriver_->stopStream();
-    }
-}
-
 // THREAD=Main
 bool
 Manager::hangupCall(const std::string& callId)
@@ -1054,7 +1035,6 @@ Manager::hangupCall(const std::string& callId)
     auto call = getCallFromCallID(callId);
     if (not call) {
         JAMI_WARN("Could not hang up non-existant call %s", callId.c_str());
-        checkAudio();
         return false;
     }
 
@@ -1631,7 +1611,6 @@ Manager::addAudio(Call& call)
     JAMI_INFO("Add audio to call %s", call.getCallId().c_str());
 
     const auto& call_id = call.getCallId();
-
     if (isConferenceParticipant(call_id)) {
         JAMI_DBG("[conf:%s] Attach local audio", call_id.c_str());
 
@@ -1646,6 +1625,8 @@ Manager::addAudio(Call& call)
 
         // bind to main
         getRingBufferPool().bindCallID(call_id, RingBufferPool::DEFAULT_ID);
+        auto oldGuard = std::move(call.audioGuard);
+        call.audioGuard = startAudioStream(AudioDeviceType::PLAYBACK);
 
         std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
         if (!pimpl_->audiodriver_) {
@@ -1655,7 +1636,6 @@ Manager::addAudio(Call& call)
         pimpl_->audiodriver_->flushUrgent();
         getRingBufferPool().flushAllBuffers();
     }
-    startAudioDriverStream();
 }
 
 void
@@ -1664,6 +1644,7 @@ Manager::removeAudio(Call& call)
     const auto& call_id = call.getCallId();
     JAMI_DBG("[call:%s] Remove local audio", call_id.c_str());
     getRingBufferPool().unBindAll(call_id);
+    call.audioGuard.reset();
 }
 
 ScheduledExecutor&
@@ -1788,7 +1769,7 @@ Manager::playDtmf(char code)
         return;
     }
 
-    pimpl_->audiodriver_->startStream();
+    std::shared_ptr<AudioDeviceGuard> audioGuard = startAudioStream(AudioDeviceType::PLAYBACK);
     if (not pimpl_->audiodriver_->waitForStart(std::chrono::seconds(1))) {
         JAMI_ERR("Failed to start audio layer...");
         return;
@@ -1814,6 +1795,9 @@ Manager::playDtmf(char code)
         pimpl_->audiodriver_->putUrgent(pimpl_->dtmfBuf_);
     }
 
+    scheduler().scheduleIn([audioGuard] { JAMI_WARN("End of dtmf"); },
+                           std::chrono::milliseconds(pulselen));
+
     // TODO Cache the DTMF
 }
 
@@ -2048,7 +2032,6 @@ Manager::peerHungupCall(Call& call)
 
     call.peerHungup();
 
-    checkAudio();
     pimpl_->removeWaitingCall(call_id);
     if (not incomingCallsWaiting())
         stopTone();
@@ -2066,7 +2049,6 @@ Manager::callBusy(Call& call)
         pimpl_->unsetCurrentCall();
     }
 
-    checkAudio();
     pimpl_->removeWaitingCall(call.getCallId());
     if (not incomingCallsWaiting())
         stopTone();
@@ -2089,7 +2071,6 @@ Manager::callFailure(Call& call)
         removeParticipant(call_id);
     }
 
-    checkAudio();
     pimpl_->removeWaitingCall(call_id);
     if (not incomingCallsWaiting())
         stopTone();
@@ -2106,6 +2087,7 @@ Manager::stopTone()
         return;
 
     pimpl_->toneCtrl_.stop();
+    pimpl_->toneDeviceGuard_.reset();
 }
 
 /**
@@ -2151,7 +2133,6 @@ void
 Manager::playRingtone(const std::string& accountID)
 {
     const auto account = getAccount(accountID);
-
     if (!account) {
         JAMI_WARN("Invalid account in ringtone");
         return;
@@ -2163,15 +2144,7 @@ Manager::playRingtone(const std::string& accountID)
     }
 
     std::string ringchoice = account->getRingtonePath();
-#if (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
-    // for ios file located in main buindle
-    CFBundleRef bundle = CFBundleGetMainBundle();
-    CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
-    CFStringRef stringPath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
-    CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
-    const char* buindlePath = CFStringGetCStringPtr(stringPath, encodingMethod);
-    ringchoice = std::string(buindlePath) + DIR_SEPARATOR_STR + ringchoice;
-#elif !defined(_WIN32)
+#if !defined(_WIN32)
     if (ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos) {
         // check inside global share directory
         static const char* const RINGDIR = "ringtones";
@@ -2188,7 +2161,8 @@ Manager::playRingtone(const std::string& accountID)
             return;
         }
         // start audio if not started AND flush all buffers (main and urgent)
-        pimpl_->audiodriver_->startStream();
+        auto oldGuard = std::move(pimpl_->toneDeviceGuard_);
+        pimpl_->toneDeviceGuard_ = startAudioStream(AudioDeviceType::RINGTONE);
         pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate());
     }
 
@@ -2214,21 +2188,13 @@ Manager::getTelephoneFile()
 void
 Manager::setAudioPlugin(const std::string& audioPlugin)
 {
-    std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-
-    audioPreference.setAlsaPlugin(audioPlugin);
-
-    bool wasStarted = pimpl_->audiodriver_->isStarted();
-
+    {
+        std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
+        audioPreference.setAlsaPlugin(audioPlugin);
+        pimpl_->audiodriver_.reset();
+        pimpl_->initAudioDriver();
+    }
     // Recreate audio driver with new settings
-    pimpl_->audiodriver_.reset();
-    pimpl_->audiodriver_.reset(audioPreference.createAudioLayer());
-
-    if (pimpl_->audiodriver_ and wasStarted)
-        pimpl_->audiodriver_->startStream();
-    else
-        JAMI_ERR("No audio layer created, possibly built without audio support");
-
     saveConfig();
 }
 
@@ -2236,7 +2202,7 @@ Manager::setAudioPlugin(const std::string& audioPlugin)
  * Set audio output device
  */
 void
-Manager::setAudioDevice(int index, DeviceType type)
+Manager::setAudioDevice(int index, AudioDeviceType type)
 {
     std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
 
@@ -2249,15 +2215,11 @@ Manager::setAudioDevice(int index, DeviceType type)
         return;
     }
 
-    const bool wasStarted = pimpl_->audiodriver_->isStarted();
     pimpl_->audiodriver_->updatePreference(audioPreference, index, type);
 
     // Recreate audio driver with new settings
-    pimpl_->audiodriver_.reset(audioPreference.createAudioLayer());
-
-    if (pimpl_->audiodriver_ and wasStarted)
-        pimpl_->audiodriver_->startStream();
-
+    pimpl_->audiodriver_.reset();
+    pimpl_->initAudioDriver();
     saveConfig();
 }
 
@@ -2300,23 +2262,50 @@ std::vector<std::string>
 Manager::getCurrentAudioDevicesIndex()
 {
     std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-
     if (not pimpl_->audiodriver_) {
         JAMI_ERR("Audio layer not initialized");
         return {};
     }
 
-    std::vector<std::string> v;
+    return {std::to_string(pimpl_->audiodriver_->getIndexPlayback()),
+            std::to_string(pimpl_->audiodriver_->getIndexCapture()),
+            std::to_string(pimpl_->audiodriver_->getIndexRingtone())};
+}
 
-    std::stringstream ssi, sso, ssr;
-    sso << pimpl_->audiodriver_->getIndexPlayback();
-    v.push_back(sso.str());
-    ssi << pimpl_->audiodriver_->getIndexCapture();
-    v.push_back(ssi.str());
-    ssr << pimpl_->audiodriver_->getIndexRingtone();
-    v.push_back(ssr.str());
+void
+Manager::startAudio()
+{
+    if (!pimpl_->audiodriver_)
+        pimpl_->audiodriver_.reset(pimpl_->base_.audioPreference.createAudioLayer());
+    constexpr std::array<AudioDeviceType, 3> TYPES {AudioDeviceType::CAPTURE,
+                                                    AudioDeviceType::PLAYBACK,
+                                                    AudioDeviceType::RINGTONE};
+    for (const auto& type : TYPES)
+        if (pimpl_->audioStreamUsers_[(unsigned) type])
+            pimpl_->audiodriver_->startStream(type);
 
-    return v;
+}
+
+AudioDeviceGuard::AudioDeviceGuard(Manager& manager, AudioDeviceType type)
+    : manager_(manager)
+    , type_(type)
+{
+    auto streamId = (unsigned) type;
+    if (streamId >= manager_.pimpl_->audioStreamUsers_.size())
+        throw std::invalid_argument("Invalid audio device type");
+    if (manager_.pimpl_->audioStreamUsers_[(unsigned) type]++ == 0) {
+        if (auto layer = manager_.getAudioDriver())
+            layer->startStream(type);
+    }
+}
+
+AudioDeviceGuard::~AudioDeviceGuard()
+{
+    auto streamId = (unsigned) type_;
+    if (--manager_.pimpl_->audioStreamUsers_[streamId] == 0) {
+        if (auto layer = manager_.getAudioDriver())
+            layer->stopStream(type_);
+    }
 }
 
 bool
@@ -2416,29 +2405,14 @@ Manager::startRecordedFilePlayback(const std::string& filepath)
             return false;
         }
 
-        pimpl_->audiodriver_->startStream();
+        auto oldGuard = std::move(pimpl_->toneDeviceGuard_);
+        pimpl_->toneDeviceGuard_ = startAudioStream(AudioDeviceType::RINGTONE);
         pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate());
     }
 
     return pimpl_->toneCtrl_.setAudioFile(filepath);
 }
 
-bool
-Manager::startAudioPlayback()
-{
-    if (not pimpl_->audiodriver_) {
-        JAMI_ERR("No audio layer");
-        return false;
-    }
-
-    if (pimpl_->audiodriver_->isStarted()) {
-        JAMI_DBG("Audio is running");
-        return true;
-    }
-    pimpl_->audiodriver_->startStream(AudioStreamType::PLAYBACK);
-    return true;
-}
-
 void
 Manager::recordingPlaybackSeek(const double value)
 {
@@ -2450,8 +2424,8 @@ Manager::stopRecordedFilePlayback()
 {
     JAMI_DBG("Stop recorded file playback");
 
-    checkAudio();
     pimpl_->toneCtrl_.stopAudioFile();
+    pimpl_->toneDeviceGuard_.reset();
 }
 
 void
@@ -2499,13 +2473,9 @@ Manager::setAudioManager(const std::string& api)
 
     {
         std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-
-        bool wasStarted = pimpl_->audiodriver_->isStarted();
         audioPreference.setAudioApi(api);
-        pimpl_->audiodriver_.reset(audioPreference.createAudioLayer());
-
-        if (pimpl_->audiodriver_ and wasStarted)
-            pimpl_->audiodriver_->startStream();
+        pimpl_->audiodriver_.reset();
+        pimpl_->initAudioDriver();
     }
 
     saveConfig();
@@ -2530,7 +2500,7 @@ Manager::getAudioInputDeviceIndex(const std::string& name)
         return 0;
     }
 
-    return pimpl_->audiodriver_->getAudioDeviceIndex(name, DeviceType::CAPTURE);
+    return pimpl_->audiodriver_->getAudioDeviceIndex(name, AudioDeviceType::CAPTURE);
 }
 
 int
@@ -2543,7 +2513,7 @@ Manager::getAudioOutputDeviceIndex(const std::string& name)
         return 0;
     }
 
-    return pimpl_->audiodriver_->getAudioDeviceIndex(name, DeviceType::PLAYBACK);
+    return pimpl_->audiodriver_->getAudioDeviceIndex(name, AudioDeviceType::PLAYBACK);
 }
 
 std::string
@@ -2580,10 +2550,15 @@ Manager::setAGCState(bool state)
  * Initialization: Main Thread
  */
 void
-Manager::initAudioDriver()
+Manager::ManagerPimpl::initAudioDriver()
 {
-    std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-    pimpl_->audiodriver_.reset(audioPreference.createAudioLayer());
+    audiodriver_.reset(base_.audioPreference.createAudioLayer());
+    constexpr std::array<AudioDeviceType, 3> TYPES {AudioDeviceType::CAPTURE,
+                                                    AudioDeviceType::PLAYBACK,
+                                                    AudioDeviceType::RINGTONE};
+    for (const auto& type : TYPES)
+        if (audioStreamUsers_[(unsigned) type])
+            audiodriver_->startStream(type);
 }
 
 AudioFormat
@@ -2991,29 +2966,6 @@ Manager::getConferenceId(const std::string& callID)
     return "";
 }
 
-void
-Manager::startAudioDriverStream()
-{
-    std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-    if (!pimpl_->audiodriver_) {
-        JAMI_ERR("Audio driver not initialized");
-        return;
-    }
-    pimpl_->audiodriver_->startStream();
-}
-
-void
-Manager::restartAudioDriverStream()
-{
-    std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_);
-    if (!pimpl_->audiodriver_) {
-        JAMI_ERR("Audio driver not initialized");
-        return;
-    }
-    pimpl_->audiodriver_->stopStream();
-    pimpl_->audiodriver_->startStream();
-}
-
 void
 Manager::registerAccounts()
 {
diff --git a/src/manager.h b/src/manager.h
index bb37c79458c689385b8faccf5195224ad60736b1..24414b362aa7c36c28d542e8b09738e7466fafd6 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -137,8 +137,10 @@ public:
      */
     std::shared_ptr<AudioLayer> getAudioDriver();
 
-    void startAudioDriverStream();
-    void restartAudioDriverStream();
+    inline std::unique_ptr<AudioDeviceGuard> startAudioStream(AudioDeviceType stream)
+    {
+        return std::make_unique<AudioDeviceGuard>(*this, stream);
+    }
 
     /**
      * Functions which occur with a user's action
@@ -546,7 +548,9 @@ public:
      * @param index The index of the soundcard
      * @param the type of stream, either PLAYBACK, CAPTURE, RINGTONE
      */
-    void setAudioDevice(int index, DeviceType streamType);
+    void setAudioDevice(int index, AudioDeviceType streamType);
+
+    void startAudio();
 
     /**
      * Get list of supported audio output device
@@ -641,11 +645,6 @@ public:
      */
     bool startRecordedFilePlayback(const std::string&);
 
-    /**
-     * Start audio playback
-     */
-    bool startAudioPlayback();
-
     void recordingPlaybackSeek(const double value);
 
     /**
@@ -782,8 +781,6 @@ public:
      */
     bool isCurrentCall(const Call& call) const;
 
-    void initAudioDriver();
-
     /**
      * Load the accounts order set by the user from the dringrc config file
      * @return std::vector<std::string> A vector containing the account ID's
@@ -874,14 +871,6 @@ public:
      */
     void unregisterAccounts();
 
-    /**
-     * Suspends audio processing if no calls remain, allowing
-     * other applications to resume audio.
-     * See:
-     * https://projects.savoirfairelinux.com/issues/7037
-     */
-    void checkAudio();
-
     /**
      * Call periodically to poll for VoIP events */
     void pollEvents();
@@ -951,11 +940,23 @@ public:
 private:
     Manager();
     ~Manager();
+    friend class AudioDeviceGuard;
 
     struct ManagerPimpl;
     std::unique_ptr<ManagerPimpl> pimpl_;
 };
 
+class AudioDeviceGuard
+{
+public:
+    AudioDeviceGuard(Manager& manager, AudioDeviceType type);
+    ~AudioDeviceGuard();
+
+private:
+    Manager& manager_;
+    const AudioDeviceType type_;
+};
+
 // Helper to install a callback to be called once by the main event loop
 template<typename Callback>
 static void
diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp
index 749f5a13c2d3ec69373761a45b446a477ed373b6..a0d1d4c031505d575f53b30898e200d9a490f56f 100644
--- a/src/media/audio/alsa/alsalayer.cpp
+++ b/src/media/audio/alsa/alsalayer.cpp
@@ -231,7 +231,7 @@ AlsaLayer::openDevice(snd_pcm_t** pcm,
     return true;
 }
 
-void AlsaLayer::startStream(AudioStreamType)
+void AlsaLayer::startStream(AudioDeviceType)
 {
     {
         std::lock_guard<std::mutex> lock(mutex_);
@@ -254,7 +254,7 @@ void AlsaLayer::startStream(AudioStreamType)
 }
 
 void
-AlsaLayer::stopStream()
+AlsaLayer::stopStream(AudioDeviceType stream)
 {
     audioThread_.reset();
 
@@ -674,7 +674,7 @@ AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const
 }
 
 bool
-AlsaLayer::soundCardIndexExists(int card, DeviceType stream)
+AlsaLayer::soundCardIndexExists(int card, AudioDeviceType stream)
 {
     const std::string name("hw:" + std::to_string(card));
 
@@ -685,17 +685,17 @@ AlsaLayer::soundCardIndexExists(int card, DeviceType stream)
     snd_pcm_info_t* pcminfo;
     snd_pcm_info_alloca(&pcminfo);
     snd_pcm_info_set_stream(pcminfo,
-                            stream == DeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK
-                                                           : SND_PCM_STREAM_CAPTURE);
+                            stream == AudioDeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK
+                                                                : SND_PCM_STREAM_CAPTURE);
     bool ret = snd_ctl_pcm_info(handle, pcminfo) >= 0;
     snd_ctl_close(handle);
     return ret;
 }
 
 int
-AlsaLayer::getAudioDeviceIndex(const std::string& description, DeviceType type) const
+AlsaLayer::getAudioDeviceIndex(const std::string& description, AudioDeviceType type) const
 {
-    std::vector<HwIDPair> devices = getAudioDeviceIndexMap(type == DeviceType::CAPTURE);
+    std::vector<HwIDPair> devices = getAudioDeviceIndexMap(type == AudioDeviceType::CAPTURE);
 
     for (const auto& dev : devices)
         if (dev.second == description)
@@ -706,17 +706,17 @@ AlsaLayer::getAudioDeviceIndex(const std::string& description, DeviceType type)
 }
 
 std::string
-AlsaLayer::getAudioDeviceName(int index, DeviceType type) const
+AlsaLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
     // a bit ugly and wrong.. i do not know how to implement it better in alsalayer.
     // in addition, for now it is used in pulselayer only due to alsa and pulse layers api
     // differences. but after some tweaking in alsalayer, it could be used in it too.
     switch (type) {
-    case DeviceType::PLAYBACK:
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::PLAYBACK:
+    case AudioDeviceType::RINGTONE:
         return getPlaybackDeviceList().at(index);
 
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         return getCaptureDeviceList().at(index);
     default:
         // Should never happen
@@ -778,18 +778,18 @@ AlsaLayer::ringtone()
 }
 
 void
-AlsaLayer::updatePreference(AudioPreference& preference, int index, DeviceType type)
+AlsaLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type)
 {
     switch (type) {
-    case DeviceType::PLAYBACK:
+    case AudioDeviceType::PLAYBACK:
         preference.setAlsaCardout(index);
         break;
 
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         preference.setAlsaCardin(index);
         break;
 
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::RINGTONE:
         preference.setAlsaCardring(index);
         break;
 
diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h
index 346c5eda69f4db16623fa6f13e3b197568ac6588..6c468af79d7f0716bddbb9211e56d72b9e6bf9c9 100644
--- a/src/media/audio/alsa/alsalayer.h
+++ b/src/media/audio/alsa/alsalayer.h
@@ -20,11 +20,11 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
  */
 
-#ifndef ALSA_LAYER_H_
-#define ALSA_LAYER_H_
+#pragma once
 
 #include "audio/audiolayer.h"
 #include "noncopyable.h"
+
 #include <alsa/asoundlib.h>
 
 #include <memory>
@@ -67,14 +67,14 @@ public:
      * The playback starts accordingly to its threshold
      * ALSA Library API
      */
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
+    virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     /**
      * Stop the playback and capture streams.
      * Drops the pending frames and put the capture and playback handles to PREPARED state
      * ALSA Library API
      */
-    virtual void stopStream();
+    virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     /**
      * Concatenate two strings. Used to build a valid pcm device name.
@@ -96,21 +96,21 @@ public:
      *streaming mode
      * @param card   An index
      * @param stream  The stream mode
-     *		  DeviceType::CAPTURE
-     *		  DeviceType::PLAYBACK
-     *		  DeviceType::RINGTONE
+     *		  AudioDeviceType::CAPTURE
+     *		  AudioDeviceType::PLAYBACK
+     *		  AudioDeviceType::RINGTONE
      * @return bool True if it exists and supports the mode
      *		    false otherwise
      */
-    static bool soundCardIndexExists(int card, DeviceType stream);
+    static bool soundCardIndexExists(int card, AudioDeviceType stream);
 
     /**
      * An index is associated with its string description
      * @param description The string description
      * @return	int	  Its index
      */
-    int getAudioDeviceIndex(const std::string& description, DeviceType type) const;
-    std::string getAudioDeviceName(int index, DeviceType type) const;
+    int getAudioDeviceIndex(const std::string& description, AudioDeviceType type) const;
+    std::string getAudioDeviceName(int index, AudioDeviceType type) const;
 
     void playback();
     void ringtone();
@@ -206,7 +206,7 @@ private:
      */
     std::unique_ptr<AudioFrame> read(unsigned frames);
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
 
     /**
      * Handles to manipulate playback stream
@@ -250,5 +250,3 @@ private:
 };
 
 } // namespace jami
-
-#endif // ALSA_LAYER_H_
diff --git a/src/media/audio/audio_input.cpp b/src/media/audio/audio_input.cpp
index 1ff1e682572ff68c52dc7bbc1f16f6645fbb4b67..c5b427342a917b8970d91c53590a422c2b7aeaec 100644
--- a/src/media/audio/audio_input.cpp
+++ b/src/media/audio/audio_input.cpp
@@ -48,11 +48,16 @@ AudioInput::AudioInput(const std::string& id)
                                          frameResized(std::move(f));
                                      }))
     , fileId_(id + "_file")
+    , deviceGuard_()
     , loop_([] { return true; }, [this] { process(); }, [] {})
 {
     JAMI_DBG() << "Creating audio input with id: " << id;
-    wakeUp_ = std::chrono::high_resolution_clock::now() + MS_PER_PACKET;
-    loop_.start();
+}
+
+AudioInput::AudioInput(const std::string& id, const std::string& resource)
+    : AudioInput(id)
+{
+    switchInput(resource);
 }
 
 AudioInput::~AudioInput()
@@ -66,9 +71,6 @@ AudioInput::~AudioInput()
 void
 AudioInput::process()
 {
-    // NOTE This is only useful if the device params weren't yet found in switchInput
-    // For both files and audio devices, this is already done
-    // foundDevOpts(devOpts_);
     if (switchPending_.exchange(false)) {
         if (devOpts_.input.empty())
             JAMI_DBG() << "Switching to default audio input";
@@ -108,9 +110,6 @@ AudioInput::setSeekTime(int64_t time)
 void
 AudioInput::readFromDevice()
 {
-    auto& mainBuffer = Manager::instance().getRingBufferPool();
-    auto bufferFormat = mainBuffer.getInternalAudioFormat();
-
     if (decodingFile_)
         while (fileBuf_->isEmpty())
             readFromFile();
@@ -128,6 +127,7 @@ AudioInput::readFromDevice()
     std::this_thread::sleep_until(wakeUp_);
     wakeUp_ += MS_PER_PACKET;
 
+    auto& mainBuffer = Manager::instance().getRingBufferPool();
     auto samples = mainBuffer.getData(id_);
     if (not samples)
         return;
@@ -136,7 +136,7 @@ AudioInput::readFromDevice()
         libav_utils::fillWithSilence(samples->pointer());
 
     std::lock_guard<std::mutex> lk(fmtMutex_);
-    if (bufferFormat != format_)
+    if (mainBuffer.getInternalAudioFormat() != format_)
         samples = resampler_->resample(std::move(samples), format_);
     resizer_->enqueue(std::move(samples));
 }
@@ -179,10 +179,13 @@ AudioInput::readFromFile()
 bool
 AudioInput::initDevice(const std::string& device)
 {
+    JAMI_WARN("AudioInput::initDevice %s", device.c_str());
     devOpts_ = {};
     devOpts_.input = device;
     devOpts_.channel = format_.nb_channels;
     devOpts_.framerate = format_.sample_rate;
+    deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::CAPTURE);
+    playingDevice_ = true;
     return true;
 }
 
@@ -217,8 +220,10 @@ AudioInput::setPaused(bool paused)
 {
     if (paused) {
         Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID, id_);
+        deviceGuard_.reset();
     } else {
         Manager::instance().getRingBufferPool().bindHalfDuplexOut(RingBufferPool::DEFAULT_ID, id_);
+        deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::PLAYBACK);
     }
     paused_ = paused;
 }
@@ -254,6 +259,7 @@ AudioInput::initFile(const std::string& path)
     // have file audio mixed into the local buffer so it gets played
     Manager::instance().getRingBufferPool().bindHalfDuplexOut(RingBufferPool::DEFAULT_ID, fileId_);
     decodingFile_ = true;
+    deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::PLAYBACK);
     return true;
 }
 
@@ -261,7 +267,6 @@ std::shared_future<DeviceParams>
 AudioInput::switchInput(const std::string& resource)
 {
     // Always switch inputs, even if it's the same resource, so audio will be in sync with video
-
     if (switchPending_) {
         JAMI_ERR() << "Audio switch already requested";
         return {};
@@ -269,12 +274,18 @@ AudioInput::switchInput(const std::string& resource)
 
     JAMI_DBG() << "Switching audio source to match '" << resource << "'";
 
+    auto oldGuard = std::move(deviceGuard_);
+
     decoder_.reset();
-    decodingFile_ = false;
-    Manager::instance().getRingBufferPool().unBindHalfDuplexOut(id_, fileId_);
-    Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID, fileId_);
+    if (decodingFile_) {
+        decodingFile_ = false;
+        Manager::instance().getRingBufferPool().unBindHalfDuplexOut(id_, fileId_);
+        Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID,
+                                                                    fileId_);
+    }
     fileBuf_.reset();
 
+    playingDevice_ = false;
     currentResource_ = resource;
     devOptsFound_ = false;
 
@@ -284,33 +295,31 @@ AudioInput::switchInput(const std::string& resource)
     if (resource.empty()) {
         if (initDevice(""))
             foundDevOpts(devOpts_);
-        switchPending_ = true;
-        futureDevOpts_ = foundDevOpts_.get_future();
-        return futureDevOpts_;
-    }
-
-    static const std::string& sep = DRing::Media::VideoProtocolPrefix::SEPARATOR;
-
-    const auto pos = resource.find(sep);
-    if (pos == std::string::npos)
-        return {};
-
-    const auto prefix = resource.substr(0, pos);
-    if ((pos + sep.size()) >= resource.size())
-        return {};
-
-    const auto suffix = resource.substr(pos + sep.size());
-    bool ready = false;
-    if (prefix == DRing::Media::VideoProtocolPrefix::FILE)
-        ready = initFile(suffix);
-    else
-        ready = initDevice(suffix);
+    } else {
+        static const std::string& sep = DRing::Media::VideoProtocolPrefix::SEPARATOR;
+        const auto pos = resource.find(sep);
+        if (pos == std::string::npos)
+            return {};
+
+        const auto prefix = resource.substr(0, pos);
+        if ((pos + sep.size()) >= resource.size())
+            return {};
+
+        const auto suffix = resource.substr(pos + sep.size());
+        bool ready = false;
+        if (prefix == DRing::Media::VideoProtocolPrefix::FILE)
+            ready = initFile(suffix);
+        else
+            ready = initDevice(suffix);
 
-    if (ready)
-        foundDevOpts(devOpts_);
+        if (ready)
+            foundDevOpts(devOpts_);
+    }
 
     switchPending_ = true;
     futureDevOpts_ = foundDevOpts_.get_future().share();
+    wakeUp_ = std::chrono::high_resolution_clock::now() + MS_PER_PACKET;
+    loop_.start();
     return futureDevOpts_;
 }
 
@@ -381,8 +390,7 @@ MediaStream
 AudioInput::getInfo() const
 {
     std::lock_guard<std::mutex> lk(fmtMutex_);
-    auto ms = MediaStream("a:local", format_, sent_samples);
-    return ms;
+    return MediaStream("a:local", format_, sent_samples);
 }
 
 MediaStream
diff --git a/src/media/audio/audio_input.h b/src/media/audio/audio_input.h
index 9fc2170c9a0a1a97eafcdf87ad7a14e257916854..6928213ee201ed45c7a511639a15610cddc69147 100644
--- a/src/media/audio/audio_input.h
+++ b/src/media/audio/audio_input.h
@@ -33,12 +33,9 @@
 #include "threadloop.h"
 
 namespace jami {
-class MediaDecoder;
-class MediaDemuxer;
-} // namespace jami
-namespace jami {
-
+class AudioDeviceGuard;
 class AudioFrameResizer;
+class MediaDemuxer;
 class MediaDecoder;
 class MediaRecorder;
 struct MediaStream;
@@ -49,9 +46,11 @@ class AudioInput : public Observable<std::shared_ptr<MediaFrame>>
 {
 public:
     AudioInput(const std::string& id);
+    AudioInput(const std::string& id, const std::string& resource);
     ~AudioInput();
 
     std::shared_future<DeviceParams> switchInput(const std::string& resource);
+    void start() { loop_.start(); };
 
     bool isCapturing() const { return loop_.isRunning(); }
     void setFormat(const AudioFormat& fmt);
@@ -76,7 +75,6 @@ private:
     void frameResized(std::shared_ptr<AudioFrame>&& ptr);
 
     std::string id_;
-    AudioBuffer micData_;
     bool muteState_ = false;
     uint64_t sent_samples = 0;
     mutable std::mutex fmtMutex_ {};
@@ -98,8 +96,11 @@ private:
     std::shared_future<DeviceParams> futureDevOpts_;
     std::atomic_bool devOptsFound_ {false};
     void foundDevOpts(const DeviceParams& params);
+
+    std::atomic_bool playingDevice_ {false};
     std::atomic_bool decodingFile_ {false};
     std::atomic_bool playingFile_ {false};
+    std::unique_ptr<AudioDeviceGuard> deviceGuard_;
 
     ThreadLoop loop_;
     void process();
diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp
index 7466bc1eb0a830c77e8be92b11f72d13711c53a3..596762c58db829454e9341cfbe0135ef11280491 100644
--- a/src/media/audio/audio_rtp_session.cpp
+++ b/src/media/audio/audio_rtp_session.cpp
@@ -184,7 +184,9 @@ AudioRtpSession::stop()
     receiveThread_.reset();
     sender_.reset();
     socketPair_.reset();
+    audioInput_.reset();
 }
+
 void
 AudioRtpSession::setMuted(bool isMuted)
 {
diff --git a/src/media/audio/audio_sender.cpp b/src/media/audio/audio_sender.cpp
index fe97eb687a495c53ef27793c950c5cf8a78db428..ffe0735db053be3be20dbd1ee1c891d931bbc158 100644
--- a/src/media/audio/audio_sender.cpp
+++ b/src/media/audio/audio_sender.cpp
@@ -94,7 +94,6 @@ AudioSender::setup(SocketPair& socketPair)
     audioInput_ = jami::getAudioInput(id_);
     audioInput_->setFormat(codec->audioformat);
     audioInput_->attach(this);
-
     return true;
 }
 
@@ -103,16 +102,8 @@ AudioSender::update(Observable<std::shared_ptr<jami::MediaFrame>>* /*obs*/,
                     const std::shared_ptr<jami::MediaFrame>& framePtr)
 {
     auto frame = framePtr->pointer();
-    auto ms = MediaStream("a:local",
-                          frame->format,
-                          rational<int>(1, frame->sample_rate),
-                          frame->sample_rate,
-                          frame->channels,
-                          frame->nb_samples);
     frame->pts = sent_samples;
-    ms.firstTimestamp = frame->pts;
     sent_samples += frame->nb_samples;
-
     if (audioEncoder_->encodeAudio(*std::static_pointer_cast<AudioFrame>(framePtr)) < 0)
         JAMI_ERR("encoding failed");
 }
diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp
index b312db227aba926cbac114edf6c750338dcb6e9e..b4ed1e4eb8681512e0afcfc990bab6e5cc0ee365 100644
--- a/src/media/audio/audiolayer.cpp
+++ b/src/media/audio/audiolayer.cpp
@@ -69,9 +69,11 @@ struct AudioLayer::EchoState
     {
         if (playbackQueue.samples() < playbackQueue.frameSize()
             or recordQueue.samples() < recordQueue.frameSize()) {
-            /* JAMI_DBG("getRecorded underflow %d / %d, %d / %d",
-                playbackQueue.samples(), playbackQueue.frameSize(),
-                recordQueue.samples(), recordQueue.frameSize()); */
+            JAMI_DBG("getRecorded underflow %d / %d, %d / %d",
+                     playbackQueue.samples(),
+                     playbackQueue.frameSize(),
+                     recordQueue.samples(),
+                     recordQueue.frameSize());
             return {};
         }
         if (recordQueue.samples() > 2 * recordQueue.frameSize() && playbackQueue.samples() == 0) {
@@ -79,11 +81,11 @@ struct AudioLayer::EchoState
             return recordQueue.dequeue();
         }
         while (playbackQueue.samples() > 10 * playbackQueue.frameSize()) {
-            JAMI_DBG("getRecorded playback underflow");
+            JAMI_DBG("getRecorded record underflow");
             playbackQueue.dequeue();
         }
         while (recordQueue.samples() > 4 * recordQueue.frameSize()) {
-            JAMI_DBG("getRecorded record underflow");
+            JAMI_DBG("getRecorded playback underflow");
             recordQueue.dequeue();
         }
         auto playback = playbackQueue.dequeue();
diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h
index 0b37db6921c391f15d081df92651bceb75728ab6..6c34840af2b3f159d8716222394b7362955cb5c1 100644
--- a/src/media/audio/audiolayer.h
+++ b/src/media/audio/audiolayer.h
@@ -32,6 +32,7 @@
 #include <vector>
 #include <atomic>
 #include <condition_variable>
+#include <array>
 
 extern "C" {
 struct SpeexEchoState_;
@@ -60,17 +61,7 @@ namespace jami {
 class AudioPreference;
 class Resampler;
 
-enum class DeviceType {
-    PLAYBACK, /** To open playback device only */
-    CAPTURE,  /** To open capture device only */
-    RINGTONE  /** To open the ringtone device only */
-};
-
-enum class AudioStreamType {
-    PLAYBACK, /** To start playback stream only */
-    CAPTURE,  /** To start capture stream only */
-    DEFAULT   /** To start both playback and capture streams */
-};
+enum class AudioDeviceType { ALL = -1, PLAYBACK = 0, CAPTURE, RINGTONE };
 
 class AudioLayer
 {
@@ -84,28 +75,26 @@ public:
     AudioLayer(const AudioPreference&);
     virtual ~AudioLayer();
 
-    virtual std::vector<std::string> getCaptureDeviceList() const = 0;
-    virtual std::vector<std::string> getPlaybackDeviceList() const = 0;
-
-    virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const = 0;
-    virtual std::string getAudioDeviceName(int index, DeviceType type) const = 0;
-    virtual int getIndexCapture() const = 0;
-    virtual int getIndexPlayback() const = 0;
-    virtual int getIndexRingtone() const = 0;
-
     /**
      * Start the capture stream and prepare the playback stream.
      * The playback starts accordingly to its threshold
-     * ALSA Library API
      */
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT) = 0;
+    virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0;
 
     /**
      * Stop the playback and capture streams.
      * Drops the pending frames and put the capture and playback handles to PREPARED state
-     * ALSA Library API
      */
-    virtual void stopStream() = 0;
+    virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0;
+
+    virtual std::vector<std::string> getCaptureDeviceList() const = 0;
+    virtual std::vector<std::string> getPlaybackDeviceList() const = 0;
+
+    virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const = 0;
+    virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const = 0;
+    virtual int getIndexCapture() const = 0;
+    virtual int getIndexPlayback() const = 0;
+    virtual int getIndexRingtone() const = 0;
 
     /**
      * Determine wether or not the audio layer is active (i.e. stream opened)
@@ -193,7 +182,7 @@ public:
      */
     void notifyIncomingCall();
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type) = 0;
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) = 0;
 
 protected:
     /**
@@ -213,9 +202,7 @@ protected:
     void setHasNativeAEC(bool hasEAC);
 
     std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples);
-
     std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples);
-
     std::shared_ptr<AudioFrame> getPlayback(AudioFormat format, size_t samples)
     {
         const auto& ringBuff = getToRing(format, samples);
diff --git a/src/media/audio/coreaudio/ios/corelayer.h b/src/media/audio/coreaudio/ios/corelayer.h
index 291e2cd1ef358f9a9a5437075d916870f46cedd3..1155f9426181e57eb840ce16dee4c94d2a67d00b 100644
--- a/src/media/audio/coreaudio/ios/corelayer.h
+++ b/src/media/audio/coreaudio/ios/corelayer.h
@@ -53,8 +53,8 @@ public:
     virtual std::vector<std::string> getCaptureDeviceList() const;
     virtual std::vector<std::string> getPlaybackDeviceList() const;
 
-    virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const;
-    virtual std::string getAudioDeviceName(int index, DeviceType type) const;
+    virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const;
+    virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const;
 
     /**
      * Get the index of the audio card for capture
@@ -77,7 +77,7 @@ public:
     /**
      * Configure the AudioUnit
      */
-    void initAudioLayerIO(AudioStreamType stream);
+    bool initAudioLayerIO(AudioDeviceType stream);
     void setupOutputBus();
     void setupInputBus();
     void bindCallbacks();
@@ -90,7 +90,7 @@ public:
      * CoreAudio Library API
      */
 
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
+    virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     void destroyAudioLayer();
 
@@ -99,7 +99,7 @@ public:
      * Drops the pending frames and put the capture and playback handles to PREPARED state
      * CoreAudio Library API
      */
-    virtual void stopStream();
+    virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
 private:
     NON_COPYABLE(CoreLayer);
@@ -132,7 +132,7 @@ private:
               UInt32 inNumberFrames,
               AudioBufferList* ioData);
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
 
     /**
      * Number of audio cards on which capture stream has been opened
@@ -160,6 +160,8 @@ private:
     UInt32 inChannelsPerFrame_;
     Float64 outSampleRate_;
     UInt32 outChannelsPerFrame_;
+
+    std::condition_variable readyCv_ {};
 };
 
 } // namespace jami
diff --git a/src/media/audio/coreaudio/ios/corelayer.mm b/src/media/audio/coreaudio/ios/corelayer.mm
index 2188f27e64784935a904dfb81e1afe64ba2fcada..54640bc66da6201ce1642eea7fce4b7207e10ac0 100644
--- a/src/media/audio/coreaudio/ios/corelayer.mm
+++ b/src/media/audio/coreaudio/ios/corelayer.mm
@@ -71,7 +71,7 @@ CoreLayer::getPlaybackDeviceList() const
 }
 
 int
-CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
+CoreLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const
 {
     (void) name;
     (void) index;
@@ -80,15 +80,15 @@ CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
 }
 
 std::string
-CoreLayer::getAudioDeviceName(int index, DeviceType type) const
+CoreLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
     (void) index;
     (void) type;
     return "";
 }
 
-void
-CoreLayer::initAudioLayerIO(AudioStreamType stream)
+bool
+CoreLayer::initAudioLayerIO(AudioDeviceType stream)
 {
     JAMI_DBG("iOS CoreLayer - initializing audio session");
 
@@ -102,22 +102,25 @@ CoreLayer::initAudioLayerIO(AudioStreamType stream)
     auto comp = AudioComponentFindNext(nullptr, &outputUnitDescription);
     if (comp == nullptr) {
         JAMI_ERR("Can't find default output audio component.");
-        return;
+        return false;
     }
 
     checkErr(AudioComponentInstanceNew(comp, &ioUnit_));
-    bool setUpOutput = stream == AudioStreamType::DEFAULT || stream == AudioStreamType::PLAYBACK;
-    bool setUpInput = stream == AudioStreamType::DEFAULT || stream == AudioStreamType::CAPTURE;
+
+    bool setUpInput = stream == AudioDeviceType::ALL || stream == AudioDeviceType::CAPTURE;
     NSError* error = nil;
     AVAudioSessionCategory audioCategory = setUpInput ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback;
     AVAudioSessionMode mode = setUpInput ? AVAudioSessionModeVoiceChat : AVAudioSessionModeMoviePlayback;
-    [[AVAudioSession sharedInstance] setCategory:audioCategory mode: mode options:AVAudioSessionCategoryOptionAllowBluetooth error:&error];
+    AVAudioSessionCategoryOptions options = setUpInput ? AVAudioSessionCategoryOptionAllowBluetooth : AVAudioSessionCategoryOptionMixWithOthers;
+    [[AVAudioSession sharedInstance] setCategory:audioCategory mode: mode options:options error:&error];
     if (error) {
-        JAMI_DBG("***Initializing audio session failed");
+        NSLog(@"Initializing audio session failed, %@",[error localizedDescription]);
+        return false;
     }
     [[AVAudioSession sharedInstance] setActive: true withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error: &error];
     if (error) {
-        JAMI_DBG("***set active audio session failed");
+        NSLog(@"Set active audio session failed, %@",[error localizedDescription]);
+        return false;
     }
     auto playBackDeviceList = getPlaybackDeviceList();
     JAMI_DBG("Setting playback device: %s", playBackDeviceList[indexOut_].c_str());
@@ -135,13 +138,12 @@ CoreLayer::initAudioLayerIO(AudioStreamType stream)
             break;
     }
 
-    if (setUpOutput) {
-        setupOutputBus();
-    }
+    setupOutputBus();
     if (setUpInput) {
         setupInputBus();
     }
     bindCallbacks();
+    return true;
 }
 
 void
@@ -309,32 +311,35 @@ CoreLayer::bindCallbacks() {
                                   inputBus,
                                   &inputCall,
                                   sizeof(AURenderCallbackStruct)));
+
 }
 
 void
-CoreLayer::startStream(AudioStreamType stream)
+CoreLayer::startStream(AudioDeviceType stream)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     JAMI_DBG("iOS CoreLayer - Start Stream");
+    auto currentCategoty =  [[AVAudioSession sharedInstance] category];
 
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
-        if (status_ != Status::Idle)
+    bool updateStream = currentCategoty == AVAudioSessionCategoryPlayback && (stream == AudioDeviceType::CAPTURE || stream == AudioDeviceType::ALL);
+    if (status_ == Status::Started) {
+        if (updateStream)
+            destroyAudioLayer();
+        else
             return;
-        status_ = Status::Started;
     }
+    status_ = Status::Started;
 
     dcblocker_.reset();
-
-    initAudioLayerIO(stream);
-
-    // Run
-    auto inputRes = AudioUnitInitialize(ioUnit_);
-    auto outputRes = AudioOutputUnitStart(ioUnit_);
-    if(inputRes || outputRes) {
-        stopStream();
-        checkErr(inputRes);
-        checkErr(outputRes);
+    if (initAudioLayerIO(stream)) {
+        auto inputRes = AudioUnitInitialize(ioUnit_);
+        auto outputRes = AudioOutputUnitStart(ioUnit_);
+        if (!inputRes && !outputRes) {
+            return;
+        }
     }
+    destroyAudioLayer();
+    status_ = Status::Idle;
 }
 
 void
@@ -347,19 +352,17 @@ CoreLayer::destroyAudioLayer()
 }
 
 void
-CoreLayer::stopStream()
+CoreLayer::stopStream(AudioDeviceType stream)
 {
     JAMI_DBG("iOS CoreLayer - Stop Stream");
-
     {
         std::lock_guard<std::mutex> lock(mutex_);
         if (status_ != Status::Started)
             return;
         status_ = Status::Idle;
+        destroyAudioLayer();
     }
 
-    destroyAudioLayer();
-
     /* Flush the ring buffers */
     flushUrgent();
     flushMain();
@@ -450,18 +453,19 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags,
     putRecorded(std::move(inBuff));
 }
 
-void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
+void CoreLayer::updatePreference(AudioPreference &preference, int index, AudioDeviceType type)
 {
     switch (type) {
-        case DeviceType::PLAYBACK:
+        case AudioDeviceType::ALL:
+        case AudioDeviceType::PLAYBACK:
             preference.setAlsaCardout(index);
             break;
 
-        case DeviceType::CAPTURE:
+        case AudioDeviceType::CAPTURE:
             preference.setAlsaCardin(index);
             break;
 
-        case DeviceType::RINGTONE:
+        case AudioDeviceType::RINGTONE:
             preference.setAlsaCardring(index);
             break;
 
diff --git a/src/media/audio/coreaudio/osx/corelayer.cpp b/src/media/audio/coreaudio/osx/corelayer.cpp
index 4e917285a30724ac692e0fdf268d8bad5e1a83b9..823f516ec07ff59dc836fb2f4de77cc3bde00599 100644
--- a/src/media/audio/coreaudio/osx/corelayer.cpp
+++ b/src/media/audio/coreaudio/osx/corelayer.cpp
@@ -68,10 +68,10 @@ CoreLayer::getPlaybackDeviceList() const
 }
 
 int
-CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
+CoreLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const
 {
     int i = 0;
-    for (const auto& device : getDeviceList(type == DeviceType::CAPTURE)) {
+    for (const auto& device : getDeviceList(type == AudioDeviceType::CAPTURE)) {
         if (device.name_ == name)
             return i;
         i++;
@@ -80,13 +80,13 @@ CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
 }
 
 std::string
-CoreLayer::getAudioDeviceName(int index, DeviceType type) const
+CoreLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
     return "";
 }
 
 void
-CoreLayer::initAudioLayerIO()
+CoreLayer::initAudioLayerIO(AudioDeviceType stream)
 {
     // OS X uses Audio Units for output. Steps:
     // 1) Create a description.
@@ -120,7 +120,11 @@ CoreLayer::initAudioLayerIO()
         return;
     }
 
-    checkErr(AudioComponentInstanceNew(comp, &ioUnit_));
+    auto initError = AudioComponentInstanceNew(comp, &ioUnit_);
+    if (initError) {
+        checkErr(initError);
+        return;
+    }
 
     // set capture device
     UInt32 size = sizeof(inputDeviceID);
@@ -288,7 +292,7 @@ CoreLayer::initAudioLayerIO()
 }
 
 void
-CoreLayer::startStream(AudioStreamType stream)
+CoreLayer::startStream(AudioDeviceType stream)
 {
     JAMI_DBG("START STREAM");
 
@@ -297,15 +301,18 @@ CoreLayer::startStream(AudioStreamType stream)
         if (status_ != Status::Idle)
             return;
         status_ = Status::Started;
-    }
 
-    dcblocker_.reset();
+        dcblocker_.reset();
 
-    initAudioLayerIO();
+        initAudioLayerIO(stream);
 
-    // Run
-    checkErr(AudioUnitInitialize(ioUnit_));
-    checkErr(AudioOutputUnitStart(ioUnit_));
+        auto inputRes = AudioUnitInitialize(ioUnit_);
+        auto outputRes = AudioOutputUnitStart(ioUnit_);
+        if (!inputRes && !outputRes) {
+            return;
+        }
+    }
+    stopStream();
 }
 
 void
@@ -317,19 +324,17 @@ CoreLayer::destroyAudioLayer()
 }
 
 void
-CoreLayer::stopStream()
+CoreLayer::stopStream(AudioDeviceType stream)
 {
     JAMI_DBG("STOP STREAM");
-
     {
         std::lock_guard<std::mutex> lock(mutex_);
         if (status_ != Status::Started)
             return;
         status_ = Status::Idle;
+        destroyAudioLayer();
     }
 
-    destroyAudioLayer();
-
     /* Flush the ring buffers */
     flushUrgent();
     flushMain();
@@ -441,18 +446,19 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags,
 }
 
 void
-CoreLayer::updatePreference(AudioPreference& preference, int index, DeviceType type)
+CoreLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type)
 {
     switch (type) {
-    case DeviceType::PLAYBACK:
+    case AudioDeviceType::ALL:
+    case AudioDeviceType::PLAYBACK:
         preference.setAlsaCardout(index);
         break;
 
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         preference.setAlsaCardin(index);
         break;
 
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::RINGTONE:
         preference.setAlsaCardring(index);
         break;
 
diff --git a/src/media/audio/coreaudio/osx/corelayer.h b/src/media/audio/coreaudio/osx/corelayer.h
index d3668ab42f8fff735c7462d1f82b25b7de612d6c..8409a49f1d61622bf9da860858be2ee50301ea48 100644
--- a/src/media/audio/coreaudio/osx/corelayer.h
+++ b/src/media/audio/coreaudio/osx/corelayer.h
@@ -57,8 +57,8 @@ public:
     virtual std::vector<std::string> getCaptureDeviceList() const;
     virtual std::vector<std::string> getPlaybackDeviceList() const;
 
-    virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const;
-    virtual std::string getAudioDeviceName(int index, DeviceType type) const;
+    virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const;
+    virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const;
 
     /**
      * Get the index of the audio card for capture
@@ -81,7 +81,7 @@ public:
     /**
      * Configure the AudioUnit
      */
-    void initAudioLayerIO();
+    void initAudioLayerIO(AudioDeviceType stream);
 
     /**
      * Start the capture stream and prepare the playback stream.
@@ -89,7 +89,7 @@ public:
      * CoreAudio Library API
      */
 
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
+    virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     void destroyAudioLayer();
 
@@ -98,7 +98,7 @@ public:
      * Drops the pending frames and put the capture and playback handles to PREPARED state
      * CoreAudio Library API
      */
-    virtual void stopStream();
+    virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
 private:
     NON_COPYABLE(CoreLayer);
@@ -135,7 +135,7 @@ private:
               UInt32 inNumberFrames,
               AudioBufferList* ioData);
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
 
     /**
      * Number of audio cards on which capture stream has been opened
diff --git a/src/media/audio/jack/jacklayer.cpp b/src/media/audio/jack/jacklayer.cpp
index 03735a04bde9a65445d8fe96d4756f3dad8e43e0..5225afff5ef22b97aa401d7af7f8b07f4368c88d 100644
--- a/src/media/audio/jack/jacklayer.cpp
+++ b/src/media/audio/jack/jacklayer.cpp
@@ -269,7 +269,7 @@ JackLayer::~JackLayer()
 }
 
 void
-JackLayer::updatePreference(AudioPreference& /*pref*/, int /*index*/, DeviceType /*type*/)
+JackLayer::updatePreference(AudioPreference& /*pref*/, int /*index*/, AudioDeviceType /*type*/)
 {}
 
 std::vector<std::string>
@@ -285,13 +285,13 @@ JackLayer::getPlaybackDeviceList() const
 }
 
 int
-JackLayer::getAudioDeviceIndex(const std::string& /*name*/, DeviceType /*type*/) const
+JackLayer::getAudioDeviceIndex(const std::string& /*name*/, AudioDeviceType /*type*/) const
 {
     return 0;
 }
 
 std::string
-JackLayer::getAudioDeviceName(int /*index*/, DeviceType /*type*/) const
+JackLayer::getAudioDeviceName(int /*index*/, AudioDeviceType /*type*/) const
 {
     return "";
 }
@@ -377,7 +377,7 @@ JackLayer::process_playback(jack_nframes_t frames, void* arg)
 /**
  * Start the capture and playback.
  */
-void JackLayer::startStream(AudioStreamType)
+void JackLayer::startStream(AudioDeviceType)
 {
     {
         std::lock_guard<std::mutex> lock(mutex_);
@@ -406,8 +406,7 @@ JackLayer::onShutdown(void* /* data */)
 /**
  * Stop playback and capture.
  */
-void
-JackLayer::stopStream()
+void JackLayer::stopStream(AudioDeviceType)
 {
     {
         std::lock_guard<std::mutex> lock(mutex_);
diff --git a/src/media/audio/jack/jacklayer.h b/src/media/audio/jack/jacklayer.h
index 1eef9123fc6ba61ed9b14494e905c29aea8640ab..30ee9ae48b524d3dbd3539e7ab3b3a552757aa87 100644
--- a/src/media/audio/jack/jacklayer.h
+++ b/src/media/audio/jack/jacklayer.h
@@ -65,22 +65,22 @@ private:
     std::vector<std::string> getCaptureDeviceList() const;
     std::vector<std::string> getPlaybackDeviceList() const;
 
-    int getAudioDeviceIndex(const std::string& name, DeviceType type) const;
-    std::string getAudioDeviceName(int index, DeviceType type) const;
+    int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const;
+    std::string getAudioDeviceName(int index, AudioDeviceType type) const;
     int getIndexCapture() const;
     int getIndexPlayback() const;
     int getIndexRingtone() const;
-    void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
 
     /**
      * Start the capture and playback.
      */
-    void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
+    void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     /**
      * Stop playback and capture.
      */
-    void stopStream();
+    void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
     static void onShutdown(void* data);
 
diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp
index 5ee20853313114da33a231f8cfa5c8e3e5c27dde..efb2fb040fd5b7eb135852430c70216d7836cd06 100644
--- a/src/media/audio/opensl/opensllayer.cpp
+++ b/src/media/audio/opensl/opensllayer.cpp
@@ -43,7 +43,9 @@ namespace jami {
 // Constructor
 OpenSLLayer::OpenSLLayer(const AudioPreference& pref)
     : AudioLayer(pref)
-{}
+{
+    initAudioEngine();
+}
 
 // Destructor
 OpenSLLayer::~OpenSLLayer()
@@ -52,61 +54,84 @@ OpenSLLayer::~OpenSLLayer()
 }
 
 void
-OpenSLLayer::init()
-{
-    initAudioEngine();
-    initAudioPlayback();
-    initAudioCapture();
-
-    flush();
-}
-
-void
-OpenSLLayer::startStream(AudioStreamType stream)
+OpenSLLayer::startStream(AudioDeviceType stream)
 {
+    using namespace std::placeholders;
     std::lock_guard<std::mutex> lock(mutex_);
-    if (status_ != Status::Idle)
-        return;
-    status_ = Status::Starting;
     JAMI_WARN("Start OpenSL audio layer");
-
-    init();
-    startAudioPlayback();
-    startAudioCapture();
+    if (stream == AudioDeviceType::PLAYBACK) {
+        if (not player_) {
+            try {
+                player_.reset(new opensl::AudioPlayer(hardwareFormat_,
+                                                      hardwareBuffSize_,
+                                                      engineInterface_,
+                                                      SL_ANDROID_STREAM_VOICE));
+                player_->setBufQueue(&playBufQueue_, &freePlayBufQueue_);
+                player_->registerCallback(std::bind(&OpenSLLayer::engineServicePlay, this));
+                player_->start();
+            } catch (const std::exception& e) {
+                JAMI_ERR("Error initializing audio playback: %s", e.what());
+            }
+            if (recorder_)
+                startAudioCapture();
+        }
+    } else if (stream == AudioDeviceType::RINGTONE) {
+        if (not ringtone_) {
+            try {
+                ringtone_.reset(new opensl::AudioPlayer(hardwareFormat_,
+                                                        hardwareBuffSize_,
+                                                        engineInterface_,
+                                                        SL_ANDROID_STREAM_VOICE));
+                ringtone_->setBufQueue(&ringBufQueue_, &freeRingBufQueue_);
+                ringtone_->registerCallback(std::bind(&OpenSLLayer::engineServiceRing, this));
+                ringtone_->start();
+            } catch (const std::exception& e) {
+                JAMI_ERR("Error initializing ringtone playback: %s", e.what());
+            }
+        }
+    } else if (stream == AudioDeviceType::CAPTURE) {
+        if (not recorder_) {
+            std::lock_guard<std::mutex> lck(recMtx);
+            try {
+                recorder_.reset(new opensl::AudioRecorder(hardwareFormat_, engineInterface_));
+                recorder_->setBufQueues(&freeRecBufQueue_, &recBufQueue_);
+                recorder_->registerCallback(std::bind(&OpenSLLayer::engineServiceRec, this));
+                setHasNativeAEC(recorder_->hasNativeAEC());
+            } catch (const std::exception& e) {
+                JAMI_ERR("Error initializing audio capture: %s", e.what());
+            }
+            if (player_)
+                startAudioCapture();
+        }
+    }
     JAMI_WARN("OpenSL audio layer started");
     status_ = Status::Started;
-    startedCv_.notify_all();
 }
 
 void
-OpenSLLayer::stopStream()
+OpenSLLayer::stopStream(AudioDeviceType stream)
 {
     std::unique_lock<std::mutex> lock(mutex_);
-    startedCv_.wait(lock, [this] { return status_ != Status::Starting; });
-    if (status_ != Status::Started)
-        return;
-    status_ = Status::Idle;
-    JAMI_WARN("Stopping OpenSL audio layer");
-
-    stopAudioPlayback();
-    stopAudioCapture();
-    flush();
+    JAMI_WARN("Stopping OpenSL audio layer for type %u", (unsigned) stream);
 
-    if (engineObject_ != nullptr) {
-        (*engineObject_)->Destroy(engineObject_);
-        engineObject_ = nullptr;
-        engineInterface_ = nullptr;
+    if (stream == AudioDeviceType::PLAYBACK) {
+        if (player_) {
+            player_->stop();
+            player_.reset();
+        }
+    } else if (stream == AudioDeviceType::RINGTONE) {
+        if (ringtone_) {
+            ringtone_->stop();
+            ringtone_.reset();
+        }
+    } else if (stream == AudioDeviceType::CAPTURE) {
+        stopAudioCapture();
     }
 
-    freePlayBufQueue_.clear();
-    freeRingBufQueue_.clear();
-    playBufQueue_.clear();
-    ringBufQueue_.clear();
-    freeRecBufQueue_.clear();
-    recBufQueue_.clear();
-    bufs_.clear();
-    dcblocker_.reset();
-    startedCv_.notify_all();
+    if (not player_ and not ringtone_ and not recorder_)
+        status_ = Status::Idle;
+
+    flush();
 }
 
 std::vector<sample_buf>
@@ -149,9 +174,33 @@ OpenSLLayer::initAudioEngine()
 void
 OpenSLLayer::shutdownAudioEngine()
 {
+    stopAudioCapture();
+    freeRecBufQueue_.clear();
+    recBufQueue_.clear();
+
+    if (player_) {
+        player_->stop();
+        player_.reset();
+    }
+    if (ringtone_) {
+        ringtone_->stop();
+        ringtone_.reset();
+    }
+    freePlayBufQueue_.clear();
+    playBufQueue_.clear();
+    freeRingBufQueue_.clear();
+    ringBufQueue_.clear();
+
     // destroy engine object, and invalidate all associated interfaces
     JAMI_DBG("Shutdown audio engine");
-    stopStream();
+    if (engineObject_ != nullptr) {
+        (*engineObject_)->Destroy(engineObject_);
+        engineObject_ = nullptr;
+        engineInterface_ = nullptr;
+    }
+
+    startedCv_.notify_all();
+    bufs_.clear();
 }
 
 uint32_t
@@ -235,34 +284,6 @@ OpenSLLayer::engineServiceRec()
     return;
 }
 
-void
-OpenSLLayer::initAudioPlayback()
-{
-    using namespace std::placeholders;
-    try {
-        player_.reset(new opensl::AudioPlayer(hardwareFormat_,
-                                              hardwareBuffSize_,
-                                              engineInterface_,
-                                              SL_ANDROID_STREAM_VOICE));
-        player_->setBufQueue(&playBufQueue_, &freePlayBufQueue_);
-        player_->registerCallback(std::bind(&OpenSLLayer::engineServicePlay, this));
-    } catch (const std::exception& e) {
-        JAMI_ERR("Error initializing audio playback: %s", e.what());
-        return;
-    }
-
-    try {
-        ringtone_.reset(new opensl::AudioPlayer(hardwareFormat_,
-                                                hardwareBuffSize_,
-                                                engineInterface_,
-                                                SL_ANDROID_STREAM_VOICE));
-        ringtone_->setBufQueue(&ringBufQueue_, &freeRingBufQueue_);
-        ringtone_->registerCallback(std::bind(&OpenSLLayer::engineServiceRing, this));
-    } catch (const std::exception& e) {
-        JAMI_ERR("Error initializing ringtone playback: %s", e.what());
-    }
-}
-
 void
 OpenSLLayer::initAudioCapture()
 {
@@ -278,20 +299,6 @@ OpenSLLayer::initAudioCapture()
     }
 }
 
-void
-OpenSLLayer::startAudioPlayback()
-{
-    if (not player_ and not ringtone_)
-        return;
-    JAMI_WARN("Start audio playback");
-    playbackChanged(true);
-    if (player_)
-        player_->start();
-    if (ringtone_)
-        ringtone_->start();
-    JAMI_WARN("Audio playback started");
-}
-
 void
 OpenSLLayer::startAudioCapture()
 {
@@ -299,10 +306,13 @@ OpenSLLayer::startAudioCapture()
         return;
     JAMI_DBG("Start audio capture");
 
-    recorder_->start();
+    if (recThread.joinable())
+        return;
     recThread = std::thread([&]() {
-        recordChanged(true);
         std::unique_lock<std::mutex> lck(recMtx);
+        if (recorder_)
+            recorder_->start();
+        recordChanged(true);
         while (recorder_) {
             recCv.wait_for(lck, std::chrono::seconds(1));
             if (not recorder_)
@@ -331,23 +341,6 @@ OpenSLLayer::startAudioCapture()
     JAMI_DBG("Audio capture started");
 }
 
-void
-OpenSLLayer::stopAudioPlayback()
-{
-    JAMI_DBG("Stop audio playback");
-    playbackChanged(false);
-    if (player_) {
-        player_->stop();
-        player_.reset();
-    }
-    if (ringtone_) {
-        ringtone_->stop();
-        ringtone_.reset();
-    }
-
-    JAMI_DBG("Audio playback stopped");
-}
-
 void
 OpenSLLayer::stopAudioCapture()
 {
@@ -360,8 +353,8 @@ OpenSLLayer::stopAudioCapture()
             recorder_.reset();
         }
     }
-    recCv.notify_all();
     if (recThread.joinable()) {
+        recCv.notify_all();
         recThread.join();
     }
 
@@ -442,7 +435,9 @@ OpenSLLayer::getPlaybackDeviceList() const
 }
 
 void
-OpenSLLayer::updatePreference(AudioPreference& /*preference*/, int /*index*/, DeviceType /*type*/)
+OpenSLLayer::updatePreference(AudioPreference& /*preference*/,
+                              int /*index*/,
+                              AudioDeviceType /*type*/)
 {}
 
 void
diff --git a/src/media/audio/opensl/opensllayer.h b/src/media/audio/opensl/opensllayer.h
index 6c1a2d5bb58a924358ee78287207210a30376ca6..71a3579cca4728608af58fdf4913d4e3a19ca245 100644
--- a/src/media/audio/opensl/opensllayer.h
+++ b/src/media/audio/opensl/opensllayer.h
@@ -68,47 +68,38 @@ public:
      * Start the capture stream and prepare the playback stream.
      * The playback starts accordingly to its threshold
      */
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
+    void startStream(AudioDeviceType stream = AudioDeviceType::ALL) override;
 
     /**
      * Stop the playback and capture streams.
      * Drops the pending frames and put the capture and playback handles to PREPARED state
      */
-    virtual void stopStream();
+    void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) override;
 
     /**
      * Scan the sound card available for capture on the system
      * @return std::vector<std::string> The vector containing the string description of the card
      */
-    virtual std::vector<std::string> getCaptureDeviceList() const;
+    std::vector<std::string> getCaptureDeviceList() const override;
 
     /**
      * Scan the sound card available for capture on the system
      * @return std::vector<std::string> The vector containing the string description of the card
      */
-    virtual std::vector<std::string> getPlaybackDeviceList() const;
+    std::vector<std::string> getPlaybackDeviceList() const override;
 
     void init();
 
     void initAudioEngine();
-
     void shutdownAudioEngine();
 
-    void initAudioPlayback();
-
     void initAudioCapture();
-
-    void startAudioPlayback();
-
     void startAudioCapture();
-
-    void stopAudioPlayback();
-
     void stopAudioCapture();
 
-    virtual int getAudioDeviceIndex(const std::string&, DeviceType) const { return 0; }
+    virtual int getAudioDeviceIndex(const std::string&, AudioDeviceType) const { return 0; }
 
-    virtual std::string getAudioDeviceName(int, DeviceType) const { return ""; }
+    virtual std::string getAudioDeviceName(int, AudioDeviceType) const { return ""; }
 
     void engineServicePlay();
     void engineServiceRing();
@@ -142,7 +133,10 @@ private:
 
     NON_COPYABLE(OpenSLLayer);
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
+
+    std::mutex recMtx {};
+    std::condition_variable recCv {};
 
     /**
      * OpenSL standard object interface
@@ -154,9 +148,8 @@ private:
      */
     SLEngineItf engineInterface_ {nullptr};
 
-    std::unique_ptr<opensl::AudioPlayer> player_ {};
-    std::unique_ptr<opensl::AudioPlayer> ringtone_ {};
-    std::unique_ptr<opensl::AudioRecorder> recorder_ {};
+    AudioFormat hardwareFormat_ {AudioFormat::MONO()};
+    size_t hardwareBuffSize_ {BUFFER_SIZE};
 
     AudioQueue freePlayBufQueue_ {BUF_COUNT};
     AudioQueue playBufQueue_ {BUF_COUNT};
@@ -167,14 +160,13 @@ private:
     AudioQueue freeRecBufQueue_ {BUF_COUNT}; // Owner of the queue
     AudioQueue recBufQueue_ {BUF_COUNT};     // Owner of the queue
 
-    std::mutex recMtx {};
-    std::condition_variable recCv {};
-    std::thread recThread {};
-
     std::vector<sample_buf> bufs_ {};
 
-    AudioFormat hardwareFormat_ {AudioFormat::MONO()};
-    size_t hardwareBuffSize_ {BUFFER_SIZE};
+    std::unique_ptr<opensl::AudioPlayer> player_ {};
+    std::unique_ptr<opensl::AudioPlayer> ringtone_ {};
+    std::unique_ptr<opensl::AudioRecorder> recorder_ {};
+
+    std::thread recThread {};
 };
 
 } // namespace jami
diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp
index e2b44c78920e935c6efbce4651e3b0d16a7ac278..8b61f2455330b9bac575197043dfa6f8f16fd54e 100644
--- a/src/media/audio/portaudio/portaudiolayer.cpp
+++ b/src/media/audio/portaudio/portaudiolayer.cpp
@@ -45,9 +45,9 @@ struct PortAudioLayer::PortAudioLayerImpl
     void terminate() const;
     void initStream(PortAudioLayer&);
 
-    std::vector<std::string> getDeviceByType(DeviceType type) const;
-    int getIndexByType(DeviceType type);
-    int getInternalIndexByType(const int index, DeviceType type);
+    std::vector<std::string> getDeviceByType(AudioDeviceType type) const;
+    int getIndexByType(AudioDeviceType type);
+    int getInternalIndexByType(const int index, AudioDeviceType type);
 
     PaDeviceIndex indexIn_;
     PaDeviceIndex indexOut_;
@@ -94,17 +94,17 @@ PortAudioLayer::~PortAudioLayer()
 std::vector<std::string>
 PortAudioLayer::getCaptureDeviceList() const
 {
-    return pimpl_->getDeviceByType(DeviceType::CAPTURE);
+    return pimpl_->getDeviceByType(AudioDeviceType::CAPTURE);
 }
 
 std::vector<std::string>
 PortAudioLayer::getPlaybackDeviceList() const
 {
-    return pimpl_->getDeviceByType(DeviceType::PLAYBACK);
+    return pimpl_->getDeviceByType(AudioDeviceType::PLAYBACK);
 }
 
 int
-PortAudioLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
+PortAudioLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const
 {
     auto deviceList = pimpl_->getDeviceByType(type);
 
@@ -124,7 +124,7 @@ PortAudioLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) co
 }
 
 std::string
-PortAudioLayer::getAudioDeviceName(int index, DeviceType type) const
+PortAudioLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
     (void) type;
     const PaDeviceInfo* deviceInfo;
@@ -135,24 +135,24 @@ PortAudioLayer::getAudioDeviceName(int index, DeviceType type) const
 int
 PortAudioLayer::getIndexCapture() const
 {
-    return pimpl_->getIndexByType(DeviceType::CAPTURE);
+    return pimpl_->getIndexByType(AudioDeviceType::CAPTURE);
 }
 
 int
 PortAudioLayer::getIndexPlayback() const
 {
-    auto index = pimpl_->getIndexByType(DeviceType::PLAYBACK);
+    auto index = pimpl_->getIndexByType(AudioDeviceType::PLAYBACK);
     return index;
 }
 
 int
 PortAudioLayer::getIndexRingtone() const
 {
-    return pimpl_->getIndexByType(DeviceType::RINGTONE);
+    return pimpl_->getIndexByType(AudioDeviceType::RINGTONE);
 }
 
 void
-PortAudioLayer::startStream(AudioStreamType stream)
+PortAudioLayer::startStream(AudioDeviceType stream)
 {
     {
         std::lock_guard<std::mutex> lock(mutex_);
@@ -167,7 +167,7 @@ PortAudioLayer::startStream(AudioStreamType stream)
 }
 
 void
-PortAudioLayer::stopStream()
+PortAudioLayer::stopStream(AudioDeviceType stream)
 {
     if (status_ != Status::Started)
         return;
@@ -198,17 +198,17 @@ PortAudioLayer::stopStream()
 }
 
 void
-PortAudioLayer::updatePreference(AudioPreference& preference, int index, DeviceType type)
+PortAudioLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type)
 {
     auto internalIndex = pimpl_->getInternalIndexByType(index, type);
     switch (type) {
-    case DeviceType::PLAYBACK:
+    case AudioDeviceType::PLAYBACK:
         preference.setAlsaCardout(internalIndex);
         break;
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         preference.setAlsaCardin(internalIndex);
         break;
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::RINGTONE:
         preference.setAlsaCardring(internalIndex);
         break;
     default:
@@ -234,7 +234,7 @@ PortAudioLayer::PortAudioLayerImpl::~PortAudioLayerImpl()
 }
 
 std::vector<std::string>
-PortAudioLayer::PortAudioLayerImpl::getDeviceByType(DeviceType type) const
+PortAudioLayer::PortAudioLayerImpl::getDeviceByType(AudioDeviceType type) const
 {
     std::vector<std::string> ret;
     int numDevices = 0;
@@ -245,7 +245,7 @@ PortAudioLayer::PortAudioLayerImpl::getDeviceByType(DeviceType type) const
     else {
         for (int i = 0; i < numDevices; i++) {
             const auto deviceInfo = Pa_GetDeviceInfo(i);
-            if (type == DeviceType::PLAYBACK) {
+            if (type == AudioDeviceType::PLAYBACK) {
                 if (deviceInfo->maxOutputChannels > 0)
                     ret.push_back(deviceInfo->name);
             } else {
@@ -304,12 +304,12 @@ PortAudioLayer::PortAudioLayerImpl::init(PortAudioLayer& parent)
 }
 
 int
-PortAudioLayer::PortAudioLayerImpl::getIndexByType(DeviceType type)
+PortAudioLayer::PortAudioLayerImpl::getIndexByType(AudioDeviceType type)
 {
     int index = indexRing_;
-    if (type == DeviceType::PLAYBACK) {
+    if (type == AudioDeviceType::PLAYBACK) {
         index = indexOut_;
-    } else if (type == DeviceType::CAPTURE) {
+    } else if (type == AudioDeviceType::CAPTURE) {
         index = indexIn_;
     }
 
@@ -334,7 +334,7 @@ PortAudioLayer::PortAudioLayerImpl::getIndexByType(DeviceType type)
 }
 
 int
-PortAudioLayer::PortAudioLayerImpl::getInternalIndexByType(const int index, DeviceType type)
+PortAudioLayer::PortAudioLayerImpl::getInternalIndexByType(const int index, AudioDeviceType type)
 {
     auto deviceList = getDeviceByType(type);
     if (!deviceList.size() || index >= deviceList.size()) {
diff --git a/src/media/audio/portaudio/portaudiolayer.h b/src/media/audio/portaudio/portaudiolayer.h
index 78eb0cf7b8d63238f475ed25c62d620cbed419a1..6a24a9dfff082b5e816057cfde53ea83cca0638c 100644
--- a/src/media/audio/portaudio/portaudiolayer.h
+++ b/src/media/audio/portaudio/portaudiolayer.h
@@ -29,7 +29,7 @@
 
 namespace jami {
 
-class PortAudioLayer : public AudioLayer
+class PortAudioLayer final : public AudioLayer
 {
 public:
     PortAudioLayer(const AudioPreference& pref);
@@ -37,8 +37,8 @@ public:
 
     std::vector<std::string> getCaptureDeviceList() const override;
     std::vector<std::string> getPlaybackDeviceList() const override;
-    int getAudioDeviceIndex(const std::string& name, DeviceType type) const override;
-    std::string getAudioDeviceName(int index, DeviceType type) const override;
+    int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const override;
+    std::string getAudioDeviceName(int index, AudioDeviceType type) const override;
     int getIndexCapture() const override;
     int getIndexPlayback() const override;
     int getIndexRingtone() const override;
@@ -47,15 +47,15 @@ public:
      * Start the capture stream and prepare the playback stream.
      * The playback starts accordingly to its threshold
      */
-    void startStream(AudioStreamType stream = AudioStreamType::DEFAULT) override;
+    void startStream(AudioDeviceType stream = AudioDeviceType::ALL) override;
 
     /**
      * Stop the playback and capture streams.
      * Drops the pending frames and put the capture and playback handles to PREPARED state
      */
-    void stopStream() override;
+    void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) override;
 
-    void updatePreference(AudioPreference& pref, int index, DeviceType type) override;
+    void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) override;
 
 private:
     NON_COPYABLE(PortAudioLayer);
diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp
index 35a8cc5cdd67d65891bcc8ef0f4f5abb9765b277..b54fa3113077e27eab9a324f0161ec8bd519a667 100644
--- a/src/media/audio/pulseaudio/pulselayer.cpp
+++ b/src/media/audio/pulseaudio/pulselayer.cpp
@@ -254,16 +254,16 @@ PulseLayer::getPlaybackDeviceList() const
 }
 
 int
-PulseLayer::getAudioDeviceIndex(const std::string& descr, DeviceType type) const
+PulseLayer::getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const
 {
     switch (type) {
-    case DeviceType::PLAYBACK:
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::PLAYBACK:
+    case AudioDeviceType::RINGTONE:
         return std::distance(sinkList_.begin(),
                              std::find_if(sinkList_.begin(),
                                           sinkList_.end(),
                                           PaDeviceInfos::DescriptionComparator(descr)));
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         return std::distance(sourceList_.begin(),
                              std::find_if(sourceList_.begin(),
                                           sourceList_.end(),
@@ -275,18 +275,18 @@ PulseLayer::getAudioDeviceIndex(const std::string& descr, DeviceType type) const
 }
 
 int
-PulseLayer::getAudioDeviceIndexByName(const std::string& name, DeviceType type) const
+PulseLayer::getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const
 {
     if (name.empty())
         return 0;
     switch (type) {
-    case DeviceType::PLAYBACK:
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::PLAYBACK:
+    case AudioDeviceType::RINGTONE:
         return std::distance(sinkList_.begin(),
                              std::find_if(sinkList_.begin(),
                                           sinkList_.end(),
                                           PaDeviceInfos::NameComparator(name)));
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         return std::distance(sourceList_.begin(),
                              std::find_if(sourceList_.begin(),
                                           sourceList_.end(),
@@ -333,18 +333,18 @@ PulseLayer::getDeviceInfos(const std::vector<PaDeviceInfos>& list, const std::st
 }
 
 std::string
-PulseLayer::getAudioDeviceName(int index, DeviceType type) const
+PulseLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
     switch (type) {
-    case DeviceType::PLAYBACK:
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::PLAYBACK:
+    case AudioDeviceType::RINGTONE:
         if (index < 0 or static_cast<size_t>(index) >= sinkList_.size()) {
             JAMI_ERR("Index %d out of range", index);
             return "";
         }
         return sinkList_[index].name;
 
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         if (index < 0 or static_cast<size_t>(index) >= sourceList_.size()) {
             JAMI_ERR("Index %d out of range", index);
             return "";
@@ -449,7 +449,7 @@ PulseLayer::disconnectAudioStream()
     record_.reset();
 }
 
-void PulseLayer::startStream(AudioStreamType)
+void PulseLayer::startStream(AudioDeviceType)
 {
     std::unique_lock<std::mutex> lk(readyMtx_);
     readyCv_.wait(lk, [this] {
@@ -473,7 +473,7 @@ void PulseLayer::startStream(AudioStreamType)
 }
 
 void
-PulseLayer::stopStream()
+PulseLayer::stopStream(AudioDeviceType stream)
 {
     std::unique_lock<std::mutex> lk(readyMtx_);
     readyCv_.wait(lk, [this] {
@@ -810,44 +810,49 @@ PulseLayer::sink_input_info_callback(pa_context* c UNUSED,
 }
 
 void
-PulseLayer::updatePreference(AudioPreference& preference, int index, DeviceType type)
+PulseLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type)
 {
     const std::string devName(getAudioDeviceName(index, type));
 
     switch (type) {
-    case DeviceType::PLAYBACK:
+    case AudioDeviceType::PLAYBACK:
         JAMI_DBG("setting %s for playback", devName.c_str());
         preference.setPulseDevicePlayback(devName);
         break;
 
-    case DeviceType::CAPTURE:
+    case AudioDeviceType::CAPTURE:
         JAMI_DBG("setting %s for capture", devName.c_str());
         preference.setPulseDeviceRecord(devName);
         break;
 
-    case DeviceType::RINGTONE:
+    case AudioDeviceType::RINGTONE:
         JAMI_DBG("setting %s for ringer", devName.c_str());
         preference.setPulseDeviceRingtone(devName);
         break;
+
+    default:
+        break;
     }
 }
 
 int
 PulseLayer::getIndexCapture() const
 {
-    return getAudioDeviceIndexByName(preference_.getPulseDeviceRecord(), DeviceType::CAPTURE);
+    return getAudioDeviceIndexByName(preference_.getPulseDeviceRecord(), AudioDeviceType::CAPTURE);
 }
 
 int
 PulseLayer::getIndexPlayback() const
 {
-    return getAudioDeviceIndexByName(preference_.getPulseDevicePlayback(), DeviceType::PLAYBACK);
+    return getAudioDeviceIndexByName(preference_.getPulseDevicePlayback(),
+                                     AudioDeviceType::PLAYBACK);
 }
 
 int
 PulseLayer::getIndexRingtone() const
 {
-    return getAudioDeviceIndexByName(preference_.getPulseDeviceRingtone(), DeviceType::RINGTONE);
+    return getAudioDeviceIndexByName(preference_.getPulseDeviceRingtone(),
+                                     AudioDeviceType::RINGTONE);
 }
 
 std::string
diff --git a/src/media/audio/pulseaudio/pulselayer.h b/src/media/audio/pulseaudio/pulselayer.h
index 3b04065c9549dd40b4880abe45d8277e968f31bf..903b8a2fa10037bdeea5dcb78d93442cda8b9c6a 100644
--- a/src/media/audio/pulseaudio/pulselayer.h
+++ b/src/media/audio/pulseaudio/pulselayer.h
@@ -134,13 +134,13 @@ public:
 
     virtual std::vector<std::string> getCaptureDeviceList() const;
     virtual std::vector<std::string> getPlaybackDeviceList() const;
-    int getAudioDeviceIndex(const std::string& descr, DeviceType type) const;
-    int getAudioDeviceIndexByName(const std::string& name, DeviceType type) const;
+    int getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const;
+    int getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const;
 
-    std::string getAudioDeviceName(int index, DeviceType type) const;
+    std::string getAudioDeviceName(int index, AudioDeviceType type) const;
 
-    virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT);
-    virtual void stopStream();
+    virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
+    virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
 
 private:
     static void context_state_callback(pa_context* c, void* user_data);
@@ -161,7 +161,7 @@ private:
                                          void* userdata);
     static void server_info_callback(pa_context*, const pa_server_info* i, void* userdata);
 
-    virtual void updatePreference(AudioPreference& pref, int index, DeviceType type);
+    virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
 
     virtual int getIndexCapture() const;
     virtual int getIndexPlayback() const;
diff --git a/src/media/audio/ringbuffer.h b/src/media/audio/ringbuffer.h
index 11cdc3fe0018a2c9f45dae4ac0574f0f7447c34b..0f1af3ed7a999550ec194dc2b135a4aa2c6e5794 100644
--- a/src/media/audio/ringbuffer.h
+++ b/src/media/audio/ringbuffer.h
@@ -136,12 +136,10 @@ public:
      * Blocks until min_data_length samples of data is available, or until deadline has passed.
      *
      * @param call_id The read offset for which data should be available.
-     * @param min_data_length Minimum number of samples that should be available for the call to
-     * return
-     * @param deadline The call is guaranteed to end after this time point. If no deadline is
-     * provided, the call blocks indefinitely.
-     * @return available data for call_id after the call returned (same as calling
-     * getLength(call_id) ).
+     * @param min_data_length Minimum number of samples that should be available for the call to return
+     * @param deadline The call is guaranteed to end after this time point. If no deadline is provided,
+     * the call blocks indefinitely.
+     * @return available data for call_id after the call returned (same as calling getLength(call_id) ).
      */
     size_t waitForDataAvailable(const std::string& call_id,
                                 const time_point& deadline = time_point::max()) const;
diff --git a/src/media/localrecorder.cpp b/src/media/localrecorder.cpp
index f5fa003f4585bc812dd7180fc6307c8c14371659..33d0186e9b2d26e9e1943e71dbaf9ba2e814f2b3 100644
--- a/src/media/localrecorder.cpp
+++ b/src/media/localrecorder.cpp
@@ -75,11 +75,11 @@ LocalRecorder::startRecording()
     // audio recording
     // create read offset in RingBuffer
     Manager::instance().getRingBufferPool().bindHalfDuplexOut(path_, RingBufferPool::DEFAULT_ID);
-    Manager::instance().startAudioDriverStream();
 
     audioInput_ = jami::getAudioInput(path_);
     audioInput_->setFormat(AudioFormat::STEREO());
     audioInput_->attach(recorder_->addStream(audioInput_->getInfo()));
+    audioInput_->switchInput("");
 
 #ifdef ENABLE_VIDEO
     // video recording
diff --git a/src/media/media_player.cpp b/src/media/media_player.cpp
index dbf51ac369ed1350e2f22744dca2a8b44526ed86..bc5f76ad4fdc02705258267d70212df7fe6fa5c2 100644
--- a/src/media/media_player.cpp
+++ b/src/media/media_player.cpp
@@ -44,7 +44,6 @@ MediaPlayer::MediaPlayer(const std::string& path)
 
     path_ = path;
     id_ = std::to_string(rand());
-    Manager::instance().startAudioPlayback();
     audioInput_ = jami::getAudioInput(id_);
     audioInput_->setPaused(paused_);
     videoInput_ = jami::getVideoInput(id_, video::VideoInputMode::ManagedByDaemon);
@@ -82,6 +81,7 @@ MediaPlayer::configureMediaInputs()
         if (hasAudio()) {
             audioInput_->configureFilePlayback(path_, demuxer_, audioStream_);
             audioInput_->updateStartTime(startTime_);
+            audioInput_->start();
         }
     } catch (const std::exception& e) {
         JAMI_ERR("media player: %s open audio input failed: %s", path_.c_str(), e.what());
diff --git a/src/preferences.cpp b/src/preferences.cpp
index 319b1b249eacc820d6e1596d30d9eaa24e4390db..1d5f42ed23f0ad473a97c73bc1d6894e21897a37 100644
--- a/src/preferences.cpp
+++ b/src/preferences.cpp
@@ -372,7 +372,7 @@ AudioPreference::AudioPreference()
 static const int ALSA_DFT_CARD_ID = 0; // Index of the default soundcard
 
 static void
-checkSoundCard(int& card, DeviceType type)
+checkSoundCard(int& card, AudioDeviceType type)
 {
     if (not AlsaLayer::soundCardIndexExists(card, type)) {
         JAMI_WARN(" Card with index %d doesn't exist or is unusable.", card);
@@ -426,9 +426,9 @@ AudioPreference::createAudioLayer()
 #if HAVE_ALSA
 
     audioApi_ = ALSA_API_STR;
-    checkSoundCard(alsaCardin_, DeviceType::CAPTURE);
-    checkSoundCard(alsaCardout_, DeviceType::PLAYBACK);
-    checkSoundCard(alsaCardring_, DeviceType::RINGTONE);
+    checkSoundCard(alsaCardin_, AudioDeviceType::CAPTURE);
+    checkSoundCard(alsaCardout_, AudioDeviceType::PLAYBACK);
+    checkSoundCard(alsaCardring_, AudioDeviceType::RINGTONE);
 
     return new AlsaLayer(*this);
 #endif
diff --git a/src/security/tlsvalidator.cpp b/src/security/tlsvalidator.cpp
index 15a05fc683b366e3d87a2b4dbc94046b96de6965..9a8394cc2d5786b5648944625ca2e8a76ac5628a 100644
--- a/src/security/tlsvalidator.cpp
+++ b/src/security/tlsvalidator.cpp
@@ -863,23 +863,15 @@ TlsValidator::privateKeyStoragePermissions()
     if (err)
         return TlsValidator::CheckResult(CheckValues::UNSUPPORTED, "");
 
-    return TlsValidator::CheckResult((statbuf.st_mode & S_IFREG)
-                                             && /* Regular file only */
-                                             /*                          READ    WRITE    EXECUTE */
-                                             /* Owner */ ((statbuf.st_mode
-                                                           & S_IRUSR) /* write is not relevant */
-                                                          && !(statbuf.st_mode & S_IXUSR))
-                                             /* Group */
-                                             && (!(statbuf.st_mode & S_IRGRP)
-                                                 && !(statbuf.st_mode & S_IWGRP)
-                                                 && !(statbuf.st_mode & S_IXGRP))
-                                             /* Other */
-                                             && (!(statbuf.st_mode & S_IROTH)
-                                                 && !(statbuf.st_mode & S_IWOTH)
-                                                 && !(statbuf.st_mode & S_IXOTH))
-                                         ? CheckValues::PASSED
-                                         : CheckValues::FAILED,
-                                     "");
+// clang-format off
+    return TlsValidator::CheckResult(
+        (statbuf.st_mode & S_IFREG) && /* Regular file only */
+        /*                          READ                      WRITE                            EXECUTE          */
+        /* Owner */    ( (statbuf.st_mode & S_IRUSR) /* write is not relevant */     && !(statbuf.st_mode & S_IXUSR))
+        /* Group */ && (!(statbuf.st_mode & S_IRGRP) && !(statbuf.st_mode & S_IWGRP) && !(statbuf.st_mode & S_IXGRP))
+        /* Other */ && (!(statbuf.st_mode & S_IROTH) && !(statbuf.st_mode & S_IWOTH) && !(statbuf.st_mode & S_IXOTH))
+        ? CheckValues::PASSED:CheckValues::FAILED, "");
+// clang-format on
 }
 
 TlsValidator::CheckResult
@@ -890,21 +882,15 @@ TlsValidator::publicKeyStoragePermissions()
     if (err)
         return TlsValidator::CheckResult(CheckValues::UNSUPPORTED, "");
 
+// clang-format off
     return TlsValidator::CheckResult(
-        (statbuf.st_mode & S_IFREG)
-                && /* Regular file only */
-                   /*                          READ    WRITE    EXECUTE    */
-                /* Owner */ ((statbuf.st_mode & S_IRUSR) /* write is not relevant */
-                             && !(statbuf.st_mode & S_IXUSR))
-                /* Group */
-                && (/* read is not relevant */ !(statbuf.st_mode & S_IWGRP)
-                    && !(statbuf.st_mode & S_IXGRP))
-                /* Other */
-                && (/* read is not relevant */ !(statbuf.st_mode & S_IWOTH)
-                    && !(statbuf.st_mode & S_IXOTH))
-            ? CheckValues::PASSED
-            : CheckValues::FAILED,
-        "");
+        (statbuf.st_mode & S_IFREG) && /* Regular file only */
+        /*                          READ                      WRITE                            EXECUTE          */
+        /* Owner */    ( (statbuf.st_mode & S_IRUSR) /* write is not relevant */   && !(statbuf.st_mode & S_IXUSR))
+        /* Group */ && ( /* read is not relevant */   !(statbuf.st_mode & S_IWGRP) && !(statbuf.st_mode & S_IXGRP))
+        /* Other */ && ( /* read is not relevant */   !(statbuf.st_mode & S_IWOTH) && !(statbuf.st_mode & S_IXOTH))
+        ? CheckValues::PASSED:CheckValues::FAILED, "");
+// clang-format on
 }
 
 TlsValidator::CheckResult
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index 49526896be37b9de5d75514b352f8cc07569d748..9b3e0e4c77ffd07fe478fb6585dbcc841939c974 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -879,15 +879,12 @@ SIPCall::sendTextMessage(const std::map<std::string, std::string>& messages, con
 void
 SIPCall::removeCall()
 {
-    {
-        std::lock_guard<std::recursive_mutex> lk {callMutex_};
-        JAMI_WARN("[call:%s] removeCall()", getCallId().c_str());
-        Call::removeCall();
-        mediaTransport_.reset();
-        inv.reset();
-        setTransport({});
-    }
-    Manager::instance().checkAudio();
+    std::lock_guard<std::recursive_mutex> lk {callMutex_};
+    JAMI_WARN("[call:%s] removeCall()", getCallId().c_str());
+    Call::removeCall();
+    mediaTransport_.reset();
+    inv.reset();
+    setTransport({});
 }
 
 void
@@ -929,7 +926,6 @@ SIPCall::onClosed()
             auto& call = *shared;
             Manager::instance().peerHungupCall(call);
             call.removeCall();
-            Manager::instance().checkAudio();
         }
     });
 }
diff --git a/src/upnp/protocol/mapping.cpp b/src/upnp/protocol/mapping.cpp
index 9c71a20c2230ea548af3b1aa79200de39d125c8a..a172a4eb234fb468b933ae9522a0f60c373aeed6 100644
--- a/src/upnp/protocol/mapping.cpp
+++ b/src/upnp/protocol/mapping.cpp
@@ -161,4 +161,4 @@ Mapping::isValid() const
 };
 
 } // namespace upnp
-} // namespace jami
\ No newline at end of file
+} // namespace jami
diff --git a/src/upnp/protocol/natpmp/nat_pmp.cpp b/src/upnp/protocol/natpmp/nat_pmp.cpp
index 6edb102023030fdb48df6c5a7e5acae24511ccff..60a7df18e639cb0704d39b150a6128d0335a0107 100644
--- a/src/upnp/protocol/natpmp/nat_pmp.cpp
+++ b/src/upnp/protocol/natpmp/nat_pmp.cpp
@@ -494,4 +494,4 @@ NatPmp::getNatPmpErrorStr(int errorCode)
 }
 
 } // namespace upnp
-} // namespace jami
\ No newline at end of file
+} // namespace jami
diff --git a/src/upnp/protocol/natpmp/pmp_igd.cpp b/src/upnp/protocol/natpmp/pmp_igd.cpp
index 2ad3ea9453dd5f2eb1895755c91e125e1c15cec1..5c1988715a25de669f57fc31dcb4d8d6f08aee1d 100644
--- a/src/upnp/protocol/natpmp/pmp_igd.cpp
+++ b/src/upnp/protocol/natpmp/pmp_igd.cpp
@@ -128,4 +128,4 @@ PMPIGD::getRenewalTime()
     return nextTime;
 }
 } // namespace upnp
-} // namespace jami
\ No newline at end of file
+} // namespace jami
diff --git a/src/upnp/protocol/natpmp/pmp_igd.h b/src/upnp/protocol/natpmp/pmp_igd.h
index efc7dd9bef9bd6478f54882a8965144596c8fd53..bf09c2ad06cba9e196c02952a6fcc73d94767116 100644
--- a/src/upnp/protocol/natpmp/pmp_igd.h
+++ b/src/upnp/protocol/natpmp/pmp_igd.h
@@ -88,4 +88,4 @@ public:
     std::atomic_bool clearAll_ {true};
 };
 } // namespace upnp
-} // namespace jami
\ No newline at end of file
+} // namespace jami