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