diff --git a/src/media/audio/audio_input.cpp b/src/media/audio/audio_input.cpp
index 64f869b82c5aa01caecd4b8810f709b70f3420da..7bf5d4d7b1969fc194b5742532e43982ed89f719 100644
--- a/src/media/audio/audio_input.cpp
+++ b/src/media/audio/audio_input.cpp
@@ -25,6 +25,7 @@
 #include <chrono>
 #include "socket_pair.h"
 #include "audio/ringbufferpool.h"
+#include "audio/resampler.h"
 #include "manager.h"
 #include "smartools.h"
 
@@ -34,6 +35,8 @@ static constexpr auto MS_PER_PACKET = std::chrono::milliseconds(20);
 
 AudioInput::AudioInput(const std::string& id) :
     id_(id),
+    format_(Manager::instance().getRingBufferPool().getInternalAudioFormat()),
+    resampler_(new Resampler),
     loop_([] { return true; },
           [this] { process(); },
           [] {})
@@ -73,7 +76,7 @@ AudioInput::process()
         return;
     }
 
-    // get data
+    // getData resets the format to internal hardware format, will have to be resampled
     micData_.setFormat(bufferFormat);
     micData_.resize(samplesToGet);
     const auto samples = mainBuffer.getData(micData_, id_);
@@ -83,9 +86,17 @@ AudioInput::process()
     if (muteState_) // audio is muted, set samples to 0
         micData_.reset();
 
-    // record frame
-    AVFrame* frame = micData_.toAVFrame();
-    auto ms = MediaStream("a:local", micData_.getFormat());
+    std::lock_guard<std::mutex> lk(fmtMutex_);
+    AudioBuffer resampled;
+    resampled.setFormat(format_);
+    if (bufferFormat != format_) {
+        resampler_->resample(micData_, resampled);
+    } else {
+        resampled = micData_;
+    }
+
+    AVFrame* frame = resampled.toAVFrame();
+    auto ms = MediaStream("a:local", format_);
     frame->pts = getNextTimestamp(sent_samples, ms.sampleRate, static_cast<rational<int64_t>>(ms.timeBase));
     sent_samples += frame->nb_samples;
 
@@ -97,6 +108,13 @@ AudioInput::process()
     }
 }
 
+void
+AudioInput::setFormat(const AudioFormat& fmt)
+{
+    std::lock_guard<std::mutex> lk(fmtMutex_);
+    format_ = fmt;
+}
+
 void
 AudioInput::setMuted(bool isMuted)
 {
diff --git a/src/media/audio/audio_input.h b/src/media/audio/audio_input.h
index 54319ed4ee4a6e5ae4899425a7d703b8d1b9d077..4623a4df11b5dd71bf0e8e90c59af713e5f4798e 100644
--- a/src/media/audio/audio_input.h
+++ b/src/media/audio/audio_input.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <future>
+#include <mutex>
 
 #include "audio/audiobuffer.h"
 #include "media_device.h"
@@ -31,6 +32,7 @@
 namespace ring {
 
 class MediaRecorder;
+class Resampler;
 
 class AudioInput
 {
@@ -40,16 +42,20 @@ public:
 
     std::shared_future<DeviceParams> switchInput(const std::string& resource);
 
+    void setFormat(const AudioFormat& fmt);
     void setMuted(bool isMuted);
     void initRecorder(const std::shared_ptr<MediaRecorder>& rec);
 
 private:
-    std::weak_ptr<MediaRecorder> recorder_;
-    uint64_t sent_samples = 0;
-
     std::string id_;
     AudioBuffer micData_;
     bool muteState_ = false;
+    uint64_t sent_samples = 0;
+    std::mutex fmtMutex_ {};
+    AudioFormat format_;
+
+    std::unique_ptr<Resampler> resampler_;
+    std::weak_ptr<MediaRecorder> recorder_;
 
     ThreadLoop loop_;
     void process();
diff --git a/src/media/localrecorder.cpp b/src/media/localrecorder.cpp
index 893b0dda76f5ac4557f27fdd3a5191f529b65f66..d2a27cc5c01d92e0c61f933747f89af78fad2181 100644
--- a/src/media/localrecorder.cpp
+++ b/src/media/localrecorder.cpp
@@ -75,6 +75,7 @@ LocalRecorder::startRecording()
     Manager::instance().startAudioDriverStream();
 
     audioInput_.reset(new AudioInput(path_));
+    audioInput_->setFormat(AudioFormat::STEREO());
     audioInput_->initRecorder(recorder_);
 
 #ifdef RING_VIDEO