Line data Source code
1 : /* 2 : * Copyright (C) 2004-2025 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 : #include <fstream> 31 : 32 : namespace jami { 33 : 34 : /** 35 : * A ring buffer for mutichannel audio samples 36 : */ 37 : class RingBuffer 38 : { 39 : public: 40 : using clock = std::chrono::high_resolution_clock; 41 : using time_point = clock::time_point; 42 : using FrameCallback = std::function<void(const std::shared_ptr<AudioFrame>&)>; 43 : 44 : /** 45 : * Constructor 46 : * @param size Size of the buffer to create 47 : */ 48 : RingBuffer(const std::string& id, size_t size, AudioFormat format = AudioFormat::MONO()); 49 : 50 : /** 51 : * Destructor 52 : */ 53 : ~RingBuffer(); 54 : 55 693 : const std::string& getId() const { return id; } 56 : 57 : /** 58 : * Reset the counters to 0 for this read offset 59 : */ 60 : void flush(const std::string& ringbufferId); 61 : 62 : void flushAll(); 63 : 64 : /** 65 : * Return the list of subscribers (Ring buffers Id that are reading this ring buffer). 66 : */ 67 : std::vector<std::string> 68 : getSubscribers(); 69 : 70 : inline AudioFormat getFormat() const { return format_; } 71 : 72 107 : inline void setFormat(const AudioFormat& format) 73 : { 74 107 : std::lock_guard l(writeLock_); 75 107 : format_ = format; 76 107 : resizer_.setFormat(format, format.sample_rate / 50); 77 107 : } 78 : 79 : /** 80 : * Add a new readoffset for this ringbuffer 81 : */ 82 : void createReadOffset(const std::string& ringbufferId); 83 : 84 : void createReadOffset(const std::string& ringbufferId, FrameCallback cb); 85 : 86 : /** 87 : * Remove a readoffset for this ringbuffer 88 : */ 89 : void removeReadOffset(const std::string& ringbufferId); 90 : 91 : size_t readOffsetCount() const { return readoffsets_.size(); } 92 : 93 : /** 94 : * Write data in the ring buffer 95 : * @param AudioFrame 96 : */ 97 : void put(std::shared_ptr<AudioFrame>&& data); 98 : 99 : /** 100 : * To get how much samples are available in the buffer to read in 101 : * @return int The available (multichannel) samples number 102 : */ 103 : size_t availableForGet(const std::string& ringbufferId) const; 104 : 105 : /** 106 : * Get data in the ring buffer 107 : * @param ringbufferId 108 : * @return AudioFRame 109 : */ 110 : std::shared_ptr<AudioFrame> get(const std::string& ringbufferId); 111 : 112 : /** 113 : * Discard data from the buffer 114 : * @param toDiscard Number of samples to discard 115 : * @return size_t Number of samples discarded 116 : */ 117 : size_t discard(size_t toDiscard, const std::string& ringbufferId); 118 : 119 : /** 120 : * Total length of the ring buffer which is available for "putting" 121 : * @return int 122 : */ 123 : size_t putLength() const; 124 : 125 : size_t getLength(const std::string& ringbufferId) const; 126 : 127 : inline bool isFull() const { return putLength() == buffer_.size(); } 128 : 129 0 : inline bool isEmpty() const { return putLength() == 0; } 130 : 131 : inline void setFrameSize(int nb_samples) { resizer_.setFrameSize(nb_samples); } 132 : 133 : /** 134 : * Blocks until min_data_length samples of data is available, or until deadline has passed. 135 : * 136 : * @param ringbufferId The read offset for which data should be available. 137 : * @param min_data_length Minimum number of samples that should be available for the call to return 138 : * @param deadline The ringbufferId is guaranteed to end after this time point. If no deadline is provided, 139 : * the call blocks indefinitely. 140 : * @return available data for ringbufferId after the call returned (same as calling getLength(ringbufferId) ). 141 : */ 142 : size_t waitForDataAvailable(const std::string& ringbufferId, 143 : const time_point& deadline = time_point::max()) const; 144 : 145 : /** 146 : * Debug function print mEnd, mStart, mBufferSize 147 : */ 148 : void debug(); 149 : 150 0 : bool isAudioMeterActive() const { return rmsSignal_; } 151 0 : void setAudioMeterState(bool state) { rmsSignal_ = state; } 152 : 153 : private: 154 : struct ReadOffset 155 : { 156 : size_t offset; 157 : FrameCallback callback; 158 : }; 159 : using ReadOffsetMap = std::map<std::string, ReadOffset>; 160 : NON_COPYABLE(RingBuffer); 161 : 162 : void putToBuffer(std::shared_ptr<AudioFrame>&& data); 163 : 164 : bool hasNoReadOffsets() const; 165 : 166 : /** 167 : * Return the smalest readoffset. Useful to evaluate if ringbuffer is full 168 : */ 169 : size_t getSmallestReadOffset() const; 170 : 171 : /** 172 : * Get read offset coresponding to this call 173 : */ 174 : size_t getReadOffset(const std::string& ringbufferId) const; 175 : 176 : /** 177 : * Move readoffset forward by offset 178 : */ 179 : void storeReadOffset(size_t offset, const std::string& ringbufferId); 180 : 181 : /** 182 : * Test if readoffset coresponding to this call is still active 183 : */ 184 : bool hasThisReadOffset(const std::string& ringbufferId) const; 185 : 186 : /** 187 : * Discard data from all read offsets to make place for new data. 188 : */ 189 : size_t discard(size_t toDiscard); 190 : 191 : const std::string id; 192 : 193 : /** Offset on the last data */ 194 : size_t endPos_; 195 : 196 : /** Data */ 197 : AudioFormat format_ {AudioFormat::DEFAULT()}; 198 : std::vector<std::shared_ptr<AudioFrame>> buffer_ {16}; 199 : 200 : mutable std::mutex lock_; 201 : mutable std::condition_variable not_empty_; 202 : std::mutex writeLock_; 203 : 204 : ReadOffsetMap readoffsets_; 205 : 206 : Resampler resampler_; 207 : AudioFrameResizer resizer_; 208 : 209 : std::atomic_bool rmsSignal_ {false}; 210 : double rmsLevel_ {0}; 211 : int rmsFrameCount_ {0}; 212 : }; 213 : 214 : } // namespace jami