mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-06-27 09:47:18 -04:00
Audio might have not work if audio streams were reused. This was fixed by introducing proper cleaning procedures.
169 lines
4.7 KiB
C++
169 lines
4.7 KiB
C++
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#pragma once
|
|
|
|
#include <memory/NonCachedMemAllocator.hpp>
|
|
#include <CriticalSectionGuard.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
namespace audio
|
|
{
|
|
class Stream
|
|
{
|
|
public:
|
|
using UniqueStreamBuffer = std::unique_ptr<std::uint8_t[], std::function<void(uint8_t[])>>;
|
|
|
|
struct Span
|
|
{
|
|
std::uint8_t *data = nullptr;
|
|
std::size_t dataSize = 0;
|
|
|
|
std::uint8_t *dataEnd() const noexcept;
|
|
};
|
|
|
|
class RawBlockIterator
|
|
{
|
|
public:
|
|
RawBlockIterator(std::uint8_t *bufStart, std::size_t bufSize, std::uint8_t *ptr, std::size_t stepSize);
|
|
|
|
bool operator==(const RawBlockIterator &rhs);
|
|
bool operator!=(const RawBlockIterator &rhs);
|
|
RawBlockIterator &operator++();
|
|
RawBlockIterator &operator--();
|
|
RawBlockIterator operator++(int);
|
|
RawBlockIterator operator--(int);
|
|
Span operator*();
|
|
|
|
private:
|
|
std::uint8_t *_bufStart = nullptr;
|
|
std::uint8_t *_bufEnd = nullptr;
|
|
std::uint8_t *_curPos = nullptr;
|
|
std::size_t _stepSize = 0;
|
|
};
|
|
|
|
class Allocator
|
|
{
|
|
public:
|
|
virtual UniqueStreamBuffer allocate(std::size_t size) = 0;
|
|
};
|
|
|
|
enum class Event
|
|
{
|
|
NoEvent,
|
|
StreamFull,
|
|
StreamHalfUsed,
|
|
StreamEmpty,
|
|
StreamOverflow,
|
|
StreamUnderFlow
|
|
};
|
|
|
|
enum class EventSourceMode
|
|
{
|
|
ISR,
|
|
Thread
|
|
};
|
|
|
|
class EventListener
|
|
{
|
|
public:
|
|
virtual void onEvent(Stream *stream, Event event, EventSourceMode source) = 0;
|
|
};
|
|
|
|
static constexpr auto defaultBufferingSize = 4U;
|
|
|
|
Stream(Allocator &allocator, std::size_t blockSize, unsigned int bufferingSize = defaultBufferingSize);
|
|
|
|
/// push
|
|
bool push(void *data, std::size_t dataSize);
|
|
bool push(const Span &span);
|
|
bool push();
|
|
|
|
/// pop
|
|
bool pop(Span &span);
|
|
|
|
/// zero copy write
|
|
bool reserve(Span &span);
|
|
void commit();
|
|
void release();
|
|
|
|
/// zero copy read
|
|
bool peek(Span &span);
|
|
void consume();
|
|
void unpeek();
|
|
|
|
/// get empty data span
|
|
Span getNullSpan() const noexcept;
|
|
|
|
void reset();
|
|
|
|
[[nodiscard]] std::size_t getBlockSize() const noexcept;
|
|
[[nodiscard]] std::size_t getBlockCount() const noexcept;
|
|
[[nodiscard]] std::size_t getUsedBlockCount() const noexcept;
|
|
[[nodiscard]] std::size_t getPeekedCount() const noexcept;
|
|
[[nodiscard]] std::size_t getReservedCount() const noexcept;
|
|
[[nodiscard]] bool isEmpty() const noexcept;
|
|
[[nodiscard]] bool isFull() const noexcept;
|
|
[[nodiscard]] bool blocksAvailable() const noexcept;
|
|
|
|
void registerListener(EventListener *listener);
|
|
void unregisterListeners(EventListener *listener);
|
|
|
|
private:
|
|
using LockGuard = cpp_freertos::CriticalSectionGuard;
|
|
|
|
void broadcastEvent(Event event);
|
|
void broadcastStateEvents();
|
|
|
|
Allocator &_allocator;
|
|
std::size_t _blockSize = 0;
|
|
std::size_t _blockCount = 0;
|
|
std::size_t _blocksUsed = 0;
|
|
std::size_t _peekCount = 0;
|
|
std::size_t _reserveCount = 0;
|
|
UniqueStreamBuffer _buffer;
|
|
UniqueStreamBuffer _emptyBuffer;
|
|
std::list<EventListener *> listeners;
|
|
|
|
RawBlockIterator _dataStart;
|
|
RawBlockIterator _dataEnd;
|
|
RawBlockIterator _peekPosition;
|
|
RawBlockIterator _writeReservationPosition;
|
|
};
|
|
|
|
class StandardStreamAllocator : public Stream::Allocator
|
|
{
|
|
public:
|
|
Stream::UniqueStreamBuffer allocate(std::size_t size);
|
|
};
|
|
|
|
class NonCacheableStreamAllocator : public Stream::Allocator
|
|
{
|
|
public:
|
|
NonCacheableStreamAllocator() = default;
|
|
Stream::UniqueStreamBuffer allocate(std::size_t size);
|
|
|
|
private:
|
|
NonCachedMemAllocator<uint8_t> allocator;
|
|
};
|
|
|
|
} // namespace audio
|
|
|
|
namespace std
|
|
{
|
|
template <> struct iterator_traits<audio::Stream::RawBlockIterator>
|
|
{
|
|
using iterator_category = std::forward_iterator_tag;
|
|
using value_type = audio::Stream::Span;
|
|
using difference_type = std::size_t;
|
|
using pointer = audio::Stream::Span *;
|
|
using reference = audio::Stream::Span &;
|
|
};
|
|
}; // namespace std
|