1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <inttypes.h>
23 #include <config.h>
24 #include <float_cast.h>
25
26 #include <unistd.h>
27 #include <errno.h>
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31
32
33 #include <stdlib.h>
34 #include <assert.h>
35
36 #include <string.h>
37 #include <stdio.h>
38 #include <pthread.h>
39 #include <gmerlin/bg_sem.h>
40
41 #include <gmerlin/parameter.h>
42 #include <gmerlin/streaminfo.h>
43 #include <gmerlin/msgqueue.h>
44
45 #include <gmerlin/utils.h>
46 #include <gmerlin/bgsocket.h>
47 #include <gmerlin/serialize.h>
48
49 #define TYPE_INT 0
50 #define TYPE_FLOAT 1
51 #define TYPE_POINTER 2
52 #define TYPE_POINTER_NOCOPY 3
53 #define TYPE_TIME 4
54 #define TYPE_COLOR_RGB 5
55 #define TYPE_COLOR_RGBA 6
56 #define TYPE_POSITION 7
57
58 struct bg_msg_s
59 {
60 uint32_t id;
61
62 struct
63 {
64 union
65 {
66 int val_i;
67 double val_f;
68 void * val_ptr;
69 gavl_time_t val_time;
70 float val_color[4];
71 double val_pos[2];
72 } value;
73 uint8_t type;
74 uint32_t size;
75 } args[BG_MSG_MAX_ARGS];
76
77 int num_args;
78
79 sem_t produced;
80
81 bg_msg_t * prev;
82 bg_msg_t * next;
83 };
84
bg_msg_set_id(bg_msg_t * msg,int id)85 void bg_msg_set_id(bg_msg_t * msg, int id)
86 {
87 msg->id = id;
88 msg->num_args = 0;
89
90 /* Zero everything */
91
92 memset(&msg->args, 0, sizeof(msg->args));
93
94 }
95
check_arg(int arg)96 static int check_arg(int arg)
97 {
98 if(arg < 0)
99 return 0;
100 assert(arg < BG_MSG_MAX_ARGS);
101 return 1;
102 }
103
104 /* Set argument to a basic type */
105
bg_msg_set_arg_int(bg_msg_t * msg,int arg,int value)106 void bg_msg_set_arg_int(bg_msg_t * msg, int arg, int value)
107 {
108 if(!check_arg(arg))
109 return;
110 msg->args[arg].value.val_i = value;
111 msg->args[arg].type = TYPE_INT;
112 if(arg+1 > msg->num_args)
113 msg->num_args = arg + 1;
114 }
115
bg_msg_set_arg_time(bg_msg_t * msg,int arg,gavl_time_t value)116 void bg_msg_set_arg_time(bg_msg_t * msg, int arg, gavl_time_t value)
117 {
118 if(!check_arg(arg))
119 return;
120 msg->args[arg].value.val_time = value;
121 msg->args[arg].type = TYPE_TIME;
122 if(arg+1 > msg->num_args)
123 msg->num_args = arg + 1;
124 }
125
126
bg_msg_set_arg_ptr(bg_msg_t * msg,int arg,int len)127 void * bg_msg_set_arg_ptr(bg_msg_t * msg, int arg, int len)
128 {
129 if(!check_arg(arg))
130 return NULL;
131
132 msg->args[arg].value.val_ptr = calloc(1, len);
133 msg->args[arg].size = len;
134 msg->args[arg].type = TYPE_POINTER;
135 if(arg+1 > msg->num_args)
136 msg->num_args = arg + 1;
137 return msg->args[arg].value.val_ptr;
138 }
139
bg_msg_set_arg_ptr_nocopy(bg_msg_t * msg,int arg,void * value)140 void bg_msg_set_arg_ptr_nocopy(bg_msg_t * msg, int arg, void * value)
141 {
142 if(!check_arg(arg))
143 return;
144 msg->args[arg].value.val_ptr = value;
145 msg->args[arg].type = TYPE_POINTER_NOCOPY;
146 if(arg+1 > msg->num_args)
147 msg->num_args = arg + 1;
148 }
149
150
bg_msg_set_arg_string(bg_msg_t * msg,int arg,const char * value)151 void bg_msg_set_arg_string(bg_msg_t * msg, int arg, const char * value)
152 {
153 int length;
154 void * dst;
155 if(!value)
156 return;
157 length = strlen(value)+1;
158 dst = bg_msg_set_arg_ptr(msg, arg, length);
159 memcpy(dst, value, length);
160
161 if(arg+1 > msg->num_args)
162 msg->num_args = arg + 1;
163 }
164
bg_msg_set_arg_float(bg_msg_t * msg,int arg,double value)165 void bg_msg_set_arg_float(bg_msg_t * msg, int arg, double value)
166 {
167 if(!check_arg(arg))
168 return;
169 msg->args[arg].value.val_f = value;
170 msg->args[arg].type = TYPE_FLOAT;
171 if(arg+1 > msg->num_args)
172 msg->num_args = arg + 1;
173 }
174
bg_msg_set_arg_color_rgb(bg_msg_t * msg,int arg,const float * value)175 void bg_msg_set_arg_color_rgb(bg_msg_t * msg, int arg, const float * value)
176 {
177 if(!check_arg(arg))
178 return;
179 msg->args[arg].value.val_color[0] = value[0];
180 msg->args[arg].value.val_color[1] = value[1];
181 msg->args[arg].value.val_color[2] = value[2];
182 msg->args[arg].type = TYPE_COLOR_RGB;
183 if(arg+1 > msg->num_args)
184 msg->num_args = arg + 1;
185 }
186
bg_msg_set_arg_color_rgba(bg_msg_t * msg,int arg,const float * value)187 void bg_msg_set_arg_color_rgba(bg_msg_t * msg, int arg, const float * value)
188 {
189 if(!check_arg(arg))
190 return;
191 msg->args[arg].value.val_color[0] = value[0];
192 msg->args[arg].value.val_color[1] = value[1];
193 msg->args[arg].value.val_color[2] = value[2];
194 msg->args[arg].value.val_color[3] = value[3];
195 msg->args[arg].type = TYPE_COLOR_RGBA;
196 if(arg+1 > msg->num_args)
197 msg->num_args = arg + 1;
198 }
199
bg_msg_set_arg_position(bg_msg_t * msg,int arg,const double * value)200 void bg_msg_set_arg_position(bg_msg_t * msg, int arg, const double * value)
201 {
202 if(!check_arg(arg))
203 return;
204 msg->args[arg].value.val_pos[0] = value[0];
205 msg->args[arg].value.val_pos[1] = value[1];
206 msg->args[arg].type = TYPE_POSITION;
207 if(arg+1 > msg->num_args)
208 msg->num_args = arg + 1;
209 }
210
211
212 /* Get basic types */
213
bg_msg_get_id(bg_msg_t * msg)214 int bg_msg_get_id(bg_msg_t * msg)
215 {
216 return msg->id;
217 }
218
bg_msg_get_arg_int(bg_msg_t * msg,int arg)219 int bg_msg_get_arg_int(bg_msg_t * msg, int arg)
220 {
221 if(!check_arg(arg))
222 return 0;
223 return msg->args[arg].value.val_i;
224 }
225
bg_msg_get_arg_time(bg_msg_t * msg,int arg)226 gavl_time_t bg_msg_get_arg_time(bg_msg_t * msg, int arg)
227 {
228 if(!check_arg(arg))
229 return 0;
230 return msg->args[arg].value.val_time;
231 }
232
bg_msg_get_arg_float(bg_msg_t * msg,int arg)233 double bg_msg_get_arg_float(bg_msg_t * msg, int arg)
234 {
235 if(!check_arg(arg))
236 return 0.0;
237 return msg->args[arg].value.val_f;
238 }
239
bg_msg_get_arg_color_rgb(bg_msg_t * msg,int arg,float * val)240 void bg_msg_get_arg_color_rgb(bg_msg_t * msg, int arg, float * val)
241 {
242 if(!check_arg(arg))
243 return;
244 val[0] = msg->args[arg].value.val_color[0];
245 val[1] = msg->args[arg].value.val_color[1];
246 val[2] = msg->args[arg].value.val_color[2];
247 }
248
bg_msg_get_arg_color_rgba(bg_msg_t * msg,int arg,float * val)249 void bg_msg_get_arg_color_rgba(bg_msg_t * msg, int arg, float * val)
250 {
251 if(!check_arg(arg))
252 return;
253 val[0] = msg->args[arg].value.val_color[0];
254 val[1] = msg->args[arg].value.val_color[1];
255 val[2] = msg->args[arg].value.val_color[2];
256 val[3] = msg->args[arg].value.val_color[3];
257 }
258
bg_msg_get_arg_position(bg_msg_t * msg,int arg,double * val)259 void bg_msg_get_arg_position(bg_msg_t * msg, int arg, double * val)
260 {
261 if(!check_arg(arg))
262 return;
263 val[0] = msg->args[arg].value.val_pos[0];
264 val[1] = msg->args[arg].value.val_pos[1];
265 }
266
bg_msg_get_arg_ptr(bg_msg_t * msg,int arg,int * length)267 void * bg_msg_get_arg_ptr(bg_msg_t * msg, int arg, int * length)
268 {
269 void * ret;
270
271 if(!check_arg(arg))
272 return NULL;
273
274 ret = msg->args[arg].value.val_ptr;
275 msg->args[arg].value.val_ptr = NULL;
276 if(length)
277 *length = msg->args[arg].size;
278 return ret;
279 }
280
bg_msg_get_arg_ptr_nocopy(bg_msg_t * msg,int arg)281 void * bg_msg_get_arg_ptr_nocopy(bg_msg_t * msg, int arg)
282 {
283 if(!check_arg(arg))
284 return NULL;
285 return msg->args[arg].value.val_ptr;
286 }
287
bg_msg_get_arg_string(bg_msg_t * msg,int arg)288 char * bg_msg_get_arg_string(bg_msg_t * msg, int arg)
289 {
290 char * ret;
291 if(!check_arg(arg))
292 return NULL;
293 ret = msg->args[arg].value.val_ptr;
294 msg->args[arg].value.val_ptr = NULL;
295 return ret;
296 }
297
298
299 /* Get/Set routines for structures */
300
get_8(uint8_t * data,uint32_t * val)301 static inline uint8_t * get_8(uint8_t * data, uint32_t * val)
302 {
303 *val = *data;
304 data++;
305 return data;
306 }
307
get_16(uint8_t * data,uint32_t * val)308 static inline uint8_t * get_16(uint8_t * data, uint32_t * val)
309 {
310 *val = ((data[0] << 8) | data[1]);
311 data+=2;
312 return data;
313 }
314
get_32(uint8_t * data,uint32_t * val)315 static inline uint8_t * get_32(uint8_t * data, uint32_t * val)
316 {
317 *val = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
318 data+=4;
319 return data;
320 }
321
get_str(uint8_t * data,char ** val)322 static inline uint8_t * get_str(uint8_t * data, char ** val)
323 {
324 uint32_t len;
325 uint8_t * ret;
326
327 ret = get_32(data, &len);
328
329 if(len)
330 {
331 *val = malloc(len+1);
332 memcpy(*val, ret, len);
333 (*val)[len] = '\0';
334 }
335 return ret + len;
336 }
337
set_8(uint8_t * data,uint8_t val)338 static inline uint8_t * set_8(uint8_t * data, uint8_t val)
339 {
340 *data = val;
341 data++;
342 return data;
343 }
344
set_16(uint8_t * data,uint16_t val)345 static inline uint8_t * set_16(uint8_t * data, uint16_t val)
346 {
347 data[0] = (val & 0xff00) >> 8;
348 data[1] = (val & 0xff);
349 data+=2;
350 return data;
351 }
352
set_32(uint8_t * data,uint32_t val)353 static inline uint8_t * set_32(uint8_t * data, uint32_t val)
354 {
355 data[0] = (val & 0xff000000) >> 24;
356 data[1] = (val & 0xff0000) >> 16;
357 data[2] = (val & 0xff00) >> 8;
358 data[3] = (val & 0xff);
359 data+=4;
360 return data;
361 }
362
str_len(const char * str)363 static int str_len(const char * str)
364 {
365 int ret = 4;
366 if(str)
367 ret += strlen(str);
368 return ret;
369 }
370
set_str(uint8_t * data,const char * val)371 static inline uint8_t * set_str(uint8_t * data, const char * val)
372 {
373 uint32_t len;
374 if(val)
375 len = strlen(val);
376 else
377 len = 0;
378
379 data = set_32(data, len);
380 if(len)
381 memcpy(data, val, len);
382 return data + len;
383 }
384
385 /*
386 int samples_per_frame;
387 int samplerate;
388 int num_channels;
389 gavl_sample_format_t sample_format;
390 gavl_interleave_mode_t interleave_mode;
391 gavl_channel_setup_t channel_setup;
392 int lfe;
393 */
394
bg_msg_set_arg_audio_format(bg_msg_t * msg,int arg,const gavl_audio_format_t * format)395 void bg_msg_set_arg_audio_format(bg_msg_t * msg, int arg,
396 const gavl_audio_format_t * format)
397 {
398 uint8_t * ptr;
399 int len;
400 len = bg_serialize_audio_format(format, NULL, 0);
401 ptr = bg_msg_set_arg_ptr(msg, arg, len);
402 bg_serialize_audio_format(format, ptr, len);
403 }
404
bg_msg_get_arg_audio_format(bg_msg_t * msg,int arg,gavl_audio_format_t * format,int * big_endian)405 void bg_msg_get_arg_audio_format(bg_msg_t * msg, int arg,
406 gavl_audio_format_t * format, int * big_endian)
407 {
408 uint8_t * ptr;
409 int len, be;
410
411 ptr = bg_msg_get_arg_ptr(msg, arg, &len);
412 bg_deserialize_audio_format(format, ptr, len, &be);
413
414 if(big_endian)
415 *big_endian = be;
416
417 free(ptr);
418 }
419
420 /* Video format */
421
422 /*
423 int frame_width;
424 int frame_height;
425 int image_width;
426 int image_height;
427 int pixel_width;
428 int pixel_height;
429 gavl_pixelformat_t pixelformat;
430 int framerate_num;
431 int frame_duration;
432
433 int free_framerate;
434 */
435
bg_msg_set_arg_video_format(bg_msg_t * msg,int arg,const gavl_video_format_t * format)436 void bg_msg_set_arg_video_format(bg_msg_t * msg, int arg,
437 const gavl_video_format_t * format)
438 {
439 uint8_t * ptr;
440 int len;
441 len = bg_serialize_video_format(format, NULL, 0);
442 ptr = bg_msg_set_arg_ptr(msg, arg, len);
443 bg_serialize_video_format(format, ptr, len);
444 }
445
bg_msg_get_arg_video_format(bg_msg_t * msg,int arg,gavl_video_format_t * format,int * big_endian)446 void bg_msg_get_arg_video_format(bg_msg_t * msg, int arg,
447 gavl_video_format_t * format, int * big_endian)
448 {
449 uint8_t * ptr;
450 int len, be;
451
452 ptr = bg_msg_get_arg_ptr(msg, arg, &len);
453 bg_deserialize_video_format(format, ptr, len, &be);
454
455 if(big_endian)
456 *big_endian = be;
457
458 free(ptr);
459 }
460
461 /*
462 char * artist;
463 char * title;
464 char * album;
465
466 int track;
467 char * date;
468 char * genre;
469 char * comment;
470
471 char * author;
472 char * copyright;
473 */
474
475
bg_msg_set_arg_metadata(bg_msg_t * msg,int arg,const gavl_metadata_t * m)476 void bg_msg_set_arg_metadata(bg_msg_t * msg, int arg,
477 const gavl_metadata_t * m)
478 {
479 int i;
480
481 uint8_t * ptr;
482 uint8_t * pos;
483
484 int len = 4;
485
486 for(i = 0; i < m->num_tags; i++)
487 {
488 len += str_len(m->tags[i].key);
489 len += str_len(m->tags[i].val);
490 }
491
492 ptr = bg_msg_set_arg_ptr(msg, arg, len);
493 pos = ptr;
494
495 pos = set_32(pos, m->num_tags);
496 for(i = 0; i < m->num_tags; i++)
497 {
498 pos = set_str(pos, m->tags[i].key);
499 pos = set_str(pos, m->tags[i].val);
500 }
501 }
502
bg_msg_get_arg_metadata(bg_msg_t * msg,int arg,gavl_metadata_t * m)503 void bg_msg_get_arg_metadata(bg_msg_t * msg, int arg,
504 gavl_metadata_t * m)
505 {
506 int i;
507 uint32_t num;
508 uint8_t * ptr;
509 uint8_t * pos;
510 char * key;
511 char * val;
512
513 ptr = bg_msg_get_arg_ptr(msg, arg, NULL);
514
515 pos = ptr;
516
517 pos = get_32(pos, &num);
518
519 for(i = 0; i < num; i++)
520 {
521 pos = get_str(pos, &key);
522 pos = get_str(pos, &val);
523 gavl_metadata_set_nocpy(m, key, val);
524 free(key);
525 }
526 free(ptr);
527 }
528
bg_msg_create()529 bg_msg_t * bg_msg_create()
530 {
531 bg_msg_t * ret;
532 ret = calloc(1, sizeof(*ret));
533
534 sem_init(&ret->produced, 0, 0);
535
536 return ret;
537 }
538
bg_msg_free(bg_msg_t * m)539 void bg_msg_free(bg_msg_t * m)
540 {
541 int i;
542 for(i = 0; i < m->num_args; i++)
543 {
544 if((m->args[i].type == TYPE_POINTER) &&
545 (m->args[i].value.val_ptr))
546 {
547 free(m->args[i].value.val_ptr);
548 m->args[i].value.val_ptr = NULL;
549 }
550 }
551 }
552
bg_msg_destroy(bg_msg_t * m)553 void bg_msg_destroy(bg_msg_t * m)
554 {
555 bg_msg_free(m);
556 sem_destroy(&m->produced);
557 free(m);
558 }
559
560 /* Audio frame:
561 .arg_0 = valid samples
562 .arg_1 = timestamp
563 .arg_2 = big endian
564 */
565
bg_msg_write_audio_frame(bg_msg_t * msg,const gavl_audio_format_t * format,const gavl_audio_frame_t * frame,bg_msg_write_callback_t cb,void * cb_data)566 int bg_msg_write_audio_frame(bg_msg_t * msg,
567 const gavl_audio_format_t * format,
568 const gavl_audio_frame_t * frame,
569 bg_msg_write_callback_t cb,
570 void * cb_data)
571 {
572 uint8_t * ptr;
573 int len;
574
575 len = bg_serialize_audio_frame_header(format, frame, NULL, 0);
576 ptr = bg_msg_set_arg_ptr(msg, 0, len);
577 bg_serialize_audio_frame_header(format, frame, ptr, len);
578
579 if(!bg_msg_write(msg, cb, cb_data))
580 return 0;
581 return bg_serialize_audio_frame(format, frame, cb, cb_data);
582 }
583
584 /** \brief Read an audio frame from a socket
585 * \param msg Message containing the frame header
586 * \param format Audio format
587 * \param frame An audio frame
588 * \param fd A socket
589 * \returns 1 on success, 0 on error
590 *
591 * Before you can use this function, msg must contain
592 * a valid audio frame header
593 */
594
bg_msg_read_audio_frame(gavl_dsp_context_t * ctx,bg_msg_t * msg,const gavl_audio_format_t * format,gavl_audio_frame_t * frame,bg_msg_read_callback_t cb,void * cb_data,int big_endian)595 int bg_msg_read_audio_frame(gavl_dsp_context_t * ctx,
596 bg_msg_t * msg,
597 const gavl_audio_format_t * format,
598 gavl_audio_frame_t * frame,
599 bg_msg_read_callback_t cb,
600 void * cb_data, int big_endian)
601 {
602 uint8_t * ptr;
603 int len;
604
605 ptr = bg_msg_get_arg_ptr(msg, 0, &len);
606 bg_deserialize_audio_frame_header(format, frame, ptr, len);
607 free(ptr);
608
609 return bg_deserialize_audio_frame(ctx, format, frame,
610 cb, cb_data, big_endian);
611 }
612
613 /* .parameters =
614 .arg_0 = name
615 .arg_1 = type (int)
616 .arg_2 = value
617 */
618
bg_msg_set_parameter(bg_msg_t * msg,const char * name,bg_parameter_type_t type,const bg_parameter_value_t * val)619 void bg_msg_set_parameter(bg_msg_t * msg,
620 const char * name,
621 bg_parameter_type_t type,
622 const bg_parameter_value_t * val)
623 {
624 if(!name)
625 return;
626
627 bg_msg_set_arg_string(msg, 0, name);
628 bg_msg_set_arg_int(msg, 1, type);
629 switch(type)
630 {
631 case BG_PARAMETER_SECTION: //!< Dummy type. It contains no data but acts as a separator in notebook style configuration windows
632 case BG_PARAMETER_BUTTON: /* Button (just tell we are called) */
633 break;
634
635 case BG_PARAMETER_CHECKBUTTON: //!< Bool
636 case BG_PARAMETER_INT: //!< Integer spinbutton
637 case BG_PARAMETER_SLIDER_INT: //!< Integer slider
638 bg_msg_set_arg_int(msg, 2, val->val_i);
639 break;
640 case BG_PARAMETER_FLOAT: // spinbutton
641 case BG_PARAMETER_SLIDER_FLOAT: //!< Float slider
642 bg_msg_set_arg_float(msg, 2, val->val_f);
643 break;
644 case BG_PARAMETER_STRING: //!< String (one line only)
645 case BG_PARAMETER_STRING_HIDDEN: //!< Encrypted string (displays as ***)
646 case BG_PARAMETER_STRINGLIST: //!< Popdown menu with string values
647 case BG_PARAMETER_FONT: //!< Font (contains fontconfig compatible fontname)
648 case BG_PARAMETER_DEVICE: //!< Device
649 case BG_PARAMETER_FILE: //!< File
650 case BG_PARAMETER_DIRECTORY: //!< Directory
651 case BG_PARAMETER_MULTI_MENU: //!< Menu with config- and infobutton
652 case BG_PARAMETER_MULTI_LIST: //!< List with config- and infobutton
653 case BG_PARAMETER_MULTI_CHAIN: //!< Several subitems (including suboptions) can be arranged in a chain
654 bg_msg_set_arg_string(msg, 2, val->val_str);
655 break;
656 case BG_PARAMETER_COLOR_RGB: //!< RGB Color
657 bg_msg_set_arg_color_rgb(msg, 2, val->val_color);
658 break;
659 case BG_PARAMETER_COLOR_RGBA: //!< RGBA Color
660 bg_msg_set_arg_color_rgba(msg, 2, val->val_color);
661 break;
662 case BG_PARAMETER_POSITION: //!< RGBA Color
663 bg_msg_set_arg_position(msg, 2, val->val_pos);
664 break;
665 case BG_PARAMETER_TIME: //!< Time
666 bg_msg_set_arg_time(msg, 2, val->val_time);
667 break;
668 }
669 }
670
bg_msg_get_parameter(bg_msg_t * msg,char ** name,bg_parameter_type_t * type,bg_parameter_value_t * val)671 void bg_msg_get_parameter(bg_msg_t * msg,
672 char ** name,
673 bg_parameter_type_t * type,
674 bg_parameter_value_t * val)
675 {
676 *name = bg_msg_get_arg_string(msg, 0);
677
678 if(!*name)
679 return;
680
681 *type = bg_msg_get_arg_int(msg, 1);
682 switch(*type)
683 {
684 case BG_PARAMETER_SECTION: //!< Dummy type. It contains no data but acts as a separator in notebook style configuration windows
685 case BG_PARAMETER_BUTTON:
686 break;
687
688 case BG_PARAMETER_CHECKBUTTON: //!< Bool
689 case BG_PARAMETER_INT: //!< Integer spinbutton
690 case BG_PARAMETER_SLIDER_INT: //!< Integer slider
691 val->val_i = bg_msg_get_arg_int(msg, 2);
692 break;
693 case BG_PARAMETER_FLOAT: // spinbutton
694 case BG_PARAMETER_SLIDER_FLOAT: //!< Float slider
695 val->val_f = bg_msg_get_arg_float(msg, 2);
696 break;
697 case BG_PARAMETER_STRING: //!< String (one line only)
698 case BG_PARAMETER_STRING_HIDDEN: //!< Encrypted string (displays as ***)
699 case BG_PARAMETER_STRINGLIST: //!< Popdown menu with string values
700 case BG_PARAMETER_FONT: //!< Font (contains fontconfig compatible fontname)
701 case BG_PARAMETER_DEVICE: //!< Device
702 case BG_PARAMETER_FILE: //!< File
703 case BG_PARAMETER_DIRECTORY: //!< Directory
704 case BG_PARAMETER_MULTI_MENU: //!< Menu with config- and infobutton
705 case BG_PARAMETER_MULTI_LIST: //!< List with config- and infobutton
706 case BG_PARAMETER_MULTI_CHAIN: //!< Several subitems (including suboptions) can be arranged in a chain
707 val->val_str = bg_msg_get_arg_string(msg, 2);
708 break;
709 case BG_PARAMETER_COLOR_RGB: //!< RGB Color
710 bg_msg_get_arg_color_rgb(msg, 2, val->val_color);
711 break;
712 case BG_PARAMETER_COLOR_RGBA: //!< RGBA Color
713 bg_msg_get_arg_color_rgba(msg, 2, val->val_color);
714 break;
715 case BG_PARAMETER_POSITION: //!< RGBA Color
716 bg_msg_get_arg_position(msg, 2, val->val_pos);
717 break;
718 case BG_PARAMETER_TIME: //!< Time
719 bg_msg_set_arg_time(msg, 2, val->val_time);
720 break;
721 }
722 }
723
724 struct bg_msg_queue_s
725 {
726 bg_msg_t * msg_input;
727 bg_msg_t * msg_output;
728 bg_msg_t * msg_last;
729
730 pthread_mutex_t chain_mutex;
731 pthread_mutex_t write_mutex;
732
733 int num_messages; /* Number of total messages */
734 };
735
bg_msg_queue_create()736 bg_msg_queue_t * bg_msg_queue_create()
737 {
738 bg_msg_queue_t * ret;
739 ret = calloc(1, sizeof(*ret));
740
741 /* Allocate at least 2 messages */
742
743 ret->msg_output = bg_msg_create();
744 ret->msg_output->next = bg_msg_create();
745
746 /* Set in- and output messages */
747
748 ret->msg_input = ret->msg_output;
749 ret->msg_last = ret->msg_output->next;
750
751 /* Initialize chain mutex */
752
753 pthread_mutex_init(&ret->chain_mutex, NULL);
754 pthread_mutex_init(&ret->write_mutex, NULL);
755
756 return ret;
757 }
758
bg_msg_queue_destroy(bg_msg_queue_t * m)759 void bg_msg_queue_destroy(bg_msg_queue_t * m)
760 {
761 bg_msg_t * tmp_message;
762 while(m->msg_output)
763 {
764 tmp_message = m->msg_output->next;
765 bg_msg_destroy(m->msg_output);
766 m->msg_output = tmp_message;
767 }
768 free(m);
769 }
770
771 /* Lock message queue for reading, block until something arrives */
772
bg_msg_queue_lock_read(bg_msg_queue_t * m)773 bg_msg_t * bg_msg_queue_lock_read(bg_msg_queue_t * m)
774 {
775 while(sem_wait(&m->msg_output->produced) == -1)
776 {
777 if(errno != EINTR)
778 return NULL;
779 }
780 return m->msg_output;
781
782 // sem_ret->msg_output
783 }
784
bg_msg_queue_try_lock_read(bg_msg_queue_t * m)785 bg_msg_t * bg_msg_queue_try_lock_read(bg_msg_queue_t * m)
786 {
787 if(!sem_trywait(&m->msg_output->produced))
788 return m->msg_output;
789 else
790 return NULL;
791 }
792
bg_msg_queue_peek(bg_msg_queue_t * m,uint32_t * id)793 int bg_msg_queue_peek(bg_msg_queue_t * m, uint32_t * id)
794 {
795 int sem_val;
796 sem_getvalue(&m->msg_output->produced, &sem_val);
797 if(sem_val)
798 {
799 if(id)
800 *id = m->msg_output->id;
801 return 1;
802 }
803 else
804 return 0;
805 }
806
bg_msg_queue_unlock_read(bg_msg_queue_t * m)807 void bg_msg_queue_unlock_read(bg_msg_queue_t * m)
808 {
809
810 bg_msg_t * old_out_message;
811
812 pthread_mutex_lock(&m->chain_mutex);
813 old_out_message = m->msg_output;
814
815 bg_msg_free(old_out_message);
816
817 m->msg_output = m->msg_output->next;
818 m->msg_last->next = old_out_message;
819 m->msg_last = m->msg_last->next;
820 m->msg_last->next = NULL;
821
822 pthread_mutex_unlock(&m->chain_mutex);
823 }
824
825 /*
826 * Lock queue for writing
827 */
828
bg_msg_queue_lock_write(bg_msg_queue_t * m)829 bg_msg_t * bg_msg_queue_lock_write(bg_msg_queue_t * m)
830 {
831 pthread_mutex_lock(&m->write_mutex);
832 return m->msg_input;
833 }
834
bg_msg_queue_unlock_write(bg_msg_queue_t * m)835 void bg_msg_queue_unlock_write(bg_msg_queue_t * m)
836 {
837 bg_msg_t * message = m->msg_input;
838
839 pthread_mutex_lock(&m->chain_mutex);
840 if(!m->msg_input->next)
841 {
842 m->msg_input->next = bg_msg_create();
843 m->msg_last = m->msg_input->next;
844 }
845
846 m->msg_input = m->msg_input->next;
847 sem_post(&message->produced);
848 pthread_mutex_unlock(&m->chain_mutex);
849 pthread_mutex_unlock(&m->write_mutex);
850
851 }
852
853 typedef struct list_entry_s
854 {
855 bg_msg_queue_t * q;
856 struct list_entry_s * next;
857 } list_entry_t;
858
859 struct bg_msg_queue_list_s
860 {
861 list_entry_t * entries;
862
863 pthread_mutex_t mutex;
864 };
865
bg_msg_queue_list_create()866 bg_msg_queue_list_t * bg_msg_queue_list_create()
867 {
868 bg_msg_queue_list_t * ret = calloc(1, sizeof(*ret));
869 pthread_mutex_init(&ret->mutex, NULL);
870 return ret;
871 }
872
bg_msg_queue_list_destroy(bg_msg_queue_list_t * l)873 void bg_msg_queue_list_destroy(bg_msg_queue_list_t * l)
874 {
875 list_entry_t * tmp_entry;
876
877 while(l->entries)
878 {
879 tmp_entry = l->entries->next;
880 free(l->entries);
881 l->entries = tmp_entry;
882 }
883 free(l);
884 }
885
886 void
bg_msg_queue_list_send(bg_msg_queue_list_t * l,void (* set_message)(bg_msg_t * message,const void * data),const void * data)887 bg_msg_queue_list_send(bg_msg_queue_list_t * l,
888 void (*set_message)(bg_msg_t * message,
889 const void * data),
890 const void * data)
891 {
892 bg_msg_t * msg;
893 list_entry_t * entry;
894
895 pthread_mutex_lock(&l->mutex);
896 entry = l->entries;
897
898 while(entry)
899 {
900 msg = bg_msg_queue_lock_write(entry->q);
901 set_message(msg, data);
902 bg_msg_queue_unlock_write(entry->q);
903 entry = entry->next;
904 }
905 pthread_mutex_unlock(&l->mutex);
906 }
907
bg_msg_queue_list_add(bg_msg_queue_list_t * list,bg_msg_queue_t * queue)908 void bg_msg_queue_list_add(bg_msg_queue_list_t * list,
909 bg_msg_queue_t * queue)
910 {
911 list_entry_t * new_entry;
912
913 new_entry = calloc(1, sizeof(*new_entry));
914
915 pthread_mutex_lock(&list->mutex);
916
917 new_entry->next = list->entries;
918 new_entry->q = queue;
919 list->entries = new_entry;
920
921 pthread_mutex_unlock(&list->mutex);
922 }
923
bg_msg_queue_list_remove(bg_msg_queue_list_t * list,bg_msg_queue_t * queue)924 void bg_msg_queue_list_remove(bg_msg_queue_list_t * list,
925 bg_msg_queue_t * queue)
926 {
927 list_entry_t * tmp_entry;
928 list_entry_t * entry_before;
929
930 pthread_mutex_lock(&list->mutex);
931
932 if(list->entries->q == queue)
933 {
934 tmp_entry = list->entries->next;
935 free(list->entries);
936 list->entries = tmp_entry;
937 }
938 else
939 {
940 entry_before = list->entries;
941
942 while(entry_before->next->q != queue)
943 entry_before = entry_before->next;
944
945 tmp_entry = entry_before->next;
946 entry_before->next = tmp_entry->next;
947 free(tmp_entry);
948 }
949 pthread_mutex_unlock(&list->mutex);
950 }
951
952 /*
953 * This on will be used for remote controls,
954 * return FALSE on error
955 */
956
957 /* This is how a message is passed through pipes and sockets:
958 *
959 * content [ id |nargs|<arg1><arg2>....
960 * bytes |0|1|2|3| 4 |5....
961 *
962 * An int argument is encoded as:
963 * content | type | value |
964 * bytes | 0 |1|2|3|4|
965 *
966 * Type is TYPE_INT, byte order is big endian (network byte order)
967 *
968 * Floating point arguments are coded with type TYPE_FLOAT and the
969 * value as an integer
970 *
971 * String arguments are coded as:
972 * content |length |string including final '\0'|
973 * bytes |0|1|2|3|4 .. 4 + len |
974 *
975 * Pointer messages cannot be transmited!
976 */
977
read_uint32(uint32_t * ret,bg_msg_read_callback_t cb,void * cb_data)978 static int read_uint32(uint32_t * ret, bg_msg_read_callback_t cb, void * cb_data)
979 {
980 uint8_t buf[4];
981
982 if(cb(cb_data, buf, 4) < 4)
983 return 0;
984
985 // bg_hexdump(buf, 4);
986
987 *ret = (buf[0]<<24) | (buf[1]<<16) |
988 (buf[2]<<8) | buf[3];
989 return 1;
990 }
991
read_uint64(uint64_t * ret,bg_msg_read_callback_t cb,void * cb_data)992 static int read_uint64(uint64_t * ret, bg_msg_read_callback_t cb, void * cb_data)
993 {
994 uint8_t buf[8];
995
996 if(cb(cb_data, buf, 8) < 8)
997 return 0;
998
999 *ret =
1000 ((gavl_time_t)(buf[0])<<56) |
1001 ((gavl_time_t)(buf[1])<<48) |
1002 ((gavl_time_t)(buf[2])<<40) |
1003 ((gavl_time_t)(buf[3])<<32) |
1004 ((gavl_time_t)(buf[4])<<24) |
1005 ((gavl_time_t)(buf[5])<<16) |
1006 ((gavl_time_t)(buf[6])<<8) |
1007 ((gavl_time_t)(buf[7]));
1008 return 1;
1009 }
1010
1011 static float
float32_be_read(unsigned char * cptr)1012 float32_be_read (unsigned char *cptr)
1013 { int exponent, mantissa, negative ;
1014 float fvalue ;
1015
1016 negative = cptr [0] & 0x80 ;
1017 exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ;
1018 mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ;
1019
1020 if (! (exponent || mantissa))
1021 return 0.0 ;
1022
1023 mantissa |= 0x800000 ;
1024 exponent = exponent ? exponent - 127 : 0 ;
1025
1026 fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ;
1027
1028 if (negative)
1029 fvalue *= -1 ;
1030
1031 if (exponent > 0)
1032 fvalue *= (1 << exponent) ;
1033 else if (exponent < 0)
1034 fvalue /= (1 << abs (exponent)) ;
1035
1036 return fvalue ;
1037 } /* float32_be_read */
1038
1039
read_float(float * ret,bg_msg_read_callback_t cb,void * cb_data)1040 static int read_float(float * ret, bg_msg_read_callback_t cb, void * cb_data)
1041 {
1042 uint8_t buf[4];
1043 if(cb(cb_data, buf, 4) < 4)
1044 return 0;
1045 *ret = float32_be_read(buf);
1046 return 1;
1047 }
1048
1049 static double
double64_be_read(unsigned char * cptr)1050 double64_be_read (unsigned char *cptr)
1051 { int exponent, negative ;
1052 double dvalue ;
1053
1054 negative = (cptr [0] & 0x80) ? 1 : 0 ;
1055 exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ;
1056
1057 /* Might not have a 64 bit long, so load the mantissa into a double. */
1058 dvalue = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ;
1059 dvalue += ((cptr [5] << 16) | (cptr [6] << 8) | cptr [7]) / ((double) 0x1000000) ;
1060
1061 if (exponent == 0 && dvalue == 0.0)
1062 return 0.0 ;
1063
1064 dvalue += 0x10000000 ;
1065
1066 exponent = exponent - 0x3FF ;
1067
1068 dvalue = dvalue / ((double) 0x10000000) ;
1069
1070 if (negative)
1071 dvalue *= -1 ;
1072
1073 if (exponent > 0)
1074 dvalue *= (1 << exponent) ;
1075 else if (exponent < 0)
1076 dvalue /= (1 << abs (exponent)) ;
1077
1078 return dvalue ;
1079 } /* double64_be_read */
1080
1081
read_double(double * ret,bg_msg_read_callback_t cb,void * cb_data)1082 static int read_double(double * ret, bg_msg_read_callback_t cb, void * cb_data)
1083 {
1084 uint8_t buf[8];
1085 if(cb(cb_data, buf, 8) < 8)
1086 return 0;
1087 *ret = double64_be_read(buf);
1088 return 1;
1089 }
1090
read_time(gavl_time_t * ret,bg_msg_read_callback_t cb,void * cb_data)1091 static int read_time(gavl_time_t * ret, bg_msg_read_callback_t cb, void * cb_data)
1092 {
1093 return read_uint64((uint64_t*)ret, cb, cb_data);
1094 }
1095
write_uint32(uint32_t * val,bg_msg_write_callback_t cb,void * cb_data)1096 static int write_uint32(uint32_t * val,
1097 bg_msg_write_callback_t cb, void * cb_data)
1098 {
1099 uint8_t buf[4];
1100
1101 buf[0] = (*val & 0xff000000) >> 24;
1102 buf[1] = (*val & 0x00ff0000) >> 16;
1103 buf[2] = (*val & 0x0000ff00) >> 8;
1104 buf[3] = (*val & 0x000000ff);
1105
1106 // bg_hexdump(buf, 4);
1107
1108 if(cb(cb_data, buf, 4) < 4)
1109 return 0;
1110 return 1;
1111 }
1112
write_uint64(uint64_t val,bg_msg_write_callback_t cb,void * cb_data)1113 static int write_uint64(uint64_t val,
1114 bg_msg_write_callback_t cb, void * cb_data)
1115 {
1116 uint8_t buf[8];
1117
1118 buf[0] = (val & 0xff00000000000000LL) >> 56;
1119 buf[1] = (val & 0x00ff000000000000LL) >> 48;
1120 buf[2] = (val & 0x0000ff0000000000LL) >> 40;
1121 buf[3] = (val & 0x000000ff00000000LL) >> 32;
1122
1123 buf[4] = (val & 0x00000000ff000000LL) >> 24;
1124 buf[5] = (val & 0x0000000000ff0000LL) >> 16;
1125 buf[6] = (val & 0x000000000000ff00LL) >> 8;
1126 buf[7] = (val & 0x00000000000000ffLL);
1127
1128 if(cb(cb_data, buf, 8) < 8)
1129 return 0;
1130 return 1;
1131 }
1132
1133 static void
float32_be_write(float in,unsigned char * out)1134 float32_be_write (float in, unsigned char *out)
1135 { int exponent, mantissa, negative = 0 ;
1136
1137 memset (out, 0, sizeof (int)) ;
1138
1139 if (in == 0.0)
1140 return ;
1141
1142 if (in < 0.0)
1143 { in *= -1.0 ;
1144 negative = 1 ;
1145 } ;
1146
1147 in = frexp (in, &exponent) ;
1148
1149 exponent += 126 ;
1150
1151 in *= (float) 0x1000000 ;
1152 mantissa = (((int) in) & 0x7FFFFF) ;
1153
1154 if (negative)
1155 out [0] |= 0x80 ;
1156
1157 if (exponent & 0x01)
1158 out [1] |= 0x80 ;
1159
1160 out [3] = mantissa & 0xFF ;
1161 out [2] = (mantissa >> 8) & 0xFF ;
1162 out [1] |= (mantissa >> 16) & 0x7F ;
1163 out [0] |= (exponent >> 1) & 0x7F ;
1164
1165 return ;
1166 } /* float32_be_write */
1167
1168
write_float(float val,bg_msg_write_callback_t cb,void * cb_data)1169 static int write_float(float val, bg_msg_write_callback_t cb, void * cb_data)
1170 {
1171 uint8_t buf[4];
1172 float32_be_write(val, buf);
1173 if(cb(cb_data, buf, 4) < 4)
1174 return 0;
1175 return 1;
1176 }
1177
1178 static void
double64_be_write(double in,unsigned char * out)1179 double64_be_write (double in, unsigned char *out)
1180 { int exponent, mantissa ;
1181
1182 memset (out, 0, sizeof (double)) ;
1183
1184 if (in == 0.0)
1185 return ;
1186
1187 if (in < 0.0)
1188 { in *= -1.0 ;
1189 out [0] |= 0x80 ;
1190 } ;
1191
1192 in = frexp (in, &exponent) ;
1193
1194 exponent += 1022 ;
1195
1196 out [0] |= (exponent >> 4) & 0x7F ;
1197 out [1] |= (exponent << 4) & 0xF0 ;
1198
1199 in *= 0x20000000 ;
1200 mantissa = lrint (floor (in)) ;
1201
1202 out [1] |= (mantissa >> 24) & 0xF ;
1203 out [2] = (mantissa >> 16) & 0xFF ;
1204 out [3] = (mantissa >> 8) & 0xFF ;
1205 out [4] = mantissa & 0xFF ;
1206
1207 in = fmod (in, 1.0) ;
1208 in *= 0x1000000 ;
1209 mantissa = lrint (floor (in)) ;
1210 out [5] = (mantissa >> 16) & 0xFF ;
1211 out [6] = (mantissa >> 8) & 0xFF ;
1212 out [7] = mantissa & 0xFF ;
1213
1214 return ;
1215 } /* double64_be_write */
1216
1217
write_double(double val,bg_msg_write_callback_t cb,void * cb_data)1218 static int write_double(double val, bg_msg_write_callback_t cb, void * cb_data)
1219 {
1220 uint8_t buf[8];
1221 double64_be_write(val, buf);
1222 if(cb(cb_data, buf, 8) < 8)
1223 return 0;
1224 return 1;
1225 }
1226
write_time(gavl_time_t val,bg_msg_write_callback_t cb,void * cb_data)1227 static int write_time(gavl_time_t val,
1228 bg_msg_write_callback_t cb, void * cb_data)
1229 {
1230 return write_uint64((uint64_t)val, cb, cb_data);
1231 }
1232
1233
bg_msg_read(bg_msg_t * ret,bg_msg_read_callback_t cb,void * cb_data)1234 int bg_msg_read(bg_msg_t * ret, bg_msg_read_callback_t cb, void * cb_data)
1235 {
1236 int i;
1237 void * ptr;
1238
1239 int32_t val_i;
1240
1241 gavl_time_t val_time;
1242
1243 uint8_t val_u8;
1244 memset(ret, 0, sizeof(*ret));
1245
1246 /* Message ID */
1247
1248 if(!read_uint32((uint32_t*)(&val_i), cb, cb_data))
1249 return 0;
1250
1251 ret->id = val_i;
1252
1253 /* Number of arguments */
1254
1255 if(!cb(cb_data, &val_u8, 1))
1256 return 0;
1257
1258 ret->num_args = val_u8;
1259
1260 for(i = 0; i < ret->num_args; i++)
1261 {
1262 if(!cb(cb_data, &val_u8, 1))
1263 return 0;
1264 ret->args[i].type = val_u8;
1265
1266 switch(ret->args[i].type)
1267 {
1268 case TYPE_INT:
1269 if(!read_uint32((uint32_t*)(&val_i), cb, cb_data))
1270 return 0;
1271
1272 ret->args[i].value.val_i = val_i;
1273 break;
1274 case TYPE_FLOAT:
1275 if(!read_double(&ret->args[i].value.val_f, cb, cb_data))
1276 return 0;
1277 break;
1278 case TYPE_POINTER:
1279 if(!read_uint32((uint32_t*)(&val_i), cb, cb_data)) /* Length */
1280 return 0;
1281 ptr = bg_msg_set_arg_ptr(ret, i, val_i);
1282 if(cb(cb_data, ret->args[i].value.val_ptr, val_i) < val_i)
1283 return 0;
1284 break;
1285 case TYPE_TIME:
1286 if(!read_time(&val_time, cb, cb_data))
1287 return 0;
1288 ret->args[i].value.val_time = val_time;
1289 break;
1290 case TYPE_POINTER_NOCOPY:
1291 break;
1292 case TYPE_COLOR_RGB:
1293 if(!read_float(&ret->args[i].value.val_color[0], cb, cb_data) ||
1294 !read_float(&ret->args[i].value.val_color[1], cb, cb_data) ||
1295 !read_float(&ret->args[i].value.val_color[2], cb, cb_data))
1296 return 0;
1297 break;
1298 case TYPE_COLOR_RGBA:
1299 if(!read_float(&ret->args[i].value.val_color[0], cb, cb_data) ||
1300 !read_float(&ret->args[i].value.val_color[1], cb, cb_data) ||
1301 !read_float(&ret->args[i].value.val_color[2], cb, cb_data) ||
1302 !read_float(&ret->args[i].value.val_color[3], cb, cb_data))
1303 return 0;
1304 break;
1305 }
1306 }
1307 return 1;
1308 }
1309
bg_msg_write(bg_msg_t * msg,bg_msg_write_callback_t cb,void * cb_data)1310 int bg_msg_write(bg_msg_t * msg, bg_msg_write_callback_t cb,
1311 void * cb_data)
1312 {
1313 int i;
1314 uint8_t val_u8;
1315
1316 /* Message id */
1317
1318 if(!write_uint32(&msg->id, cb, cb_data))
1319 return 0;
1320
1321 /* Number of arguments */
1322 val_u8 = msg->num_args;
1323
1324 if(!cb(cb_data, &val_u8, 1))
1325 return 0;
1326
1327 /* Arguments */
1328
1329 for(i = 0; i < msg->num_args; i++)
1330 {
1331 cb(cb_data, &msg->args[i].type, 1);
1332
1333 switch(msg->args[i].type)
1334 {
1335 case TYPE_INT:
1336 if(!write_uint32((uint32_t*)(&msg->args[i].value.val_i), cb, cb_data))
1337 return 0;
1338 break;
1339 case TYPE_TIME:
1340 if(!write_time(msg->args[i].value.val_time, cb, cb_data))
1341 return 0;
1342 break;
1343 case TYPE_FLOAT:
1344 if(!write_double(msg->args[i].value.val_f, cb, cb_data))
1345 return 0;
1346 break;
1347 case TYPE_POINTER:
1348 if(!write_uint32(&msg->args[i].size, cb, cb_data))
1349 return 0;
1350 if(cb(cb_data, msg->args[i].value.val_ptr, msg->args[i].size) <
1351 msg->args[i].size)
1352 return 0;
1353 break;
1354 case TYPE_POINTER_NOCOPY:
1355 break;
1356 case TYPE_COLOR_RGB:
1357 if(!write_float(msg->args[i].value.val_color[0], cb, cb_data) ||
1358 !write_float(msg->args[i].value.val_color[1], cb, cb_data) ||
1359 !write_float(msg->args[i].value.val_color[2], cb, cb_data))
1360 return 0;
1361 break;
1362 case TYPE_COLOR_RGBA:
1363 if(!write_float(msg->args[i].value.val_color[0], cb, cb_data) ||
1364 !write_float(msg->args[i].value.val_color[1], cb, cb_data) ||
1365 !write_float(msg->args[i].value.val_color[2], cb, cb_data) ||
1366 !write_float(msg->args[i].value.val_color[3], cb, cb_data))
1367 return 0;
1368 break;
1369 }
1370 }
1371 return 1;
1372 }
1373
1374 typedef struct
1375 {
1376 int timeout;
1377 int fd;
1378 } socket_data;
1379
socket_read_cb(void * data,uint8_t * ptr,int len)1380 static int socket_read_cb(void * data, uint8_t * ptr, int len)
1381 {
1382 int result;
1383 socket_data * cb_data = (socket_data *)data;
1384 result = bg_socket_read_data(cb_data->fd,
1385 ptr, len, cb_data->timeout);
1386
1387 /* After a successful read, timeout must be disabled */
1388 if(result && cb_data->timeout >= 0)
1389 cb_data->timeout = -1;
1390 return result;
1391 }
1392
socket_write_cb(void * data,const uint8_t * ptr,int len)1393 static int socket_write_cb(void * data, const uint8_t * ptr, int len)
1394 {
1395 socket_data * cb_data = (socket_data *)data;
1396 return bg_socket_write_data(cb_data->fd, ptr, len);
1397
1398 }
1399
bg_msg_read_socket(bg_msg_t * ret,int fd,int milliseconds)1400 int bg_msg_read_socket(bg_msg_t * ret, int fd, int milliseconds)
1401 {
1402 socket_data cb_data;
1403 cb_data.fd = fd;
1404 cb_data.timeout = milliseconds;
1405 return bg_msg_read(ret, socket_read_cb, &cb_data);
1406 }
1407
bg_msg_write_socket(bg_msg_t * msg,int fd)1408 int bg_msg_write_socket(bg_msg_t * msg, int fd)
1409 {
1410 socket_data cb_data;
1411 cb_data.fd = fd;
1412 cb_data.timeout = 0;
1413 return bg_msg_write(msg, socket_write_cb, &cb_data);
1414 }
1415