diff --git a/src/media/audio/resampler.cpp b/src/media/audio/resampler.cpp
index cc0818a0e5645fe9143c5ea85c8750b48da3f493..6409287a66cc30c6b664ebeb412b8972a5c71391 100644
--- a/src/media/audio/resampler.cpp
+++ b/src/media/audio/resampler.cpp
@@ -3,6 +3,7 @@
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,11 +22,7 @@
 
 #include "libav_deps.h"
 #include "logger.h"
-#include "media_buffer.h"
-#include "media_filter.h"
-#include "media_stream.h"
 #include "resampler.h"
-#include "ring_types.h"
 
 extern "C" {
 #include <libswresample/swresample.h>
@@ -35,7 +32,7 @@ namespace ring {
 
 Resampler::Resampler()
     : swrCtx_(swr_alloc())
-    , initialized_(false)
+    , initCount_(0)
 {}
 
 Resampler::~Resampler()
@@ -57,17 +54,25 @@ Resampler::reinit(const AVFrame* in, const AVFrame* out)
     av_opt_set_sample_fmt(swrCtx_, "osf", static_cast<AVSampleFormat>(out->format), 0);
 
     swr_init(swrCtx_);
-    initialized_ = true;
+    ++initCount_;
 }
 
 int
 Resampler::resample(const AVFrame* input, AVFrame* output)
 {
-    if (!initialized_)
+    if (!initCount_)
         reinit(input, output);
 
     int ret = swr_convert_frame(swrCtx_, output, input);
     if (ret & AVERROR_INPUT_CHANGED || ret & AVERROR_OUTPUT_CHANGED) {
+        // Under certain conditions, the resampler reinits itself in an infinite loop. This is
+        // indicative of an underlying problem in the code. This check is so the backtrace
+        // doesn't get mangled with a bunch of calls to Resampler::resample
+        if (initCount_ > 1) {
+            std::string msg = "Infinite loop detected in audio resampler, please open an issue on https://git.jami.net";
+            RING_ERR() << msg;
+            throw std::runtime_error(msg);
+        }
         reinit(input, output);
         return resample(input, output);
     } else if (ret < 0) {
@@ -75,6 +80,8 @@ Resampler::resample(const AVFrame* input, AVFrame* output)
         return -1;
     }
 
+    // Resampling worked, reset count to 1 so reinit isn't called again
+    initCount_ = 1;
     return 0;
 }
 
@@ -126,5 +133,4 @@ Resampler::resample(std::shared_ptr<AudioFrame>&& in, const AudioFormat& format)
     return output;
 }
 
-
 } // namespace ring
diff --git a/src/media/audio/resampler.h b/src/media/audio/resampler.h
index 9bc5b19e65dc5d0b34eea4a64b4092eca70b5ad2..b0a6c1d23338ac8f22a23fbde0d31e8da5267bdf 100644
--- a/src/media/audio/resampler.h
+++ b/src/media/audio/resampler.h
@@ -3,6 +3,7 @@
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -22,8 +23,8 @@
 #pragma once
 
 #include "audiobuffer.h"
+#include "media_buffer.h"
 #include "noncopyable.h"
-#include "ring_types.h"
 
 struct AVFrame;
 struct SwrContext;
@@ -34,38 +35,47 @@ namespace ring {
  * Wrapper class for libswresample
  */
 class Resampler {
-    public:
-        Resampler();
-        ~Resampler();
+public:
+    Resampler();
+    ~Resampler();
 
-        /**
-         * Resample from @input format to @output format.
-         * NOTE: sample_rate, channel_layout, and format should be set on @output
-         */
-        int resample(const AVFrame* input, AVFrame* output);
+    /**
+     * Resample from @input format to @output format.
+     * NOTE: sample_rate, channel_layout, and format should be set on @output
+     */
+    int resample(const AVFrame* input, AVFrame* output);
 
-        /**
-         * Resample from @dataIn format to @dataOut format.
-         *
-         * NOTE: This is a wrapper for resample(AVFrame*, AVFrame*)
-         */
-        void resample(const AudioBuffer& dataIn, AudioBuffer& dataOut);
+    /**
+     * Wrappers around resample(AVFrame*, AVFrame*) for convenience.
+     */
+    void resample(const AudioBuffer& dataIn, AudioBuffer& dataOut);
+    std::unique_ptr<AudioFrame> resample(std::unique_ptr<AudioFrame>&& in, const AudioFormat& out);
+    std::shared_ptr<AudioFrame> resample(std::shared_ptr<AudioFrame>&& in, const AudioFormat& out);
 
-        std::unique_ptr<AudioFrame> resample(std::unique_ptr<AudioFrame>&& in, const AudioFormat& out);
-        std::shared_ptr<AudioFrame> resample(std::shared_ptr<AudioFrame>&& in, const AudioFormat& out);
+private:
+    NON_COPYABLE(Resampler);
 
-    private:
-        NON_COPYABLE(Resampler);
+    /**
+     * Reinitializes the resampler when new settings are detected. As long as both input and
+     * output formats don't change, this will only be called once.
+     */
+    void reinit(const AVFrame* in, const AVFrame* out);
 
-        /**
-         * Reinitializes the resampler when new settings are detected. As long as both input and
-         * output buffers always have the same formats, will never be called, as the first
-         * initialization is done in swr_convert_frame.
-         */
-        void reinit(const AVFrame* in, const AVFrame* out);
+    /**
+     * Libswresample resampler context.
+     *
+     * NOTE SwrContext is an imcomplete type and cannot be stored in a smart pointer.
+     */
+    SwrContext* swrCtx_;
 
-        SwrContext* swrCtx_; // incomplete type, cannot be a unique_ptr
-        bool initialized_;
+    /**
+     * Number of times @swrCtx_ has been initialized with no successful audio resampling.
+     *
+     * 0: Uninitialized
+     * 1: Initialized
+     * >1: Invalid frames or formats, reinit is going to be called in an infinite loop
+     */
+    unsigned initCount_;
 };
 
 } // namespace ring