Ring Daemon 16.0.0
Loading...
Searching...
No Matches
buf_manager.h
Go to the documentation of this file.
1/*
2 * Copyright 2015 The Android Open Source Project
3 * Copyright 2015-2025 Savoir-faire Linux Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#pragma once
19
20#include "logger.h"
21#include "noncopyable.h"
22
23#include <SLES/OpenSLES.h>
24#include <sys/types.h>
25
26#include <atomic>
27#include <cassert>
28#include <memory>
29#include <limits>
30#include <vector>
31
32/*
33 * ProducerConsumerQueue, borrowed from Ian NiLewis
34 */
35template<typename T>
37{
38public:
39 explicit ProducerConsumerQueue(size_t size)
40 : buffer_(size)
41 {
42 // This is necessary because we depend on twos-complement wraparound
43 // to take care of overflow conditions.
44 assert(size < std::numeric_limits<int>::max());
45 }
46
47 void clear()
48 {
49 read_.store(0);
50 write_.store(0);
51 }
52
53 bool push(const T& item)
54 {
55 return push([&](T* ptr) -> bool {
56 *ptr = item;
57 return true;
58 });
59 }
60
61 // get() is idempotent between calls to commit().
63 {
64 T* result = nullptr;
65
66 bool check __attribute__((unused)); //= false;
67
68 check = push([&](T* head) -> bool {
69 result = head;
70 return false; // don't increment
71 });
72
73 // if there's no space, result should not have been set, and vice versa
74 assert(check == (result != nullptr));
75
76 return result;
77 }
78
79 bool commitWriteablePtr(T* ptr)
80 {
81 bool result = push([&](T* head) -> bool {
82 // this writer func does nothing, because we assume that the caller
83 // has already written to *ptr after acquiring it from a call to get().
84 // So just double-check that ptr is actually at the write head, and
85 // return true to indicate that it's safe to advance.
86
87 // if this isn't the same pointer we got from a call to get(), then
88 // something has gone terribly wrong. Either there was an intervening
89 // call to push() or commit(), or the pointer is spurious.
90 assert(ptr == head);
91 return true;
92 });
93 return result;
94 }
95
96 // writer() can return false, which indicates that the caller
97 // of push() changed its mind while writing (e.g. ran out of bytes)
98 template<typename F>
99 bool push(const F& writer)
100 {
101 bool result = false;
102 int readptr = read_.load(std::memory_order_acquire);
103 int writeptr = write_.load(std::memory_order_relaxed);
104
105 // note that while readptr and writeptr will eventually
106 // wrap around, taking their difference is still valid as
107 // long as size_ < MAXINT.
108 int space = buffer_.size() - (int) (writeptr - readptr);
109 if (space >= 1) {
110 result = true;
111
112 // writer
113 if (writer(buffer_.data() + (writeptr % buffer_.size()))) {
114 ++writeptr;
115 write_.store(writeptr, std::memory_order_release);
116 }
117 }
118 return result;
119 }
120 // front out the queue, but not pop-out
121 bool front(T* out_item)
122 {
123 return front([&](T* ptr) -> bool {
124 *out_item = *ptr;
125 return true;
126 });
127 }
128
129 void pop(void)
130 {
131 int readptr = read_.load(std::memory_order_relaxed);
132 ++readptr;
133 read_.store(readptr, std::memory_order_release);
134 }
135
136 template<typename F>
137 bool front(const F& reader)
138 {
139 bool result = false;
140
141 int writeptr = write_.load(std::memory_order_acquire);
142 int readptr = read_.load(std::memory_order_relaxed);
143
144 // As above, wraparound is ok
145 int available = (int) (writeptr - readptr);
146 if (available >= 1) {
147 result = true;
148 reader(buffer_.data() + (readptr % buffer_.size()));
149 }
150
151 return result;
152 }
153 uint32_t size(void)
154 {
155 int writeptr = write_.load(std::memory_order_acquire);
156 int readptr = read_.load(std::memory_order_relaxed);
157
158 return (uint32_t) (writeptr - readptr);
159 }
160
161private:
163 std::vector<T> buffer_;
164 std::atomic<int> read_ {0};
165 std::atomic<int> write_ {0};
166};
167
169{
170 uint8_t* buf_ {nullptr}; // audio sample container
171 size_t cap_ {0}; // buffer capacity in byte
172 size_t size_ {0}; // audio sample size (n buf) in byte
174 sample_buf(size_t alloc, size_t size)
175 : buf_(new uint8_t[alloc])
176 , cap_(size)
177 {}
178 sample_buf(size_t alloc)
179 : buf_(new uint8_t[alloc])
180 , cap_(alloc)
181 {}
183 : buf_(o.buf_)
184 , cap_(o.cap_)
185 , size_(o.size_)
186 {
187 o.buf_ = nullptr;
188 o.cap_ = 0;
189 o.size_ = 0;
190 }
192 {
193 buf_ = o.buf_;
194 cap_ = o.cap_;
195 size_ = o.size_;
196 o.buf_ = nullptr;
197 o.cap_ = 0;
198 o.size_ = 0;
199 return *this;
200 }
201
203 {
204 if (buf_)
205 delete[] buf_;
206 }
208};
209
bool front(T *out_item)
uint32_t size(void)
bool commitWriteablePtr(T *ptr)
Definition buf_manager.h:79
ProducerConsumerQueue(size_t size)
Definition buf_manager.h:39
bool push(const T &item)
Definition buf_manager.h:53
bool front(const F &reader)
bool push(const F &writer)
Definition buf_manager.h:99
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30
sample_buf(size_t alloc)
size_t cap_
sample_buf(sample_buf &&o)
uint8_t * buf_
sample_buf & operator=(sample_buf &&o)
size_t size_
sample_buf(size_t alloc, size_t size)
NON_COPYABLE(sample_buf)