diff --git a/src/media/audio/coreaudio/ios/corelayer.cpp b/src/media/audio/coreaudio/ios/corelayer.cpp
index 5d3e9a04a855409158fb5a743845600c8258e392..6950000ad9b8e800297f4013aa7ab937e9b3c1fa 100644
--- a/src/media/audio/coreaudio/ios/corelayer.cpp
+++ b/src/media/audio/coreaudio/ios/corelayer.cpp
@@ -29,6 +29,9 @@
 #include <cmath>
 #include <vector>
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
 namespace ring {
 
 // AudioLayer implementation.
@@ -61,7 +64,7 @@ CoreLayer::getPlaybackDeviceList() const
     // The notion of input devices can be ignored, and output devices can describe
     // input/output pairs.
     // Unavailable options like the receiver on iPad can be ignored by the client.
-    ret.assign({"built_in_spk", "bluetooth", "headphones", "receiver", "dummy"});
+    ret.assign({"built_in_spk", "bluetooth", "headphones", "receiver"});
 
     return ret;
 }
@@ -69,12 +72,17 @@ CoreLayer::getPlaybackDeviceList() const
 int
 CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const
 {
+    (void) name;
+    (void) index;
+    (void) type;
     return 0;
 }
 
 std::string
 CoreLayer::getAudioDeviceName(int index, DeviceType type) const
 {
+    (void) index;
+    (void) type;
     return "";
 }
 
@@ -122,7 +130,8 @@ CoreLayer::initAudioLayerIO()
             checkErr(AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute,
                                              sizeof(audioRouteOverrideNone),
                                              &audioRouteOverrideNone));
-        case 4:
+            break;
+        default:
             break;
     }
 
@@ -147,12 +156,13 @@ CoreLayer::setupOutputBus() {
                             &size,
                             &outSampleRate);
     outputASBD.mSampleRate = outSampleRate;
-    outputASBD.mFormatID = kAudioFormatLinearPCM;
-    outputASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
 
     audioFormat_ = {static_cast<unsigned int>(outputASBD.mSampleRate),
                     static_cast<unsigned int>(outputASBD.mChannelsPerFrame)};
 
+    outSampleRate_ = outputASBD.mSampleRate;
+    outChannelsPerFrame_ = outputASBD.mChannelsPerFrame;
+
     size = sizeof(outputASBD);
     checkErr(AudioUnitGetProperty(ioUnit_,
                                   kAudioUnitProperty_StreamFormat,
@@ -163,6 +173,8 @@ CoreLayer::setupOutputBus() {
 
     // Only change sample rate.
     outputASBD.mSampleRate = audioFormat_.sample_rate;
+    outputASBD.mFormatID = kAudioFormatLinearPCM;
+    outputASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
 
     // Set output steam format
     checkErr(AudioUnitSetProperty(ioUnit_,
@@ -181,7 +193,7 @@ CoreLayer::setupInputBus() {
 
     AudioUnitScope inputBus = 1;
     UInt32 size;
- 
+
     AudioStreamBasicDescription inputASBD;
     size = sizeof(inputASBD);
 
@@ -212,7 +224,7 @@ CoreLayer::setupInputBus() {
     inputASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
 
     audioInputFormat_ = {static_cast<unsigned int>(inputASBD.mSampleRate),
-        static_cast<unsigned int>(inputASBD.mChannelsPerFrame)};
+                         static_cast<unsigned int>(inputASBD.mChannelsPerFrame)};
     hardwareInputFormatAvailable(audioInputFormat_);
 
     // Keep some values to not ask them every time the read callback is fired up
@@ -364,17 +376,75 @@ CoreLayer::write(AudioUnitRenderActionFlags* ioActionFlags,
     UInt32 inNumberFrames,
     AudioBufferList* ioData)
 {
-    auto& ringBuff = getToRing(audioFormat_, inNumberFrames);
-    auto& playBuff = getToPlay(audioFormat_, inNumberFrames);
+    (void) ioActionFlags;
+    (void) inTimeStamp;
+    (void) inBusNumber;
+
+    auto& manager = Manager::instance();
+    auto& bufferPool = manager.getRingBufferPool();
+
+    auto mainBufferFormat = bufferPool.getInternalAudioFormat();
+    const AudioFormat currentOutFormat = {  static_cast<unsigned int>(outSampleRate_),
+                                            static_cast<unsigned int>(outChannelsPerFrame_)};
+
+    auto resample = currentOutFormat.sample_rate != mainBufferFormat.sample_rate;
+
+    auto normalFramesToGet = bufferPool.availableForGet(RingBufferPool::DEFAULT_ID);
+    auto urgentFramesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID);
+
+    double resampleFactor;
+    decltype(normalFramesToGet) readableSamples;
+    decltype(urgentFramesToGet) readableUrgentSamples;
+
+    if (resample) {
+        resampleFactor = mainBufferFormat.sample_rate / static_cast<double>(currentOutFormat.sample_rate);
+        readableSamples = std::ceil(inNumberFrames * resampleFactor);
+    } else {
+        readableSamples = inNumberFrames;
+    }
+
+    // incoming call during call
+    if (urgentFramesToGet > 0) {
+        readableUrgentSamples = std::min(readableSamples, urgentFramesToGet);
+
+        playbackBuff_.setFormat(currentOutFormat);
+        playbackBuff_.resize(readableUrgentSamples);
+        urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID);
+        playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+
+        for (unsigned i = 0; i < currentOutFormat.nb_channels; ++i) {
+            playbackBuff_.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i);
+        }
+        manager.getRingBufferPool().discard(readableUrgentSamples, RingBufferPool::DEFAULT_ID);
+    }
+
+    if (normalFramesToGet > 0) {
+        readableSamples = std::min(readableSamples, normalFramesToGet);
+    }
+
+    auto& ringBuff = getToRing(audioFormat_, readableSamples);
+    auto& playBuff = getToPlay(audioFormat_, readableSamples);
 
     auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff;
 
     if (toPlay.frames() == 0) {
-        for (unsigned i = 0; i < audioFormat_.nb_channels; ++i) {
+        // clear buffer
+        for (unsigned i = 0; i < currentOutFormat.nb_channels; ++i) {
             std::fill_n(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData),
                         ioData->mBuffers[i].mDataByteSize / sizeof(Float32), 0);
         }
+    } else if (resample) {
+        // resample
+        playbackBuff_.setFormat(currentOutFormat);
+        playbackBuff_.resize(readableSamples);
+        resampler_->resample(toPlay, playbackBuff_);
+        playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
+        for (unsigned i = 0; i < audioFormat_.nb_channels; ++i) {
+            playbackBuff_.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i);
+        }
     } else {
+        // normal play
+        const_cast<AudioBuffer&>(toPlay).applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
         for (unsigned i = 0; i < audioFormat_.nb_channels; ++i) {
             toPlay.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i);
         }
@@ -400,6 +470,8 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags,
     UInt32 inNumberFrames,
     AudioBufferList* ioData)
 {
+    (void) ioData;
+
     if (inNumberFrames <= 0) {
         RING_WARN("No frames for input.");
         return;
@@ -461,3 +533,5 @@ void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceT
 }
 
 } // namespace ring
+
+#pragma GCC diagnostic pop
diff --git a/src/media/audio/coreaudio/ios/corelayer.h b/src/media/audio/coreaudio/ios/corelayer.h
index f3d80a2a30ec2287f528b8e25e50f8c85cd13c87..3baa1c299ee8f6afd18190eae3702fcd459dfcf8 100644
--- a/src/media/audio/coreaudio/ios/corelayer.h
+++ b/src/media/audio/coreaudio/ios/corelayer.h
@@ -160,14 +160,12 @@ class CoreLayer : public AudioLayer {
         ::AudioBufferList* captureBuff_ {nullptr}; // CoreAudio buffer (pointer is casted rawBuff_)
         std::unique_ptr<Byte[]> rawBuff_; // raw allocation of captureBuff_
 
-        /** Interleaved buffer */
-        std::vector<AudioSample> playbackIBuff_;
-        std::vector<AudioSample> captureIBuff_;
-
         AudioUnit ioUnit_;
 
         Float64 inSampleRate_;
         UInt32 inChannelsPerFrame_;
+        Float64 outSampleRate_;
+        UInt32 outChannelsPerFrame_;
 
         std::shared_ptr<RingBuffer> mainRingBuffer_;
 };