From b08cb148ae387ed685dd3ec935bb23e2f7935a60 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 26 Oct 2017 09:27:36 +0200
Subject: [PATCH] output/alsa: move class PeriodBuffer to
 lib/alsa/PeriodBuffer.hxx

---
 Makefile.am                             |   1 +
 src/lib/alsa/PeriodBuffer.hxx           | 138 ++++++++++++++++++++++++
 src/output/plugins/AlsaOutputPlugin.cxx | 106 +-----------------
 3 files changed, 141 insertions(+), 104 deletions(-)
 create mode 100644 src/lib/alsa/PeriodBuffer.hxx

diff --git a/Makefile.am b/Makefile.am
index c2ea42f06..c9e5a82f5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -258,6 +258,7 @@ UPNP_SOURCES = \
 
 ALSA_SOURCES = \
 	src/lib/alsa/Version.cxx src/lib/alsa/Version.hxx \
+	src/lib/alsa/PeriodBuffer.hxx \
 	src/lib/alsa/NonBlock.cxx src/lib/alsa/NonBlock.hxx
 
 #
diff --git a/src/lib/alsa/PeriodBuffer.hxx b/src/lib/alsa/PeriodBuffer.hxx
new file mode 100644
index 000000000..0beba20c4
--- /dev/null
+++ b/src/lib/alsa/PeriodBuffer.hxx
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2003-2017 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ALSA_PERIOD_BUFFER_HXX
+#define MPD_ALSA_PERIOD_BUFFER_HXX
+
+#include "check.h"
+
+#include <alsa/asoundlib.h>
+
+#include <algorithm>
+
+#include <stdint.h>
+
+namespace Alsa {
+
+class PeriodBuffer {
+	size_t capacity, head, tail;
+
+	uint8_t *buffer;
+
+public:
+	PeriodBuffer() = default;
+	PeriodBuffer(const PeriodBuffer &) = delete;
+	PeriodBuffer &operator=(const PeriodBuffer &) = delete;
+
+	void Allocate(size_t n_frames, size_t frame_size) noexcept {
+		capacity = n_frames * frame_size;
+
+		/* reserve space for one more (partial) frame,
+		   to be able to fill the buffer with silence,
+		   after moving an unfinished frame to the
+		   end */
+		buffer = new uint8_t[capacity + frame_size - 1];
+		head = tail = 0;
+	}
+
+	void Free() noexcept {
+		delete[] buffer;
+	}
+
+	bool IsEmpty() const noexcept {
+		return head == tail;
+	}
+
+	bool IsFull() const noexcept {
+		return tail >= capacity;
+	}
+
+	uint8_t *GetTail() noexcept {
+		return buffer + tail;
+	}
+
+	size_t GetSpaceBytes() const noexcept {
+		assert(tail <= capacity);
+
+		return capacity - tail;
+	}
+
+	void AppendBytes(size_t n) noexcept {
+		assert(n <= capacity);
+		assert(tail <= capacity - n);
+
+		tail += n;
+	}
+
+	void FillWithSilence(const uint8_t *_silence,
+			     const size_t frame_size) noexcept {
+		size_t partial_frame = tail % frame_size;
+		auto *dest = GetTail() - partial_frame;
+
+		/* move the partial frame to the end */
+		std::copy(dest, GetTail(), buffer + capacity);
+
+		size_t silence_size = capacity - tail - partial_frame;
+		std::copy_n(_silence, silence_size, dest);
+
+		tail = capacity + partial_frame;
+	}
+
+	const uint8_t *GetHead() const noexcept {
+		return buffer + head;
+	}
+
+	snd_pcm_uframes_t GetFrames(size_t frame_size) const noexcept {
+		return (tail - head) / frame_size;
+	}
+
+	void ConsumeBytes(size_t n) noexcept {
+		head += n;
+
+		assert(head <= capacity);
+
+		if (head >= capacity) {
+			tail -= head;
+			/* copy the partial frame (if any)
+			   back to the beginning */
+			std::copy_n(GetHead(), tail, buffer);
+			head = 0;
+		}
+	}
+
+	void ConsumeFrames(snd_pcm_uframes_t n, size_t frame_size) noexcept {
+		ConsumeBytes(n * frame_size);
+	}
+
+	snd_pcm_uframes_t GetPeriodPosition(size_t frame_size) const noexcept {
+		return head / frame_size;
+	}
+
+	void Rewind() noexcept {
+		head = 0;
+	}
+
+	void Clear() noexcept {
+		head = tail = 0;
+	}
+};
+
+} // namespace Alsa
+
+#endif
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index b022e7347..893f46a39 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "AlsaOutputPlugin.hxx"
 #include "lib/alsa/NonBlock.hxx"
+#include "lib/alsa/PeriodBuffer.hxx"
 #include "lib/alsa/Version.hxx"
 #include "../OutputAPI.hxx"
 #include "mixer/MixerList.hxx"
@@ -153,110 +154,7 @@ class AlsaOutput final
 	 */
 	boost::lockfree::spsc_queue<uint8_t> *ring_buffer;
 
-	class PeriodBuffer {
-		size_t capacity, head, tail;
-
-		uint8_t *buffer;
-
-	public:
-		PeriodBuffer() = default;
-		PeriodBuffer(const PeriodBuffer &) = delete;
-		PeriodBuffer &operator=(const PeriodBuffer &) = delete;
-
-		void Allocate(size_t n_frames, size_t frame_size) noexcept {
-			capacity = n_frames * frame_size;
-
-			/* reserve space for one more (partial) frame,
-			   to be able to fill the buffer with silence,
-			   after moving an unfinished frame to the
-			   end */
-			buffer = new uint8_t[capacity + frame_size - 1];
-			head = tail = 0;
-		}
-
-		void Free() noexcept {
-			delete[] buffer;
-		}
-
-		bool IsEmpty() const noexcept {
-			return head == tail;
-		}
-
-		bool IsFull() const noexcept {
-			return tail >= capacity;
-		}
-
-		uint8_t *GetTail() noexcept {
-			return buffer + tail;
-		}
-
-		size_t GetSpaceBytes() const noexcept {
-			assert(tail <= capacity);
-
-			return capacity - tail;
-		}
-
-		void AppendBytes(size_t n) noexcept {
-			assert(n <= capacity);
-			assert(tail <= capacity - n);
-
-			tail += n;
-		}
-
-		void FillWithSilence(const uint8_t *_silence,
-				     const size_t frame_size) noexcept {
-			size_t partial_frame = tail % frame_size;
-			auto *dest = GetTail() - partial_frame;
-
-			/* move the partial frame to the end */
-			std::copy(dest, GetTail(), buffer + capacity);
-
-			size_t silence_size = capacity - tail - partial_frame;
-			std::copy_n(_silence, silence_size, dest);
-
-			tail = capacity + partial_frame;
-		}
-
-		const uint8_t *GetHead() const noexcept {
-			return buffer + head;
-		}
-
-		snd_pcm_uframes_t GetFrames(size_t frame_size) const noexcept {
-			return (tail - head) / frame_size;
-		}
-
-		void ConsumeBytes(size_t n) noexcept {
-			head += n;
-
-			assert(head <= capacity);
-
-			if (head >= capacity) {
-				tail -= head;
-				/* copy the partial frame (if any)
-				   back to the beginning */
-				std::copy_n(GetHead(), tail, buffer);
-				head = 0;
-			}
-		}
-
-		void ConsumeFrames(snd_pcm_uframes_t n, size_t frame_size) noexcept {
-			ConsumeBytes(n * frame_size);
-		}
-
-		snd_pcm_uframes_t GetPeriodPosition(size_t frame_size) const noexcept {
-			return head / frame_size;
-		}
-
-		void Rewind() noexcept {
-			head = 0;
-		}
-
-		void Clear() noexcept {
-			head = tail = 0;
-		}
-	};
-
-	PeriodBuffer period_buffer;
+	Alsa::PeriodBuffer period_buffer;
 
 	/**
 	 * Protects #cond, #error, #drain.