From b08cb148ae387ed685dd3ec935bb23e2f7935a60 Mon Sep 17 00:00:00 2001 From: Max Kellermann 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 + +#include + +#include + +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 *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.