diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp
index 3e3c4c0b73525a570abe543f7feaf332479a335e..fbb2f185fd0c3f5b0bbd8e1c7080f2e151c4d738 100644
--- a/src/media/audio/audiolayer.cpp
+++ b/src/media/audio/audiolayer.cpp
@@ -109,4 +109,101 @@ void AudioLayer::notifyIncomingCall()
     putUrgent(buf);
 }
 
+
+const AudioBuffer& AudioLayer::getToRing(AudioFormat format, size_t writableSamples)
+{
+    ringtoneBuffer_.resize(0);
+    AudioLoop *fileToPlay = Manager::instance().getTelephoneFile();
+    if (fileToPlay) {
+        auto fileformat = fileToPlay->getFormat();
+        bool resample = format.sample_rate != fileformat.sample_rate;
+
+        size_t readableSamples = resample
+                ? fileformat.sample_rate * (double) writableSamples / (double) audioFormat_.sample_rate
+                : writableSamples;
+
+        ringtoneBuffer_.setFormat(fileformat);
+        ringtoneBuffer_.resize(readableSamples);
+        fileToPlay->getNext(ringtoneBuffer_, 1.0);
+        ringtoneBuffer_.setChannelNum(format.nb_channels, true);
+        AudioBuffer* out;
+        if (resample) {
+            ringtoneResampleBuffer_.setSampleRate(format.sample_rate);
+            resampler_->resample(ringtoneBuffer_, ringtoneResampleBuffer_);
+            out = &ringtoneResampleBuffer_;
+        } else {
+            out = &ringtoneBuffer_;
+        }
+        return *out;
+    }
+    return ringtoneBuffer_;
+}
+
+const AudioBuffer& AudioLayer::getToPlay(AudioFormat format, size_t writableSamples)
+{
+    playbackBuffer_.resize(0);
+    playbackResampleBuffer_.resize(0);
+
+    notifyIncomingCall();
+
+    size_t urgentSamples = std::min(urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID), writableSamples);
+
+    if (urgentSamples) {
+        playbackBuffer_.setFormat(format);
+        playbackBuffer_.resize(urgentSamples);
+        urgentRingBuffer_.get(playbackBuffer_, RingBufferPool::DEFAULT_ID); // retrive only the first sample_spec->channels channels
+        playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+        // Consume the regular one as well (same amount of samples)
+        Manager::instance().getRingBufferPool().discard(urgentSamples, RingBufferPool::DEFAULT_ID);
+        return playbackBuffer_;
+    }
+
+    // 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
+    if (AudioLoop* toneToPlay = Manager::instance().getTelephoneTone()) {
+        playbackBuffer_.setFormat(format);
+        playbackBuffer_.resize(writableSamples);
+        toneToPlay->getNext(playbackBuffer_, playbackGain_); // retrive only n_channels
+        return playbackBuffer_;
+    }
+
+    flushUrgent(); // flush remaining samples in _urgentRingBuffer
+
+    size_t availSamples = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID);
+    if (not availSamples)
+        return playbackBuffer_;
+
+    // how many samples we want to read from the buffer
+    size_t readableSamples = writableSamples;
+
+    AudioFormat mainBufferAudioFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
+
+    bool resample = audioFormat_.sample_rate != mainBufferAudioFormat.sample_rate;
+    double resampleFactor = 1.;
+    if (resample) {
+        resampleFactor = (double) audioFormat_.sample_rate / mainBufferAudioFormat.sample_rate;
+        readableSamples = (double) readableSamples / resampleFactor;
+    }
+
+    readableSamples = std::min(readableSamples, availSamples);
+    size_t nResampled = (double) readableSamples * resampleFactor;
+
+    playbackBuffer_.setFormat(mainBufferAudioFormat);
+    playbackBuffer_.resize(readableSamples);
+    Manager::instance().getRingBufferPool().getData(playbackBuffer_, RingBufferPool::DEFAULT_ID);
+    playbackBuffer_.setChannelNum(format.nb_channels, true);
+
+    if (resample) {
+        playbackResampleBuffer_.setFormat(format);
+        playbackResampleBuffer_.resize(nResampled);
+        resampler_->resample(playbackBuffer_, playbackResampleBuffer_);
+        playbackResampleBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+        return playbackResampleBuffer_;
+    } else {
+        playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+        return playbackBuffer_;
+    }
+}
+
+
 } // namespace ring
diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h
index 92d767bba86655ef0f19378ce3a296a01902773f..b1a79bd936cb730061c06a409cb684a0f8efa851 100644
--- a/src/media/audio/audiolayer.h
+++ b/src/media/audio/audiolayer.h
@@ -219,6 +219,11 @@ class AudioLayer {
          */
         void hardwareInputFormatAvailable(AudioFormat capture);
 
+
+        const AudioBuffer& getToPlay(AudioFormat format, size_t writableSamples);
+
+        const AudioBuffer& getToRing(AudioFormat format, size_t writableSamples);
+
         /**
          * True if capture is not to be used
          */
@@ -239,6 +244,14 @@ class AudioLayer {
          */
         double playbackGain_;
 
+        /**
+         * Buffers for audio processing
+         */
+        AudioBuffer playbackBuffer_;
+        AudioBuffer playbackResampleBuffer_;
+        AudioBuffer ringtoneBuffer_;
+        AudioBuffer ringtoneResampleBuffer_;
+
         /**
          * Whether or not the audio layer stream is started
          */
diff --git a/src/media/audio/opensl/Makefile.am b/src/media/audio/opensl/Makefile.am
index 4e3c0d9e2a8989b42f40883ae87dcea574e1c492..782af065481759059cde0f080351cb4763f62411 100644
--- a/src/media/audio/opensl/Makefile.am
+++ b/src/media/audio/opensl/Makefile.am
@@ -4,8 +4,8 @@ if BUILD_OPENSL
 
 noinst_LTLIBRARIES = libopensl.la
 
-libopensl_la_SOURCES = opensllayer.cpp
+libopensl_la_SOURCES = opensllayer.cpp audio_player.cpp audio_recorder.cpp
 
-noinst_HEADERS = opensllayer.h
+noinst_HEADERS = opensllayer.h audio_common.h audio_player.h audio_recorder.h buf_manager.h
 
 endif
diff --git a/src/media/audio/opensl/audio_common.h b/src/media/audio/opensl/audio_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..b1a8fd8cbd04b59784f886735e695ca0b11c276c
--- /dev/null
+++ b/src/media/audio/opensl/audio_common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#include <SLES/OpenSLES_Android.h>
+
+#include "buf_manager.h"
+
+namespace ring {
+namespace opensl {
+
+/*
+ * Sample Buffer Controls...
+ */
+#define RECORD_DEVICE_KICKSTART_BUF_COUNT   2
+#define PLAY_KICKSTART_BUFFER_COUNT         8
+#define DEVICE_SHADOW_BUFFER_QUEUE_LEN      4
+#define BUF_COUNT                           16
+
+inline SLDataFormat_PCM convertToSLSampleFormat(const ring::AudioFormat& infos)
+{
+    return SLDataFormat_PCM {
+        .formatType     = SL_DATAFORMAT_PCM,
+        .numChannels    = infos.nb_channels <= 1 ? 1u : 2u,
+        .samplesPerSec     = infos.sample_rate * 1000,
+        .bitsPerSample  = SL_PCMSAMPLEFORMAT_FIXED_16,
+        .containerSize  = SL_PCMSAMPLEFORMAT_FIXED_16,
+        .channelMask    = infos.nb_channels <= 1 ? SL_SPEAKER_FRONT_CENTER : SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
+        .endianness     = SL_BYTEORDER_LITTLEENDIAN,
+    };
+}
+
+#define SLASSERT(x) { \
+        if(SL_RESULT_SUCCESS != (x))\
+            throw std::runtime_error("OpenSLES error");\
+    }
+
+/*
+ * Interface for player and recorder to communicate with engine
+ */
+#define ENGINE_SERVICE_MSG_KICKSTART_PLAYER    1
+#define ENGINE_SERVICE_MSG_RETRIEVE_DUMP_BUFS  2
+
+using EngineCallback = std::function<void(bool waiting)>;
+
+}}
diff --git a/src/media/audio/opensl/audio_player.cpp b/src/media/audio/opensl/audio_player.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9673ddac5baa6201c016a07f702ef68cc6e1204f
--- /dev/null
+++ b/src/media/audio/opensl/audio_player.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "audio_player.h"
+#include "logger.h"
+
+#include <SLES/OpenSLES_AndroidConfiguration.h>
+
+#include <cstdlib>
+
+namespace ring {
+namespace opensl {
+
+/*
+ * Called by OpenSL SimpleBufferQueue for every audio buffer played
+ * directly pass thru to our handler.
+ * The regularity of this callback from openSL/Android System affects
+ * playback continuity. If it does not callback in the regular time
+ * slot, you are under big pressure for audio processing[here we do
+ * not do any filtering/mixing]. Callback from fast audio path are
+ * much more regular than other audio paths by my observation. If it
+ * very regular, you could buffer much less audio samples between
+ * recorder and player, hence lower latency.
+ */
+void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *ctx) {
+    (static_cast<AudioPlayer *>(ctx))->processSLCallback(bq);
+}
+void AudioPlayer::processSLCallback(SLAndroidSimpleBufferQueueItf bq) {
+    std::lock_guard<std::mutex> lk(m_);
+
+    // retrieve the finished device buf and put onto the free queue
+    // so recorder could re-use it
+    sample_buf *buf;
+    if(!devShadowQueue_.front(&buf)) {
+        RING_ERR("AudioPlayer buffer lost");
+        /*
+         * This should not happen: we got a callback,
+         * but we have no buffer in deviceShadowedQueue
+         * we lost buffers this way...(ERROR)
+         */
+        callback_(true);
+        return;
+    }
+    devShadowQueue_.pop();
+    buf->size_ = 0;
+    if (!freeQueue_->push(buf)) {
+        RING_ERR("buffer lost");
+    }
+
+    callback_(false);
+
+    while(playQueue_->front(&buf) && devShadowQueue_.push(buf)) {
+        if ((*bq)->Enqueue(bq, buf->buf_, buf->size_) != SL_RESULT_SUCCESS) {
+            devShadowQueue_.pop();
+            RING_ERR("enqueue failed %zu %zu %zu %zu", buf->size_, freeQueue_->size(), playQueue_->size(), devShadowQueue_.size());
+            break;
+        } else
+            playQueue_->pop();
+    }
+    if (devShadowQueue_.size() == 0) {
+        RING_ERR("AudioPlayer: nothing to play %zu %zu %zu", freeQueue_->size(), playQueue_->size(), devShadowQueue_.size());
+        waiting_ = true;
+        callback_(true);
+    }
+}
+
+AudioPlayer::AudioPlayer(ring::AudioFormat sampleFormat, SLEngineItf slEngine, SLint32 streamType) :
+    sampleInfo_(sampleFormat)
+{
+    SLresult result;
+    result = (*slEngine)->CreateOutputMix(slEngine, &outputMixObjectItf_, 0, nullptr, nullptr);
+    SLASSERT(result);
+
+    // realize the output mix
+    result = (*outputMixObjectItf_)->Realize(outputMixObjectItf_, SL_BOOLEAN_FALSE);
+    SLASSERT(result);
+
+    // configure audio source
+    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
+            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+            DEVICE_SHADOW_BUFFER_QUEUE_LEN };
+
+    auto format_pcm = convertToSLSampleFormat(sampleInfo_);
+    SLDataSource audioSrc = {&loc_bufq, &format_pcm};
+
+    // configure audio sink
+    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObjectItf_};
+    SLDataSink audioSnk = {&loc_outmix, nullptr};
+    /*
+     * create fast path audio player: SL_IID_BUFFERQUEUE and SL_IID_VOLUME interfaces ok,
+     * NO others!
+     */
+    SLInterfaceID  ids[3] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
+    SLboolean      req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+    result = (*slEngine)->CreateAudioPlayer(slEngine, &playerObjectItf_, &audioSrc, &audioSnk,
+                                            sizeof(ids)/sizeof(ids[0]), ids, req);
+    SLASSERT(result);
+
+    SLAndroidConfigurationItf playerConfig;
+    result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
+    result = (*playerConfig)->SetConfiguration(playerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
+
+    // realize the player
+    result = (*playerObjectItf_)->Realize(playerObjectItf_, SL_BOOLEAN_FALSE);
+    SLASSERT(result);
+
+    // get the play interface
+    result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_PLAY, &playItf_);
+    SLASSERT(result);
+
+    // get the buffer queue interface
+    result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_BUFFERQUEUE, &playBufferQueueItf_);
+    SLASSERT(result);
+
+    // register callback on the buffer queue
+    result = (*playBufferQueueItf_)->RegisterCallback(playBufferQueueItf_, bqPlayerCallback, this);
+    SLASSERT(result);
+
+    result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
+    SLASSERT(result);
+}
+
+AudioPlayer::~AudioPlayer() {
+
+    // destroy buffer queue audio player object, and invalidate all associated interfaces
+    if (playerObjectItf_) {
+        (*playerObjectItf_)->Destroy(playerObjectItf_);
+    }
+
+    // destroy output mix object, and invalidate all associated interfaces
+    if (outputMixObjectItf_) {
+        (*outputMixObjectItf_)->Destroy(outputMixObjectItf_);
+    }
+}
+
+void AudioPlayer::setBufQueue(AudioQueue *playQ, AudioQueue *freeQ) {
+    playQueue_ = playQ;
+    freeQueue_ = freeQ;
+}
+
+bool AudioPlayer::start() {
+    SLuint32   state;
+    SLresult  result = (*playItf_)->GetPlayState(playItf_, &state);
+    if (result != SL_RESULT_SUCCESS)
+        return false;
+    if(state == SL_PLAYSTATE_PLAYING)
+        return true;
+
+    result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
+    SLASSERT(result);
+
+    result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_PLAYING);
+    SLASSERT(result);
+
+    // send pre-defined audio buffers to device
+    int i = PLAY_KICKSTART_BUFFER_COUNT;
+    while(i--) {
+        sample_buf *buf;
+        if(!playQueue_->front(&buf))    //we have buffers for sure
+            break;
+        if(SL_RESULT_SUCCESS !=
+           (*playBufferQueueItf_)->Enqueue(playBufferQueueItf_, buf, buf->size_))
+        {
+            RING_ERR("====failed to enqueue (%d) in %s", i, __FUNCTION__);
+            return false;
+        } else {
+            playQueue_->pop();
+            devShadowQueue_.push(buf);
+        }
+    }
+    waiting_ = devShadowQueue_.size() == 0;
+    return true;
+}
+
+bool AudioPlayer::started() const
+{
+    if (!playItf_)
+        return false;
+    SLuint32 state;
+    SLresult result = (*playItf_)->GetPlayState(playItf_, &state);
+    return result == SL_RESULT_SUCCESS && state == SL_PLAYSTATE_PLAYING;
+}
+
+void AudioPlayer::stop() {
+    SLuint32   state;
+
+    SLresult   result = (*playItf_)->GetPlayState(playItf_, &state);
+    SLASSERT(result);
+
+    if(state == SL_PLAYSTATE_STOPPED)
+        return;
+
+    result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
+    SLASSERT(result);
+
+    waiting_ = false;
+
+    // Consume all non-completed audio buffers
+    sample_buf *buf = nullptr;
+    while(devShadowQueue_.front(&buf)) {
+        buf->size_ = 0;
+        devShadowQueue_.pop();
+        freeQueue_->push(buf);
+    }
+    while(playQueue_->front(&buf)) {
+        buf->size_ = 0;
+        playQueue_->pop();
+        freeQueue_->push(buf);
+    }
+}
+
+void AudioPlayer::playAudioBuffers(unsigned count) {
+    while (count--) {
+        sample_buf *buf = nullptr;
+        if(!playQueue_->front(&buf)) {
+            RING_ERR("====Run out of buffers in %s @(count = %d)", __FUNCTION__, count);
+            break;
+        }
+        if(!devShadowQueue_.push(buf)) {
+            break;  // PlayerBufferQueue is full!!!
+        }
+
+        SLresult result = (*playBufferQueueItf_)->Enqueue(playBufferQueueItf_,
+                                                  buf->buf_, buf->size_);
+        if(result != SL_RESULT_SUCCESS) {
+            RING_ERR("%s Error @( %p, %d ), result = %d", __FUNCTION__, (void*)buf->buf_, buf->size_, result);
+            /*
+             * when this happens, a buffer is lost. Need to remove the buffer
+             * from top of the devShadowQueue. Since I do not have it now,
+             * just pop out the one that is being played right now. Afer a
+             * cycle it will be normal.
+             */
+            devShadowQueue_.front(&buf), devShadowQueue_.pop();
+            freeQueue_->push(buf);
+            break;
+        }
+        playQueue_->pop();   // really pop out the buffer
+    }
+    waiting_ = devShadowQueue_.size() == 0;
+}
+
+size_t AudioPlayer::dbgGetDevBufCount(void) {
+    return devShadowQueue_.size();
+}
+
+}}
diff --git a/src/media/audio/opensl/audio_player.h b/src/media/audio/opensl/audio_player.h
new file mode 100644
index 0000000000000000000000000000000000000000..025a2aa34fd3a6353581843f0237c9158348d051
--- /dev/null
+++ b/src/media/audio/opensl/audio_player.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "audio_common.h"
+#include "buf_manager.h"
+
+#include <sys/types.h>
+#include <SLES/OpenSLES_Android.h>
+
+#include <mutex>
+
+namespace ring {
+namespace opensl {
+
+class AudioPlayer {
+    // buffer queue player interfaces
+    SLObjectItf outputMixObjectItf_;
+    SLObjectItf playerObjectItf_;
+    SLPlayItf   playItf_;
+    SLAndroidSimpleBufferQueueItf playBufferQueueItf_;
+
+    ring::AudioFormat sampleInfo_;
+    AudioQueue *freeQueue_ {nullptr};       // user
+    AudioQueue *playQueue_ {nullptr};       // user
+    AudioQueue devShadowQueue_ {DEVICE_SHADOW_BUFFER_QUEUE_LEN};  // owner
+
+    EngineCallback callback_ {};
+
+public:
+    explicit AudioPlayer(ring::AudioFormat sampleFormat, SLEngineItf engine, SLint32 streamType);
+    ~AudioPlayer();
+    bool start();
+    void stop();
+    bool started() const;
+
+    void setBufQueue(AudioQueue *playQ, AudioQueue *freeQ);
+    void processSLCallback(SLAndroidSimpleBufferQueueItf bq);
+    void playAudioBuffers(unsigned count);
+    void registerCallback(EngineCallback cb) {callback_ = cb;}
+    size_t dbgGetDevBufCount();
+
+    std::mutex m_;
+    std::atomic_bool waiting_ {false};
+};
+
+}}
diff --git a/src/media/audio/opensl/audio_recorder.cpp b/src/media/audio/opensl/audio_recorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..34f3c73127c01e71802d361882b5d2d9802901dd
--- /dev/null
+++ b/src/media/audio/opensl/audio_recorder.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstring>
+#include <cstdlib>
+#include "audio_recorder.h"
+
+namespace ring {
+namespace opensl {
+
+/*
+ * bqRecorderCallback(): called for every buffer is full;
+ *                       pass directly to handler
+ */
+void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *rec) {
+    (static_cast<AudioRecorder *>(rec))->processSLCallback(bq);
+}
+
+void AudioRecorder::processSLCallback(SLAndroidSimpleBufferQueueItf bq) {
+    assert(bq == recBufQueueItf_);
+    sample_buf *dataBuf {nullptr};
+    devShadowQueue_.front(&dataBuf);
+    devShadowQueue_.pop();
+    dataBuf->size_ = dataBuf->cap_;           //device only calls us when it is really full
+    recQueue_->push(dataBuf);
+
+    sample_buf* freeBuf;
+    while (freeQueue_->front(&freeBuf) && devShadowQueue_.push(freeBuf)) {
+        freeQueue_->pop();
+        SLresult result = (*bq)->Enqueue(bq, freeBuf->buf_, freeBuf->cap_);
+        SLASSERT(result);
+    }
+
+    // should leave the device to sleep to save power if no buffers
+    if (devShadowQueue_.size() == 0) {
+        (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
+    }
+    callback_(false);
+}
+
+AudioRecorder::AudioRecorder(ring::AudioFormat sampleFormat, SLEngineItf slEngine) :
+        sampleInfo_(sampleFormat)
+{
+    // configure audio source
+    SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
+                                      SL_IODEVICE_AUDIOINPUT,
+                                      SL_DEFAULTDEVICEID_AUDIOINPUT,
+                                      nullptr };
+    SLDataSource audioSrc = {&loc_dev, nullptr };
+
+    // configure audio sink
+    SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
+            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+            DEVICE_SHADOW_BUFFER_QUEUE_LEN };
+
+    auto format_pcm = convertToSLSampleFormat(sampleInfo_);
+    SLDataSink audioSnk = {&loc_bq, &format_pcm};
+
+    // create audio recorder
+    // (requires the RECORD_AUDIO permission)
+    const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
+    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
+    SLresult result;
+    result = (*slEngine)->CreateAudioRecorder(slEngine,
+                                              &recObjectItf_,
+                                              &audioSrc,
+                                              &audioSnk,
+                                              1, id, req);
+    SLASSERT(result);
+
+    result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE);
+    SLASSERT(result);
+    result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_);
+    SLASSERT(result);
+
+    result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recBufQueueItf_);
+    SLASSERT(result);
+
+    result = (*recBufQueueItf_)->RegisterCallback(recBufQueueItf_, bqRecorderCallback, this);
+    SLASSERT(result);
+}
+
+bool
+AudioRecorder::start()
+{
+    if(!freeQueue_ || !recQueue_) {
+        RING_ERR("====NULL pointer to Start(%p, %p)", freeQueue_, recQueue_);
+        return false;
+    }
+    audioBufCount = 0;
+
+    SLresult result;
+    // in case already recording, stop recording and clear buffer queue
+    result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
+    SLASSERT(result);
+    result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
+    SLASSERT(result);
+
+    for(int i =0; i < RECORD_DEVICE_KICKSTART_BUF_COUNT; i++ ) {
+        sample_buf *buf = NULL;
+        if(!freeQueue_->front(&buf)) {
+            RING_ERR("=====OutOfFreeBuffers @ startingRecording @ (%d)", i);
+            break;
+        }
+        freeQueue_->pop();
+        assert(buf->buf_ && buf->cap_ && !buf->size_);
+
+        result = (*recBufQueueItf_)->Enqueue(recBufQueueItf_, buf->buf_,
+                                                 buf->cap_);
+        SLASSERT(result);
+        devShadowQueue_.push(buf);
+    }
+
+    result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_RECORDING);
+    SLASSERT(result);
+
+    return result == SL_RESULT_SUCCESS;
+}
+
+bool
+AudioRecorder::stop()
+{
+    // in case already recording, stop recording and clear buffer queue
+    SLuint32 curState;
+    SLresult result = (*recItf_)->GetRecordState(recItf_, &curState);
+    SLASSERT(result);
+    if (curState == SL_RECORDSTATE_STOPPED)
+        return true;
+
+    result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
+    SLASSERT(result);
+    result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
+    SLASSERT(result);
+
+    sample_buf *buf {nullptr};
+    while(devShadowQueue_.front(&buf)) {
+        devShadowQueue_.pop();
+        freeQueue_->push(buf);
+    }
+
+    return true;
+}
+
+AudioRecorder::~AudioRecorder() {
+    // destroy audio recorder object, and invalidate all associated interfaces
+    if (recObjectItf_) {
+        (*recObjectItf_)->Destroy(recObjectItf_);
+    }
+}
+
+void AudioRecorder::setBufQueues(AudioQueue *freeQ, AudioQueue *recQ) {
+    assert(freeQ && recQ);
+    freeQueue_ = freeQ;
+    recQueue_ = recQ;
+}
+
+size_t AudioRecorder::dbgGetDevBufCount() {
+     return devShadowQueue_.size();
+}
+
+}}
diff --git a/src/media/audio/opensl/audio_recorder.h b/src/media/audio/opensl/audio_recorder.h
new file mode 100644
index 0000000000000000000000000000000000000000..e26d34acd251bc92c68a4001d80f9f5fa4dda1fa
--- /dev/null
+++ b/src/media/audio/opensl/audio_recorder.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+
+#include "audio_common.h"
+#include "buf_manager.h"
+
+namespace ring {
+namespace opensl {
+
+class AudioRecorder {
+    SLObjectItf recObjectItf_;
+    SLRecordItf recItf_;
+    SLAndroidSimpleBufferQueueItf recBufQueueItf_;
+
+    ring::AudioFormat  sampleInfo_;
+    AudioQueue *freeQueue_ {nullptr};         // user
+    AudioQueue *recQueue_ {nullptr};          // user
+    AudioQueue  devShadowQueue_ {DEVICE_SHADOW_BUFFER_QUEUE_LEN};    // owner
+    uint32_t    audioBufCount;
+
+    EngineCallback callback_ {};
+
+public:
+    explicit AudioRecorder(ring::AudioFormat, SLEngineItf engineEngine);
+    ~AudioRecorder();
+    bool start();
+    bool stop();
+    void setBufQueues(AudioQueue *freeQ, AudioQueue *recQ);
+    void processSLCallback(SLAndroidSimpleBufferQueueItf bq);
+    void registerCallback(EngineCallback cb) {callback_ = cb;}
+    size_t dbgGetDevBufCount();
+};
+
+}
+}
diff --git a/src/media/audio/opensl/buf_manager.h b/src/media/audio/opensl/buf_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..0cea34b7de412ce4ce470ed43586dadfe359af0e
--- /dev/null
+++ b/src/media/audio/opensl/buf_manager.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ * Copyright 2015 Savoir-faire Linux Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "audio/audiobuffer.h"
+#include "logger.h"
+
+#include <SLES/OpenSLES.h>
+#include <sys/types.h>
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+#include <limits>
+#include <vector>
+
+#ifndef CACHE_ALIGN
+#define CACHE_ALIGN 64
+#endif
+
+/*
+ * ProducerConsumerQueue, borrowed from Ian NiLewis
+ */
+template <typename T>
+class ProducerConsumerQueue {
+public:
+    explicit ProducerConsumerQueue(size_t size) : buffer_(size) {
+        // This is necessary because we depend on twos-complement wraparound
+        // to take care of overflow conditions.
+        assert(size < std::numeric_limits<int>::max());
+    }
+
+    void clear() {
+        read_.store(0);
+        write_.store(0);
+    }
+
+    bool push(const T& item) {
+        return push([&](T* ptr) -> bool {*ptr = item; return true; });
+    }
+
+    // get() is idempotent between calls to commit().
+    T* getWriteablePtr() {
+        T* result = nullptr;
+
+
+        bool check  __attribute__((unused));//= false;
+
+        check = push([&](T* head)-> bool {
+            result = head;
+            return false; // don't increment
+        });
+
+        // if there's no space, result should not have been set, and vice versa
+        assert(check == (result != nullptr));
+
+        return result;
+    }
+
+    bool commitWriteablePtr(T *ptr) {
+        bool result = push([&](T* head)-> bool {
+            // this writer func does nothing, because we assume that the caller
+            // has already written to *ptr after acquiring it from a call to get().
+            // So just double-check that ptr is actually at the write head, and
+            // return true to indicate that it's safe to advance.
+
+            // if this isn't the same pointer we got from a call to get(), then
+            // something has gone terribly wrong. Either there was an intervening
+            // call to push() or commit(), or the pointer is spurious.
+            assert(ptr == head);
+            return true;
+        });
+        return result;
+    }
+
+    // writer() can return false, which indicates that the caller
+    // of push() changed its mind while writing (e.g. ran out of bytes)
+    template<typename F>
+    bool push(const F& writer) {
+        bool result = false;
+        int readptr = read_.load(std::memory_order_acquire);
+        int writeptr = write_.load(std::memory_order_relaxed);
+
+        // note that while readptr and writeptr will eventually
+        // wrap around, taking their difference is still valid as
+        // long as size_ < MAXINT.
+        int space = buffer_.size() - (int)(writeptr - readptr);
+        if (space >= 1) {
+            result = true;
+
+            // writer
+            if (writer(buffer_.data() + (writeptr % buffer_.size()))) {
+                ++writeptr;
+                write_.store(writeptr, std::memory_order_release);
+            }
+        }
+        return result;
+    }
+    // front out the queue, but not pop-out
+    bool front(T* out_item) {
+        return front([&](T* ptr)-> bool {*out_item = *ptr; return true;});
+    }
+
+    void pop(void) {
+        int readptr = read_.load(std::memory_order_relaxed);
+        ++readptr;
+        read_.store(readptr, std::memory_order_release);
+    }
+
+    template<typename F>
+    bool front(const F& reader) {
+        bool result = false;
+
+        int writeptr = write_.load(std::memory_order_acquire);
+        int readptr = read_.load(std::memory_order_relaxed);
+
+        // As above, wraparound is ok
+        int available = (int)(writeptr - readptr);
+        if (available >= 1) {
+            result = true;
+            reader(buffer_.data() + (readptr % buffer_.size()));
+        }
+
+        return result;
+    }
+    uint32_t size(void) {
+        int writeptr = write_.load(std::memory_order_acquire);
+        int readptr = read_.load(std::memory_order_relaxed);
+
+        return (uint32_t)(writeptr - readptr);
+    }
+
+private:
+    std::vector<T> buffer_;
+
+    // forcing cache line alignment to eliminate false sharing of the
+    // frequently-updated read and write pointers. The object is to never
+    // let these get into the "shared" state where they'd cause a cache miss
+    // for every write.
+    alignas(CACHE_ALIGN) std::atomic<int> read_ { 0 };
+    alignas(CACHE_ALIGN) std::atomic<int> write_ { 0 };
+};
+
+struct sample_buf {
+    uint8_t* buf_ {nullptr};       // audio sample container
+    size_t   cap_ {0};       // buffer capacity in byte
+    size_t   size_ {0};      // audio sample size (n buf) in byte
+    sample_buf() {}
+    sample_buf(size_t alloc, size_t size) : buf_(new uint8_t[alloc]), cap_(size) {}
+    ~sample_buf() {
+        if (buf_) delete[] buf_;
+    }
+};
+
+using AudioQueue = ProducerConsumerQueue<sample_buf*>;
+
+__inline__ std::vector<sample_buf>
+allocateSampleBufs(unsigned count, size_t sizeInByte)
+{
+    std::vector<sample_buf> bufs;
+    if (!count || !sizeInByte)
+        return bufs;
+    bufs.reserve(count);
+    size_t allocSize = (sizeInByte + 3) & ~3;   // padding to 4 bytes aligned
+    for(unsigned i =0; i < count; i++)
+        bufs.emplace_back(allocSize, sizeInByte);
+    return bufs;
+}
diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp
index 3eafa8a5bf036a5f25f232e49d04b85209da1fb4..1155f5839cd7ac45917640cc0f6a0fb93bb62b8a 100644
--- a/src/media/audio/opensl/opensllayer.cpp
+++ b/src/media/audio/opensl/opensllayer.cpp
@@ -22,11 +22,11 @@
 
 #include "client/ring_signal.h"
 
-#include "manager.h"
 #include "audio/resampler.h"
 #include "audio/ringbufferpool.h"
 #include "audio/ringbuffer.h"
 #include "audio/dcblocker.h"
+#include "manager.h"
 #include "logger.h"
 #include "array_size.h"
 
@@ -45,40 +45,17 @@
 
 namespace ring {
 
-const int OpenSLLayer::NB_BUFFER_PLAYBACK_QUEUE = ANDROID_BUFFER_QUEUE_LENGTH;
-const int OpenSLLayer::NB_BUFFER_CAPTURE_QUEUE = ANDROID_BUFFER_QUEUE_LENGTH;
-
 // Constructor
 OpenSLLayer::OpenSLLayer(const AudioPreference &pref)
-    : AudioLayer(pref)
-    , indexIn_(0)
-    , indexOut_(0)
-    , indexRing_(0)
-    , audioThread_(nullptr)
-    , engineObject_(nullptr)
-    , engineInterface_(nullptr)
-    , outputMixer_(nullptr)
-    , playerObject_(nullptr)
-    , recorderObject_(nullptr)
-    , playerInterface_(nullptr)
-    , recorderInterface_(nullptr)
-    , playbackBufferQueue_(nullptr)
-    , recorderBufferQueue_(nullptr)
-    , playbackBufferIndex_(0)
-    , recordBufferIndex_(0)
-    , hardwareFormat_(AudioFormat::MONO())
-    , hardwareBuffSize_(BUFFER_SIZE)
-    , playbackBufferStack_(ANDROID_BUFFER_QUEUE_LENGTH, AudioBuffer(hardwareBuffSize_, AudioFormat::MONO()))
-    , recordBufferStack_(ANDROID_BUFFER_QUEUE_LENGTH, AudioBuffer(hardwareBuffSize_, AudioFormat::MONO()))
-    , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID))
-{
-}
+    : AudioLayer(pref),
+     audioInputDescriptor_(),
+     mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID))
+{}
 
 // Destructor
 OpenSLLayer::~OpenSLLayer()
 {
-    stopAudioPlayback();
-    stopAudioCapture();
+    shutdownAudioEngine();
 }
 
 void
@@ -111,12 +88,6 @@ OpenSLLayer::startStream()
     emitSignal<DRing::ConfigurationSignal::GetHardwareAudioFormat>(&hw_infos);
     hardwareFormat_ = AudioFormat(hw_infos[0], 1); // Mono on Android
     hardwareBuffSize_ = hw_infos[1];
-
-    for(auto& buf : playbackBufferStack_)
-        buf.resize(hardwareBuffSize_);
-    for(auto& buf : recordBufferStack_)
-        buf.resize(hardwareBuffSize_);
-
     hardwareFormatAvailable(hardwareFormat_);
 
     std::thread launcher([this](){
@@ -150,388 +121,256 @@ OpenSLLayer::stopStream()
 
     flushMain();
     flushUrgent();
-}
-
-void
-OpenSLLayer::initAudioEngine() const
-{
-    SLresult result;
-
-    RING_DBG("Create Audio Engine\n");
-    result = slCreateEngine((const SLObjectItf_ * const **)&engineObject_, 0, nullptr, 0, nullptr, nullptr);
-    assert(SL_RESULT_SUCCESS == result);
 
-    RING_DBG("Realize Audio Engine\n");
-    result = (*engineObject_)->Realize(engineObject_, SL_BOOLEAN_FALSE);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Create Audio Engine Interface\n");
-    result = (*engineObject_)->GetInterface(engineObject_, SL_IID_ENGINE,
-                                            (void *)&engineInterface_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Create Output Mixer\n");
-    result = (*engineInterface_)->CreateOutputMix(engineInterface_,
-                                                  (const SLObjectItf_ * const **)&outputMixer_,
-                                                  0, nullptr, nullptr);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Realize Output Mixer\n");
-    result = (*outputMixer_)->Realize(outputMixer_, SL_BOOLEAN_FALSE);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Audio Engine Initialization Done\n");
-}
-
-void
-OpenSLLayer::shutdownAudioEngine()
-{
-
-    // destroy buffer queue audio player object, and invalidate all associated interfaces
-    RING_DBG("Shutdown audio player\n");
-
-    if (playerObject_ != nullptr) {
-        (*playerObject_)->Destroy(playerObject_);
-        playerObject_ = nullptr;
-        playerInterface_ = nullptr;
-        playbackBufferQueue_ = nullptr;
-    }
-
-    // destroy output mix object, and invalidate all associated interfaces
-    RING_DBG("Shutdown audio mixer\n");
-
-    if (outputMixer_ != nullptr) {
-        (*outputMixer_)->Destroy(outputMixer_);
-        outputMixer_ = nullptr;
-    }
-
-    if (recorderObject_ != nullptr) {
-        (*recorderObject_)->Destroy(recorderObject_);
-        recorderObject_ = nullptr;
-        recorderInterface_ = nullptr;
-        recorderBufferQueue_ = nullptr;
-    }
-
-    // destroy engine object, and invalidate all associated interfaces
-    RING_DBG("Shutdown audio engine\n");
     if (engineObject_ != nullptr) {
         (*engineObject_)->Destroy(engineObject_);
         engineObject_ = nullptr;
         engineInterface_ = nullptr;
     }
+
+    freePlayBufQueue_.clear();
+    freeRingBufQueue_.clear();
+    playBufQueue_.clear();
+    ringBufQueue_.clear();
+    freeRecBufQueue_.clear();
+    recBufQueue_.clear();
+    bufs_.clear();
 }
 
 void
-OpenSLLayer::initAudioPlayback() const
+OpenSLLayer::initAudioEngine()
 {
-    assert(nullptr != engineObject_);
-    assert(nullptr != engineInterface_);
-    assert(nullptr != outputMixer_);
-
     SLresult result;
 
-    // Initialize the location of the buffer queue
-    RING_DBG("Create playback queue\n");
-    SLDataLocator_AndroidSimpleBufferQueue bufferLocation = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
-                                                            NB_BUFFER_PLAYBACK_QUEUE
-                                                            };
-
-    // Initnialize the audio format for this queue
-    RING_DBG("Setting audio format\n");
-    SLDataFormat_PCM audioFormat = {SL_DATAFORMAT_PCM,
-                                    1,
-                                    audioFormat_.sample_rate * 1000,
-                                    SL_PCMSAMPLEFORMAT_FIXED_16,
-                                    SL_PCMSAMPLEFORMAT_FIXED_16,
-                                    SL_SPEAKER_FRONT_CENTER,
-                                    SL_BYTEORDER_LITTLEENDIAN
-                                   };
-
-    // Create the audio source
-    RING_DBG("Set Audio Sources\n");
-    SLDataSource audioSource = {&bufferLocation, &audioFormat};
-
-    RING_DBG("Get Output Mixer interface\n");
-    result = (*outputMixer_)->GetInterface(outputMixer_, SL_IID_OUTPUTMIX,
-                                           (void *)&outputMixInterface_);
-    CheckErr(result);
-
-    // Cofiguration fo the audio sink as an output mixer
-    RING_DBG("Set output mixer location\n");
-    SLDataLocator_OutputMix mixerLocation = {SL_DATALOCATOR_OUTPUTMIX, outputMixer_};
-    SLDataSink audioSink = {&mixerLocation, nullptr};
-
-    const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
-                                 SL_IID_VOLUME,
-                                 SL_IID_ANDROIDCONFIGURATION,
-                                 SL_IID_PLAY};
-    const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
-
-    const unsigned nbInterface = arraySize(ids);
-
-    // create audio player
-    RING_DBG("Create audio player\n");
-    result = (*engineInterface_)->CreateAudioPlayer(engineInterface_,
-                                                    (const SLObjectItf_ * const **)&playerObject_,
-                                                    &audioSource,
-                                                    &audioSink,
-                                                    nbInterface,
-                                                    ids, req);
-    assert(SL_RESULT_SUCCESS == result);
-
-    SLAndroidConfigurationItf playerConfig;
-    SLint32 streamType = SL_ANDROID_STREAM_VOICE;
-
+    result = slCreateEngine(&engineObject_, 0, nullptr, 0, nullptr, nullptr);
+    SLASSERT(result);
 
-    result = (*playerObject_)->GetInterface(playerObject_,
-                                            SL_IID_ANDROIDCONFIGURATION,
-                                            (void *)&playerConfig);
-
-    if (result == SL_RESULT_SUCCESS && playerConfig) {
-        result = (*playerConfig)->SetConfiguration(
-                     playerConfig, SL_ANDROID_KEY_STREAM_TYPE,
-                     &streamType, sizeof(SLint32));
-    }
-
-    RING_DBG("Realize audio player\n");
-    result = (*playerObject_)->Realize(playerObject_, SL_BOOLEAN_FALSE);
-    assert(SL_RESULT_SUCCESS == result);
-
-    if (result != SL_RESULT_SUCCESS) {
-        RING_ERR("Unable to set android player configuration");
-    }
-
-    // create audio interface
-    RING_DBG("Create audio player interface\n");
-    result = (*playerObject_)->GetInterface(playerObject_, SL_IID_PLAY,
-                                            (void *)&playerInterface_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    // create the buffer queue interface
-    RING_DBG("Create buffer queue interface\n");
-    result = (*playerObject_)->GetInterface(playerObject_, SL_IID_BUFFERQUEUE,
-                                            (void *)&playbackBufferQueue_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    // register the buffer queue on the buffer object
-    RING_DBG("Register audio callback\n");
-    result = (*playbackBufferQueue_)->RegisterCallback(playbackBufferQueue_,
-                                                       audioPlaybackCallback,
-                                                       (void *)this);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Audio Playback Initialization Done\n");
+    result = (*engineObject_)->Realize(engineObject_, SL_BOOLEAN_FALSE);
+    SLASSERT(result);
+
+    result = (*engineObject_)->GetInterface(engineObject_, SL_IID_ENGINE, &engineInterface_);
+    SLASSERT(result);
+
+    uint32_t bufSize = hardwareBuffSize_ * hardwareFormat_.getBytesPerFrame();
+    bufs_ = allocateSampleBufs(BUF_COUNT*3, bufSize);
+    for(int i=0; i<BUF_COUNT; i++)
+        freePlayBufQueue_.push(&bufs_[i]);
+    for(int i=BUF_COUNT; i<2*BUF_COUNT; i++)
+        freeRingBufQueue_.push(&bufs_[i]);
+    for(int i=2*BUF_COUNT; i<3*BUF_COUNT; i++)
+        freeRecBufQueue_.push(&bufs_[i]);
 }
 
 void
-OpenSLLayer::initAudioCapture() const
+OpenSLLayer::shutdownAudioEngine()
 {
-    SLresult result;
+    // destroy engine object, and invalidate all associated interfaces
+    RING_DBG("Shutdown audio engine");
+    stopStream();
+}
 
-    // configure audio source
-    RING_DBG("Configure audio source\n");
-    SLDataLocator_IODevice deviceLocator = {SL_DATALOCATOR_IODEVICE,
-                                            SL_IODEVICE_AUDIOINPUT,
-                                            SL_DEFAULTDEVICEID_AUDIOINPUT,
-                                            nullptr
-                                           };
-
-    SLDataSource audioSource = {&deviceLocator,
-                                nullptr
-                               };
-
-    // configure audio sink
-    RING_DBG("Configure audio sink\n");
-
-    SLDataLocator_AndroidSimpleBufferQueue bufferLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
-                                           NB_BUFFER_CAPTURE_QUEUE
-                                                           };
-
-    RING_DBG("Capture-> Sampling Rate: %d", audioFormat_.sample_rate);
-    RING_DBG("Capture-> getInternalSamplingRate: %d", Manager::instance().getRingBufferPool().getInternalSamplingRate());
-    SLDataFormat_PCM audioFormat = {SL_DATAFORMAT_PCM, 1,
-                                    audioFormat_.sample_rate * 1000,
-                                    SL_PCMSAMPLEFORMAT_FIXED_16,
-                                    SL_PCMSAMPLEFORMAT_FIXED_16,
-                                    SL_SPEAKER_FRONT_CENTER,
-                                    SL_BYTEORDER_LITTLEENDIAN
-                                   };
-
-    SLDataSink audioSink = {&bufferLocator,
-                            &audioFormat
-                           };
-
-    // create audio recorder
-    // (requires the RECORD_AUDIO permission)
-    RING_DBG("Create audio recorder\n");
-    const SLInterfaceID id[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
-                                SL_IID_ANDROIDCONFIGURATION};
-    const SLboolean req[2] ={SL_BOOLEAN_TRUE,
-                             SL_BOOLEAN_TRUE};
-    SLAndroidConfigurationItf recorderConfig;
-
-    if (engineInterface_ != nullptr) {
-        result = (*engineInterface_)->CreateAudioRecorder(engineInterface_,
-                                                          (const SLObjectItf_ * const **)&recorderObject_,
-                                                          &audioSource,
-                                                          &audioSink,
-                                                          2, id, req);
+uint32_t
+OpenSLLayer::dbgEngineGetBufCount() {
+    uint32_t count_player = player_->dbgGetDevBufCount();
+    count_player += freePlayBufQueue_.size();
+    count_player += playBufQueue_.size();
+
+    uint32_t count_ringtone = ringtone_->dbgGetDevBufCount();
+    count_ringtone += freeRingBufQueue_.size();
+    count_ringtone += ringBufQueue_.size();
+
+    RING_ERR("Buf Disrtibutions: PlayerDev=%d, PlayQ=%d, FreePlayQ=%d",
+         player_->dbgGetDevBufCount(),
+         playBufQueue_.size(),
+         freePlayBufQueue_.size());
+    RING_ERR("Buf Disrtibutions: RingDev=%d, RingQ=%d, FreeRingQ=%d",
+         ringtone_->dbgGetDevBufCount(),
+         ringBufQueue_.size(),
+         freeRingBufQueue_.size());
+
+    if(count_player != BUF_COUNT) {
+        RING_ERR("====Lost Bufs among the queue(supposed = %d, found = %d)",
+             BUF_COUNT, count_player);
     }
+    return count_player;
+}
 
-    if (SL_RESULT_SUCCESS != result) {
-        RING_DBG("Error: could not create audio recorder");
-        return;
+bool
+OpenSLLayer::engineServicePlay(bool waiting) {
+    if (waiting) {
+        playCv.notify_one();
+        return false;
     }
-
-    /* Set Android configuration */
-    result = (*recorderObject_)->GetInterface(recorderObject_,
-                                                SL_IID_ANDROIDCONFIGURATION,
-                                                (void *)&recorderConfig);
-    if (result == SL_RESULT_SUCCESS) {
-       SLint32 streamType = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
-       result = (*recorderConfig)->SetConfiguration(
-                recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET,
-                &streamType, sizeof(SLint32));
+    sample_buf* buf;
+    while (player_ and freePlayBufQueue_.front(&buf)) {
+        const AudioBuffer& dat = getToPlay(hardwareFormat_, hardwareBuffSize_);
+        if (dat.frames() != 0) {
+            buf->size_ = dat.interleave((AudioSample*)buf->buf_) * sizeof(AudioSample);
+            if (!playBufQueue_.push(buf)) {
+                RING_WARN("playThread player_ PLAY_KICKSTART_BUFFER_COUNT 1");
+                break;
+            } else
+                freePlayBufQueue_.pop();
+        } else
+            break;
     }
+    return true;
+}
 
-    if (result != SL_RESULT_SUCCESS) {
-        RING_DBG("Warning: Unable to set android recorder configuration");
-        return;
+bool
+OpenSLLayer::engineServiceRing(bool waiting) {
+    if (waiting) {
+        playCv.notify_one();
+        return false;
     }
-
-    // realize the audio recorder
-    RING_DBG("Realize the audio recorder\n");
-    result = (*recorderObject_)->Realize(recorderObject_, SL_BOOLEAN_FALSE);
-
-    if (SL_RESULT_SUCCESS != result) {
-        RING_DBG("Error: could not realize audio recorder");
-        return;
+    sample_buf* buf;
+    while (ringtone_ and freeRingBufQueue_.front(&buf)) {
+        freeRingBufQueue_.pop();
+        const AudioBuffer& dat = getToRing(hardwareFormat_, hardwareBuffSize_);
+        if (dat.frames() != 0) {
+            buf->size_ = dat.interleave((AudioSample*)buf->buf_) * sizeof(AudioSample);
+            if (!ringBufQueue_.push(buf)) {
+                RING_WARN("playThread ringtone_ PLAY_KICKSTART_BUFFER_COUNT 1");
+                freeRingBufQueue_.push(buf);
+                break;
+            }
+        } else {
+            freeRingBufQueue_.push(buf);
+            break;
+        }
     }
+    return true;
+}
 
-    // get the record interface
-    RING_DBG("Create the record interface\n");
-    result = (*recorderObject_)->GetInterface(recorderObject_,
-                                              SL_IID_RECORD,
-                                              (void *)&recorderInterface_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    // get the buffer queue interface
-    RING_DBG("Create the buffer queue interface\n");
-    result = (*recorderObject_)->GetInterface(recorderObject_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
-             (void *)&recorderBufferQueue_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    // register callback on the buffer queue
-    RING_DBG("Register the audio capture callback\n");
-    result = (*recorderBufferQueue_)->RegisterCallback(recorderBufferQueue_,
-                                                       audioCaptureCallback,
-                                                       (void *)this);
-    assert(SL_RESULT_SUCCESS == result);
+bool
+OpenSLLayer::engineServiceRec(bool waiting) {
+    playCv.notify_one();
+    recCv.notify_one();
+    return true;
+}
 
-    RING_DBG("Audio capture initialized\n");
+void
+OpenSLLayer::initAudioPlayback()
+{
+    using namespace std::placeholders;
+    std::lock_guard<std::mutex> lck(playMtx);
+    player_.reset(new opensl::AudioPlayer(hardwareFormat_, engineInterface_, SL_ANDROID_STREAM_VOICE));
+    player_->setBufQueue(&playBufQueue_, &freePlayBufQueue_);
+    player_->registerCallback(std::bind(&OpenSLLayer::engineServicePlay, this, _1));
+
+    ringtone_.reset(new opensl::AudioPlayer(hardwareFormat_, engineInterface_, SL_ANDROID_STREAM_VOICE));
+    ringtone_->setBufQueue(&ringBufQueue_, &freeRingBufQueue_);
+    ringtone_->registerCallback(std::bind(&OpenSLLayer::engineServiceRing, this, _1));
 }
 
+void
+OpenSLLayer::initAudioCapture()
+{
+    using namespace std::placeholders;
+    std::lock_guard<std::mutex> lck(recMtx);
+    recorder_.reset(new opensl::AudioRecorder(hardwareFormat_, engineInterface_));
+    recorder_->setBufQueues(&freeRecBufQueue_, &recBufQueue_);
+    recorder_->registerCallback(std::bind(&OpenSLLayer::engineServiceRec, this, _1));
+}
 
 void
 OpenSLLayer::startAudioPlayback()
 {
-    assert(nullptr != playbackBufferQueue_);
-
-    RING_DBG("Start audio playback\n");
-
-    SLresult result;
-
-    for (int i = 0; i < NB_BUFFER_PLAYBACK_QUEUE; i++) {
-        AudioBuffer &buffer = getNextPlaybackBuffer();
-        incrementPlaybackIndex();
-
-        buffer.reset();
-
-        result = (*playbackBufferQueue_)->Enqueue(playbackBufferQueue_, buffer.getChannel(0)->data(), buffer.frames());
-
-        if (SL_RESULT_SUCCESS != result) {
-            RING_DBG("Error could not enqueue initial buffers\n");
+    RING_WARN("Start audio playback");
+
+    player_->start();
+    ringtone_->start();
+    playThread = std::thread([&]() {
+        std::unique_lock<std::mutex> lck(playMtx);
+        while (player_ || ringtone_) {
+            playCv.wait(lck);
+            if (player_ && player_->waiting_) {
+                std::lock_guard<std::mutex> lk(player_->m_);
+                engineServicePlay(false);
+                auto n = playBufQueue_.size();
+                if (n >= PLAY_KICKSTART_BUFFER_COUNT)
+                    player_->playAudioBuffers(n);
+            }
+            if (ringtone_ && ringtone_->waiting_) {
+                std::lock_guard<std::mutex> lk(ringtone_->m_);
+                engineServiceRing(false);
+                auto n = ringBufQueue_.size();
+                if (n >= PLAY_KICKSTART_BUFFER_COUNT)
+                    ringtone_->playAudioBuffers(n);
+            }
         }
-    }
-
-    result = (*playerInterface_)->SetPlayState(playerInterface_, SL_PLAYSTATE_PLAYING);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("Audio playback started\n");
+    });
+    RING_WARN("Audio playback started");
 }
 
 void
 OpenSLLayer::startAudioCapture()
 {
-    assert(nullptr != playbackBufferQueue_);
-
-    RING_DBG("Start audio capture\n");
-
-    SLresult result;
-
-
-    // in case already recording, stop recording and clear buffer queue
-    if (recorderInterface_ != nullptr) {
-        result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED);
-        assert(SL_RESULT_SUCCESS == result);
-    }
-
-    RING_DBG("Clearing recorderBufferQueue\n");
-    result = (*recorderBufferQueue_)->Clear(recorderBufferQueue_);
-    assert(SL_RESULT_SUCCESS == result);
-
-    RING_DBG("getting next record buffer\n");
-    // enqueue an empty buffer to be filled by the recorder
-    // (for streaming recording, we enqueue at least 2 empty buffers to start things off)
-    AudioBuffer &buffer = getNextRecordBuffer();
-    incrementRecordIndex();
-
-    buffer.reset();
-
-    RING_DBG("Enqueue record buffer\n");
-    result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getChannel(0)->data(), buffer.frames());
-
-    // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
-    // which for this code example would indicate a programming error
-    if (SL_RESULT_SUCCESS != result) {
-        RING_DBG("Error could not enqueue buffers in audio capture\n");
-        return;
-    }
-
-    // start recording
-    result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_RECORDING);
-    assert(SL_RESULT_SUCCESS == result);
+    RING_DBG("Start audio capture");
+
+    recorder_->start();
+    recThread = std::thread([&]() {
+        std::unique_lock<std::mutex> lck(recMtx);
+        while (recorder_) {
+            recCv.wait(lck);
+            while (true) {
+                sample_buf *buf;
+                if(!recBufQueue_.front(&buf))
+                    break;
+                recBufQueue_.pop();
+                if (buf->size_ > 0) {
+                    AudioBuffer dat {(const AudioSample*)buf->buf_, buf->size_ / hardwareFormat_.getBytesPerFrame(), hardwareFormat_};
+                    audioCaptureFillBuffer(dat);
+                }
+                buf->size_ = 0;
+                freeRecBufQueue_.push(buf);
+            }
+        }
+    });
 
-    RING_DBG("Audio capture started\n");
+    RING_DBG("Audio capture started");
 }
 
 void
 OpenSLLayer::stopAudioPlayback()
 {
-    RING_DBG("Stop audio playback\n");
+    RING_DBG("Stop audio playback");
 
-    if (playerInterface_ != nullptr) {
-        SLresult result;
-        result = (*playerInterface_)->SetPlayState(playerInterface_, SL_PLAYSTATE_STOPPED);
-        assert(SL_RESULT_SUCCESS == result);
+    {
+        std::lock_guard<std::mutex> lck(playMtx);
+        if (player_) {
+            player_->stop();
+            player_.reset();
+        }
+        if (ringtone_) {
+            ringtone_->stop();
+            ringtone_.reset();
+        }
+    }
+    if (playThread.joinable()) {
+        playCv.notify_all();
+        playThread.join();
     }
 
-    RING_DBG("Audio playback stopped\n");
+    RING_DBG("Audio playback stopped");
 }
 
 void
 OpenSLLayer::stopAudioCapture()
 {
-    RING_DBG("Stop audio capture\n");
+    RING_DBG("Stop audio capture");
 
-    if (recorderInterface_ != nullptr) {
-        SLresult result;
-        result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED);
-        assert(SL_RESULT_SUCCESS == result);
+    {
+        std::lock_guard<std::mutex> lck(recMtx);
+        recorder_->stop();
+        recorder_.reset();
+    }
+    if (recThread.joinable()) {
+        recCv.notify_all();
+        recThread.join();
     }
 
-    RING_DBG("Audio capture stopped\n");
-
+    RING_DBG("Audio capture stopped");
 }
 
 std::vector<std::string>
@@ -539,12 +378,10 @@ OpenSLLayer::getCaptureDeviceList() const
 {
     std::vector<std::string> captureDeviceList;
 
-
-
-// Although OpenSL ES specification allows enumerating
-// available output (and also input) devices, NDK implementation is not mature enough to
-// obtain or select proper one (SLAudioIODeviceCapabilitiesItf, the official interface
-// to obtain such an information)-> SL_FEATURE_UNSUPPORTED
+    // Although OpenSL ES specification allows enumerating
+    // available output (and also input) devices, NDK implementation is not mature enough to
+    // obtain or select proper one (SLAudioIODeviceCapabilitiesItf, the official interface
+    // to obtain such an information)-> SL_FEATURE_UNSUPPORTED
 
     SLuint32 InputDeviceIDs[MAX_NUMBER_INPUT_DEVICES];
     SLint32 numInputs = 0;
@@ -553,41 +390,39 @@ OpenSLLayer::getCaptureDeviceList() const
 
     SLresult res;
 
-    initAudioEngine();
-    initAudioPlayback();
-    initAudioCapture();
-
-
     // Get the Audio IO DEVICE CAPABILITIES interface, implicit
     RING_DBG("Get the Audio IO DEVICE CAPABILITIES interface, implicit");
 
     res = (*engineObject_)->GetInterface(engineObject_, SL_IID_AUDIOIODEVICECAPABILITIES, (void*)&AudioIODeviceCapabilitiesItf);
-    CheckErr(res);
+    if (res != SL_RESULT_SUCCESS)
+        return captureDeviceList;
 
     RING_DBG("Get the Audio IO DEVICE CAPABILITIES interface, implicit");
     numInputs = MAX_NUMBER_INPUT_DEVICES;
 
     res = (*AudioIODeviceCapabilitiesItf)->GetAvailableAudioInputs(AudioIODeviceCapabilitiesItf, &numInputs, InputDeviceIDs);
-    CheckErr(res);
+    if (res != SL_RESULT_SUCCESS)
+        return captureDeviceList;
 
     // Search for either earpiece microphone or headset microphone input
     // device - with a preference for the latter
     for (int i = 0; i < numInputs; i++) {
         res = (*AudioIODeviceCapabilitiesItf)->QueryAudioInputCapabilities(AudioIODeviceCapabilitiesItf,
                                                                            InputDeviceIDs[i],
-                                                                           (SLAudioInputDescriptor *)&AudioInputDescriptor);
-        CheckErr(res);
+                                                                           (SLAudioInputDescriptor_ *)&audioInputDescriptor_);
+        if (res != SL_RESULT_SUCCESS)
+            return captureDeviceList;
 
-        if (AudioInputDescriptor.deviceConnection == SL_DEVCONNECTION_ATTACHED_WIRED and
-            AudioInputDescriptor.deviceScope == SL_DEVSCOPE_USER and
-            AudioInputDescriptor.deviceLocation == SL_DEVLOCATION_HEADSET) {
+        if (audioInputDescriptor_.deviceConnection == SL_DEVCONNECTION_ATTACHED_WIRED and
+            audioInputDescriptor_.deviceScope == SL_DEVSCOPE_USER and
+            audioInputDescriptor_.deviceLocation == SL_DEVLOCATION_HEADSET) {
             RING_DBG("SL_DEVCONNECTION_ATTACHED_WIRED : mic_deviceID: %d", InputDeviceIDs[i] );
             mic_deviceID = InputDeviceIDs[i];
             mic_available = SL_BOOLEAN_TRUE;
             break;
-        } else if (AudioInputDescriptor.deviceConnection == SL_DEVCONNECTION_INTEGRATED and
-                   AudioInputDescriptor.deviceScope == SL_DEVSCOPE_USER and
-                   AudioInputDescriptor.deviceLocation == SL_DEVLOCATION_HANDSET) {
+        } else if (audioInputDescriptor_.deviceConnection == SL_DEVCONNECTION_INTEGRATED and
+                   audioInputDescriptor_.deviceScope == SL_DEVSCOPE_USER and
+                   audioInputDescriptor_.deviceLocation == SL_DEVLOCATION_HANDSET) {
             RING_DBG("SL_DEVCONNECTION_INTEGRATED : mic_deviceID: %d", InputDeviceIDs[i] );
             mic_deviceID = InputDeviceIDs[i];
             mic_available = SL_BOOLEAN_TRUE;
@@ -595,133 +430,26 @@ OpenSLLayer::getCaptureDeviceList() const
         }
     }
 
-    if (!mic_available) {
-        // Appropriate error message here
-        RING_ERR("No mic available quitting");
-        exit(1);
-    }
-
+    if (!mic_available)
+        RING_ERR("No mic available");
 
     return captureDeviceList;
 }
 
-/* Checks for error. If any errors exit the application! */
-void
-OpenSLLayer::CheckErr( SLresult res ) const
-{
-    if (res != SL_RESULT_SUCCESS) {
-        // Debug printing to be placed here
-        exit(1);
-    }
-}
-
 std::vector<std::string>
 OpenSLLayer::getPlaybackDeviceList() const
 {
     std::vector<std::string> playbackDeviceList;
-
     return playbackDeviceList;
 }
 
 void
-OpenSLLayer::audioPlaybackCallback(SLAndroidSimpleBufferQueueItf queue, void *context)
-{
-    assert(nullptr != context);
-    //auto start = std::chrono::high_resolution_clock::now();
-    static_cast<OpenSLLayer*>(context)->playback(queue);
-    //auto end = std::chrono::high_resolution_clock::now();
-    //auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
-    //RING_DBG("Took %d us\n", elapsed/1000);
-}
-
-void
-OpenSLLayer::playback(SLAndroidSimpleBufferQueueItf queue)
-{
-    assert(nullptr != queue);
-    notifyIncomingCall();
-
-    AudioBuffer &buffer = getNextPlaybackBuffer();
-    size_t urgentSamplesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID);
-
-    bufferIsFilled_ = false;
-    if (urgentSamplesToGet > 0) {
-        bufferIsFilled_ = audioPlaybackFillWithUrgent(buffer, std::min(urgentSamplesToGet, hardwareBuffSize_));
-    } else {
-        auto& main_buffer = Manager::instance().getRingBufferPool();
-        buffer.resize(hardwareBuffSize_);
-        size_t samplesToGet = audioPlaybackFillWithVoice(buffer);
-        if (samplesToGet == 0) {
-            bufferIsFilled_ = audioPlaybackFillWithToneOrRingtone(buffer);
-        } else {
-            bufferIsFilled_ = true;
-        }
-    }
-
-    if (bufferIsFilled_) {
-        SLresult result = (*queue)->Enqueue(queue, buffer.getChannel(0)->data(), buffer.frames()*sizeof(AudioSample));
-        if (SL_RESULT_SUCCESS != result) {
-            RING_DBG("Error could not enqueue buffers in playback callback\n");
-        }
-        incrementPlaybackIndex();
-    } else {
-        RING_DBG("Error buffer not filled in audio playback\n");
-    }
-}
-
-void
-OpenSLLayer::audioCaptureCallback(SLAndroidSimpleBufferQueueItf queue, void *context)
-{
-    assert(nullptr != context);
-    static_cast<OpenSLLayer*>(context)->capture(queue);
-}
-
-void
-OpenSLLayer::capture(SLAndroidSimpleBufferQueueItf queue)
-{
-    assert(nullptr != queue);
-
-    AudioBuffer &old_buffer = getNextRecordBuffer();
-    incrementRecordIndex();
-    AudioBuffer &buffer = getNextRecordBuffer();
-
-    SLresult result;
-    // enqueue an empty buffer to be filled by the recorder
-    // (for streaming recording, we enqueue at least 2 empty buffers to start things off)
-    result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.getChannel(0)->data(), buffer.frames()*sizeof(AudioSample));
-
-    audioCaptureFillBuffer(old_buffer);
-
-    // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
-    // which for this code example would indicate a programming error
-    assert(SL_RESULT_SUCCESS == result);
-}
-
-
-
-void
-OpenSLLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
-{
-#ifdef OUTSIDE_TESTING
-
-    switch (type) {
-        case Device::PLAYBACK:
-            break;
-
-        case Device::CAPTURE:
-            break;
-
-        case Device::RINGTONE:
-            break;
-    }
-
-#endif
-}
+OpenSLLayer::updatePreference(AudioPreference& /*preference*/, int /*index*/, DeviceType /*type*/)
+{}
 
 void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer)
 {
     RingBufferPool &mbuffer = Manager::instance().getRingBufferPool();
-
-    //const unsigned mainBufferSampleRate = mbuffer.getInternalSamplingRate();
     const AudioFormat mainBufferFormat = mbuffer.getInternalAudioFormat();
     const bool resample = mainBufferFormat.sample_rate != audioFormat_.sample_rate;
 
@@ -739,66 +467,17 @@ void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer)
     }
 }
 
-bool OpenSLLayer::audioPlaybackFillWithToneOrRingtone(AudioBuffer &buffer)
-{
-    buffer.resize(hardwareBuffSize_);
-    AudioLoop *tone = Manager::instance().getTelephoneTone();
-    AudioLoop *file_tone = Manager::instance().getTelephoneFile();
-
-    // In case of a dtmf, the pointers will be set to nullptr once the dtmf length is
-    // reached. For this reason we need to fill audio buffer with zeros if pointer is nullptr
-    if (tone) {
-        tone->getNext(buffer, playbackGain_);
-    } else if (file_tone) {
-        file_tone->getNext(buffer, playbackGain_);
-    } else {
-        buffer.reset();
-    }
-
-    return true;
-}
-
-bool OpenSLLayer::audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t samplesToGet)
-{
-    // Urgent data (dtmf, incoming call signal) come first.
-    samplesToGet = std::min(samplesToGet, hardwareBuffSize_);
-    buffer.resize(samplesToGet);
-    urgentRingBuffer_.get(buffer, RingBufferPool::DEFAULT_ID);
-    buffer.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
-
-    // Consume the regular one as well (same amount of samples)
-    Manager::instance().getRingBufferPool().discard(samplesToGet, RingBufferPool::DEFAULT_ID);
-
-    return true;
-}
-
-size_t OpenSLLayer::audioPlaybackFillWithVoice(AudioBuffer &buffer)
-{
-    RingBufferPool &mainBuffer = Manager::instance().getRingBufferPool();
-    size_t got = mainBuffer.getAvailableData(buffer, RingBufferPool::DEFAULT_ID);
-    buffer.resize(got);
-    buffer.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
-    if (audioFormat_.sample_rate != mainBuffer.getInternalSamplingRate()) {
-        RING_DBG("OpenSLLayer::audioPlaybackFillWithVoice sample_rate != mainBuffer.getInternalSamplingRate() \n");
-        AudioBuffer out(buffer, false);
-        out.setSampleRate(audioFormat_.sample_rate);
-        resampler_->resample(buffer, out);
-        buffer = out;
-    }
-    return buffer.size();
-}
-
 void dumpAvailableEngineInterfaces()
 {
     SLresult result;
-    RING_DBG("Engine Interfaces\n");
+    RING_DBG("Engine Interfaces");
     SLuint32 numSupportedInterfaces;
     result = slQueryNumSupportedEngineInterfaces(&numSupportedInterfaces);
     assert(SL_RESULT_SUCCESS == result);
     result = slQueryNumSupportedEngineInterfaces(NULL);
     assert(SL_RESULT_PARAMETER_INVALID == result);
 
-    RING_DBG("Engine number of supported interfaces %lu\n", numSupportedInterfaces);
+    RING_DBG("Engine number of supported interfaces %u", numSupportedInterfaces);
     for(SLuint32 i=0; i< numSupportedInterfaces; i++){
         SLInterfaceID  pInterfaceId;
         slQuerySupportedEngineInterfaces(i, &pInterfaceId);
diff --git a/src/media/audio/opensl/opensllayer.h b/src/media/audio/opensl/opensllayer.h
index defba741bad3b07339b6492f1f1b17e04a55c400..df14ca583471c592560751acdb62e15090626b73 100644
--- a/src/media/audio/opensl/opensllayer.h
+++ b/src/media/audio/opensl/opensllayer.h
@@ -24,8 +24,11 @@
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
 #include <vector>
+#include <thread>
 
 #include "audio/audiolayer.h"
+#include "audio_player.h"
+#include "audio_recorder.h"
 
 class AudioPreference;
 
@@ -35,7 +38,6 @@ class AudioPreference;
 
 namespace ring {
 
-class OpenSLThread;
 class RingBuffer;
 
 #define ANDROID_BUFFER_QUEUE_LENGTH 2U
@@ -87,13 +89,13 @@ class OpenSLLayer : public AudioLayer {
 
         void init();
 
-        void initAudioEngine() const;
+        void initAudioEngine();
 
         void shutdownAudioEngine();
 
-        void initAudioPlayback() const;
+        void initAudioPlayback();
 
-        void initAudioCapture() const;
+        void initAudioCapture();
 
         void startAudioPlayback();
 
@@ -111,41 +113,20 @@ class OpenSLLayer : public AudioLayer {
             return "";
         }
 
-    private:
-        typedef std::vector<AudioBuffer> AudioBufferStack;
-
-
-        bool audioBufferFillWithZeros(AudioBuffer &buffer);
-
-        /**
-         * Here fill the input buffer with tone or ringtone samples
-         */
-        bool audioPlaybackFillWithToneOrRingtone(AudioBuffer &buffer);
-
-        bool audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t bytesAvail);
-
-        size_t audioPlaybackFillWithVoice(AudioBuffer &buffer);
+        bool engineServicePlay(bool waiting);
+        bool engineServiceRing(bool waiting);
+        bool engineServiceRec(bool waiting);
 
+    private:
         void audioCaptureFillBuffer(AudioBuffer &buffer);
 
-
-        /**
-         * This is the main audio playabck callback called by the OpenSL layer
-         */
-        static void audioPlaybackCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
-
-        /**
-         * This is the main audio capture callback called by the OpenSL layer
-         */
-        static void audioCaptureCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
-
         /**
          * Get the index of the audio card for capture
          * @return int The index of the card used for capture
          *                     0 for the first available card on the system, 1 ...
          */
         virtual int getIndexCapture() const {
-            return indexIn_;
+            return 0;
         }
 
         /**
@@ -154,7 +135,7 @@ class OpenSLLayer : public AudioLayer {
          *                     0 for the first available card on the system, 1 ...
          */
         virtual int getIndexPlayback() const {
-            return indexOut_;
+            return 0;
         }
 
         /**
@@ -163,99 +144,56 @@ class OpenSLLayer : public AudioLayer {
          *                 0 for the first available card on the system, 1 ...
          */
         virtual int getIndexRingtone() const {
-            return indexRing_;
-        }
-
-        AudioBuffer &getNextPlaybackBuffer(void) {
-            return playbackBufferStack_[playbackBufferIndex_];
-        }
-
-        AudioBuffer &getNextRecordBuffer(void) {
-            return recordBufferStack_[recordBufferIndex_];
-        }
-
-        void incrementPlaybackIndex(void) {
-            playbackBufferIndex_ = (playbackBufferIndex_ + 1) % NB_BUFFER_PLAYBACK_QUEUE;
-        }
-
-        void incrementRecordIndex(void) {
-            recordBufferIndex_ = (recordBufferIndex_ + 1) % NB_BUFFER_CAPTURE_QUEUE;
+            return 0;
         }
 
-        void CheckErr( SLresult res ) const;
-
-        void playback(SLAndroidSimpleBufferQueueItf queue);
-        void capture(SLAndroidSimpleBufferQueueItf queue);
+        uint32_t dbgEngineGetBufCount();
 
         void dumpAvailableEngineInterfaces();
-        friend class OpenSLThread;
-
-        static const int NB_BUFFER_PLAYBACK_QUEUE;
-
-        static const int NB_BUFFER_CAPTURE_QUEUE;
-
-        /**
-         * Number of audio cards on which capture stream has been opened
-         */
-        int indexIn_;
-
-        /**
-         * Number of audio cards on which playback stream has been opened
-         */
-        int indexOut_;
-
-        /**
-         * Number of audio cards on which ringtone stream has been opened
-         */
-        int indexRing_;
 
         NON_COPYABLE(OpenSLLayer);
 
         virtual void updatePreference(AudioPreference &pref, int index, DeviceType type);
 
-        OpenSLThread *audioThread_;
-
         /**
          * OpenSL standard object interface
          */
-        SLObjectItf engineObject_;
+        SLObjectItf engineObject_ {nullptr};
 
         /**
          * OpenSL sound engine interface
          */
-        SLEngineItf engineInterface_;
+        SLEngineItf engineInterface_ {nullptr};
 
-        /**
-         * Output mix interface
-         */
-        SLObjectItf outputMixer_;
-        SLObjectItf playerObject_;
-        SLObjectItf recorderObject_;
+        std::unique_ptr<opensl::AudioPlayer> player_ {};
+        std::unique_ptr<opensl::AudioPlayer> ringtone_ {};
+        std::unique_ptr<opensl::AudioRecorder> recorder_ {};
 
+        AudioQueue     freePlayBufQueue_ {BUF_COUNT};
+        AudioQueue     playBufQueue_ {BUF_COUNT};
 
-        SLOutputMixItf outputMixInterface_;
-        SLPlayItf playerInterface_;
+        AudioQueue     freeRingBufQueue_ {BUF_COUNT};
+        AudioQueue     ringBufQueue_ {BUF_COUNT};
 
-        SLRecordItf recorderInterface_;
+        std::thread    playThread;
+        std::mutex     playMtx;
+        std::condition_variable playCv;
 
-        SLAudioIODeviceCapabilitiesItf AudioIODeviceCapabilitiesItf;
-        SLAudioInputDescriptor AudioInputDescriptor;
+        AudioQueue     freeRecBufQueue_ {BUF_COUNT};    //Owner of the queue
+        AudioQueue     recBufQueue_ {BUF_COUNT};     //Owner of the queue
 
-        /**
-         * OpenSL playback buffer
-         */
-        SLAndroidSimpleBufferQueueItf playbackBufferQueue_;
-        SLAndroidSimpleBufferQueueItf recorderBufferQueue_;
+        std::thread    recThread;
+        std::mutex     recMtx;
+        std::condition_variable recCv;
+
+        std::vector<sample_buf> bufs_;
 
-        int playbackBufferIndex_;
-        int recordBufferIndex_;
+        SLAudioIODeviceCapabilitiesItf AudioIODeviceCapabilitiesItf {nullptr};
+        SLAudioInputDescriptor audioInputDescriptor_;
 
-        bool bufferIsFilled_;
-        AudioFormat hardwareFormat_;
-        size_t hardwareBuffSize_;
+        AudioFormat hardwareFormat_ {AudioFormat::MONO()};
+        size_t hardwareBuffSize_ {BUFFER_SIZE};
 
-        AudioBufferStack playbackBufferStack_;
-        AudioBufferStack recordBufferStack_;
         std::shared_ptr<RingBuffer> mainRingBuffer_;
 };