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 679 : 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 84 : inline void setFormat(const AudioFormat& format) 71 : { 72 84 : std::lock_guard l(writeLock_); 73 84 : format_ = format; 74 84 : resizer_.setFormat(format, static_cast<int>(format.sample_rate) / 50); 75 84 : } 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