diff --git a/.gitignore b/.gitignore
index c332f108424624b6348f9774784a40aa88e2bbac..ac09f4b9dde5d2bbfb0e4bcef482eb31cd357afd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,3 +84,6 @@ nbproject
 
 # Windows
 *.exe
+
+# Mac
+.DS_Store
diff --git a/daemon/.gitignore b/daemon/.gitignore
index 9e296754491b0c8242b2924550a3ca437c9b05f1..135e9127e6a26dff6501e7c8632d9970d85f87c2 100644
--- a/daemon/.gitignore
+++ b/daemon/.gitignore
@@ -5,4 +5,3 @@ configure
 bin/dbus/*.adaptor.h
 bin/dbus/org.sflphone.SFLphone.service
 bin/sflphoned
-.DS_Store
diff --git a/daemon/bin/osxmain.cpp b/daemon/bin/osxmain.cpp
index ef891f4cd2a3fcfc7e96cd8f321c7ee99421c38c..b88e2ae12194c3a7d1adee54f8016d552dfa2d92 100644
--- a/daemon/bin/osxmain.cpp
+++ b/daemon/bin/osxmain.cpp
@@ -34,6 +34,7 @@
 #include <cstring>
 #include <signal.h>
 #include <getopt.h>
+#include <string>
 
 #include "sflphone.h"
 #include "fileutils.h"
@@ -129,10 +130,24 @@ static bool parse_args(int argc, char *argv[], bool &persistent)
     return quit;
 }
 
+void myOnIncomingCall(const std::string& acc_id, const std::string& call_id, const std::string& from)
+{
+    std::cout << std::endl << "INCOMING CALL!" << std::endl <<
+        "Account: " << acc_id <<
+        ", Id: " << call_id <<
+        ", From: " << from << std::endl << std::endl;
+
+    sflph_call_accept(call_id);
+    sflph_call_set_recording(call_id);
+    //sflph_call_join_participant(call_id, "patate");
+}
+
 static int osxTests()
 {
     sflph_ev_handlers evHandlers = {
-        .call_ev_handlers = {},
+        .call_ev_handlers = {
+            .on_incoming_call = myOnIncomingCall
+        },
         .config_ev_handlers = {},
 #ifdef SFL_PRESENCE
         .pres_ev_handlers = {}
@@ -145,15 +160,25 @@ static int osxTests()
     sflph_init(&evHandlers, static_cast<sflph_init_flag>(sflphFlags));
 
     sflph_call_play_dtmf("0");
-    for (auto x : sflph_config_get_audio_output_device_list())
-        std::cout << x << std::endl;
+    sleep(1);
+    sflph_call_play_dtmf("1");
+    sleep(1);
+
+    //sflph_call_place("IP2IP", "patate", "127.0.0.1");
+    //sflph_call_set_recording("patate");
+
+    while (true) {
+        sflph_poll_events();
+        sleep(1);
+    }
 
+    sflph_fini();
 }
 
 static int run()
 {
     osxTests();
-    return 1;
+    return 0;
 }
 
 static void interrupt()
diff --git a/daemon/src/audio/audiobuffer.cpp b/daemon/src/audio/audiobuffer.cpp
index 26b843ec6f07c771262bb5ac4d50c357b7e563c9..9aeab1834a9e11a04697b7f28ecd165f590f094f 100644
--- a/daemon/src/audio/audiobuffer.cpp
+++ b/daemon/src/audio/audiobuffer.cpp
@@ -154,6 +154,15 @@ void AudioBuffer::applyGain(double gain)
             sample *= g;
 }
 
+size_t AudioBuffer::channelToFloat(float* out, const int& channel) const
+{
+
+    for (int i=0, f=frames(); i < f; i++)
+        *out++ = (float) samples_[channel][i] * .000030517578125f;
+
+    return frames() * samples_.size();
+}
+
 size_t AudioBuffer::interleave(SFLAudioSample* out) const
 {
     for (unsigned i=0, f=frames(), c=channels(); i < f; ++i)
diff --git a/daemon/src/audio/audiobuffer.h b/daemon/src/audio/audiobuffer.h
index 82e23b8243eb1129128d121bf4639114bb273ca4..ac227bbcd3508d8c1fd1494aae641abea5eb0fd9 100644
--- a/daemon/src/audio/audiobuffer.h
+++ b/daemon/src/audio/audiobuffer.h
@@ -239,6 +239,14 @@ class AudioBuffer {
             return raw_data;
         }
 
+        /**
+         * Convert fixed-point channel to float and write in the out buffer (Float 32-bits).
+         * The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes.
+         *
+         * @returns Number of samples writen.
+         */
+        size_t channelToFloat(float* out, const int& channel) const;
+
         /**
          * Write interleaved multichannel data to the out buffer (fixed-point 16-bits).
          * The out buffer must be at least of size capacity()*sizeof(SFLAudioSample) bytes.
diff --git a/daemon/src/audio/coreaudio/audiodevice.h b/daemon/src/audio/coreaudio/audiodevice.h
index cae2017ae2925cf65a0732b6cc6e9dd2a357c4d2..9611e9bdd7cee8646df9b9c56991c9960dafae45 100644
--- a/daemon/src/audio/coreaudio/audiodevice.h
+++ b/daemon/src/audio/coreaudio/audiodevice.h
@@ -42,11 +42,8 @@ class AudioDevice {
 public:
     AudioDevice() : id_(kAudioDeviceUnknown) { }
     AudioDevice(AudioDeviceID devid, bool isInput);
-
     void init(AudioDeviceID devid, bool isInput);
-
     bool valid() const;
-
     void setBufferSize(UInt32 size);
 
 public:
diff --git a/daemon/src/audio/coreaudio/corelayer.cpp b/daemon/src/audio/coreaudio/corelayer.cpp
index 088200d46f78874e965db527767adf02c1164121..008ad8b71e82792f0a446457224c3a6a5476610f 100644
--- a/daemon/src/audio/coreaudio/corelayer.cpp
+++ b/daemon/src/audio/coreaudio/corelayer.cpp
@@ -31,6 +31,7 @@
 #include "corelayer.h"
 #include "manager.h"
 #include "noncopyable.h"
+#include "audio/resampler.h"
 #include "audio/ringbufferpool.h"
 #include "audio/ringbuffer.h"
 #include "audiodevice.h"
@@ -40,46 +41,6 @@
 
 namespace sfl {
 
-// Actual audio thread.
-class CoreAudioThread {
-public:
-    CoreAudioThread(CoreLayer* coreAudio);
-    ~CoreAudioThread();
-    void start();
-private:
-    NON_COPYABLE(CoreAudioThread);
-    void run();
-    std::thread thread_;
-    CoreLayer* coreAudio_;
-    std::atomic_bool running_;
-};
-
-CoreAudioThread::CoreAudioThread(CoreLayer* coreAudio)
-    : thread_(), coreAudio_(coreAudio), running_(false)
-{}
-
-CoreAudioThread::~CoreAudioThread()
-{
-    running_ = false;
-    if (thread_.joinable())
-        thread_.join();
-}
-
-void CoreAudioThread::start()
-{
-    running_ = true;
-    thread_ = std::thread(&CoreAudioThread::run, this);
-}
-
-void CoreAudioThread::run()
-{
-    // Actual playback is here.
-    while (running_) {
-
-    }
-}
-
-
 // AudioLayer implementation.
 CoreLayer::CoreLayer(const AudioPreference &pref)
     : AudioLayer(pref)
@@ -87,27 +48,32 @@ CoreLayer::CoreLayer(const AudioPreference &pref)
     , indexOut_(pref.getAlsaCardout())
     , indexRing_(pref.getAlsaCardring())
     , playbackBuff_(0, audioFormat_)
-    , captureBuff_(0, audioFormat_)
-    , playbackIBuff_(1024)
-    , captureIBuff_(1024)
-    , is_playback_prepared_(false)
-    , is_capture_prepared_(false)
+    , captureBuff_(0)
     , is_playback_running_(false)
     , is_capture_running_(false)
-    , is_playback_open_(false)
-    , is_capture_open_(false)
-    , audioThread_(nullptr)
     , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID))
 {}
 
 CoreLayer::~CoreLayer()
 {
     isStarted_ = false;
+
+    if (captureBuff_) {
+        for (UInt32 i = 0; i < captureBuff_->mNumberBuffers; ++i)
+            free(captureBuff_->mBuffers[i].mData);
+        free(captureBuff_);
+        captureBuff_ = 0;
+    }
 }
 
 std::vector<std::string> CoreLayer::getCaptureDeviceList() const
 {
-    return {};
+    std::vector<std::string> ret;
+
+    for (auto x : getDeviceList(true))
+        ret.push_back(x.name_);
+
+    return ret;
 }
 
 std::vector<std::string> CoreLayer::getPlaybackDeviceList() const
@@ -122,34 +88,350 @@ std::vector<std::string> CoreLayer::getPlaybackDeviceList() const
     return ret;
 }
 
-void CoreLayer::startStream()
+int CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
 {
-    dcblocker_.reset();
+    return 0;
+}
 
-    if (is_playback_running_ and is_capture_running_)
+std::string CoreLayer::getAudioDeviceName(int index, DeviceType type) const
+{
+    return "";
+}
+
+void CoreLayer::initAudioLayerPlayback()
+{
+    // OS X uses Audio Units for output. Steps:
+    // 1) Create a description.
+    // 2) Find the audio unit that fits that.
+    // 3) Set the audio unit callback.
+    // 4) Initialize everything.
+    // 5) Profit...
+
+    SFL_DBG("INIT AUDIO PLAYBACK");
+
+    AudioComponentDescription outputDesc = {0};
+    outputDesc.componentType = kAudioUnitType_Output;
+    outputDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
+    outputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+    AudioComponent outComp = AudioComponentFindNext(NULL, &outputDesc);
+    if (outComp == NULL) {
+        SFL_ERR("Can't find default output audio component.");
         return;
+    }
+
+    checkErr(AudioComponentInstanceNew(outComp, &outputUnit_));
+
+    AURenderCallbackStruct callback;
+    callback.inputProc = outputCallback;
+    callback.inputProcRefCon = this;
+
+    checkErr(AudioUnitSetProperty(outputUnit_,
+               kAudioUnitProperty_SetRenderCallback,
+               kAudioUnitScope_Input,
+               0,
+               &callback,
+               sizeof(callback)));
+
+    checkErr(AudioUnitInitialize(outputUnit_));
+    checkErr(AudioOutputUnitStart(outputUnit_));
+
+    is_playback_running_ = true;
+    is_capture_running_ = true;
+
+    initAudioFormat();
 }
 
+void CoreLayer::initAudioLayerCapture()
+{
+    // HALUnit description.
+    AudioComponentDescription desc;
+    desc = {0};
+    desc.componentType = kAudioUnitType_Output;
+    desc.componentSubType = kAudioUnitSubType_HALOutput;
+    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+    AudioComponent comp = AudioComponentFindNext(NULL, &desc);
+    if (comp == NULL)
+        SFL_ERR("Can't find an input HAL unit that matches description.");
+    checkErr(AudioComponentInstanceNew(comp, &inputUnit_));
+
+    // HALUnit settings.
+    AudioUnitScope outputBus = 0;
+    AudioUnitScope inputBus = 1;
+    UInt32 enableIO = 1;
+    UInt32 disableIO = 0;
+    UInt32 size = 0;
+
+    checkErr(AudioUnitSetProperty(inputUnit_,
+                kAudioOutputUnitProperty_EnableIO,
+                kAudioUnitScope_Input,
+                inputBus,
+                &enableIO,
+                sizeof(enableIO)));
+
+    checkErr(AudioUnitSetProperty(inputUnit_,
+                kAudioOutputUnitProperty_EnableIO,
+                kAudioUnitScope_Output,
+                outputBus,
+                &disableIO,
+                sizeof(disableIO)));
+
+    AudioDeviceID defaultDevice = kAudioObjectUnknown;
+    size = sizeof(defaultDevice);
+    AudioObjectPropertyAddress defaultDeviceProperty;
+    defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+    defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal;
+    defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster;
+
+    checkErr(AudioObjectGetPropertyData(kAudioObjectSystemObject,
+                &defaultDeviceProperty,
+                outputBus,
+                NULL,
+                &size,
+                &defaultDevice));
+
+    checkErr(AudioUnitSetProperty(inputUnit_,
+                kAudioOutputUnitProperty_CurrentDevice,
+                kAudioUnitScope_Global,
+                outputBus,
+                &defaultDevice,
+                sizeof(defaultDevice)));
+
+    // Set format on output *SCOPE* in input *BUS*.
+    AudioStreamBasicDescription info;
+    size = sizeof(AudioStreamBasicDescription);
+    checkErr(AudioUnitGetProperty(inputUnit_,
+                kAudioUnitProperty_StreamFormat,
+                kAudioUnitScope_Output,
+                inputBus,
+                &info,
+                &size));
+
+    const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
+
+    audioFormat_ = {(unsigned int)info.mSampleRate, (unsigned int)info.mChannelsPerFrame};
+    //hardwareFormatAvailable(audioFormat_);
+    SFL_DBG("Input format : %d, %d\n\n", audioFormat_.sample_rate, audioFormat_.nb_channels);
+
+    // Input buffer setup. Note that ioData is empty and we have to store data
+    // in another buffer.
+    UInt32 bufferSizeFrames = 0;
+    size = sizeof(UInt32);
+    checkErr(AudioUnitGetProperty(inputUnit_,
+                kAudioDevicePropertyBufferFrameSize,
+                kAudioUnitScope_Global,
+                outputBus,
+                &bufferSizeFrames,
+                &size));
+
+    UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
+    size = offsetof(AudioBufferList, mBuffers[0]) +
+        (sizeof(AudioBuffer) * info.mChannelsPerFrame);
+    captureBuff_ = (AudioBufferList *)malloc(size);
+    captureBuff_->mNumberBuffers = info.mChannelsPerFrame;
+
+    for (UInt32 i = 0; i < captureBuff_->mNumberBuffers; ++i) {
+        captureBuff_->mBuffers[i].mNumberChannels = 1;
+        captureBuff_->mBuffers[i].mDataByteSize = bufferSizeBytes;
+        captureBuff_->mBuffers[i].mData = malloc(bufferSizeBytes);
+    }
 
-int CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
+    // Input callback setup.
+    AURenderCallbackStruct inputCall;
+    inputCall.inputProc = inputCallback;
+    inputCall.inputProcRefCon = this;
+
+    checkErr(AudioUnitSetProperty(inputUnit_,
+                kAudioOutputUnitProperty_SetInputCallback,
+                kAudioUnitScope_Global,
+                outputBus,
+                &inputCall,
+                sizeof(inputCall)));
+
+    // Start it up.
+    checkErr(AudioUnitInitialize(inputUnit_));
+    checkErr(AudioOutputUnitStart(inputUnit_));
+
+}
+
+void CoreLayer::startStream()
 {
-    return 0;
+    SFL_DBG("START STREAM");
+    dcblocker_.reset();
+
+    if (is_playback_running_ and is_capture_running_)
+        return;
+
+    initAudioLayerPlayback();
+    initAudioLayerCapture();
 }
 
-std::string CoreLayer::getAudioDeviceName(int index, DeviceType type) const
+void CoreLayer::destroyAudioLayer()
 {
-    return "";
+    AudioOutputUnitStop(outputUnit_);
+    AudioUnitUninitialize(outputUnit_);
+    AudioComponentInstanceDispose(outputUnit_);
+
+    AudioOutputUnitStop(inputUnit_);
+    AudioUnitUninitialize(inputUnit_);
+    AudioComponentInstanceDispose(inputUnit_);
 }
 
 void CoreLayer::stopStream()
 {
-    isStarted_ = false;
+    SFL_DBG("STOP STREAM");
+
+    isStarted_ = is_playback_running_ = is_capture_running_ = false;
+
+    destroyAudioLayer();
 
     /* Flush the ring buffers */
     flushUrgent();
     flushMain();
 }
 
+
+//// PRIVATE /////
+
+
+void CoreLayer::initAudioFormat()
+{
+    AudioStreamBasicDescription info;
+    UInt32 size = sizeof(info);
+    checkErr(AudioUnitGetProperty(outputUnit_,
+            kAudioUnitProperty_StreamFormat,
+            kAudioUnitScope_Input,
+            0,
+            &info,
+            &size));
+
+    audioFormat_ = {(unsigned int)info.mSampleRate, (unsigned int)info.mChannelsPerFrame};
+    hardwareFormatAvailable(audioFormat_);
+}
+
+
+OSStatus CoreLayer::outputCallback(void* inRefCon,
+    AudioUnitRenderActionFlags* ioActionFlags,
+    const AudioTimeStamp* inTimeStamp,
+    UInt32 inBusNumber,
+    UInt32 inNumberFrames,
+    AudioBufferList* ioData)
+{
+    static_cast<CoreLayer*>(inRefCon)->write(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
+    return kAudioServicesNoError;
+}
+
+void CoreLayer::write(AudioUnitRenderActionFlags* ioActionFlags,
+    const AudioTimeStamp* inTimeStamp,
+    UInt32 inBusNumber,
+    UInt32 inNumberFrames,
+    AudioBufferList* ioData)
+{
+    unsigned framesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID);
+
+    if (framesToGet <= 0) {
+        for (int i = 0; i < inNumberFrames; ++i) {
+            Float32* outDataL = (Float32*)ioData->mBuffers[0].mData;
+            outDataL[i] = 0.0;
+            Float32* outDataR = (Float32*)ioData->mBuffers[1].mData;
+            outDataR[i] = 0.0;
+        }
+        return;
+    }
+
+    size_t totSample = std::min(inNumberFrames, framesToGet);
+
+    playbackBuff_.setFormat(audioFormat_);
+    playbackBuff_.resize(totSample);
+    urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID);
+
+    playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+
+    for (int i = 0; i < audioFormat_.nb_channels; ++i)
+        playbackBuff_.channelToFloat((Float32*)ioData->mBuffers[i].mData, i); // Write
+
+    Manager::instance().getRingBufferPool().discard(totSample, RingBufferPool::DEFAULT_ID);
+
+
+}
+
+
+OSStatus CoreLayer::inputCallback(void* inRefCon,
+    AudioUnitRenderActionFlags* ioActionFlags,
+    const AudioTimeStamp* inTimeStamp,
+    UInt32 inBusNumber,
+    UInt32 inNumberFrames,
+    AudioBufferList* ioData)
+{
+    static_cast<CoreLayer*>(inRefCon)->read(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
+    return kAudioServicesNoError;
+}
+
+void CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags,
+    const AudioTimeStamp* inTimeStamp,
+    UInt32 inBusNumber,
+    UInt32 inNumberFrames,
+    AudioBufferList* ioData)
+{
+    //SFL_DBG("INPUT CALLBACK");
+
+    if (inNumberFrames <= 0) {
+        SFL_WARN("No frames for input.");
+        return;
+    }
+
+    // Write the mic samples in our buffer
+    checkErr(AudioUnitRender(inputUnit_,
+            ioActionFlags,
+            inTimeStamp,
+            inBusNumber,
+            inNumberFrames,
+            captureBuff_));
+
+
+    AudioStreamBasicDescription info;
+    UInt32 size = sizeof(AudioStreamBasicDescription);
+    checkErr(AudioUnitGetProperty(inputUnit_,
+                kAudioUnitProperty_StreamFormat,
+                kAudioUnitScope_Output,
+                inBusNumber,
+                &info,
+                &size));
+
+
+    // Add them to sflphone ringbuffer.
+    const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
+    bool resample = info.mSampleRate != mainBufferFormat.sample_rate;
+
+
+    // FIXME: Performance! There *must* be a better way. This is testing only.
+    AudioBuffer inBuff(inNumberFrames, audioFormat_);
+
+    for (int i = 0; i < info.mChannelsPerFrame; ++i) {
+        Float32* data = (Float32*)captureBuff_->mBuffers[i].mData;
+        for (int j = 0; j < inNumberFrames; ++j) {
+            (*inBuff.getChannel(i))[j] = (SFLAudioSample)((data)[j] / .000030517578125f);
+        }
+    }
+
+    if (resample) {
+        //SFL_WARN("Resampling Input.");
+
+        //FIXME: May be a multiplication, check alsa vs pulse implementation.
+        int outSamples = inNumberFrames / (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate);
+
+        AudioBuffer out(outSamples, mainBufferFormat);
+        resampler_->resample(inBuff, out);
+        dcblocker_.process(out);
+        mainRingBuffer_->put(out);
+    } else {
+        dcblocker_.process(inBuff);
+        mainRingBuffer_->put(inBuff);
+    }
+
+
+}
+
 void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
 {
     switch (type) {
diff --git a/daemon/src/audio/coreaudio/corelayer.h b/daemon/src/audio/coreaudio/corelayer.h
index c5331f84aab9a34869b183bf7beaab1e9bc7ea02..f9e0179a73c84a40ed86cfd93079d1dccba92e00 100644
--- a/daemon/src/audio/coreaudio/corelayer.h
+++ b/daemon/src/audio/coreaudio/corelayer.h
@@ -33,6 +33,19 @@
 
 #include "audio/audiolayer.h"
 #include "noncopyable.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <AudioToolbox/AudioToolbox.h>
+#include <CoreAudio/AudioHardware.h>
+
+#define checkErr( err) \
+    if(err) {\
+            OSStatus error = static_cast<OSStatus>(err);\
+                fprintf(stdout, "CoreAudio Error: %ld ->  %s:  %d\n",  (long)error,\
+                                       __FILE__, \
+                                       __LINE__\
+                                       );\
+                           fflush(stdout);\
+    }
 
 /**
  * @file  CoreLayer.h
@@ -41,7 +54,6 @@
 
 namespace sfl {
 
-class CoreAudioThread;
 class RingBuffer;
 class AudioDevice;
 
@@ -84,6 +96,9 @@ class CoreLayer : public AudioLayer {
             return indexRing_;
         }
 
+        void initAudioLayerPlayback();
+        void initAudioLayerCapture();
+
         /**
          * Start the capture stream and prepare the playback stream.
          * The playback starts accordingly to its threshold
@@ -92,6 +107,8 @@ class CoreLayer : public AudioLayer {
 
         virtual void startStream();
 
+        void destroyAudioLayer();
+
         /**
          * Stop the playback and capture streams.
          * Drops the pending frames and put the capture and playback handles to PREPARED state
@@ -99,9 +116,39 @@ class CoreLayer : public AudioLayer {
          */
         virtual void stopStream();
 
+
+
     private:
         NON_COPYABLE(CoreLayer);
-        friend class CoreAudioThread;
+
+        void initAudioFormat();
+
+        static OSStatus outputCallback(void* inRefCon,
+            AudioUnitRenderActionFlags* ioActionFlags,
+            const AudioTimeStamp* inTimeStamp,
+            UInt32 inBusNumber,
+            UInt32 inNumberFrames,
+            AudioBufferList* ioData);
+
+        void write(AudioUnitRenderActionFlags* ioActionFlags,
+            const AudioTimeStamp* inTimeStamp,
+            UInt32 inBusNumber,
+            UInt32 inNumberFrames,
+            AudioBufferList* ioData);
+
+        static OSStatus inputCallback(void* inRefCon,
+            AudioUnitRenderActionFlags* ioActionFlags,
+            const AudioTimeStamp* inTimeStamp,
+            UInt32 inBusNumber,
+            UInt32 inNumberFrames,
+            AudioBufferList* ioData);
+
+        void read(AudioUnitRenderActionFlags* ioActionFlags,
+            const AudioTimeStamp* inTimeStamp,
+            UInt32 inBusNumber,
+            UInt32 inNumberFrames,
+            AudioBufferList* ioData);
+
         virtual void updatePreference(AudioPreference &pref, int index, DeviceType type);
 
         /**
@@ -121,21 +168,18 @@ class CoreLayer : public AudioLayer {
 
         /** Non-interleaved audio buffers */
         AudioBuffer playbackBuff_;
-        AudioBuffer captureBuff_;
+        ::AudioBufferList* captureBuff_; // CoreAudio buffer.
 
         /** Interleaved buffer */
         std::vector<SFLAudioSample> playbackIBuff_;
         std::vector<SFLAudioSample> captureIBuff_;
 
-        bool is_playback_prepared_;
-        bool is_capture_prepared_;
+        AudioUnit outputUnit_;
+        AudioUnit inputUnit_;
+        std::shared_ptr<RingBuffer> mainRingBuffer_;
+
         bool is_playback_running_;
         bool is_capture_running_;
-        bool is_playback_open_;
-        bool is_capture_open_;
-
-        CoreAudioThread* audioThread_;
-        std::shared_ptr<RingBuffer> mainRingBuffer_;
 
         std::vector<AudioDevice> getDeviceList(bool getCapture) const;
 };