1 /* Libvisual - The audio visualisation framework.
2  *
3  * Copyright (C) 2004, 2005, 2006 Dennis Smit <ds@nerds-incorporated.org>
4  *
5  * Authors: Dennis Smit <ds@nerds-incorporated.org>
6  *
7  * $Id: lv_ringbuffer.c,v 1.8 2006/01/22 13:23:37 synap Exp $
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as
11  * published by the Free Software Foundation; either version 2.1
12  * of the License, or (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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <gettext.h>
30 
31 #include <lvconfig.h>
32 #include "lv_ringbuffer.h"
33 #include "lv_log.h"
34 #include "lv_mem.h"
35 
36 static int ringbuffer_dtor (VisObject *object);
37 static int ringbuffer_entry_dtor (VisObject *object);
38 
39 static int fixate_with_partial_data_request (VisRingBuffer *ringbuffer, VisBuffer *data, int offset, int nbytes,
40 		int *buffercorr);
41 
42 
ringbuffer_dtor(VisObject * object)43 static int ringbuffer_dtor (VisObject *object)
44 {
45 	VisRingBuffer *ringbuffer = VISUAL_RINGBUFFER (object);
46 
47 	if (ringbuffer->entries != NULL)
48 		visual_object_unref (VISUAL_OBJECT (ringbuffer->entries));
49 
50 	ringbuffer->entries = NULL;
51 
52 	return VISUAL_OK;
53 }
54 
ringbuffer_entry_dtor(VisObject * object)55 static int ringbuffer_entry_dtor (VisObject *object)
56 {
57 	VisRingBufferEntry *entry = VISUAL_RINGBUFFER_ENTRY (object);
58 
59 	if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_BUFFER) {
60 
61 		if (entry->buffer != NULL)
62 			visual_object_unref (VISUAL_OBJECT (entry->buffer));
63 
64 	} else if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION) {
65 
66 		if (entry->destroyfunc != NULL)
67 			entry->destroyfunc (entry);
68 	}
69 
70 	entry->type = VISUAL_RINGBUFFER_ENTRY_TYPE_NONE;
71 	entry->datafunc = NULL;
72 	entry->destroyfunc = NULL;
73 	entry->sizefunc = NULL;
74 	entry->buffer = NULL;
75 	entry->functiondata = NULL;
76 
77 	return VISUAL_OK;
78 }
79 
80 /**
81  * @defgroup VisRingBuffer VisRingBuffer
82  * @{
83  */
84 
85 /**
86  * Creates a new VisRingBuffer structure.
87  * The VisRingBuffer system is a double linked ringbuffer implementation.
88  *
89  * @return A newly allocated VisRingBuffer.
90  */
visual_ringbuffer_new()91 VisRingBuffer *visual_ringbuffer_new ()
92 {
93 	VisRingBuffer *ringbuffer;
94 
95 	ringbuffer = visual_mem_new0 (VisRingBuffer, 1);
96 
97 	visual_ringbuffer_init (ringbuffer);
98 
99 	/* Do the VisObject initialization */
100 	visual_object_set_allocated (VISUAL_OBJECT (ringbuffer), TRUE);
101 	visual_object_ref (VISUAL_OBJECT (ringbuffer));
102 
103 	return ringbuffer;
104 }
105 
visual_ringbuffer_init(VisRingBuffer * ringbuffer)106 int visual_ringbuffer_init (VisRingBuffer *ringbuffer)
107 {
108 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
109 
110 	/* Do the VisObject initialization */
111 	visual_object_clear (VISUAL_OBJECT (ringbuffer));
112 	visual_object_set_dtor (VISUAL_OBJECT (ringbuffer), ringbuffer_dtor);
113 	visual_object_set_allocated (VISUAL_OBJECT (ringbuffer), FALSE);
114 
115 	/* Reset the VisRingBuffer structure */
116 	ringbuffer->entries = visual_list_new (visual_object_collection_destroyer);
117 
118 	return VISUAL_OK;
119 }
120 
121 /**
122  * Adds a VisRingBufferEntry to the end of the ringbuffer.
123  *
124  * @param ringbuffer The VisRingBuffer to which the VisRingBufferEntry is added.
125  * @param entry The VisRingBufferEntry that is added to the end of the ringbuffer.
126  *
127  * @return VISUAL_OK on succes, -VISUAL_ERROR_RINGBUFFER_NULL or -VISUAL_ERROR_RINGBUFFER_ENTRY_NULL
128  *	on failure.
129  */
visual_ringbuffer_add_entry(VisRingBuffer * ringbuffer,VisRingBufferEntry * entry)130 int visual_ringbuffer_add_entry (VisRingBuffer *ringbuffer, VisRingBufferEntry *entry)
131 {
132 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
133 	visual_log_return_val_if_fail (entry != NULL, -VISUAL_ERROR_RINGBUFFER_ENTRY_NULL);
134 
135 	visual_list_add (ringbuffer->entries, entry);
136 
137 	return VISUAL_OK;
138 }
139 
140 /**
141  * Adds a VisBuffer to the end of the ringbuffer.
142  *
143  * @param ringbuffer The VisRingBuffer to which the VisBuffer is added.
144  * @param buffer The VisBuffer that is added to the VisRingBuffer.
145  *
146  * @return VISUAL_OK on succes or -VISUAL_ERROR_RINGBUFFER_NULL, -VISUAL_ERROR_RINGBUFFER_ENTRY_NULL
147  *	on failure.
148  */
visual_ringbuffer_add_buffer(VisRingBuffer * ringbuffer,VisBuffer * buffer)149 int visual_ringbuffer_add_buffer (VisRingBuffer *ringbuffer, VisBuffer *buffer)
150 {
151 	VisRingBufferEntry *entry;
152 
153 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
154 
155 	entry = visual_ringbuffer_entry_new (buffer);
156 
157 	return visual_ringbuffer_add_entry (ringbuffer, entry);
158 }
159 
160 /**
161  * Adds a portion of data to the ringbuffer of nbytes byte size.
162  *
163  * @param ringbuffer Pointer to the ringbuffer to which the data is added.
164  * @param data Pointer to the data that is added to the ringbuffer.
165  * @param nbytes The size of the data that is added to the ringbuffer.
166  *
167  * @return VISUAL_OK on succes or -VISUAL_ERROR_RINGBUFFER_NULL, -VISUAL_ERROR_NULL,
168  *	-VISUAL_ERROR_RINGBUFFER_ENTRY_NULL on failure.
169  */
visual_ringbuffer_add_buffer_by_data(VisRingBuffer * ringbuffer,void * data,int nbytes)170 int visual_ringbuffer_add_buffer_by_data (VisRingBuffer *ringbuffer, void *data, int nbytes)
171 {
172 	VisBuffer *buffer;
173 
174 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
175 	visual_log_return_val_if_fail (data != NULL, -VISUAL_ERROR_NULL);
176 
177 	buffer = visual_buffer_new_with_buffer (data, nbytes, NULL);
178 
179 	return visual_ringbuffer_add_buffer (ringbuffer, buffer);
180 }
181 
visual_ringbuffer_add_function(VisRingBuffer * ringbuffer,VisRingBufferDataFunc datafunc,VisRingBufferDestroyFunc destroyfunc,VisRingBufferSizeFunc sizefunc,void * functiondata)182 int visual_ringbuffer_add_function (VisRingBuffer *ringbuffer,
183 		VisRingBufferDataFunc datafunc,
184 		VisRingBufferDestroyFunc destroyfunc,
185 		VisRingBufferSizeFunc sizefunc,
186 		void *functiondata)
187 {
188 	VisRingBufferEntry *entry;
189 
190 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
191 	visual_log_return_val_if_fail (datafunc != NULL, -VISUAL_ERROR_RINGBUFFER_DATAFUNC_NULL);
192 
193 	entry = visual_ringbuffer_entry_new_function (datafunc, destroyfunc, sizefunc, functiondata);
194 
195 	return visual_ringbuffer_add_entry (ringbuffer, entry);
196 }
197 
visual_ringbuffer_get_size(VisRingBuffer * ringbuffer)198 int visual_ringbuffer_get_size (VisRingBuffer *ringbuffer)
199 {
200 	VisListEntry *le = NULL;
201 	VisRingBufferEntry *entry;
202 	int totalsize = 0;
203 
204 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
205 
206 	while ((entry = visual_list_next (ringbuffer->entries, &le)) != NULL) {
207 		int bsize = 0;
208 
209 		if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_BUFFER) {
210 
211 			if ((bsize = visual_buffer_get_size (entry->buffer)) > 0)
212 					totalsize += bsize;
213 
214 		} else if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION) {
215 
216 			if (entry->sizefunc != NULL) {
217 				totalsize += entry->sizefunc (ringbuffer, entry);
218 			} else {
219 				VisBuffer *tempbuf = entry->datafunc (ringbuffer, entry);
220 
221 				if ((bsize = visual_buffer_get_size (tempbuf)) > 0)
222 						totalsize += bsize;
223 
224 				visual_object_unref (VISUAL_OBJECT (tempbuf));
225 			}
226 		}
227 	}
228 
229 	return totalsize;
230 }
231 
232 /**
233  * Gets a list of all ringbuffer fragments that are currently in the ringbuffer.
234  *
235  * @param ringbuffer Pointer to the VisRingBuffer of which the fragments are requested.
236  *
237  * @return A VisList of VisRingBufferEntry items or NULL on failure.
238  */
visual_ringbuffer_get_list(VisRingBuffer * ringbuffer)239 VisList *visual_ringbuffer_get_list (VisRingBuffer *ringbuffer)
240 {
241 	visual_log_return_val_if_fail (ringbuffer != NULL, NULL);
242 
243 	return ringbuffer->entries;
244 }
245 
visual_ringbuffer_get_data(VisRingBuffer * ringbuffer,VisBuffer * data,int nbytes)246 int visual_ringbuffer_get_data (VisRingBuffer *ringbuffer, VisBuffer *data, int nbytes)
247 {
248 	return visual_ringbuffer_get_data_offset (ringbuffer, data, 0, nbytes);
249 }
250 
visual_ringbuffer_get_data_offset(VisRingBuffer * ringbuffer,VisBuffer * data,int offset,int nbytes)251 int visual_ringbuffer_get_data_offset (VisRingBuffer *ringbuffer, VisBuffer *data, int offset, int nbytes)
252 {
253 	VisListEntry *le = NULL;
254 	VisRingBufferEntry *entry;
255 	int curposition = 0;
256 	int curoffset = 0;
257 	int positioncorr = 0;
258 	int startat = 0;
259 	int buffercorr = 0;
260 
261 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
262 	visual_log_return_val_if_fail (data != NULL, -VISUAL_ERROR_BUFFER_NULL);
263 
264 	/* Fixate possible partial buffer */
265 	if (offset > 0)
266 		startat = fixate_with_partial_data_request (ringbuffer, data, offset, nbytes, &buffercorr);
267 
268 	curposition = buffercorr;
269 
270 	/* Buffer fixated with partial segment, request the other segments */
271 	while (curposition < nbytes) {
272 		int lindex = 0;
273 		le = NULL;
274 
275 		while ((entry = visual_list_next (ringbuffer->entries, &le)) != NULL) {
276 			VisBuffer *tempbuf;
277 
278 			lindex++;
279 
280 			/* Skip to the right offset buffer fragment */
281 			if (lindex <= startat)
282 				continue;
283 
284 			if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_BUFFER) {
285 
286 				tempbuf = entry->buffer;
287 
288 			} else if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION) {
289 
290 				/* Will bail out through visual_error_raise(), this is fatal, let's not try to
291 				 * recover, it's a very obvious bug in the software */
292 				if (entry->datafunc == NULL) {
293 					visual_log (VISUAL_LOG_ERROR,
294 							_("No VisRingBufferDataFunc data provider function set on "
295 								"type VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION"));
296 
297 					return -VISUAL_ERROR_IMPOSSIBLE;
298 				}
299 
300 				tempbuf = entry->datafunc (ringbuffer, entry);
301 			}
302 
303 			if (curposition + visual_buffer_get_size (tempbuf) > nbytes) {
304 				VisBuffer buf;
305 
306 				visual_buffer_init (&buf, visual_buffer_get_data (tempbuf),
307 						nbytes - curposition, NULL);
308 
309 				visual_buffer_put (data, &buf, curposition);
310 
311 				if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION)
312 					visual_object_unref (VISUAL_OBJECT (tempbuf));
313 
314 				return VISUAL_OK;
315 			}
316 
317 			visual_buffer_put (data, tempbuf, curposition);
318 
319 			curposition += visual_buffer_get_size (tempbuf);
320 
321 			if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION)
322 				visual_object_unref (VISUAL_OBJECT (tempbuf));
323 
324 			/* Filled without room for partial buffer addition */
325 			if (curposition == nbytes)
326 				return VISUAL_OK;
327 		}
328 
329 		startat = 0;
330 	}
331 
332 	return VISUAL_OK;
333 }
334 
fixate_with_partial_data_request(VisRingBuffer * ringbuffer,VisBuffer * data,int offset,int nbytes,int * buffercorr)335 static int fixate_with_partial_data_request (VisRingBuffer *ringbuffer, VisBuffer *data, int offset, int nbytes,
336 		int *buffercorr)
337 {
338 	VisListEntry *le = NULL;
339 	VisRingBufferEntry *entry;
340 	int curposition = 0;
341 	int curoffset = 0;
342 	int startat = 0;
343 
344 	*buffercorr = 0;
345 
346 	while ((entry = visual_list_next (ringbuffer->entries, &le)) != NULL) {
347 		int bsize = 0;
348 
349 		startat++;
350 
351 		if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_BUFFER) {
352 
353 			if ((bsize = visual_buffer_get_size (entry->buffer)) > 0)
354 				curoffset += bsize;
355 
356 			/* This buffer partially falls within the offset */
357 			if (curoffset > offset) {
358 				visual_buffer_put_data (data,
359 						(visual_buffer_get_data (entry->buffer) +
360 						 visual_buffer_get_size (entry->buffer)) -
361 						(curoffset - offset), curoffset - offset, 0);
362 
363 				*buffercorr = curoffset - offset;
364 
365 				break;
366 			}
367 		} else if (entry->type == VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION) {
368 
369 			if (entry->sizefunc != NULL) {
370 				curoffset += entry->sizefunc (ringbuffer, entry);
371 
372 				/* This buffer partially falls within the offset */
373 				if (curoffset > offset) {
374 
375 					VisBuffer *tempbuf = entry->datafunc (ringbuffer, entry);
376 
377 					visual_buffer_put_data (data,
378 							(visual_buffer_get_data (tempbuf) +
379 							visual_buffer_get_size (tempbuf)) -
380 							(curoffset - offset), curoffset - offset, 0);
381 
382 					visual_object_unref (VISUAL_OBJECT (tempbuf));
383 
384 					*buffercorr = curoffset - offset;
385 
386 					break;
387 				}
388 			} else {
389 				VisBuffer *tempbuf = entry->datafunc (ringbuffer, entry);
390 
391 				if ((bsize = visual_buffer_get_size (tempbuf)) > 0)
392 					curoffset += bsize;
393 
394 				/* This buffer partially falls within the offset */
395 				if (curoffset > offset) {
396 					visual_buffer_put_data (data,
397 							(visual_buffer_get_data (tempbuf) +
398 							visual_buffer_get_size (tempbuf)) -
399 							(curoffset - offset), curoffset - offset, 0);
400 
401 					*buffercorr = curoffset - offset;
402 
403 					break;
404 				}
405 
406 				visual_object_unref (VISUAL_OBJECT (tempbuf));
407 			}
408 		}
409 	}
410 
411 	return startat;
412 }
413 
visual_ringbuffer_get_data_from_end(VisRingBuffer * ringbuffer,VisBuffer * data,int nbytes)414 int visual_ringbuffer_get_data_from_end (VisRingBuffer *ringbuffer, VisBuffer *data, int nbytes)
415 {
416 	int totalsize = visual_ringbuffer_get_size (ringbuffer);
417 	int offset = totalsize - nbytes;
418 
419 	if ((nbytes / totalsize) > 0)
420 		offset = totalsize - (nbytes % totalsize);
421 
422 	return visual_ringbuffer_get_data_offset (ringbuffer, data, offset, nbytes);
423 }
424 
visual_ringbuffer_get_data_without_wrap(VisRingBuffer * ringbuffer,VisBuffer * data,int nbytes)425 int visual_ringbuffer_get_data_without_wrap (VisRingBuffer *ringbuffer, VisBuffer *data, int nbytes)
426 {
427 	int ringsize;
428 	int amount = nbytes;
429 
430 	visual_log_return_val_if_fail (ringbuffer != NULL, -VISUAL_ERROR_RINGBUFFER_NULL);
431 
432 	if ((ringsize = visual_ringbuffer_get_size (ringbuffer)) < nbytes)
433 		amount = ringsize;
434 
435 	return visual_ringbuffer_get_data_offset (ringbuffer, data, 0, amount);
436 }
437 
visual_ringbuffer_get_data_new(VisRingBuffer * ringbuffer,int nbytes)438 VisBuffer *visual_ringbuffer_get_data_new (VisRingBuffer *ringbuffer, int nbytes)
439 {
440 	VisBuffer *buffer;
441 
442 	visual_log_return_val_if_fail (ringbuffer != NULL, NULL);
443 
444 	buffer = visual_buffer_new_allocate (nbytes, NULL);
445 
446 	visual_ringbuffer_get_data_offset (ringbuffer, buffer, 0, nbytes);
447 
448 	return buffer;
449 }
450 
visual_ringbuffer_get_data_new_without_wrap(VisRingBuffer * ringbuffer,int nbytes)451 VisBuffer *visual_ringbuffer_get_data_new_without_wrap (VisRingBuffer *ringbuffer, int nbytes)
452 {
453 	VisBuffer *buffer;
454 	int ringsize;
455 	int amount = nbytes;
456 
457 	visual_log_return_val_if_fail (ringbuffer != NULL, NULL);
458 
459 	if ((ringsize = visual_ringbuffer_get_size (ringbuffer)) < nbytes)
460 		amount = ringsize;
461 
462 	buffer = visual_buffer_new_allocate (amount, NULL);
463 
464 	visual_ringbuffer_get_data_without_wrap (ringbuffer, buffer, amount);
465 
466 	return buffer;
467 }
468 
visual_ringbuffer_entry_new(VisBuffer * buffer)469 VisRingBufferEntry *visual_ringbuffer_entry_new (VisBuffer *buffer)
470 {
471 	VisRingBufferEntry *entry;
472 
473 	entry = visual_mem_new0 (VisRingBufferEntry, 1);
474 
475 	visual_ringbuffer_entry_init (entry, buffer);
476 
477 	/* Do the VisObject initialization */
478 	visual_object_set_allocated (VISUAL_OBJECT (entry), TRUE);
479 	visual_object_ref (VISUAL_OBJECT (entry));
480 
481 	return entry;
482 }
483 
visual_ringbuffer_entry_init(VisRingBufferEntry * entry,VisBuffer * buffer)484 int visual_ringbuffer_entry_init (VisRingBufferEntry *entry, VisBuffer *buffer)
485 {
486 	visual_log_return_val_if_fail (entry != NULL, -VISUAL_ERROR_RINGBUFFER_ENTRY_NULL);
487 
488 	/* Do the VisObject initialization */
489 	visual_object_clear (VISUAL_OBJECT (entry));
490 	visual_object_set_dtor (VISUAL_OBJECT (entry), ringbuffer_entry_dtor);
491 	visual_object_set_allocated (VISUAL_OBJECT (entry), FALSE);
492 
493 	/* Reset the VisRingBufferEntry data */
494 	entry->type = VISUAL_RINGBUFFER_ENTRY_TYPE_BUFFER;
495 	entry->datafunc = NULL;
496 	entry->destroyfunc = NULL;
497 	entry->sizefunc = NULL;
498 	entry->buffer = buffer;
499 	entry->functiondata = NULL;
500 
501 	return VISUAL_OK;
502 }
503 
visual_ringbuffer_entry_new_function(VisRingBufferDataFunc datafunc,VisRingBufferDestroyFunc destroyfunc,VisRingBufferSizeFunc sizefunc,void * functiondata)504 VisRingBufferEntry *visual_ringbuffer_entry_new_function (
505 		VisRingBufferDataFunc datafunc,
506 		VisRingBufferDestroyFunc destroyfunc,
507 		VisRingBufferSizeFunc sizefunc,
508 		void *functiondata)
509 {
510 	VisRingBufferEntry *entry;
511 
512 	entry = visual_mem_new0 (VisRingBufferEntry, 1);
513 
514 	visual_ringbuffer_entry_init_function (entry, datafunc, destroyfunc, sizefunc, functiondata);
515 
516 	/* Do the VisObject initialization */
517 	visual_object_set_allocated (VISUAL_OBJECT (entry), TRUE);
518 	visual_object_ref (VISUAL_OBJECT (entry));
519 
520 	return entry;
521 }
522 
visual_ringbuffer_entry_init_function(VisRingBufferEntry * entry,VisRingBufferDataFunc datafunc,VisRingBufferDestroyFunc destroyfunc,VisRingBufferSizeFunc sizefunc,void * functiondata)523 int visual_ringbuffer_entry_init_function (VisRingBufferEntry *entry,
524 		VisRingBufferDataFunc datafunc,
525 		VisRingBufferDestroyFunc destroyfunc,
526 		VisRingBufferSizeFunc sizefunc,
527 		void *functiondata)
528 {
529 	visual_log_return_val_if_fail (entry != NULL, -VISUAL_ERROR_RINGBUFFER_ENTRY_NULL);
530 
531 	/* Do the VisObject initialization */
532 	visual_object_clear (VISUAL_OBJECT (entry));
533 	visual_object_set_dtor (VISUAL_OBJECT (entry), ringbuffer_entry_dtor);
534 	visual_object_set_allocated (VISUAL_OBJECT (entry), FALSE);
535 
536 	/* Reset the VisRingBufferEntry data */
537 	entry->type = VISUAL_RINGBUFFER_ENTRY_TYPE_FUNCTION;
538 	entry->datafunc = datafunc;
539 	entry->destroyfunc = destroyfunc;
540 	entry->sizefunc = sizefunc;
541 	entry->buffer = NULL;
542 	entry->functiondata = functiondata;
543 
544 	return VISUAL_OK;
545 }
546 
visual_ringbuffer_entry_get_functiondata(VisRingBufferEntry * entry)547 void *visual_ringbuffer_entry_get_functiondata (VisRingBufferEntry *entry)
548 {
549 	visual_log_return_val_if_fail (entry != NULL, NULL);
550 
551 	return entry->functiondata;
552 }
553 
554 /**
555  * @}
556  */
557 
558