diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp
index 3de960930d47beeb205735e316d9bbfd036f9486..b8f91d75ef0e3708268140ee2bc8e1c7f36ce7cc 100644
--- a/src/media/audio/alsa/alsalayer.cpp
+++ b/src/media/audio/alsa/alsalayer.cpp
@@ -132,7 +132,9 @@ void AlsaThread::run()
     alsa_->startedCv_.notify_all();
 
     while (alsa_->status_ == AudioLayer::Status::Started and running_) {
-        alsa_->audioCallback();
+        alsa_->playback();
+        alsa_->ringtone();
+        alsa_->capture();
     }
 }
 
@@ -188,7 +190,10 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre
     } while (err == -EBUSY and ++tries <= MAX_RETRIES);
 
     if (err < 0) {
-        RING_ERR("Alsa: couldn't open device %s : %s",  dev.c_str(),
+        RING_ERR("Alsa: couldn't open %s device %s : %s",
+              (stream == SND_PCM_STREAM_CAPTURE)? "capture" :
+              (stream == SND_PCM_STREAM_PLAYBACK)? "playback" : "ringtone",
+              dev.c_str(),
               snd_strerror(err));
         return false;
     }
@@ -681,6 +686,9 @@ AlsaLayer::getAudioDeviceName(int index, DeviceType type) const
 
 void AlsaLayer::capture()
 {
+    if (!captureHandle_ or !is_capture_running_)
+        return;
+
     AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
 
     int toGetFrames = snd_pcm_avail_update(captureHandle_);
@@ -718,120 +726,51 @@ void AlsaLayer::capture()
     }
 }
 
-void AlsaLayer::playback(int maxFrames)
+void AlsaLayer::playback()
 {
-    unsigned framesToGet = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID);
-
-    // no audio available, play tone or silence
-    if (framesToGet <= 0) {
-        // FIXME: not thread safe! we only lock the mutex when we get the
-        // pointer, we have no guarantee that it will stay safe to use
-        AudioLoop *tone = Manager::instance().getTelephoneTone();
-        AudioLoop *file_tone = Manager::instance().getTelephoneFile();
-
-        playbackBuff_.setFormat(audioFormat_);
-        playbackBuff_.resize(maxFrames);
 
-        if (tone)
-            tone->getNext(playbackBuff_, playbackGain_);
-        else if (file_tone && !ringtoneHandle_)
-            file_tone->getNext(playbackBuff_, playbackGain_);
-        else
-            playbackBuff_.reset();
-
-        playbackBuff_.interleave(playbackIBuff_);
-        write(playbackIBuff_.data(), playbackBuff_.frames(), playbackHandle_);
-    } else {
-        // play the regular sound samples
-        const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
-        const bool resample = audioFormat_.sample_rate != mainBufferFormat.sample_rate;
+    if (!playbackHandle_)
+        return;
 
-        double resampleFactor = 1.0;
-        unsigned maxNbFramesToGet = maxFrames;
+    snd_pcm_wait(playbackHandle_, 20);
 
-        if (resample) {
-            resampleFactor = static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate;
-            maxNbFramesToGet = maxFrames / resampleFactor;
-        }
+    int maxFrames = 0;
 
-        framesToGet = std::min(framesToGet, maxNbFramesToGet);
+    if (not safeUpdate(playbackHandle_, maxFrames))
+        return;
 
-        playbackBuff_.setFormat(mainBufferFormat);
-        playbackBuff_.resize(framesToGet);
+    auto& ringBuff = getToRing(audioFormat_, maxFrames);
+    auto& playBuff = getToPlay(audioFormat_, maxFrames);
+    auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff;
 
-        Manager::instance().getRingBufferPool().getData(playbackBuff_, RingBufferPool::DEFAULT_ID);
-        playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+    if (!toPlay.frames() > 0)
+        return;
 
-        if (audioFormat_.nb_channels != mainBufferFormat.nb_channels) {
-            playbackBuff_.setChannelNum(audioFormat_.nb_channels, true);
-        }
-        if (resample) {
-            const size_t outFrames = framesToGet * resampleFactor;
-            AudioBuffer rsmpl_out(outFrames, audioFormat_);
-            resampler_->resample(playbackBuff_, rsmpl_out);
-            rsmpl_out.interleave(playbackIBuff_);
-            write(playbackIBuff_.data(), outFrames, playbackHandle_);
-        } else {
-            playbackBuff_.interleave(playbackIBuff_);
-            write(playbackIBuff_.data(), framesToGet, playbackHandle_);
-        }
-    }
+    toPlay.interleave(playbackIBuff_);
+    write(playbackIBuff_.data(), toPlay.frames(), playbackHandle_);
 }
 
-void AlsaLayer::audioCallback()
+void AlsaLayer::ringtone()
 {
-    if (!playbackHandle_ or !captureHandle_)
+    if (!ringtoneHandle_)
         return;
 
-    notifyIncomingCall();
-
-    snd_pcm_wait(playbackHandle_, 20);
-
-    int playbackAvailFrames = 0;
+    AudioLoop *file_tone = Manager::instance().getTelephoneFile();
+    int ringtoneAvailFrames = 0;
 
-    if (not safeUpdate(playbackHandle_, playbackAvailFrames))
+    if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames))
         return;
 
-    unsigned framesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID);
-
-    if (framesToGet > 0) {
-        // Urgent data (dtmf, incoming call signal) come first.
-        framesToGet = std::min(framesToGet, (unsigned)playbackAvailFrames);
-        playbackBuff_.setFormat(audioFormat_);
-        playbackBuff_.resize(framesToGet);
-        urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID);
-        playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
-        playbackBuff_.interleave(playbackIBuff_);
-        write(playbackIBuff_.data(), framesToGet, playbackHandle_);
-        // Consume the regular one as well (same amount of frames)
-        Manager::instance().getRingBufferPool().discard(framesToGet, RingBufferPool::DEFAULT_ID);
-    } else {
-        // regular audio data
-        playback(playbackAvailFrames);
-    }
-
-    if (ringtoneHandle_) {
-        AudioLoop *file_tone = Manager::instance().getTelephoneFile();
-        int ringtoneAvailFrames = 0;
-
-        if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames))
-            return;
-
-        playbackBuff_.setFormat(audioFormat_);
-        playbackBuff_.resize(ringtoneAvailFrames);
-
-        if (file_tone) {
-            RING_DBG("playback gain %.3f", playbackGain_);
-            file_tone->getNext(playbackBuff_, playbackGain_);
-        }
+    playbackBuff_.setFormat(audioFormat_);
+    playbackBuff_.resize(ringtoneAvailFrames);
 
-        playbackBuff_.interleave(playbackIBuff_);
-        write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_);
+    if (file_tone) {
+        RING_DBG("playback gain %.3f", playbackGain_);
+        file_tone->getNext(playbackBuff_, playbackGain_);
     }
 
-    // Additionally handle the mic's audio stream
-    if (is_capture_running_)
-        capture();
+    playbackBuff_.interleave(playbackIBuff_);
+    write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_);
 }
 
 void AlsaLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h
index 57203c50c50c740b9f4a6e4cf4a70206540d6284..c408b612a8f3caa798e704a25353d50ef7d6b2f9 100644
--- a/src/media/audio/alsa/alsalayer.h
+++ b/src/media/audio/alsa/alsalayer.h
@@ -111,11 +111,10 @@ class AlsaLayer : public AudioLayer {
         int getAudioDeviceIndex(const std::string &description, DeviceType type) const;
         std::string getAudioDeviceName(int index, DeviceType type) const;
 
-        void playback(int maxSamples);
+        void playback();
+        void ringtone();
         void capture();
 
-        void audioCallback();
-
         /**
          * Get the index of the audio card for capture
          * @return int The index of the card used for capture