| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_MEDIA_AUDIO_AUDIO_CORE_RING_BUFFER_H_ |
| #define SRC_MEDIA_AUDIO_AUDIO_CORE_RING_BUFFER_H_ |
| |
| #include <lib/zx/vmo.h> |
| |
| #include <memory> |
| |
| #include "src/media/audio/audio_core/stream.h" |
| #include "src/media/audio/audio_core/utils.h" |
| #include "src/media/audio/audio_core/versioned_timeline_function.h" |
| |
| namespace media::audio { |
| |
| class ReadableRingBuffer; |
| class WritableRingBuffer; |
| |
| // Base class for streams based on ring buffers. |
| class BaseRingBuffer { |
| public: |
| // Creates a ring buffer buffer backed by the given |vmo|. |
| // |
| // Readable buffers will function as if there is an AudioInput device populating the |vmo| with |
| // audio frames conforming to |format|. Essentially the ring will consider frames |frame_count| |
| // frames before |reference_clock_to_fractional_frames(now)| to be valid. |
| // |
| // Conversely, writable buffers will vend out empty buffers that are up to |frame_count| frames |
| // ahead of |reference_clock_to_fractional_frames(now)|, with the expectation there is a hardware |
| // device consuming frames at the trailing edge. |
| // |
| // |offset_frames| determines how logical frame numbers are mapped to physical frame locations in |
| // the ring buffer. Ex: if |offset_frames| is 5, then frame 0 will be located at frame 5 in the |
| // ring buffer. |
| static std::shared_ptr<ReadableRingBuffer> CreateReadableHardwareBuffer( |
| const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, zx::vmo vmo, |
| uint32_t frame_count, uint32_t offset_frames); |
| |
| static std::shared_ptr<WritableRingBuffer> CreateWritableHardwareBuffer( |
| const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, zx::vmo vmo, |
| uint32_t frame_count, uint32_t offset_frames); |
| |
| struct Endpoints { |
| std::shared_ptr<ReadableRingBuffer> reader; |
| std::shared_ptr<WritableRingBuffer> writer; |
| }; |
| |
| // Creates a ring buffer with a freshly-allocated VMO. |
| static Endpoints AllocateSoftwareBuffer( |
| const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, |
| uint32_t frame_count, uint32_t frame_offset = 0); |
| |
| uint64_t size() const { return vmo_mapper_->size(); } |
| uint32_t frames() const { return frames_; } |
| uint32_t offset_frames() const { return offset_frames_; } |
| uint8_t* virt() const { return reinterpret_cast<uint8_t*>(vmo_mapper_->start()); } |
| |
| protected: |
| BaseRingBuffer(const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, |
| fbl::RefPtr<RefCountedVmoMapper> vmo_mapper, uint32_t frame_count, |
| uint32_t offset_frames, bool is_hardware_buffer); |
| virtual ~BaseRingBuffer() = default; |
| |
| BaseStream::TimelineFunctionSnapshot ReferenceClockToFractionalFramesImpl() const; |
| |
| const fbl::RefPtr<RefCountedVmoMapper> vmo_mapper_; |
| const uint32_t frames_ = 0; |
| const fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frame_; |
| const uint32_t offset_frames_; |
| const bool is_hardware_buffer_; |
| }; |
| |
| class ReadableRingBuffer : public ReadableStream, public BaseRingBuffer { |
| public: |
| // This constructor is public so it's accessible by make_shared, but it should never |
| // be called directly. Use static methods in BaseRingBuffer. |
| ReadableRingBuffer(const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, |
| fbl::RefPtr<RefCountedVmoMapper> vmo_mapper, uint32_t frame_count, |
| uint32_t offset_frames, bool is_hardware_buffer); |
| |
| // |media::audio::ReadableStream| |
| std::optional<ReadableStream::Buffer> ReadLock(zx::time now, int64_t frame, |
| uint32_t frame_count) override; |
| void Trim(zx::time trim_threshold) override {} |
| BaseStream::TimelineFunctionSnapshot ReferenceClockToFractionalFrames() const override; |
| }; |
| |
| class WritableRingBuffer : public WritableStream, public BaseRingBuffer { |
| public: |
| // This constructor is public so it's accessible by make_shared, but it should never |
| // be called directly. Use static methods in BaseRingBuffer. |
| WritableRingBuffer(const Format& format, |
| fbl::RefPtr<VersionedTimelineFunction> reference_clock_to_fractional_frames, |
| fbl::RefPtr<RefCountedVmoMapper> vmo_mapper, uint32_t frame_count, |
| uint32_t offset_frames, bool is_hardware_buffer); |
| |
| // |media::audio::WritableStream| |
| std::optional<WritableStream::Buffer> WriteLock(zx::time now, int64_t frame, |
| uint32_t frame_count) override; |
| BaseStream::TimelineFunctionSnapshot ReferenceClockToFractionalFrames() const override; |
| }; |
| |
| } // namespace media::audio |
| |
| #endif // SRC_MEDIA_AUDIO_AUDIO_CORE_RING_BUFFER_H_ |