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