UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
ring_buffer.cpp File Reference
#include "utils/ring_buffer.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <atomic>
Include dependency graph for ring_buffer.cpp:

Go to the source code of this file.

Classes

struct  ring_buffer
 

Functions

static int calculate_avail_read (int start, int end, int buf_len)
 
static int calculate_avail_write (int start, int end, int buf_len)
 
void ring_advance_read_idx (struct ring_buffer *ring, int amount)
 
bool ring_advance_write_idx (struct ring_buffer *ring, int amount)
 
void ring_buffer_destroy (struct ring_buffer *ring)
 
void ring_buffer_flush (struct ring_buffer *buf)
 
struct ring_buffer * ring_buffer_init (int size)
 
int ring_buffer_read (struct ring_buffer *ring, char *out, int max_len)
 
void ring_buffer_write (struct ring_buffer *ring, const char *in, int len)
 
void ring_fill (struct ring_buffer *ring, int c, int size)
 
int ring_get_available_write_size (struct ring_buffer *ring)
 
int ring_get_current_size (struct ring_buffer *ring)
 
int ring_get_read_regions (struct ring_buffer *ring, int max_len, void **ptr1, int *size1, void **ptr2, int *size2)
 
int ring_get_size (struct ring_buffer *ring)
 
int ring_get_write_regions (struct ring_buffer *ring, int requested_len, void **ptr1, int *size1, void **ptr2, int *size2)
 

Variables

struct audio_buffer_api ring_buffer_fns
 

Detailed Description

Function Documentation

◆ calculate_avail_read()

static int calculate_avail_read ( int start,
int end,
int buf_len )
static

Definition at line 83 of file ring_buffer.cpp.

83 {
84 int avail = (end - start + 2 * buf_len) % buf_len;
85 if(avail == 0 && (end >= buf_len) != (start >= buf_len))
86 avail += buf_len;
87
88 return avail;
89}
static void start()
Definition sdp.c:202

References start().

Referenced by calculate_avail_write(), ring_get_current_size(), and ring_get_read_regions().

Here is the call graph for this function:

◆ calculate_avail_write()

static int calculate_avail_write ( int start,
int end,
int buf_len )
static

Definition at line 91 of file ring_buffer.cpp.

91 {
92 return buf_len - calculate_avail_read(start, end, buf_len);
93}
static int calculate_avail_read(int start, int end, int buf_len)

References calculate_avail_read(), and start().

Referenced by ring_advance_write_idx(), and ring_get_available_write_size().

Here is the call graph for this function:

◆ ring_advance_read_idx()

void ring_advance_read_idx ( struct ring_buffer * ring,
int amount )

Marks memory as already read and free for writing. Use after reading using ring_get_read_regions(), or simply for discarding unwanted unread data.

Parameters
amountamount in bytes to discard

Definition at line 127 of file ring_buffer.cpp.

127 {
128 // start index is modified only by this (reader) thread, so relaxed is enough
129 int start = std::atomic_load_explicit(&ring->start, std::memory_order_relaxed);
130
131 /* Use release order to ensure that all reads are completed (no reads
132 * or writes in the current thread can be reordered after this store).
133 */
134 std::atomic_store_explicit(&ring->start,
135 (start + amount) % (2*ring->len), std::memory_order_release);
136}
std::atomic< int > start

References ring_buffer::len, ring_buffer::start, and start().

Referenced by echo_cancel(), and ring_buffer_read().

Here is the call graph for this function:

◆ ring_advance_write_idx()

bool ring_advance_write_idx ( struct ring_buffer * ring,
int amount )

Marks written memory as ready for reading. Use after writing using ring_get_write_regions().

Parameters
amountamount in bytes to discard
Returns
true if an overflow occured

Definition at line 192 of file ring_buffer.cpp.

192 {
193 const int start = std::atomic_load_explicit(&ring->start, std::memory_order_acquire);
194 // end index is modified only by this (writer) thread, so relaxed is enough
195 const int end = std::atomic_load_explicit(&ring->end, std::memory_order_relaxed);
196
197 /* Use release order to ensure that all writes to the buffer are
198 * completed before advancing the end index (no reads or writes in the
199 * current thread can be reordered after this store).
200 */
201 std::atomic_store_explicit(&ring->end,
202 (end + amount) % (2*ring->len), std::memory_order_release);
203
204 return amount > calculate_avail_write(start, end, ring->len);
205}
static int calculate_avail_write(int start, int end, int buf_len)
std::atomic< int > end

References calculate_avail_write(), ring_buffer::end, ring_buffer::len, ring_buffer::start, and start().

Referenced by audio_export_raw_ch(), echo_cancel(), echo_play(), ring_buffer_write(), and ring_fill().

Here is the call graph for this function:

◆ ring_buffer_destroy()

◆ ring_buffer_flush()

void ring_buffer_flush ( struct ring_buffer * ring)

Flushes all data from ring buffer. Not thread safe - needs external synchronization to ensure that this is not called while the buffer is being read or written.

Definition at line 155 of file ring_buffer.cpp.

155 {
156 /* This should only be called while the buffer is not being read or
157 * written. The only way to safely flush without locking is by reading
158 * all available data from the reader thread.
159 */
160 buf->start = 0;
161 buf->end = 0;
162}

References ring_buffer::end, and ring_buffer::start.

Referenced by audio_reading_thread(), flush_captured_data(), reconfigure_echo(), and reset_import().

◆ ring_buffer_init()

struct ring_buffer * ring_buffer_init ( int size)

◆ ring_buffer_read()

int ring_buffer_read ( struct ring_buffer * ring,
char * out,
int max_len )

Definition at line 138 of file ring_buffer.cpp.

138 {
139 void *ptr1;
140 int size1;
141 void *ptr2;
142 int size2;
143
144 int read_len = ring_get_read_regions(ring, max_len, &ptr1, &size1, &ptr2, &size2);
145
146 memcpy(out, ptr1, size1);
147 if(ptr2) {
148 memcpy(out + size1, ptr2, size2);
149 }
150
151 ring_advance_read_idx(ring, read_len);
152 return read_len;
153}
void ring_advance_read_idx(struct ring_buffer *ring, int amount)
int ring_get_read_regions(struct ring_buffer *ring, int max_len, void **ptr1, int *size1, void **ptr2, int *size2)

References ring_advance_read_idx(), and ring_get_read_regions().

Referenced by audio_buffer_read(), audio_cap_ca_read(), audio_cap_jack_read(), audio_cap_pipewire_read(), audio_cap_portaudio_read(), audio_cap_sdl_mixer_read(), audio_export_thread(), display_deltacast_putf(), display_dvs_run(), echo_cancel(), filter(), get_audio(), on_process(), display_bluefish444_state::playback_loop(), sdl_audio_callback(), and vidcap_import_grab().

Here is the call graph for this function:

◆ ring_buffer_write()

void ring_buffer_write ( struct ring_buffer * ring,
const char * in,
int len )

Definition at line 207 of file ring_buffer.cpp.

207 {
208 void *ptr1;
209 int size1;
210 void *ptr2;
211 int size2;
212 if(len == 0)
213 return;
214 if(!ring_get_write_regions(ring, len, &ptr1, &size1, &ptr2, &size2)){
215 fprintf(stderr, "Warning: too long write request for ring buffer (%d B)!!!\n", len);
216 return;
217 }
218
219 memcpy(ptr1, in, size1);
220 if(ptr2){
221 memcpy(ptr2, in + size1, size2);
222 }
223
224 if(ring_advance_write_idx(ring, len)) {
225 fprintf(stderr, "Warning: ring buffer overflow!!!\n");
226 }
227}
int void size_t * len
bool ring_advance_write_idx(struct ring_buffer *ring, int amount)
int ring_get_write_regions(struct ring_buffer *ring, int requested_len, void **ptr1, int *size1, void **ptr2, int *size2)

References len, ring_advance_write_idx(), and ring_get_write_regions().

Referenced by audio_buffer_write(), audio_export_raw(), audio_play_pw_put_frame(), audio_reading_thread(), callback(), display_deltacast_put_audio_frame(), display_dvs_put_audio_frame(), display_sdl_put_audio_frame(), echo_cancel(), echo_play(), filter(), InputProc(), jack_process_callback(), on_process(), sdl_mixer_audio_callback(), and vidcap_file_write_audio().

Here is the call graph for this function:

◆ ring_fill()

void ring_fill ( struct ring_buffer * ring,
int c,
int size )

Definition at line 233 of file ring_buffer.cpp.

233 {
234 void *ptr1;
235 int size1;
236 void *ptr2;
237 int size2;
238 if(size == 0)
239 return;
240 if(!ring_get_write_regions(ring, size, &ptr1, &size1, &ptr2, &size2)){
241 fprintf(stderr, "Warning: too long write request for ring buffer (%d B)!!!\n", size);
242 return;
243 }
244
245 memset(ptr1, c, size1);
246 if(ptr2){
247 memset(ptr2, c, size2);
248 }
249
250 if(ring_advance_write_idx(ring, size)) {
251 fprintf(stderr, "Warning: ring buffer overflow!!!\n");
252 }
253}

References ring_advance_write_idx(), and ring_get_write_regions().

Referenced by set_delay_size().

Here is the call graph for this function:

◆ ring_get_available_write_size()

int ring_get_available_write_size ( struct ring_buffer * ring)

Returns size available for writing

Definition at line 276 of file ring_buffer.cpp.

276 {
277 int start = std::atomic_load_explicit(&ring->start, std::memory_order_acquire);
278 int end = std::atomic_load_explicit(&ring->end, std::memory_order_acquire);
279 return calculate_avail_write(start, end, ring->len);
280}

References calculate_avail_write(), ring_buffer::end, ring_buffer::len, ring_buffer::start, and start().

Referenced by audio_play_pw_put_frame(), echo_cancel(), and echo_play().

Here is the call graph for this function:

◆ ring_get_current_size()

int ring_get_current_size ( struct ring_buffer * ring)

Returns actual buffer usage

Definition at line 270 of file ring_buffer.cpp.

270 {
271 int start = std::atomic_load_explicit(&ring->start, std::memory_order_acquire);
272 int end = std::atomic_load_explicit(&ring->end, std::memory_order_acquire);
273 return calculate_avail_read(start, end, ring->len);
274}

References calculate_avail_read(), ring_buffer::end, ring_buffer::len, ring_buffer::start, and start().

Referenced by audio_buffer_read(), audio_cap_jack_read(), audio_export_thread(), audio_reading_thread(), echo_cancel(), echo_play(), get_audio(), on_process(), vidcap_file_write_audio(), and vidcap_import_grab().

Here is the call graph for this function:

◆ ring_get_read_regions()

int ring_get_read_regions ( struct ring_buffer * ring,
int max_len,
void ** ptr1,
int * size1,
void ** ptr2,
int * size2 )

Returns pointers to memory available for reading. After reading use ring_advance_read_idx() to mark the memory as free for writing.

Parameters
max_lencap returned size to this value
ptr1pointer to the first region
size1size of available data in the first region
ptr2pointer to the second region
size2size of available data in the second region
Returns
size1 + size2

Definition at line 96 of file ring_buffer.cpp.

99{
100 /* end index is modified by the writer thread, use acquire order to ensure
101 * that all writes by the writer thread made before the modification are
102 * observable in this (reader) thread */
103 int end = std::atomic_load_explicit(&ring->end, std::memory_order_acquire);
104 // start index is modified only by this (reader) thread, so relaxed is enough
105 int start = std::atomic_load_explicit(&ring->start, std::memory_order_relaxed);
106
107 int read_len = calculate_avail_read(start, end, ring->len);
108 if(read_len > max_len)
109 read_len = max_len;
110
111 int start_idx = start % ring->len;
112 int to_end = ring->len - start_idx;
113 *ptr1 = ring->data.get() + start_idx;
114 if(read_len <= to_end) {
115 *size1 = read_len;
116 *ptr2 = nullptr;
117 *size2 = 0;
118 } else {
119 *size1 = to_end;
120 *ptr2 = ring->data.get();
121 *size2 = read_len - to_end;
122 }
123
124 return read_len;
125}
std::unique_ptr< char[]> data

References calculate_avail_read(), ring_buffer::data, ring_buffer::end, ring_buffer::len, ring_buffer::start, and start().

Referenced by ring_buffer_read().

Here is the call graph for this function:

◆ ring_get_size()

int ring_get_size ( struct ring_buffer * ring)

Definition at line 229 of file ring_buffer.cpp.

229 {
230 return ring->len;
231}

References ring_buffer::len.

Referenced by audio_reading_thread(), and display_dvs_reconfigure_audio().

◆ ring_get_write_regions()

int ring_get_write_regions ( struct ring_buffer * ring,
int requested_len,
void ** ptr1,
int * size1,
void ** ptr2,
int * size2 )

Returns pointers to memory available for writing. After writing use ring_advance_write_idx() to mark the memory as available for reading.

Does not check for overflow, returns regions of requested size even if buffer is full.

If the requested_len is longer than the whole buffer, returns 0.

Parameters
requested_lenamount you want to write
ptr1pointer to the first region
size1size of the first region
ptr2pointer to the second region
size2size of the second region
Returns
size1 + size2

Definition at line 164 of file ring_buffer.cpp.

167{
168 *ptr1 = nullptr;
169 *size1 = 0;
170 *ptr2 = nullptr;
171 *size2 = 0;
172
173 // end index is modified only by this (writer) thread, so relaxed is enough
174 int end = std::atomic_load_explicit(&ring->end, std::memory_order_relaxed);
175
176 if(requested_len > ring->len) {
177 return 0;
178 }
179
180 int end_idx = end % ring->len;
181 int to_end = ring->len - end_idx;
182 *ptr1 = ring->data.get() + end_idx;
183 *size1 = requested_len < to_end ? requested_len : to_end;
184 if(*size1 < requested_len){
185 *ptr2 = ring->data.get();
186 *size2 = requested_len - *size1;
187 }
188
189 return *size1 + *size2;
190}

References ring_buffer::data, ring_buffer::end, and ring_buffer::len.

Referenced by audio_export_raw_ch(), echo_cancel(), echo_play(), ring_buffer_write(), and ring_fill().

Variable Documentation

◆ ring_buffer_fns

struct audio_buffer_api ring_buffer_fns
Initial value:
= {
(void (*)(void *)) ring_buffer_destroy,
(int (*)(void *, char *, int)) ring_buffer_read,
(void (*)(void *, const char *, int)) ring_buffer_write
}
void ring_buffer_destroy(struct ring_buffer *ring)
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)

Definition at line 282 of file ring_buffer.cpp.

282 {
283 (void (*)(void *)) ring_buffer_destroy,
284 (int (*)(void *, char *, int)) ring_buffer_read,
285 (void (*)(void *, const char *, int)) ring_buffer_write
286};

Referenced by audio_play_ca_reconfigure(), and audio_play_jack_reconfigure().