diff --git a/src/media/audio/pulseaudio/audiostream.cpp b/src/media/audio/pulseaudio/audiostream.cpp
index 4db4676b1519b2df513bbaa0067ed825e219f4ab..8b311ab5679acace9f19d02ceae7f60dfa724b6d 100644
--- a/src/media/audio/pulseaudio/audiostream.cpp
+++ b/src/media/audio/pulseaudio/audiostream.cpp
@@ -31,11 +31,12 @@ namespace ring {
 AudioStream::AudioStream(pa_context *c,
                          pa_threaded_mainloop *m,
                          const char *desc,
-                         int type,
+                         StreamType type,
                          unsigned samplrate,
                          const PaDeviceInfos* infos,
-                         bool ec)
-    : audiostream_(0), mainloop_(m)
+                         bool ec,
+                         OnReady onReady)
+    : audiostream_(0), mainloop_(m), onReady_(std::move(onReady))
 {
     const pa_channel_map channel_map = infos->channel_map;
 
@@ -66,17 +67,24 @@ AudioStream::AudioStream(pa_context *c,
     attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec);
     attributes.minreq = (uint32_t) -1;
 
+    pa_stream_set_state_callback(audiostream_, [](pa_stream* s, void* user_data){
+        static_cast<AudioStream*>(user_data)->stateChanged(s);
+    }, this);
+    pa_stream_set_moved_callback(audiostream_, [](pa_stream* s, void* user_data){
+        static_cast<AudioStream*>(user_data)->moved(s);
+    }, this);
+
     {
         PulseMainLoopLock lock(mainloop_);
-        const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
+        const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_START_CORKED);
 
-        if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) {
+        if (type == StreamType::Playback || type == StreamType::Ringtone) {
             pa_stream_connect_playback(audiostream_,
                     infos->name.empty() ? nullptr : infos->name.c_str(),
                     &attributes,
                     flags,
                     nullptr, nullptr);
-        } else if (type == CAPTURE_STREAM) {
+        } else if (type == StreamType::Capture) {
             pa_stream_connect_record(audiostream_,
                     infos->name.empty() ? nullptr : infos->name.c_str(),
                     &attributes,
@@ -84,12 +92,6 @@ AudioStream::AudioStream(pa_context *c,
         }
     }
 
-    pa_stream_set_state_callback(audiostream_, [](pa_stream* s, void* user_data){
-        static_cast<AudioStream*>(user_data)->stateChanged(s);
-    }, this);
-    pa_stream_set_moved_callback(audiostream_, [](pa_stream* s, void* user_data){
-        static_cast<AudioStream*>(user_data)->moved(s);
-    }, this);
 }
 
 AudioStream::~AudioStream()
@@ -99,16 +101,23 @@ AudioStream::~AudioStream()
     pa_stream_disconnect(audiostream_);
 
     // make sure we don't get any further callback
-    pa_stream_set_state_callback(audiostream_, NULL, NULL);
-    pa_stream_set_write_callback(audiostream_, NULL, NULL);
-    pa_stream_set_read_callback(audiostream_, NULL, NULL);
-    pa_stream_set_moved_callback(audiostream_, NULL, NULL);
-    pa_stream_set_underflow_callback(audiostream_, NULL, NULL);
-    pa_stream_set_overflow_callback(audiostream_, NULL, NULL);
+    pa_stream_set_state_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_write_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_read_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_moved_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_underflow_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_overflow_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_suspended_callback(audiostream_, nullptr, nullptr);
+    pa_stream_set_started_callback(audiostream_, nullptr, nullptr);
 
     pa_stream_unref(audiostream_);
 }
 
+void
+AudioStream::start() {
+    pa_stream_cork(audiostream_, 0, nullptr, nullptr);
+}
+
 void AudioStream::moved(pa_stream* s)
 {
     audiostream_ = s;
@@ -137,6 +146,7 @@ AudioStream::stateChanged(pa_stream* s)
             //RING_DBG("minreq %u", pa_stream_get_buffer_attr(s)->minreq);
             //RING_DBG("fragsize %u", pa_stream_get_buffer_attr(s)->fragsize);
             //RING_DBG("samplespec %s", pa_sample_spec_snprint(str, sizeof(str), pa_stream_get_sample_spec(s)));
+            onReady_();
             break;
 
         case PA_STREAM_UNCONNECTED:
diff --git a/src/media/audio/pulseaudio/audiostream.h b/src/media/audio/pulseaudio/audiostream.h
index a27c8b022b00c69b42dbb0ca6982c1cf683939dc..fb6fb421755cd5ec1eb87f9bef3d7774c58c76a5 100644
--- a/src/media/audio/pulseaudio/audiostream.h
+++ b/src/media/audio/pulseaudio/audiostream.h
@@ -18,8 +18,7 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
  */
 
-#ifndef _AUDIO_STREAM_H
-#define _AUDIO_STREAM_H
+#pragma once
 
 #include "noncopyable.h"
 #include "pulselayer.h"
@@ -32,85 +31,86 @@ namespace ring {
 /**
  * This data structure contains the different king of audio streams available
  */
-enum STREAM_TYPE {
-    PLAYBACK_STREAM, CAPTURE_STREAM, RINGTONE_STREAM
-};
+enum class StreamType { Playback, Capture, Ringtone };
 
 class AudioStream {
-    public:
-
-        /**
-         * Constructor
-         *
-         * @param context pulseaudio's application context.
-         * @param mainloop pulseaudio's main loop
-         * @param description
-         * @param types
-         * @param audio sampling rate
-         * @param pointer to pa_source_info or pa_sink_info (depending on type).
-         * @param true if echo cancelling should be used with this stream
-         */
-        AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, unsigned, const PaDeviceInfos*, bool);
-
-        ~AudioStream();
-
-        /**
-         * Accessor: Get the pulseaudio stream object
-         * @return pa_stream* The stream
-         */
-        pa_stream* stream() {
-            return audiostream_;
-        }
-
-        const pa_sample_spec * sampleSpec() const {
-            return pa_stream_get_sample_spec(audiostream_);
-        }
-
-        inline size_t sampleSize() const {
-            return pa_sample_size(sampleSpec());
-        }
-        inline size_t frameSize() const {
-            return pa_frame_size(sampleSpec());
-        }
-
-        inline uint8_t channels() const {
-            return sampleSpec()->channels;
-        }
-
-        inline AudioFormat format() const {
-            auto s = sampleSpec();
-            return AudioFormat(s->rate, s->channels);
-        }
-
-        inline std::string getDeviceName() const {
-            auto res = pa_stream_get_device_name(audiostream_);
-            if (res == reinterpret_cast<decltype(res)>(-PA_ERR_NOTSUPPORTED) or !res)
-                return {};
-            return res;
-        }
-
-        bool isReady();
-
-    private:
-        NON_COPYABLE(AudioStream);
-
-        /**
-         * Mandatory asynchronous callback on the audio stream state
-         */
-        void stateChanged(pa_stream* s);
-        void moved(pa_stream* s);
-
-        /**
-         * The pulse audio object
-         */
-        pa_stream* audiostream_;
-
-        /**
-         * A pointer to the opaque threaded main loop object
-         */
-        pa_threaded_mainloop * mainloop_;
+public:
+    using OnReady = std::function<void()>;
+
+    /**
+     * Constructor
+     *
+     * @param context pulseaudio's application context.
+     * @param mainloop pulseaudio's main loop
+     * @param description
+     * @param types
+     * @param audio sampling rate
+     * @param pointer to pa_source_info or pa_sink_info (depending on type).
+     * @param true if echo cancelling should be used with this stream
+     */
+    AudioStream(pa_context *, pa_threaded_mainloop *, const char *, StreamType, unsigned, const PaDeviceInfos*, bool, OnReady onReady);
+
+    ~AudioStream();
+
+    void start();
+
+    /**
+     * Accessor: Get the pulseaudio stream object
+     * @return pa_stream* The stream
+     */
+    pa_stream* stream() {
+        return audiostream_;
+    }
+
+    const pa_sample_spec * sampleSpec() const {
+        return pa_stream_get_sample_spec(audiostream_);
+    }
+
+    inline size_t sampleSize() const {
+        return pa_sample_size(sampleSpec());
+    }
+    inline size_t frameSize() const {
+        return pa_frame_size(sampleSpec());
+    }
+
+    inline uint8_t channels() const {
+        return sampleSpec()->channels;
+    }
+
+    inline AudioFormat format() const {
+        auto s = sampleSpec();
+        return AudioFormat(s->rate, s->channels);
+    }
+
+    inline std::string getDeviceName() const {
+        auto res = pa_stream_get_device_name(audiostream_);
+        if (res == reinterpret_cast<decltype(res)>(-PA_ERR_NOTSUPPORTED) or !res)
+            return {};
+        return res;
+    }
+
+    bool isReady();
+
+private:
+    NON_COPYABLE(AudioStream);
+
+    OnReady onReady_;
+
+    /**
+     * Mandatory asynchronous callback on the audio stream state
+     */
+    void stateChanged(pa_stream* s);
+    void moved(pa_stream* s);
+
+    /**
+     * The pulse audio object
+     */
+    pa_stream* audiostream_;
+
+    /**
+     * A pointer to the opaque threaded main loop object
+     */
+    pa_threaded_mainloop * mainloop_;
 };
 
 }
-
-#endif // _AUDIO_STREAM_H
diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp
index 40aa7324562b5b707be8b716dae27fe3ec3aa366..7f7efe2d0624b8fae40b91e42417f584a0b646cc 100644
--- a/src/media/audio/pulseaudio/pulselayer.cpp
+++ b/src/media/audio/pulseaudio/pulselayer.cpp
@@ -323,9 +323,21 @@ void PulseLayer::createStreams(pa_context* c)
 {
     hardwareFormatAvailable(defaultAudioFormat_);
 
+    auto onReady = [this] {
+        bool playbackReady = not playback_ or playback_->isReady();
+        bool ringtoneReady = not ringtone_ or ringtone_->isReady();
+        bool recordReady = not record_ or record_->isReady();
+        if (playbackReady and recordReady and ringtoneReady) {
+            RING_DBG("All streams ready, starting !");
+            if (playback_) playback_->start();
+            if (ringtone_) ringtone_->start();
+            if (record_) record_->start();
+        }
+    };
+
     // Create playback stream
     if (auto dev_infos = getDeviceInfos(sinkList_, getPreferredPlaybackDevice())) {
-        playback_.reset(new AudioStream(c, mainloop_.get(), "Playback", PLAYBACK_STREAM, audioFormat_.sample_rate, dev_infos, true));
+        playback_.reset(new AudioStream(c, mainloop_.get(), "Playback", StreamType::Playback, audioFormat_.sample_rate, dev_infos, true, onReady));
         pa_stream_set_write_callback(playback_->stream(), [](pa_stream * /*s*/, size_t /*bytes*/, void* userdata) {
             static_cast<PulseLayer*>(userdata)->writeToSpeaker();
         }, this);
@@ -334,7 +346,7 @@ void PulseLayer::createStreams(pa_context* c)
     // Create ringtone stream
     // Echo canceling is not enabled for ringtone, because PA can only cancel a single output source with an input source
     if (auto dev_infos = getDeviceInfos(sinkList_, getPreferredRingtoneDevice())) {
-        ringtone_.reset(new AudioStream(c, mainloop_.get(), "Ringtone", RINGTONE_STREAM, audioFormat_.sample_rate, dev_infos, false));
+        ringtone_.reset(new AudioStream(c, mainloop_.get(), "Ringtone", StreamType::Ringtone, audioFormat_.sample_rate, dev_infos, false, onReady));
         pa_stream_set_write_callback(ringtone_->stream(), [](pa_stream * /*s*/, size_t /*bytes*/, void* userdata) {
             static_cast<PulseLayer*>(userdata)->ringtoneToSpeaker();
         }, this);
@@ -342,7 +354,7 @@ void PulseLayer::createStreams(pa_context* c)
 
     // Create capture stream
     if (auto dev_infos = getDeviceInfos(sourceList_, getPreferredCaptureDevice())) {
-        record_.reset(new AudioStream(c, mainloop_.get(), "Capture", CAPTURE_STREAM, audioFormat_.sample_rate, dev_infos, true));
+        record_.reset(new AudioStream(c, mainloop_.get(), "Capture", StreamType::Capture, audioFormat_.sample_rate, dev_infos, true, onReady));
         pa_stream_set_read_callback(record_->stream() , [](pa_stream * /*s*/, size_t /*bytes*/, void* userdata) {
             static_cast<PulseLayer*>(userdata)->readFromMic();
         }, this);
@@ -483,10 +495,8 @@ void PulseLayer::ringtoneToSpeaker()
 }
 
 
-std::string stripEchoSufix(std::string deviceName) {
-
+std::string stripEchoSufix(const std::string& deviceName) {
     return std::regex_replace(deviceName, PA_EC_SUFFIX, "");
-
 }
 
 void
@@ -560,8 +570,15 @@ void PulseLayer::waitForDeviceList()
             return;
 
         // If a current device changed, restart streams
-        if (!playback_ || stripEchoSufix(playback_->getDeviceName()) != getDeviceInfos(sinkList_, getPreferredPlaybackDevice())->name
-         || !record_   || stripEchoSufix(record_->getDeviceName())   != getDeviceInfos(sourceList_, getPreferredCaptureDevice())->name) {
+        auto playbackInfo = getDeviceInfos(sinkList_, getPreferredPlaybackDevice());
+        bool playbackDeviceChanged = !playback_ or (!playbackInfo->name.empty() and
+                                                     playbackInfo->name != stripEchoSufix(playback_->getDeviceName()));
+
+        auto recordInfo = getDeviceInfos(sourceList_, getPreferredCaptureDevice());
+        bool recordDeviceChanged = !record_ or (!recordInfo->name.empty() and
+                                                 recordInfo->name != stripEchoSufix(record_->getDeviceName()));
+
+        if (playbackDeviceChanged or recordDeviceChanged) {
             RING_WARN("Audio devices changed, restarting streams.");
             stopStream();
             startStream();