Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Macros | Functions
data_buffer.c File Reference

Data Buffer API. More...

#include "asterisk.h"
#include "asterisk/logger.h"
#include "asterisk/strings.h"
#include "asterisk/data_buffer.h"
#include "asterisk/linkedlists.h"
Include dependency graph for data_buffer.c:

Go to the source code of this file.

Data Structures

struct  ast_data_buffer
 Data buffer containing fixed number of data payloads. More...
 
struct  data_buffer_payload_entry
 Payload entry placed inside of the data buffer list. More...
 

Macros

#define CACHED_PAYLOAD_MAX   5
 The number of payloads to increment the cache by. More...
 

Functions

struct ast_data_bufferast_data_buffer_alloc (ast_data_buffer_free_callback free_fn, size_t size)
 Allocate a data buffer. More...
 
static void ast_data_buffer_cache_adjust (struct ast_data_buffer *buffer)
 Helper function that sets the cache to its maximum number of payloads. More...
 
size_t ast_data_buffer_count (const struct ast_data_buffer *buffer)
 Return the number of payloads in a data buffer. More...
 
void ast_data_buffer_free (struct ast_data_buffer *buffer)
 Free a data buffer (and all held data payloads) More...
 
void * ast_data_buffer_get (const struct ast_data_buffer *buffer, size_t pos)
 Retrieve a data payload from the data buffer. More...
 
size_t ast_data_buffer_max (const struct ast_data_buffer *buffer)
 Return the maximum number of payloads a data buffer can hold. More...
 
int ast_data_buffer_put (struct ast_data_buffer *buffer, size_t pos, void *payload)
 Place a data payload at a position in the data buffer. More...
 
void * ast_data_buffer_remove (struct ast_data_buffer *buffer, size_t pos)
 Remove a data payload from the data buffer. More...
 
void * ast_data_buffer_remove_head (struct ast_data_buffer *buffer)
 Remove the first payload from the data buffer. More...
 
void ast_data_buffer_resize (struct ast_data_buffer *buffer, size_t size)
 Resize a data buffer. More...
 
static void data_buffer_free_buffer_payload (struct ast_data_buffer *buffer, struct data_buffer_payload_entry *buffer_payload)
 
static struct data_buffer_payload_entrydata_buffer_payload_alloc (void *payload, size_t pos)
 Helper function to allocate a data payload. More...
 
static void free_fn_do_nothing (void *data)
 

Detailed Description

Data Buffer API.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om
Ben Ford bford.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file data_buffer.c.

Macro Definition Documentation

◆ CACHED_PAYLOAD_MAX

#define CACHED_PAYLOAD_MAX   5

The number of payloads to increment the cache by.

Definition at line 42 of file data_buffer.c.

Function Documentation

◆ ast_data_buffer_alloc()

struct ast_data_buffer * ast_data_buffer_alloc ( ast_data_buffer_free_callback  free_fn,
size_t  size 
)

Allocate a data buffer.

Parameters
free_fnCallback function to free a data payload
sizeThe maximum number of data payloads to contain in the data buffer
Return values
non-NULLsuccess
NULLfailure
Note
free_fn can be NULL. It is up to the consumer of this API to ensure that memory is managed appropriately.
Since
15.4.0

Definition at line 145 of file data_buffer.c.

146{
147 struct ast_data_buffer *buffer;
148
149 ast_assert(size != 0);
150
151 buffer = ast_calloc(1, sizeof(*buffer));
152 if (!buffer) {
153 return NULL;
154 }
155
158
159 /* If free_fn is NULL, just use free_fn_do_nothing as a default */
161 buffer->max = size;
162
164
165 return buffer;
166}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static void ast_data_buffer_cache_adjust(struct ast_data_buffer *buffer)
Helper function that sets the cache to its maximum number of payloads.
Definition: data_buffer.c:100
static void free_fn_do_nothing(void *data)
Definition: data_buffer.c:74
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define NULL
Definition: resample.c:96
Data buffer containing fixed number of data payloads.
Definition: data_buffer.c:59
size_t max
Maximum number of data payloads in the buffer.
Definition: data_buffer.c:69
struct ast_data_buffer::@340 payloads
A linked list of data payloads.
ast_data_buffer_free_callback free_fn
Callback function to free a data payload.
Definition: data_buffer.c:61
struct ast_data_buffer::@341 cached_payloads
A linked list of unused cached data payloads.
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_calloc, ast_data_buffer_cache_adjust(), AST_LIST_HEAD_INIT_NOLOCK, ast_data_buffer::cached_payloads, ast_data_buffer::free_fn, free_fn_do_nothing(), ast_data_buffer::max, NULL, and ast_data_buffer::payloads.

Referenced by ast_rtp_prop_set(), and AST_TEST_DEFINE().

◆ ast_data_buffer_cache_adjust()

static void ast_data_buffer_cache_adjust ( struct ast_data_buffer buffer)
static

Helper function that sets the cache to its maximum number of payloads.

Definition at line 100 of file data_buffer.c.

101{
102 int buffer_space;
103
104 ast_assert(buffer != NULL);
105
106 buffer_space = buffer->max - buffer->count;
107
108 if (buffer->cache_count == buffer_space) {
109 return;
110 }
111
112 if (buffer->cache_count < buffer_space) {
113 /* Add payloads to the cache, if able */
114 while (buffer->cache_count < CACHED_PAYLOAD_MAX && buffer->cache_count < buffer_space) {
115 struct data_buffer_payload_entry *buffer_payload;
116
117 buffer_payload = data_buffer_payload_alloc(NULL, -1);
118 if (buffer_payload) {
119 AST_LIST_INSERT_TAIL(&buffer->cached_payloads, buffer_payload, list);
120 buffer->cache_count++;
121 continue;
122 }
123
124 ast_log(LOG_ERROR, "Failed to allocate memory to the cache.");
125 break;
126 }
127 } else if (buffer->cache_count > buffer_space) {
128 /* Remove payloads from the cache */
129 while (buffer->cache_count > buffer_space) {
130 struct data_buffer_payload_entry *buffer_payload;
131
132 buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->cached_payloads, list);
133 if (buffer_payload) {
134 ast_free(buffer_payload);
135 buffer->cache_count--;
136 continue;
137 }
138
139 ast_log(LOG_ERROR, "Failed to remove memory from the cache.");
140 break;
141 }
142 }
143}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
#define CACHED_PAYLOAD_MAX
The number of payloads to increment the cache by.
Definition: data_buffer.c:42
static struct data_buffer_payload_entry * data_buffer_payload_alloc(void *payload, size_t pos)
Helper function to allocate a data payload.
Definition: data_buffer.c:82
#define LOG_ERROR
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
size_t count
The current number of data payloads in the buffer.
Definition: data_buffer.c:67
size_t cache_count
The current number of data payloads in the cache.
Definition: data_buffer.c:71
Payload entry placed inside of the data buffer list.
Definition: data_buffer.c:47
struct data_buffer_payload_entry::@339 list
Linked list information.

References ast_assert, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, ast_log, ast_data_buffer::cache_count, CACHED_PAYLOAD_MAX, ast_data_buffer::cached_payloads, ast_data_buffer::count, data_buffer_payload_alloc(), data_buffer_payload_entry::list, LOG_ERROR, ast_data_buffer::max, and NULL.

Referenced by ast_data_buffer_alloc(), ast_data_buffer_put(), and ast_data_buffer_resize().

◆ ast_data_buffer_count()

size_t ast_data_buffer_count ( const struct ast_data_buffer buffer)

Return the number of payloads in a data buffer.

Parameters
bufferThe data buffer
Returns
the number of data payloads
Since
15.4.0

Definition at line 356 of file data_buffer.c.

357{
358 ast_assert(buffer != NULL);
359
360 return buffer->count;
361}

References ast_assert, ast_data_buffer::count, and NULL.

Referenced by ast_rtp_read(), and AST_TEST_DEFINE().

◆ ast_data_buffer_free()

void ast_data_buffer_free ( struct ast_data_buffer buffer)

Free a data buffer (and all held data payloads)

Parameters
bufferThe data buffer
Since
15.4.0

Definition at line 338 of file data_buffer.c.

339{
340 struct data_buffer_payload_entry *buffer_payload;
341
342 ast_assert(buffer != NULL);
343
344 while ((buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->payloads, list))) {
345 buffer->free_fn(buffer_payload->payload);
346 ast_free(buffer_payload);
347 }
348
349 while ((buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->cached_payloads, list))) {
350 ast_free(buffer_payload);
351 }
352
353 ast_free(buffer);
354}
void * payload
The payload for this position.
Definition: data_buffer.c:49

References ast_assert, ast_free, AST_LIST_REMOVE_HEAD, ast_data_buffer::cached_payloads, ast_data_buffer::free_fn, data_buffer_payload_entry::list, NULL, data_buffer_payload_entry::payload, and ast_data_buffer::payloads.

Referenced by ast_data_buffer_free_wrapper(), ast_rtp_destroy(), and ast_rtp_prop_set().

◆ ast_data_buffer_get()

void * ast_data_buffer_get ( const struct ast_data_buffer buffer,
size_t  pos 
)

Retrieve a data payload from the data buffer.

Parameters
bufferThe data buffer
posThe position of the data payload
Return values
non-NULLsuccess
NULLfailure
Note
This does not remove the data payload from the data buffer. It will be removed when it is displaced.
Since
15.4.0

Definition at line 269 of file data_buffer.c.

270{
271 struct data_buffer_payload_entry *buffer_payload;
272
273 ast_assert(buffer != NULL);
274
275 AST_LIST_TRAVERSE(&buffer->payloads, buffer_payload, list) {
276 if (buffer_payload->pos == pos) {
277 return buffer_payload->payload;
278 }
279 }
280
281 return NULL;
282}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
size_t pos
The provided position for this.
Definition: data_buffer.c:51

References ast_assert, AST_LIST_TRAVERSE, data_buffer_payload_entry::list, NULL, data_buffer_payload_entry::payload, ast_data_buffer::payloads, and data_buffer_payload_entry::pos.

Referenced by ast_rtp_read(), ast_rtp_rtcp_handle_nack(), and AST_TEST_DEFINE().

◆ ast_data_buffer_max()

size_t ast_data_buffer_max ( const struct ast_data_buffer buffer)

Return the maximum number of payloads a data buffer can hold.

Parameters
bufferThe data buffer
Returns
the maximum number of data payloads
Since
15.4.0

Definition at line 363 of file data_buffer.c.

364{
365 ast_assert(buffer != NULL);
366
367 return buffer->max;
368}

References ast_assert, ast_data_buffer::max, and NULL.

Referenced by ast_rtp_read(), ast_rtp_rtcp_handle_nack(), and AST_TEST_DEFINE().

◆ ast_data_buffer_put()

int ast_data_buffer_put ( struct ast_data_buffer buffer,
size_t  pos,
void *  payload 
)

Place a data payload at a position in the data buffer.

Parameters
bufferThe data buffer
posThe position of the data payload
payloadThe data payload
Return values
0success
-1failure
Note
It is up to the consumer of this API to ensure proper memory management of data payloads
Since
15.4.0

Definition at line 203 of file data_buffer.c.

204{
205 struct data_buffer_payload_entry *buffer_payload = NULL;
206 struct data_buffer_payload_entry *existing_payload;
207 int inserted = 0;
208
209 ast_assert(buffer != NULL);
211
212 /* If the data buffer has reached its maximum size then the head goes away and
213 * we will reuse its buffer payload
214 */
215 if (buffer->count == buffer->max) {
216 buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->payloads, list);
217 buffer->free_fn(buffer_payload->payload);
218 buffer->count--;
219
220 /* Update this buffer payload with its new information */
221 buffer_payload->payload = payload;
222 buffer_payload->pos = pos;
223 }
224 if (!buffer_payload) {
225 if (!buffer->cache_count) {
227 }
228 buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->cached_payloads, list);
229 buffer->cache_count--;
230
231 /* Update the payload from the cache with its new information */
232 buffer_payload->payload = payload;
233 buffer_payload->pos = pos;
234 }
235 if (!buffer_payload) {
236 return -1;
237 }
238
239 /* Given the position find its ideal spot within the buffer */
240 AST_LIST_TRAVERSE_SAFE_BEGIN(&buffer->payloads, existing_payload, list) {
241 /* If it's already in the buffer, drop it */
242 if (existing_payload->pos == pos) {
243 ast_debug(3, "Packet with position %zu is already in buffer. Not inserting.\n", pos);
244 inserted = -1;
245 break;
246 }
247
248 if (existing_payload->pos > pos) {
249 AST_LIST_INSERT_BEFORE_CURRENT(buffer_payload, list);
250 inserted = 1;
251 break;
252 }
253 }
255
256 if (inserted == -1) {
257 return -1;
258 }
259
260 if (!inserted) {
261 AST_LIST_INSERT_TAIL(&buffer->payloads, buffer_payload, list);
262 }
263
264 buffer->count++;
265
266 return 0;
267}
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529

References ast_assert, ast_data_buffer_cache_adjust(), ast_debug, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_data_buffer::cache_count, ast_data_buffer::cached_payloads, ast_data_buffer::count, ast_data_buffer::free_fn, data_buffer_payload_entry::list, ast_data_buffer::max, NULL, data_buffer_payload_entry::payload, ast_data_buffer::payloads, and data_buffer_payload_entry::pos.

Referenced by ast_rtp_read(), AST_TEST_DEFINE(), and rtp_raw_write().

◆ ast_data_buffer_remove()

void * ast_data_buffer_remove ( struct ast_data_buffer buffer,
size_t  pos 
)

Remove a data payload from the data buffer.

Parameters
bufferThe data buffer
posThe position of the data payload
Return values
non-NULLsuccess
NULLfailure
Note
This DOES remove the data payload from the data buffer. It does not free it, though.
Since
15.5.0

Definition at line 299 of file data_buffer.c.

300{
301 struct data_buffer_payload_entry *buffer_payload;
302
303 ast_assert(buffer != NULL);
304
305 AST_LIST_TRAVERSE_SAFE_BEGIN(&buffer->payloads, buffer_payload, list) {
306 if (buffer_payload->pos == pos) {
307 void *payload = buffer_payload->payload;
308
310 data_buffer_free_buffer_payload(buffer, buffer_payload);
311
312 return payload;
313 }
314 }
316
317 return NULL;
318}
static void data_buffer_free_buffer_payload(struct ast_data_buffer *buffer, struct data_buffer_payload_entry *buffer_payload)
Definition: data_buffer.c:284
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557

References ast_assert, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, data_buffer_free_buffer_payload(), data_buffer_payload_entry::list, NULL, data_buffer_payload_entry::payload, ast_data_buffer::payloads, and data_buffer_payload_entry::pos.

Referenced by ast_rtp_read(), and AST_TEST_DEFINE().

◆ ast_data_buffer_remove_head()

void * ast_data_buffer_remove_head ( struct ast_data_buffer buffer)

Remove the first payload from the data buffer.

Parameters
bufferThe data buffer
Return values
non-NULLsuccess
NULLfailure
Note
This DOES remove the data payload from the data buffer.
Since
15.5.0

Definition at line 320 of file data_buffer.c.

321{
322 ast_assert(buffer != NULL);
323
324 if (buffer->count > 0) {
325 struct data_buffer_payload_entry *buffer_payload;
326 void *payload;
327
328 buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->payloads, list);
329 payload = buffer_payload->payload;
330 data_buffer_free_buffer_payload(buffer, buffer_payload);
331
332 return payload;
333 }
334
335 return NULL;
336}

References ast_assert, AST_LIST_REMOVE_HEAD, ast_data_buffer::count, data_buffer_free_buffer_payload(), data_buffer_payload_entry::list, NULL, data_buffer_payload_entry::payload, and ast_data_buffer::payloads.

Referenced by AST_TEST_DEFINE().

◆ ast_data_buffer_resize()

void ast_data_buffer_resize ( struct ast_data_buffer buffer,
size_t  size 
)

Resize a data buffer.

Parameters
bufferThe data buffer
sizeThe new maximum size of the data buffer
Note
If the data buffer is shrunk any old data payloads will be freed using the configured callback. The data buffer is flexible and can be used for multiple purposes. Therefore it is up to the caller of the function to know whether or not a buffer should have its size changed. Increasing the size of the buffer may make sense in some scenarios, but shrinking should always be handled with caution since data can be lost.
Since
15.4.0

Definition at line 168 of file data_buffer.c.

169{
170 struct data_buffer_payload_entry *existing_payload;
171
172 ast_assert(buffer != NULL);
173
174 /* The buffer must have at least a size of 1 */
175 ast_assert(size > 0);
176
177 if (buffer->max == size) {
178 return;
179 }
180
181 /* If the size is decreasing, some payloads will need to be freed */
182 if (buffer->max > size) {
183 int remove = buffer->max - size;
184
185 AST_LIST_TRAVERSE_SAFE_BEGIN(&buffer->payloads, existing_payload, list) {
186 if (remove) {
188 buffer->free_fn(existing_payload->payload);
189 ast_free(existing_payload);
190 buffer->count--;
191 remove--;
192 continue;
193 }
194 break;
195 }
197 }
198
199 buffer->max = size;
201}
#define remove

References ast_assert, ast_data_buffer_cache_adjust(), ast_free, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_data_buffer::count, ast_data_buffer::free_fn, data_buffer_payload_entry::list, ast_data_buffer::max, NULL, data_buffer_payload_entry::payload, ast_data_buffer::payloads, and remove.

Referenced by ast_rtp_read(), ast_rtp_rtcp_handle_nack(), and AST_TEST_DEFINE().

◆ data_buffer_free_buffer_payload()

static void data_buffer_free_buffer_payload ( struct ast_data_buffer buffer,
struct data_buffer_payload_entry buffer_payload 
)
static

Definition at line 284 of file data_buffer.c.

286{
287 buffer_payload->payload = NULL;
288 buffer->count--;
289
290 if (buffer->cache_count < CACHED_PAYLOAD_MAX
291 && buffer->cache_count < (buffer->max - buffer->count)) {
292 AST_LIST_INSERT_TAIL(&buffer->cached_payloads, buffer_payload, list);
293 buffer->cache_count++;
294 } else {
295 ast_free(buffer_payload);
296 }
297}

References ast_free, AST_LIST_INSERT_TAIL, ast_data_buffer::cache_count, CACHED_PAYLOAD_MAX, ast_data_buffer::cached_payloads, ast_data_buffer::count, data_buffer_payload_entry::list, ast_data_buffer::max, NULL, and data_buffer_payload_entry::payload.

Referenced by ast_data_buffer_remove(), and ast_data_buffer_remove_head().

◆ data_buffer_payload_alloc()

static struct data_buffer_payload_entry * data_buffer_payload_alloc ( void *  payload,
size_t  pos 
)
static

Helper function to allocate a data payload.

Definition at line 82 of file data_buffer.c.

83{
84 struct data_buffer_payload_entry *data_payload;
85
86 data_payload = ast_calloc(1, sizeof(*data_payload));
87 if (!data_payload) {
88 return NULL;
89 }
90
91 data_payload->payload = payload;
92 data_payload->pos = pos;
93
94 return data_payload;
95}

References ast_calloc, NULL, data_buffer_payload_entry::payload, and data_buffer_payload_entry::pos.

Referenced by ast_data_buffer_cache_adjust().

◆ free_fn_do_nothing()

static void free_fn_do_nothing ( void *  data)
static

Definition at line 74 of file data_buffer.c.

75{
76 return;
77}

Referenced by ast_data_buffer_alloc().