Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include "audio_format.h"
20 : #include "noncopyable.h"
21 : #include "audio_frame_resizer.h"
22 : #include "resampler.h"
23 :
24 : #include <atomic>
25 : #include <condition_variable>
26 : #include <mutex>
27 : #include <chrono>
28 : #include <map>
29 : #include <vector>
30 :
31 : namespace jami {
32 :
33 : /**
34 : * A ring buffer for mutichannel audio samples
35 : */
36 : class RingBuffer
37 : {
38 : public:
39 : using clock = std::chrono::steady_clock;
40 : using time_point = clock::time_point;
41 : using FrameCallback = std::function<void(const std::shared_ptr<AudioFrame>&)>;
42 :
43 : /**
44 : * Constructor
45 : * @param size Size of the buffer to create
46 : */
47 : RingBuffer(const std::string& id, AudioFormat format = AudioFormat::MONO());
48 :
49 : /**
50 : * Destructor
51 : */
52 : ~RingBuffer();
53 :
54 702 : const std::string& getId() const { return id; }
55 :
56 : /**
57 : * Reset the counters to 0 for this read offset
58 : */
59 : void flush(const std::string& ringbufferId);
60 :
61 : void flushAll();
62 :
63 : /**
64 : * Return the list of subscribers (Ring buffers Id that are reading this ring buffer).
65 : */
66 : std::vector<std::string> getSubscribers();
67 :
68 : inline AudioFormat getFormat() const { return format_; }
69 :
70 101 : inline void setFormat(const AudioFormat& format)
71 : {
72 101 : std::lock_guard l(writeLock_);
73 101 : format_ = format;
74 101 : resizer_.setFormat(format, static_cast<int>(format.sample_rate) / 50);
75 101 : }
76 :
77 : /**
78 : * Add a new readoffset for this ringbuffer
79 : */
80 : void createReadOffset(const std::string& ringbufferId);
81 :
82 : void createReadOffset(const std::string& ringbufferId, FrameCallback cb);
83 :
84 : /**
85 : * Remove a readoffset for this ringbuffer
86 : */
87 : void removeReadOffset(const std::string& ringbufferId);
88 :
89 : size_t readOffsetCount() const { return readoffsets_.size(); }
90 :
91 : /**
92 : * Write data in the ring buffer
93 : * @param AudioFrame
94 : */
95 : void put(std::shared_ptr<AudioFrame>&& data);
96 :
97 : /**
98 : * To get how much samples are available in the buffer to read in
99 : * @return int The available (multichannel) samples number
100 : */
101 : size_t availableForGet(const std::string& ringbufferId) const;
102 :
103 : /**
104 : * Get data in the ring buffer
105 : * @param ringbufferId
106 : * @return AudioFRame
107 : */
108 : std::shared_ptr<AudioFrame> get(const std::string& ringbufferId);
109 :
110 : /**
111 : * Discard data from the buffer
112 : * @param toDiscard Number of samples to discard
113 : * @return size_t Number of samples discarded
114 : */
115 : size_t discard(size_t toDiscard, const std::string& ringbufferId);
116 :
117 : /**
118 : * Total length of the ring buffer which is available for "putting"
119 : * @return int
120 : */
121 : size_t putLength() const;
122 :
123 : size_t getLength(const std::string& ringbufferId) const;
124 :
125 : inline bool isFull() const { return putLength() == buffer_.size(); }
126 :
127 0 : inline bool isEmpty() const { return putLength() == 0; }
128 :
129 : inline void setFrameSize(int nb_samples) { resizer_.setFrameSize(nb_samples); }
130 :
131 : /**
132 : * Blocks until min_data_length samples of data is available, or until deadline has passed.
133 : *
134 : * @param ringbufferId The read offset for which data should be available.
135 : * @param min_data_length Minimum number of samples that should be available for the call to return
136 : * @param deadline The ringbufferId is guaranteed to end after this time point. If no deadline is provided,
137 : * the call blocks indefinitely.
138 : * @return available data for ringbufferId after the call returned (same as calling getLength(ringbufferId) ).
139 : */
140 : size_t waitForDataAvailable(const std::string& ringbufferId, const time_point& deadline = time_point::max()) const;
141 :
142 : /**
143 : * Debug function print mEnd, mStart, mBufferSize
144 : */
145 : void debug();
146 :
147 0 : bool isAudioMeterActive() const { return rmsSignal_; }
148 0 : void setAudioMeterState(bool state) { rmsSignal_ = state; }
149 :
150 : private:
151 : struct ReadOffset
152 : {
153 : size_t offset;
154 : FrameCallback callback;
155 : };
156 : using ReadOffsetMap = std::map<std::string, ReadOffset>;
157 : NON_COPYABLE(RingBuffer);
158 :
159 : void putToBuffer(std::shared_ptr<AudioFrame>&& data);
160 :
161 : bool hasNoReadOffsets() const;
162 :
163 : /**
164 : * Return the smalest readoffset. Useful to evaluate if ringbuffer is full
165 : */
166 : size_t getSmallestReadOffset() const;
167 :
168 : /**
169 : * Get read offset coresponding to this call
170 : */
171 : size_t getReadOffset(const std::string& ringbufferId) const;
172 :
173 : /**
174 : * Move readoffset forward by offset
175 : */
176 : void storeReadOffset(size_t offset, const std::string& ringbufferId);
177 :
178 : /**
179 : * Test if readoffset coresponding to this call is still active
180 : */
181 : bool hasThisReadOffset(const std::string& ringbufferId) const;
182 :
183 : /**
184 : * Discard data from all read offsets to make place for new data.
185 : */
186 : size_t discard(size_t toDiscard);
187 :
188 : const std::string id;
189 :
190 : /** Offset on the last data */
191 : size_t endPos_;
192 :
193 : /** Data */
194 : AudioFormat format_ {AudioFormat::DEFAULT()};
195 : std::vector<std::shared_ptr<AudioFrame>> buffer_ {16};
196 :
197 : mutable std::mutex lock_;
198 : mutable std::condition_variable not_empty_;
199 : std::mutex writeLock_;
200 :
201 : ReadOffsetMap readoffsets_;
202 :
203 : Resampler resampler_;
204 : AudioFrameResizer resizer_;
205 :
206 : std::atomic_bool rmsSignal_ {false};
207 : double rmsLevel_ {0};
208 : int rmsFrameCount_ {0};
209 : };
210 :
211 : } // namespace jami
|