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 "media_buffer.h"
21 : #include "noncopyable.h"
22 :
23 : #include <map>
24 : #include <set>
25 : #include <string>
26 : #include <mutex>
27 : #include <memory>
28 :
29 : namespace jami {
30 :
31 : class RingBuffer;
32 :
33 : class RingBufferPool
34 : {
35 : public:
36 : using clock = std::chrono::steady_clock;
37 : using time_point = clock::time_point;
38 : using duration = clock::duration;
39 : static const char* const DEFAULT_ID;
40 :
41 : RingBufferPool();
42 : ~RingBufferPool();
43 :
44 32 : int getInternalSamplingRate() const { return static_cast<int>(internalAudioFormat_.sample_rate); }
45 :
46 631 : AudioFormat getInternalAudioFormat() const { return internalAudioFormat_; }
47 :
48 : void setInternalSamplingRate(unsigned sr);
49 :
50 : void setInternalAudioFormat(AudioFormat format);
51 :
52 : /**
53 : * Bind two RingBuffer together (full duplex).
54 : * @param ringbufferId1
55 : * @param ringbufferId2
56 : */
57 : void bindRingBuffers(const std::string& ringbufferId1, const std::string& ringbufferId2);
58 :
59 : /**
60 : * Unbind two RingBuffer (full duplex).
61 : */
62 : void unbindRingBuffers(const std::string& ringbufferId1, const std::string& ringbufferId2);
63 :
64 : /**
65 : * Attaches a reader the specified source.
66 : * @param readerBufferId The ID of the RingBuffer that will act as the reader of the
67 : * sourceBuffer.
68 : * @param sourceBufferId The iID of the RingBuffer that will be the source (to be read from).
69 : */
70 : void bindHalfDuplexOut(const std::string& readerBufferId, const std::string& sourceBufferId);
71 :
72 : /**
73 : * Detaches a reader from the specified source.
74 : * @param readerBufferId The ID of the RingBuffer that acts as the reader to be detached from the
75 : * sourceBuffer.
76 : * @param sourceBufferId The RingBuffer that serves as the source (being read from).
77 : */
78 : void unBindHalfDuplexOut(const std::string& readerBufferId, const std::string& sourceBufferId);
79 :
80 : /**
81 : * Detaches a reader from all his sources.
82 : * @param readerBufferId The ID of the RingBuffer that acts as the reader to be detached from the
83 : * sources.
84 : */
85 : void unBindAllHalfDuplexOut(const std::string& ringbufferId);
86 :
87 : /**
88 : * Detaches a source from all its readers.
89 : * @param sourceBufferId The ID of the RingBuffer that serves as the source (being read from).
90 : */
91 : void unBindAllHalfDuplexIn(const std::string& sourceBufferId);
92 :
93 : void unBindAll(const std::string& ringbufferId);
94 :
95 : bool waitForDataAvailable(const std::string& ringbufferId, const duration& max_wait) const;
96 : bool waitForDataAvailable(const std::string& ringbufferId, const time_point& deadline) const;
97 :
98 : std::shared_ptr<AudioFrame> getData(const std::string& ringbufferId);
99 :
100 : std::shared_ptr<AudioFrame> getAvailableData(const std::string& ringbufferId);
101 :
102 : size_t availableForGet(const std::string& ringbufferId) const;
103 :
104 : size_t discard(size_t toDiscard, const std::string& ringbufferId);
105 :
106 : void flush(const std::string& ringbufferId);
107 :
108 : void flushAllBuffers();
109 :
110 : /**
111 : * Create a new ringbuffer with a default readoffset.
112 : * This class keeps a weak reference on returned pointer,
113 : * so the caller is responsible of the referred instance.
114 : */
115 : std::shared_ptr<RingBuffer> createRingBuffer(const std::string& id);
116 :
117 : /**
118 : * Obtain a shared pointer on a RingBuffer given by its ID.
119 : * If the ID doesn't match to any RingBuffer, the shared pointer
120 : * is empty. This non-const version flushes internal weak pointers
121 : * if the ID was used and the associated RingBuffer has been deleted.
122 : */
123 : std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id);
124 :
125 : /**
126 : * Works as non-const getRingBuffer, without the weak reference flush.
127 : */
128 : std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id) const;
129 :
130 : bool isAudioMeterActive(const std::string& id);
131 : void setAudioMeterState(const std::string& id, bool state);
132 :
133 : private:
134 : NON_COPYABLE(RingBufferPool);
135 :
136 : // A set of RingBuffers readable by a call
137 : using ReadBindings = std::set<std::shared_ptr<RingBuffer>, std::owner_less<std::shared_ptr<RingBuffer>>>;
138 :
139 : const ReadBindings* getReadBindings(const std::string& ringbufferId) const;
140 : ReadBindings* getReadBindings(const std::string& ringbufferId);
141 :
142 : void removeReadBindings(const std::string& ringbufferId);
143 :
144 : /**
145 : * Internal versions that assume stateLock_ is already held by caller.
146 : * These methods do not acquire the lock themselves.
147 : */
148 : std::shared_ptr<RingBuffer> getRingBufferLocked(const std::string& id);
149 : std::shared_ptr<RingBuffer> getRingBufferLocked(const std::string& id) const;
150 : void flushAllBuffersLocked();
151 :
152 : /**
153 : * Attaches a reader to the specified source.
154 : * @param sourceBuffer The RingBuffer that will be the source (to be read from).
155 : * @param readerBufferId The ID of the RingBuffer that will act as the reader of the
156 : * sourceBuffer.
157 : */
158 : void addReaderToRingBuffer(const std::shared_ptr<RingBuffer>& sourceBuffer, const std::string& readerBufferId);
159 :
160 : /**
161 : * Detaches a reader from the specified source.
162 : * @param sourceBuffer The RingBuffer that serves as the source (being read from).
163 : * @param readerBufferId The ID of the RingBuffer that acts as the reader to be detached from the
164 : * sourceBuffer.
165 : */
166 : void removeReaderFromRingBuffer(const std::shared_ptr<RingBuffer>& sourceBuffer, const std::string& readerBufferId);
167 :
168 : // A cache of created RingBuffers listed by IDs.
169 : std::map<std::string, std::weak_ptr<RingBuffer>> ringBufferMap_ {};
170 :
171 : // A map of which RingBuffers a call has some ReadOffsets
172 : std::map<std::string, ReadBindings> readBindingsMap_ {};
173 :
174 : mutable std::mutex stateLock_ {};
175 :
176 : AudioFormat internalAudioFormat_ {AudioFormat::DEFAULT()};
177 :
178 : std::shared_ptr<RingBuffer> defaultRingBuffer_;
179 : };
180 :
181 : } // namespace jami
|