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