diff --git a/NEWS b/NEWS
index 2e8dc14a6..a8d8e763c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,7 @@
 ver 0.22.1 (not yet released)
 * output
   - alsa: don't deadlock when the ALSA driver is buggy
-  - pulse: reduce the delay when stopping or pausing playback
+  - jack, pulse: reduce the delay when stopping or pausing playback
 
 ver 0.22 (2020/09/23)
 * protocol
diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx
index 8c6da5405..e2f0a63f1 100644
--- a/src/output/plugins/JackOutputPlugin.cxx
+++ b/src/output/plugins/JackOutputPlugin.cxx
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "JackOutputPlugin.hxx"
 #include "../OutputAPI.hxx"
+#include "../Error.hxx"
 #include "output/Features.h"
 #include "thread/Mutex.hxx"
 #include "util/ScopeExit.hxx"
@@ -79,6 +80,15 @@ class JackOutput final : public AudioOutput {
 	 */
 	std::atomic_bool pause;
 
+	/**
+	 * Was Interrupt() called?  This will unblock Play().  It will
+	 * be reset by Cancel() and Pause(), as documented by the
+	 * #AudioOutput interface.
+	 *
+	 * Only initialized while the output is open.
+	 */
+	bool interrupted;
+
 	/**
 	 * Protects #error.
 	 */
@@ -156,6 +166,8 @@ public:
 		Stop();
 	}
 
+	void Interrupt() noexcept override;
+
 	std::chrono::steady_clock::duration Delay() const noexcept override {
 		return pause && !LockWasShutdown()
 			? std::chrono::seconds(1)
@@ -164,6 +176,7 @@ public:
 
 	size_t Play(const void *chunk, size_t size) override;
 
+	void Cancel() noexcept override;
 	bool Pause() override;
 
 private:
@@ -613,9 +626,21 @@ JackOutput::Open(AudioFormat &new_audio_format)
 	new_audio_format.format = SampleFormat::FLOAT;
 	audio_format = new_audio_format;
 
+	interrupted = false;
+
 	Start();
 }
 
+void
+JackOutput::Interrupt() noexcept
+{
+	const std::unique_lock<Mutex> lock(mutex);
+
+	/* the "interrupted" flag will prevent Play() from waiting,
+	   and will instead throw AudioOutputInterrupted */
+	interrupted = true;
+}
+
 inline size_t
 JackOutput::WriteSamples(const float *src, size_t n_frames)
 {
@@ -671,6 +696,9 @@ JackOutput::Play(const void *chunk, size_t size)
 			const std::lock_guard<Mutex> lock(mutex);
 			if (error)
 				std::rethrow_exception(error);
+
+			if (interrupted)
+				throw AudioOutputInterrupted{};
 		}
 
 		size_t frames_written =
@@ -684,11 +712,19 @@ JackOutput::Play(const void *chunk, size_t size)
 	}
 }
 
+void
+JackOutput::Cancel() noexcept
+{
+	const std::unique_lock<Mutex> lock(mutex);
+	interrupted = false;
+}
+
 inline bool
 JackOutput::Pause()
 {
 	{
 		const std::lock_guard<Mutex> lock(mutex);
+		interrupted = false;
 		if (error)
 			std::rethrow_exception(error);
 	}