// 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 #include #include #include #include #include #include #include namespace audio { class Stream { public: using UniqueStreamBuffer = std::unique_ptr>; 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 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 allocator; }; } // namespace audio namespace std { template <> struct iterator_traits { 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