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