| /* |
| * Copyright (c) 2026 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef MODULES_AUDIO_DEVICE_MAC_AUDIO_RING_BUFFER_MAC_H_ |
| #define MODULES_AUDIO_DEVICE_MAC_AUDIO_RING_BUFFER_MAC_H_ |
| |
| #include <algorithm> |
| #include <atomic> |
| #include <cstddef> |
| #include <span> |
| #include <vector> |
| |
| #include "rtc_base/checks.h" |
| |
| namespace webrtc { |
| |
| // A lightweight, lock-free, single-producer single-consumer (SPSC) ring buffer |
| // for streaming audio samples. |
| template <typename T> |
| class AudioRingBufferMac { |
| public: |
| explicit AudioRingBufferMac(size_t capacity) |
| : capacity_(capacity), |
| buffer_(capacity + 1), |
| read_index_(0), |
| write_index_(0) { |
| RTC_DCHECK_GT(capacity, 0); |
| } |
| |
| AudioRingBufferMac(const AudioRingBufferMac&) = delete; |
| AudioRingBufferMac& operator=(const AudioRingBufferMac&) = delete; |
| |
| // Resets the buffer to empty. Should only be called when the buffer |
| // is idle or externally synchronized. |
| void Clear() { |
| write_index_.store(0, std::memory_order_relaxed); |
| read_index_.store(0, std::memory_order_relaxed); |
| } |
| |
| size_t capacity() const { return capacity_; } |
| |
| // Returns the number of readable elements currently in the buffer. |
| size_t AvailableToRead() const { |
| const size_t w = write_index_.load(std::memory_order_acquire); |
| const size_t r = read_index_.load(std::memory_order_relaxed); |
| return (w >= r) ? (w - r) : (buffer_.size() - (r - w)); |
| } |
| |
| // Returns the number of writable element slots available in the buffer. |
| size_t AvailableToWrite() const { |
| const size_t w = write_index_.load(std::memory_order_relaxed); |
| const size_t r = read_index_.load(std::memory_order_acquire); |
| const size_t used = (w >= r) ? (w - r) : (buffer_.size() - (r - w)); |
| return capacity_ - used; |
| } |
| |
| // Writes up to `data.size()` elements from `data` into the buffer. |
| // If there are fewer writeable element slots than `data.size()` in the |
| // buffer, the available slots are filled. |
| // Returns the number of elements written. |
| size_t Write(std::span<const T> data) { |
| const size_t to_write = std::min(data.size(), AvailableToWrite()); |
| if (to_write == 0) { |
| return 0; |
| } |
| |
| const size_t w = write_index_.load(std::memory_order_relaxed); |
| const size_t first = std::min(to_write, buffer_.size() - w); |
| |
| std::copy_n(data.data(), first, buffer_.data() + w); |
| std::copy_n(data.data() + first, to_write - first, buffer_.data()); |
| |
| const size_t new_w = w + to_write; |
| write_index_.store(new_w >= buffer_.size() ? new_w - buffer_.size() : new_w, |
| std::memory_order_release); |
| return to_write; |
| } |
| |
| // Reads up to `data.size()` elements from the buffer into `data`. |
| // If there are fewer readable elements than `data.size()` available in the |
| // buffer, those available are read. |
| // Returns the number of elements read. |
| size_t Read(std::span<T> data) { |
| const size_t to_read = std::min(data.size(), AvailableToRead()); |
| if (to_read == 0) { |
| return 0; |
| } |
| |
| const size_t r = read_index_.load(std::memory_order_relaxed); |
| const size_t first = std::min(to_read, buffer_.size() - r); |
| |
| std::copy_n(buffer_.data() + r, first, data.data()); |
| std::copy_n(buffer_.data(), to_read - first, data.data() + first); |
| |
| const size_t new_r = r + to_read; |
| read_index_.store(new_r >= buffer_.size() ? new_r - buffer_.size() : new_r, |
| std::memory_order_release); |
| return to_read; |
| } |
| |
| private: |
| const size_t capacity_; |
| std::vector<T> buffer_; |
| alignas(64) std::atomic<size_t> read_index_; |
| alignas(64) std::atomic<size_t> write_index_; |
| }; |
| |
| } // namespace webrtc |
| |
| #endif // MODULES_AUDIO_DEVICE_MAC_AUDIO_RING_BUFFER_MAC_H_ |