1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2019 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/osc/controller/ags_osc_node_controller.h>
21 
22 #include <ags/audio/ags_sound_provider.h>
23 #include <ags/audio/ags_audio.h>
24 #include <ags/audio/ags_channel.h>
25 #include <ags/audio/ags_output.h>
26 #include <ags/audio/ags_input.h>
27 #include <ags/audio/ags_recall.h>
28 #include <ags/audio/ags_recall_audio.h>
29 #include <ags/audio/ags_recall_channel.h>
30 #include <ags/audio/ags_port.h>
31 
32 #include <ags/audio/osc/ags_osc_response.h>
33 #include <ags/audio/osc/ags_osc_buffer_util.h>
34 
35 #include <ags/i18n.h>
36 
37 #include <stdlib.h>
38 #include <string.h>
39 #include <strings.h>
40 
41 #include <sys/types.h>
42 #include <regex.h>
43 
44 void ags_osc_node_controller_class_init(AgsOscNodeControllerClass *osc_node_controller);
45 void ags_osc_node_controller_init(AgsOscNodeController *osc_node_controller);
46 void ags_osc_node_controller_set_property(GObject *gobject,
47 					  guint prop_id,
48 					  const GValue *value,
49 					  GParamSpec *param_spec);
50 void ags_osc_node_controller_get_property(GObject *gobject,
51 					  guint prop_id,
52 					  GValue *value,
53 					  GParamSpec *param_spec);
54 void ags_osc_node_controller_dispose(GObject *gobject);
55 void ags_osc_node_controller_finalize(GObject *gobject);
56 
57 gpointer ags_osc_node_controller_get_data_soundcard(AgsOscNodeController *osc_node_controller,
58 						    AgsOscConnection *osc_connection,
59 						    GObject *soundcard,
60 						    unsigned char *message, guint message_size,
61 						    gchar *type_tag,
62 						    gchar *path, guint path_offset);
63 gpointer ags_osc_node_controller_get_data_sequencer(AgsOscNodeController *osc_node_controller,
64 						    AgsOscConnection *osc_connection,
65 						    GObject *sequencer,
66 						    unsigned char *message, guint message_size,
67 						    gchar *type_tag,
68 						    gchar *path, guint path_offset);
69 
70 gpointer ags_osc_node_controller_get_data_audio(AgsOscNodeController *osc_node_controller,
71 						AgsOscConnection *osc_connection,
72 						AgsAudio *audio,
73 						unsigned char *message, guint message_size,
74 						gchar *type_tag,
75 						gchar *path, guint path_offset);
76 gpointer ags_osc_node_controller_get_data_channel(AgsOscNodeController *osc_node_controller,
77 						  AgsOscConnection *osc_connection,
78 						  AgsChannel *channel,
79 						  unsigned char *message, guint message_size,
80 						  gchar *type_tag,
81 						  gchar *path, guint path_offset);
82 
83 gpointer ags_osc_node_controller_get_data_recall(AgsOscNodeController *osc_node_controller,
84 						 AgsOscConnection *osc_connection,
85 						 AgsRecall *recall,
86 						 unsigned char *message, guint message_size,
87 						 gchar *type_tag,
88 						 gchar *path, guint path_offset);
89 
90 gpointer ags_osc_node_controller_get_data_port(AgsOscNodeController *osc_node_controller,
91 					       AgsOscConnection *osc_connection,
92 					       AgsRecall *parent,
93 					       AgsPort *port,
94 					       unsigned char *message, guint message_size,
95 					       gchar *type_tag,
96 					       gchar *path, guint path_offset);
97 
98 gpointer ags_osc_node_controller_real_get_data(AgsOscNodeController *osc_node_controller,
99 					       AgsOscConnection *osc_connection,
100 					       unsigned char *message, guint message_size);
101 
102 /**
103  * SECTION:ags_osc_node_controller
104  * @short_description: OSC node controller
105  * @title: AgsOscNodeController
106  * @section_id:
107  * @include: ags/audio/osc/controller/ags_osc_node_controller.h
108  *
109  * The #AgsOscNodeController implements the OSC node controller.
110  */
111 
112 enum{
113   PROP_0,
114 };
115 
116 enum{
117   GET_DATA,
118   LAST_SIGNAL,
119 };
120 
121 static gpointer ags_osc_node_controller_parent_class = NULL;
122 static guint osc_node_controller_signals[LAST_SIGNAL];
123 
124 static GMutex regex_mutex;
125 
126 GType
ags_osc_node_controller_get_type()127 ags_osc_node_controller_get_type()
128 {
129   static volatile gsize g_define_type_id__volatile = 0;
130 
131   if(g_once_init_enter (&g_define_type_id__volatile)){
132     GType ags_type_osc_node_controller = 0;
133 
134     static const GTypeInfo ags_osc_node_controller_info = {
135       sizeof (AgsOscNodeControllerClass),
136       NULL, /* base_init */
137       NULL, /* base_finalize */
138       (GClassInitFunc) ags_osc_node_controller_class_init,
139       NULL, /* class_finalize */
140       NULL, /* class_data */
141       sizeof (AgsOscNodeController),
142       0,    /* n_preallocs */
143       (GInstanceInitFunc) ags_osc_node_controller_init,
144     };
145 
146     ags_type_osc_node_controller = g_type_register_static(AGS_TYPE_OSC_CONTROLLER,
147 							  "AgsOscNodeController",
148 							  &ags_osc_node_controller_info,
149 							  0);
150 
151     g_once_init_leave(&g_define_type_id__volatile, ags_type_osc_node_controller);
152   }
153 
154   return g_define_type_id__volatile;
155 }
156 
157 void
ags_osc_node_controller_class_init(AgsOscNodeControllerClass * osc_node_controller)158 ags_osc_node_controller_class_init(AgsOscNodeControllerClass *osc_node_controller)
159 {
160   GObjectClass *gobject;
161   GParamSpec *param_spec;
162 
163   ags_osc_node_controller_parent_class = g_type_class_peek_parent(osc_node_controller);
164 
165   /* GObjectClass */
166   gobject = (GObjectClass *) osc_node_controller;
167 
168   gobject->set_property = ags_osc_node_controller_set_property;
169   gobject->get_property = ags_osc_node_controller_get_property;
170 
171   gobject->dispose = ags_osc_node_controller_dispose;
172   gobject->finalize = ags_osc_node_controller_finalize;
173 
174   /* properties */
175 
176   /* AgsOscNodeControllerClass */
177   osc_node_controller->get_data = ags_osc_node_controller_real_get_data;
178 
179   /* signals */
180   /**
181    * AgsOscNodeController::get-data:
182    * @osc_node_controller: the #AgsOscNodeController
183    * @osc_connection: the #AgsOscConnection
184    * @message: the message received
185    * @message_size: the message size
186    *
187    * The ::get-data signal is emited during get data of node controller.
188    *
189    * Returns: the #AgsOscResponse
190    *
191    * Since: 3.0.0
192    */
193   osc_node_controller_signals[GET_DATA] =
194     g_signal_new("get-data",
195 		 G_TYPE_FROM_CLASS(osc_node_controller),
196 		 G_SIGNAL_RUN_LAST,
197 		 G_STRUCT_OFFSET(AgsOscNodeControllerClass, get_data),
198 		 NULL, NULL,
199 		 ags_cclosure_marshal_POINTER__OBJECT_POINTER_UINT,
200 		 G_TYPE_POINTER, 3,
201 		 G_TYPE_OBJECT,
202 		 G_TYPE_POINTER,
203 		 G_TYPE_UINT);
204 }
205 
206 void
ags_osc_node_controller_init(AgsOscNodeController * osc_node_controller)207 ags_osc_node_controller_init(AgsOscNodeController *osc_node_controller)
208 {
209   g_object_set(osc_node_controller,
210 	       "context-path", "/node",
211 	       NULL);
212 }
213 
214 void
ags_osc_node_controller_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)215 ags_osc_node_controller_set_property(GObject *gobject,
216 				     guint prop_id,
217 				     const GValue *value,
218 				     GParamSpec *param_spec)
219 {
220   AgsOscNodeController *osc_node_controller;
221 
222   GRecMutex *osc_controller_mutex;
223 
224   osc_node_controller = AGS_OSC_NODE_CONTROLLER(gobject);
225 
226   /* get osc controller mutex */
227   osc_controller_mutex = AGS_OSC_CONTROLLER_GET_OBJ_MUTEX(osc_node_controller);
228 
229   switch(prop_id){
230   default:
231     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
232     break;
233   }
234 }
235 
236 void
ags_osc_node_controller_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)237 ags_osc_node_controller_get_property(GObject *gobject,
238 				     guint prop_id,
239 				     GValue *value,
240 				     GParamSpec *param_spec)
241 {
242   AgsOscNodeController *osc_node_controller;
243 
244   GRecMutex *osc_controller_mutex;
245 
246   osc_node_controller = AGS_OSC_NODE_CONTROLLER(gobject);
247 
248   /* get osc controller mutex */
249   osc_controller_mutex = AGS_OSC_CONTROLLER_GET_OBJ_MUTEX(osc_node_controller);
250 
251   switch(prop_id){
252   default:
253     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
254     break;
255   }
256 }
257 
258 void
ags_osc_node_controller_dispose(GObject * gobject)259 ags_osc_node_controller_dispose(GObject *gobject)
260 {
261   AgsOscNodeController *osc_node_controller;
262 
263   osc_node_controller = AGS_OSC_NODE_CONTROLLER(gobject);
264 
265   /* call parent */
266   G_OBJECT_CLASS(ags_osc_node_controller_parent_class)->dispose(gobject);
267 }
268 
269 void
ags_osc_node_controller_finalize(GObject * gobject)270 ags_osc_node_controller_finalize(GObject *gobject)
271 {
272   AgsOscNodeController *osc_node_controller;
273 
274   osc_node_controller = AGS_OSC_NODE_CONTROLLER(gobject);
275 
276   /* call parent */
277   G_OBJECT_CLASS(ags_osc_node_controller_parent_class)->finalize(gobject);
278 }
279 
280 gpointer
ags_osc_node_controller_get_data_soundcard(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,GObject * soundcard,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)281 ags_osc_node_controller_get_data_soundcard(AgsOscNodeController *osc_node_controller,
282 					   AgsOscConnection *osc_connection,
283 					   GObject *soundcard,
284 					   unsigned char *message, guint message_size,
285 					   gchar *type_tag,
286 					   gchar *path, guint path_offset)
287 {
288   AgsOscResponse *osc_response;
289 
290   AgsApplicationContext *application_context;
291 
292   GList *start_response;
293   GList *start_list;
294 
295   unsigned char *packet;
296   gchar *current_path;
297 
298   guint real_packet_size;
299   guint packet_size;
300   gint nth_soundcard;
301 
302   if(!AGS_IS_SOUNDCARD(soundcard)){
303     return(NULL);
304   }
305 
306   start_response = NULL;
307 
308   application_context = ags_application_context_get_instance();
309 
310   real_packet_size = 0;
311   packet_size = 0;
312 
313   if(!strncmp(path + path_offset,
314 	      ":",
315 	      1)){
316     /* get nth soundcard */
317     start_list = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
318 
319     nth_soundcard = g_list_index(start_list,
320 				 soundcard);
321 
322     g_list_free_full(start_list,
323 		     g_object_unref);
324 
325     osc_response = ags_osc_response_new();
326     start_response = g_list_prepend(start_response,
327 				    osc_response);
328 
329     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
330     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
331 
332     g_object_set(osc_response,
333 		 "packet", packet,
334 		 "packet-size", packet_size,
335 		 NULL);
336 
337     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
338 
339     path_offset += 1;
340 
341     if(!strncmp(path + path_offset,
342 		"device",
343 		7)){
344       gchar *device;
345 
346       guint length;
347 
348       /* create current path */
349       current_path = g_strdup_printf("/AgsSoundProvider/AgsSoundcard[%d]:device", nth_soundcard);
350 
351       /* message path */
352       packet_size = 4;
353 
354       ags_osc_buffer_util_put_string(packet + packet_size,
355 				     "/node", -1);
356 
357       /* message type tag */
358       packet_size += 8;
359 
360       ags_osc_buffer_util_put_string(packet + packet_size,
361 				     ",ss", -1);
362 
363       /* node path */
364       packet_size += 4;
365 
366       length = strlen(current_path);
367 
368       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
369 	ags_osc_response_set_flags(osc_response,
370 				   AGS_OSC_RESPONSE_ERROR);
371 
372 	g_object_set(osc_response,
373 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
374 		     NULL);
375 
376 	return(start_response);
377       }
378 
379       ags_osc_buffer_util_put_string(packet + packet_size,
380 				     current_path, -1);
381 
382       /* node argument */
383       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
384 
385       device = ags_soundcard_get_device(AGS_SOUNDCARD(soundcard));
386       length = strlen(device);
387 
388       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
389 	ags_osc_response_set_flags(osc_response,
390 				   AGS_OSC_RESPONSE_ERROR);
391 
392 	g_object_set(osc_response,
393 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
394 		     NULL);
395 
396 	return(start_response);
397       }
398 
399       ags_osc_buffer_util_put_string(packet + packet_size,
400 				     device, -1);
401 
402       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
403 
404       /* packet size */
405       ags_osc_buffer_util_put_int32(packet,
406 				    packet_size);
407     }else if(!strncmp(path + path_offset,
408 		      "pcm-channels",
409 		      13)){
410       guint pcm_channels;
411       guint length;
412 
413       /* create current path */
414       current_path = g_strdup_printf("/AgsSoundProvider/AgsSoundcard[%d]:pcm-channels", nth_soundcard);
415 
416       /* message path */
417       packet_size = 4;
418 
419       ags_osc_buffer_util_put_string(packet + packet_size,
420 				     "/node", -1);
421 
422       /* message type tag */
423       packet_size += 8;
424 
425       ags_osc_buffer_util_put_string(packet + packet_size,
426 				     ",si", -1);
427 
428       /* node path */
429       packet_size += 4;
430 
431       length = strlen(current_path);
432 
433       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
434 	ags_osc_response_set_flags(osc_response,
435 				   AGS_OSC_RESPONSE_ERROR);
436 
437 	g_object_set(osc_response,
438 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
439 		     NULL);
440 
441 	return(start_response);
442       }
443 
444       ags_osc_buffer_util_put_string(packet + packet_size,
445 				     current_path, -1);
446 
447       /* node argument */
448       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
449 
450       ags_soundcard_get_presets(AGS_SOUNDCARD(soundcard),
451 				&pcm_channels,
452 				NULL,
453 				NULL,
454 				NULL);
455       ags_osc_buffer_util_put_int32(packet + packet_size,
456 				    pcm_channels);
457 
458       packet_size += 4;
459 
460       /* packet size */
461       ags_osc_buffer_util_put_int32(packet,
462 				    packet_size);
463     }else if(!strncmp(path + path_offset,
464 		      "samplerate",
465 		      11)){
466       guint samplerate;
467       guint length;
468 
469       /* create current path */
470       current_path = g_strdup_printf("/AgsSoundProvider/AgsSoundcard[%d]:samplerate", nth_soundcard);
471 
472       /* message path */
473       packet_size = 4;
474 
475       ags_osc_buffer_util_put_string(packet + packet_size,
476 				     "/node", -1);
477 
478       /* message type tag */
479       packet_size += 8;
480 
481       ags_osc_buffer_util_put_string(packet + packet_size,
482 				     ",si", -1);
483 
484       /* node path */
485       packet_size += 4;
486 
487       length = strlen(current_path);
488 
489       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
490 	ags_osc_response_set_flags(osc_response,
491 				   AGS_OSC_RESPONSE_ERROR);
492 
493 	g_object_set(osc_response,
494 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
495 		     NULL);
496 
497 	return(start_response);
498       }
499 
500       ags_osc_buffer_util_put_string(packet + packet_size,
501 				     current_path, -1);
502 
503       /* node argument */
504       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
505 
506       packet_size = 16 + length;
507 
508       ags_soundcard_get_presets(AGS_SOUNDCARD(soundcard),
509 				NULL,
510 				&samplerate,
511 				NULL,
512 				NULL);
513       ags_osc_buffer_util_put_int32(packet + packet_size,
514 				    samplerate);
515 
516       packet_size += 4;
517 
518       /* packet size */
519       ags_osc_buffer_util_put_int32(packet,
520 				    packet_size);
521     }else if(!strncmp(path + path_offset,
522 		      "buffer-size",
523 		      12)){
524       guint buffer_size;
525       guint length;
526 
527       /* create current path */
528       current_path = g_strdup_printf("/AgsSoundProvider/AgsSoundcard[%d]:buffer-size", nth_soundcard);
529 
530       /* message path */
531       packet_size = 4;
532 
533       ags_osc_buffer_util_put_string(packet + packet_size,
534 				     "/node", -1);
535 
536       /* message type tag */
537       packet_size += 8;
538 
539       ags_osc_buffer_util_put_string(packet + packet_size,
540 				     ",si", -1);
541 
542       /* node path */
543       packet_size += 4;
544 
545       length = strlen(current_path);
546 
547       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
548 	ags_osc_response_set_flags(osc_response,
549 				   AGS_OSC_RESPONSE_ERROR);
550 
551 	g_object_set(osc_response,
552 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
553 		     NULL);
554 
555 	return(start_response);
556       }
557 
558       ags_osc_buffer_util_put_string(packet + packet_size,
559 				     current_path, -1);
560 
561       /* node argument */
562       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
563 
564       ags_soundcard_get_presets(AGS_SOUNDCARD(soundcard),
565 				NULL,
566 				NULL,
567 				&buffer_size,
568 				NULL);
569       ags_osc_buffer_util_put_int32(packet + packet_size,
570 				    buffer_size);
571 
572       packet_size += 4;
573 
574       /* packet size */
575       ags_osc_buffer_util_put_int32(packet,
576 				    packet_size);
577     }else if(!strncmp(path + path_offset,
578 		      "format",
579 		      7)){
580       guint format;
581       guint length;
582 
583       /* create current path */
584       current_path = g_strdup_printf("/AgsSoundProvider/AgsSoundcard[%d]:format", nth_soundcard);
585 
586       /* message path */
587       packet_size = 4;
588 
589       ags_osc_buffer_util_put_string(packet + packet_size,
590 				     "/node", -1);
591 
592       /* message type tag */
593       packet_size += 8;
594 
595       length = strlen(current_path);
596 
597       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
598 	ags_osc_response_set_flags(osc_response,
599 				   AGS_OSC_RESPONSE_ERROR);
600 
601 	g_object_set(osc_response,
602 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
603 		     NULL);
604 
605 	return(start_response);
606       }
607 
608       ags_osc_buffer_util_put_string(packet + packet_size,
609 				     ",si", -1);
610 
611       /* node path */
612       packet_size += 4;
613 
614       ags_osc_buffer_util_put_string(packet + packet_size,
615 				     current_path, -1);
616 
617       /* node argument */
618       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
619 
620       ags_soundcard_get_presets(AGS_SOUNDCARD(soundcard),
621 				NULL,
622 				NULL,
623 				NULL,
624 				&format);
625 
626       ags_osc_buffer_util_put_int32(packet + packet_size,
627 				    format);
628 
629       packet_size += 4;
630 
631       /* packet size */
632       ags_osc_buffer_util_put_int32(packet,
633 				    packet_size);
634     }else{
635       ags_osc_response_set_flags(osc_response,
636 				 AGS_OSC_RESPONSE_ERROR);
637 
638       g_object_set(osc_response,
639 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
640 		   NULL);
641 
642       return(start_response);
643     }
644 
645     g_object_set(osc_response,
646 		 "packet-size", packet_size,
647 		 NULL);
648   }else{
649     osc_response = ags_osc_response_new();
650     start_response = g_list_prepend(start_response,
651 				    osc_response);
652 
653     ags_osc_response_set_flags(osc_response,
654 			       AGS_OSC_RESPONSE_ERROR);
655 
656     g_object_set(osc_response,
657 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_PATH,
658 		 NULL);
659 
660     return(start_response);
661   }
662 
663   return(start_response);
664 }
665 
666 gpointer
ags_osc_node_controller_get_data_sequencer(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,GObject * sequencer,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)667 ags_osc_node_controller_get_data_sequencer(AgsOscNodeController *osc_node_controller,
668 					   AgsOscConnection *osc_connection,
669 					   GObject *sequencer,
670 					   unsigned char *message, guint message_size,
671 					   gchar *type_tag,
672 					   gchar *path, guint path_offset)
673 {
674   AgsOscResponse *osc_response;
675 
676   AgsApplicationContext *application_context;
677 
678   GList *start_response;
679   GList *start_list;
680 
681   unsigned char *packet;
682   gchar *current_path;
683 
684   guint real_packet_size;
685   guint packet_size;
686   gint nth_sequencer;
687 
688   if(!AGS_IS_SEQUENCER(sequencer)){
689     return(NULL);
690   }
691 
692   start_response = NULL;
693 
694   application_context = ags_application_context_get_instance();
695 
696   real_packet_size = 0;
697   packet_size = 0;
698 
699   if(!strncmp(path + path_offset,
700 	      ":",
701 	      1)){
702     /* get nth sequencer */
703     start_list = ags_sound_provider_get_sequencer(AGS_SOUND_PROVIDER(application_context));
704 
705     nth_sequencer = g_list_index(start_list,
706 				 sequencer);
707 
708     g_list_free_full(start_list,
709 		     g_object_unref);
710 
711     osc_response = ags_osc_response_new();
712     start_response = g_list_prepend(start_response,
713 				    osc_response);
714 
715     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
716     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
717 
718     g_object_set(osc_response,
719 		 "packet", packet,
720 		 "packet-size", packet_size,
721 		 NULL);
722 
723     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
724 
725     path_offset += 1;
726 
727     if(!strncmp(path + path_offset,
728 		"device",
729 		7)){
730       gchar *device;
731 
732       guint length;
733 
734       /* create current path */
735       current_path = g_strdup_printf("/AgsSoundProvider/AgsSequencer[%d]:device", nth_sequencer);
736 
737       /* message path */
738       packet_size = 4;
739 
740       ags_osc_buffer_util_put_string(packet + packet_size,
741 				     "/node", -1);
742 
743       /* message type tag */
744       packet_size += 8;
745 
746       ags_osc_buffer_util_put_string(packet + packet_size,
747 				     ",ss", -1);
748 
749       /* node path */
750       packet_size += 4;
751 
752       length = strlen(current_path);
753 
754       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
755 	ags_osc_response_set_flags(osc_response,
756 				   AGS_OSC_RESPONSE_ERROR);
757 
758 	g_object_set(osc_response,
759 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
760 		     NULL);
761 
762 	return(start_response);
763       }
764 
765       ags_osc_buffer_util_put_string(packet + packet_size,
766 				     current_path, -1);
767 
768       /* node argument */
769       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
770 
771       device = ags_sequencer_get_device(AGS_SEQUENCER(sequencer));
772       length = strlen(device);
773 
774       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
775 	ags_osc_response_set_flags(osc_response,
776 				   AGS_OSC_RESPONSE_ERROR);
777 
778 	g_object_set(osc_response,
779 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
780 		     NULL);
781 
782 	return(start_response);
783       }
784 
785       ags_osc_buffer_util_put_string(packet + packet_size,
786 				     device, -1);
787 
788       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
789 
790       /* packet size */
791       ags_osc_buffer_util_put_int32(packet,
792 				    packet_size);
793     }else{
794       ags_osc_response_set_flags(osc_response,
795 				 AGS_OSC_RESPONSE_ERROR);
796 
797       g_object_set(osc_response,
798 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
799 		   NULL);
800 
801       return(start_response);
802     }
803 
804     g_object_set(osc_response,
805 		 "packet-size", packet_size,
806 		 NULL);
807   }else{
808     osc_response = ags_osc_response_new();
809     start_response = g_list_prepend(start_response,
810 				    osc_response);
811 
812     ags_osc_response_set_flags(osc_response,
813 			       AGS_OSC_RESPONSE_ERROR);
814 
815     g_object_set(osc_response,
816 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_PATH,
817 		 NULL);
818 
819     return(start_response);
820   }
821 
822   return(start_response);
823 }
824 
825 gpointer
ags_osc_node_controller_get_data_audio(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,AgsAudio * audio,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)826 ags_osc_node_controller_get_data_audio(AgsOscNodeController *osc_node_controller,
827 				       AgsOscConnection *osc_connection,
828 				       AgsAudio *audio,
829 				       unsigned char *message, guint message_size,
830 				       gchar *type_tag,
831 				       gchar *path, guint path_offset)
832 {
833   AgsOscResponse *osc_response;
834 
835   AgsApplicationContext *application_context;
836 
837   GList *start_response;
838   GList *start_list;
839 
840   unsigned char *packet;
841   gchar *current_path;
842 
843   guint real_packet_size;
844   guint packet_size;
845   gint nth_audio;
846 
847   if(!AGS_IS_AUDIO(audio)){
848     return(NULL);
849   }
850 
851   start_response = NULL;
852 
853   application_context = ags_application_context_get_instance();
854 
855   real_packet_size = 0;
856   packet_size = 0;
857 
858   if(!strncmp(path + path_offset,
859 	      ":",
860 	      1)){
861     guint length;
862 
863     /* get nth audio */
864     start_list = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
865 
866     nth_audio = g_list_index(start_list,
867 			     audio);
868 
869     g_list_free_full(start_list,
870 		     g_object_unref);
871 
872     osc_response = ags_osc_response_new();
873     start_response = g_list_prepend(start_response,
874 				    osc_response);
875 
876     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
877     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
878 
879     g_object_set(osc_response,
880 		 "packet", packet,
881 		 "packet-size", packet_size,
882 		 NULL);
883 
884     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
885 
886     path_offset += 1;
887 
888     /* properties */
889     if(!strncmp(path + path_offset,
890 		"audio-channels",
891 		15)){
892       guint audio_channels;
893 
894       /* create current path */
895       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:audio-channels", nth_audio);
896 
897       /* message path */
898       packet_size = 4;
899 
900       ags_osc_buffer_util_put_string(packet + packet_size,
901 				     "/node", -1);
902 
903       /* message type tag */
904       packet_size += 8;
905 
906       ags_osc_buffer_util_put_string(packet + packet_size,
907 				     ",si", -1);
908 
909       /* node path */
910       packet_size += 4;
911 
912       length = strlen(current_path);
913 
914       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
915 	ags_osc_response_set_flags(osc_response,
916 				   AGS_OSC_RESPONSE_ERROR);
917 
918 	g_object_set(osc_response,
919 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
920 		     NULL);
921 
922 	return(start_response);
923       }
924 
925       ags_osc_buffer_util_put_string(packet + packet_size,
926 				     current_path, -1);
927 
928       /* node argument */
929       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
930 
931       g_object_get(audio,
932 		   "audio-channels", &audio_channels,
933 		   NULL);
934       ags_osc_buffer_util_put_int32(packet + packet_size,
935 				    audio_channels);
936 
937       packet_size += 4;
938 
939       /* packet size */
940       ags_osc_buffer_util_put_int32(packet,
941 				    packet_size);
942     }else if(!strncmp(path + path_offset,
943 		      "output-pads",
944 		      12)){
945       guint output_pads;
946 
947       /* create current path */
948       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:output-pads", nth_audio);
949 
950       /* message path */
951       packet_size = 4;
952 
953       ags_osc_buffer_util_put_string(packet + packet_size,
954 				     "/node", -1);
955 
956       /* message type tag */
957       packet_size += 8;
958 
959       ags_osc_buffer_util_put_string(packet + packet_size,
960 				     ",si", -1);
961 
962       /* node path */
963       packet_size += 4;
964 
965       length = strlen(current_path);
966 
967       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
968 	ags_osc_response_set_flags(osc_response,
969 				   AGS_OSC_RESPONSE_ERROR);
970 
971 	g_object_set(osc_response,
972 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
973 		     NULL);
974 
975 	return(start_response);
976       }
977 
978       ags_osc_buffer_util_put_string(packet + packet_size,
979 				     current_path, -1);
980 
981       /* node argument */
982       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
983 
984       g_object_get(audio,
985 		   "output-pads", &output_pads,
986 		   NULL);
987       ags_osc_buffer_util_put_int32(packet + packet_size,
988 				    output_pads);
989 
990       packet_size += 4;
991 
992       /* packet size */
993       ags_osc_buffer_util_put_int32(packet,
994 				    packet_size);
995     }else if(!strncmp(path + path_offset,
996 		      "input-pads",
997 		      11)){
998       guint input_pads;
999 
1000       /* create current path */
1001       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:input-pads", nth_audio);
1002 
1003       /* message path */
1004       packet_size = 4;
1005 
1006       ags_osc_buffer_util_put_string(packet + packet_size,
1007 				     "/node", -1);
1008 
1009       /* message type tag */
1010       packet_size += 8;
1011 
1012       ags_osc_buffer_util_put_string(packet + packet_size,
1013 				     ",si", -1);
1014 
1015       /* node path */
1016       packet_size += 4;
1017 
1018       length = strlen(current_path);
1019 
1020       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
1021 	ags_osc_response_set_flags(osc_response,
1022 				   AGS_OSC_RESPONSE_ERROR);
1023 
1024 	g_object_set(osc_response,
1025 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
1026 		     NULL);
1027 
1028 	return(start_response);
1029       }
1030 
1031       ags_osc_buffer_util_put_string(packet + packet_size,
1032 				     current_path, -1);
1033 
1034       /* node argument */
1035       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
1036 
1037       g_object_get(audio,
1038 		   "input-pads", &input_pads,
1039 		   NULL);
1040       ags_osc_buffer_util_put_int32(packet + packet_size,
1041 				    input_pads);
1042 
1043       packet_size += 4;
1044 
1045       /* packet size */
1046       ags_osc_buffer_util_put_int32(packet,
1047 				    packet_size);
1048     }else if(!strncmp(path + path_offset,
1049 		      "buffer-size",
1050 		      12)){
1051       guint buffer_size;
1052 
1053       /* create current path */
1054       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:buffer-size", nth_audio);
1055 
1056       /* message path */
1057       packet_size = 4;
1058 
1059       ags_osc_buffer_util_put_string(packet + packet_size,
1060 				     "/node", -1);
1061 
1062       /* message type tag */
1063       packet_size += 8;
1064 
1065       ags_osc_buffer_util_put_string(packet + packet_size,
1066 				     ",si", -1);
1067 
1068       /* node path */
1069       packet_size += 4;
1070 
1071       length = strlen(current_path);
1072 
1073       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
1074 	ags_osc_response_set_flags(osc_response,
1075 				   AGS_OSC_RESPONSE_ERROR);
1076 
1077 	g_object_set(osc_response,
1078 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
1079 		     NULL);
1080 
1081 	return(start_response);
1082       }
1083 
1084       ags_osc_buffer_util_put_string(packet + packet_size,
1085 				     current_path, -1);
1086 
1087       /* node argument */
1088       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
1089 
1090       g_object_get(audio,
1091 		   "buffer-size", &buffer_size,
1092 		   NULL);
1093       ags_osc_buffer_util_put_int32(packet + packet_size,
1094 				    buffer_size);
1095 
1096       packet_size += 4;
1097 
1098       /* packet size */
1099       ags_osc_buffer_util_put_int32(packet,
1100 				    packet_size);
1101     }else if(!strncmp(path + path_offset,
1102 		      "samplerate",
1103 		      11)){
1104       guint samplerate;
1105 
1106       /* create current path */
1107       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:samplerate", nth_audio);
1108 
1109       /* message path */
1110       packet_size = 4;
1111 
1112       ags_osc_buffer_util_put_string(packet + packet_size,
1113 				     "/node", -1);
1114 
1115       /* message type tag */
1116       packet_size += 8;
1117 
1118       ags_osc_buffer_util_put_string(packet + packet_size,
1119 				     ",si", -1);
1120 
1121       /* node path */
1122       packet_size += 4;
1123 
1124       length = strlen(current_path);
1125 
1126       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
1127 	ags_osc_response_set_flags(osc_response,
1128 				   AGS_OSC_RESPONSE_ERROR);
1129 
1130 	g_object_set(osc_response,
1131 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
1132 		     NULL);
1133 
1134 	return(start_response);
1135       }
1136 
1137       ags_osc_buffer_util_put_string(packet + packet_size,
1138 				     current_path, -1);
1139 
1140       /* node argument */
1141       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
1142 
1143       g_object_get(audio,
1144 		   "samplerate", &samplerate,
1145 		   NULL);
1146       ags_osc_buffer_util_put_int32(packet + packet_size,
1147 				    samplerate);
1148 
1149       packet_size += 4;
1150 
1151       /* packet size */
1152       ags_osc_buffer_util_put_int32(packet,
1153 				    packet_size);
1154     }else if(!strncmp(path + path_offset,
1155 		      "format",
1156 		      7)){
1157       guint format;
1158 
1159       /* create current path */
1160       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]:format", nth_audio);
1161 
1162       /* message path */
1163       packet_size = 4;
1164 
1165       ags_osc_buffer_util_put_string(packet + packet_size,
1166 				     "/node", -1);
1167 
1168       /* message type tag */
1169       packet_size += 8;
1170 
1171       ags_osc_buffer_util_put_string(packet + packet_size,
1172 				     ",si", -1);
1173 
1174       /* node path */
1175       packet_size += 4;
1176 
1177       length = strlen(current_path);
1178 
1179       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
1180 	ags_osc_response_set_flags(osc_response,
1181 				   AGS_OSC_RESPONSE_ERROR);
1182 
1183 	g_object_set(osc_response,
1184 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
1185 		     NULL);
1186 
1187 	return(start_response);
1188       }
1189 
1190       ags_osc_buffer_util_put_string(packet + packet_size,
1191 				     current_path, -1);
1192 
1193       /* node argument */
1194       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
1195 
1196       g_object_get(audio,
1197 		   "format", &format,
1198 		   NULL);
1199       ags_osc_buffer_util_put_int32(packet + packet_size,
1200 				    format);
1201 
1202       packet_size += 4;
1203 
1204       /* packet size */
1205       ags_osc_buffer_util_put_int32(packet,
1206 				    packet_size);
1207     }else{
1208       ags_osc_response_set_flags(osc_response,
1209 				 AGS_OSC_RESPONSE_ERROR);
1210 
1211       g_object_set(osc_response,
1212 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
1213 		   NULL);
1214 
1215       return(start_response);
1216     }
1217 
1218     g_object_set(osc_response,
1219 		 "packet-size", packet_size,
1220 		 NULL);
1221   }else if(!strncmp(path + path_offset,
1222 		    "/AgsOutput",
1223 		    10) ||
1224 	   !strncmp(path + path_offset,
1225 		    "/AgsInput",
1226 		    9)){
1227     AgsChannel *start_channel;
1228     AgsChannel *channel, *next_channel;
1229 
1230     regmatch_t match_arr[2];
1231 
1232     static regex_t single_access_regex;
1233     static regex_t range_access_regex;
1234     static regex_t voluntary_access_regex;
1235     static regex_t more_access_regex;
1236     static regex_t wildcard_access_regex;
1237 
1238     static gboolean regex_compiled = FALSE;
1239 
1240     static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
1241     static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
1242     static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
1243     static const gchar *more_access_pattern = "^\\[(\\+)\\]";
1244     static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
1245 
1246     static const size_t max_matches = 2;
1247     static const size_t index_max_matches = 1;
1248 
1249     start_channel = NULL;
1250 
1251     if(!strncmp(path + path_offset,
1252 		"/AgsOutput",
1253 		10)){
1254       path_offset += 10;
1255 
1256       g_object_get(audio,
1257 		   "output", &start_channel,
1258 		   NULL);
1259     }else{
1260       path_offset += 9;
1261 
1262       g_object_get(audio,
1263 		   "input", &start_channel,
1264 		   NULL);
1265     }
1266 
1267     /* compile regex */
1268     g_mutex_lock(&regex_mutex);
1269 
1270     if(!regex_compiled){
1271       regex_compiled = TRUE;
1272 
1273       ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
1274       ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
1275       ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
1276       ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
1277       ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
1278     }
1279 
1280     g_mutex_unlock(&regex_mutex);
1281 
1282     if(ags_regexec(&single_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
1283       gchar *endptr;
1284 
1285       guint i_stop;
1286 
1287       endptr = NULL;
1288       i_stop = g_ascii_strtoull(path + path_offset + 1,
1289 				&endptr,
1290 				10);
1291 
1292       channel = ags_channel_nth(start_channel,
1293 				i_stop);
1294 
1295       path_offset += ((endptr + 1) - (path + path_offset));
1296 
1297       start_response = ags_osc_node_controller_get_data_channel(osc_node_controller,
1298 								osc_connection,
1299 								channel,
1300 								message, message_size,
1301 								type_tag,
1302 								path, path_offset);
1303 
1304       if(start_channel != NULL){
1305 	g_object_unref(start_channel);
1306       }
1307 
1308       if(channel != NULL){
1309 	g_object_unref(channel);
1310       }
1311     }else if(ags_regexec(&range_access_regex, path + path_offset, max_matches, match_arr, 0) == 0){
1312       gchar *endptr;
1313 
1314       guint i;
1315       guint i_start, i_stop;
1316 
1317       endptr = NULL;
1318       i_start = g_ascii_strtoull(path + path_offset + 1,
1319 				 &endptr,
1320 				 10);
1321 
1322       i_stop = g_ascii_strtoull(endptr + 1,
1323 				&endptr,
1324 				10);
1325 
1326       path_offset += ((endptr + 1) - (path + path_offset));
1327 
1328       channel = ags_channel_nth(start_channel,
1329 				i_start);
1330 
1331       next_channel = NULL;
1332 
1333       for(i = i_start; i <= i_stop && channel != NULL; i++){
1334 	GList *retval;
1335 
1336 	retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
1337 							  osc_connection,
1338 							  channel,
1339 							  message, message_size,
1340 							  type_tag,
1341 							  path, path_offset);
1342 
1343 	if(start_response != NULL){
1344 	  start_response = g_list_concat(start_response,
1345 					 retval);
1346 	}else{
1347 	  start_response = retval;
1348 	}
1349 
1350 	/* iterate */
1351 	next_channel = ags_channel_next(channel);
1352 
1353 	g_object_unref(channel);
1354 
1355 	channel = next_channel;
1356       }
1357 
1358       if(start_channel != NULL){
1359 	g_object_unref(start_channel);
1360       }
1361 
1362       if(next_channel != NULL){
1363 	g_object_unref(next_channel);
1364       }
1365     }else if(ags_regexec(&voluntary_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
1366       path_offset += 3;
1367 
1368       if(start_channel != NULL){
1369 	GList *retval;
1370 
1371 	retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
1372 							  osc_connection,
1373 							  start_channel,
1374 							  message, message_size,
1375 							  type_tag,
1376 							  path, path_offset);
1377       }else{
1378 	osc_response = ags_osc_response_new();
1379 	start_response = g_list_prepend(start_response,
1380 					osc_response);
1381 
1382 	ags_osc_response_set_flags(osc_response,
1383 				   AGS_OSC_RESPONSE_OK);
1384 
1385 	return(start_response);
1386       }
1387     }else if(ags_regexec(&more_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
1388       path_offset += 3;
1389 
1390       if(start_channel == NULL){
1391 	osc_response = ags_osc_response_new();
1392 	start_response = g_list_prepend(start_response,
1393 					osc_response);
1394 
1395 	ags_osc_response_set_flags(osc_response,
1396 				   AGS_OSC_RESPONSE_ERROR);
1397 
1398 	g_object_set(osc_response,
1399 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
1400 		     NULL);
1401 
1402 	return(start_response);
1403       }
1404 
1405       /* prepare */
1406       channel = start_channel;
1407       g_object_ref(channel);
1408 
1409       next_channel = NULL;
1410 
1411       while(channel != NULL){
1412 	GList *retval;
1413 
1414 	retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
1415 							  osc_connection,
1416 							  channel,
1417 							  message, message_size,
1418 							  type_tag,
1419 							  path, path_offset);
1420 
1421 	if(start_response != NULL){
1422 	  start_response = g_list_concat(start_response,
1423 					 retval);
1424 	}else{
1425 	  start_response = retval;
1426 	}
1427 
1428 	/* iterate */
1429 	next_channel = ags_channel_next(channel);
1430 
1431 	g_object_unref(channel);
1432 
1433 	channel = next_channel;
1434       }
1435 
1436       /* unref */
1437       if(start_channel != NULL){
1438 	g_object_unref(start_channel);
1439       }
1440 
1441       if(next_channel != NULL){
1442 	g_object_unref(next_channel);
1443       }
1444     }else if(ags_regexec(&wildcard_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
1445       path_offset += 3;
1446 
1447       if(start_channel == NULL){
1448 	osc_response = ags_osc_response_new();
1449 	start_response = g_list_prepend(start_response,
1450 					osc_response);
1451 
1452 	ags_osc_response_set_flags(osc_response,
1453 				   AGS_OSC_RESPONSE_OK);
1454 
1455 	return(start_response);
1456       }
1457 
1458       /* prepare */
1459       channel = start_channel;
1460       g_object_ref(channel);
1461 
1462       next_channel = NULL;
1463 
1464       while(channel != NULL){
1465 	GList *retval;
1466 
1467 	retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
1468 							  osc_connection,
1469 							  channel,
1470 							  message, message_size,
1471 							  type_tag,
1472 							  path, path_offset);
1473 
1474 	if(start_response != NULL){
1475 	  start_response = g_list_concat(start_response,
1476 					 retval);
1477 	}else{
1478 	  start_response = retval;
1479 	}
1480 
1481 	/* iterate */
1482 	next_channel = ags_channel_next(channel);
1483 
1484 	g_object_unref(channel);
1485 
1486 	channel = next_channel;
1487       }
1488 
1489       /* unref */
1490       if(start_channel != NULL){
1491 	g_object_unref(start_channel);
1492       }
1493 
1494       if(next_channel != NULL){
1495 	g_object_unref(next_channel);
1496       }
1497     }else{
1498       osc_response = ags_osc_response_new();
1499       start_response = g_list_prepend(start_response,
1500 				      osc_response);
1501 
1502       ags_osc_response_set_flags(osc_response,
1503 				 AGS_OSC_RESPONSE_ERROR);
1504 
1505       g_object_set(osc_response,
1506 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
1507 		   NULL);
1508 
1509       /* unref */
1510       if(start_channel != NULL){
1511 	g_object_unref(start_channel);
1512       }
1513 
1514       return(start_response);
1515     }
1516   }else{
1517     GType recall_type;
1518 
1519     GList *start_play, *play;
1520     GList *start_recall, *recall;
1521 
1522     regmatch_t match_arr[3];
1523 
1524     gchar *type_name;
1525     gchar *str;
1526 
1527     guint type_name_length;
1528     guint str_length;
1529 
1530     static regex_t recall_regex;
1531     static regex_t single_access_regex;
1532     static regex_t range_access_regex;
1533     static regex_t voluntary_access_regex;
1534     static regex_t more_access_regex;
1535     static regex_t wildcard_access_regex;
1536 
1537     static gboolean regex_compiled = FALSE;
1538 
1539     static const gchar *recall_pattern = "^\\/([a-zA-Z]+)(\\/|\\[[0-9]+\\]|\\[[0-9]+\\-[0-9]+\\]|\\[\\?\\]|\\[\\+\\]|\\[\\*\\]|:)";
1540     static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
1541     static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
1542     static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
1543     static const gchar *more_access_pattern = "^\\[(\\+)\\]";
1544     static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
1545 
1546     static const size_t max_matches = 3;
1547     static const size_t index_max_matches = 2;
1548 
1549     /* compile regex */
1550     g_mutex_lock(&regex_mutex);
1551 
1552     if(!regex_compiled){
1553       regex_compiled = TRUE;
1554 
1555       ags_regcomp(&recall_regex, recall_pattern, REG_EXTENDED);
1556 
1557       ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
1558       ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
1559       ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
1560       ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
1561       ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
1562     }
1563 
1564     g_mutex_unlock(&regex_mutex);
1565 
1566     if(ags_regexec(&recall_regex, path + path_offset, max_matches, match_arr, 0) == 0){
1567       type_name_length = match_arr[1].rm_eo - match_arr[1].rm_so;
1568       type_name = g_strndup(path + path_offset + 1,
1569 			    type_name_length);
1570 
1571       str_length = match_arr[2].rm_eo - match_arr[2].rm_so;
1572       str = g_strndup(path + path_offset + 1 + type_name_length,
1573 		      str_length);
1574     }else{
1575       osc_response = ags_osc_response_new();
1576       start_response = g_list_prepend(start_response,
1577 				      osc_response);
1578 
1579       ags_osc_response_set_flags(osc_response,
1580 				 AGS_OSC_RESPONSE_ERROR);
1581 
1582       g_object_set(osc_response,
1583 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_PATH,
1584 		   NULL);
1585 
1586       return(start_response);
1587     }
1588 
1589     recall_type = g_type_from_name(type_name);
1590 
1591     g_object_get(audio,
1592 		 "play", &start_play,
1593 		 "recall", &start_recall,
1594 		 NULL);
1595 
1596     if(ags_regexec(&single_access_regex, str, index_max_matches, match_arr, 0) == 0){
1597       guint i;
1598       guint i_stop;
1599 
1600       path_offset += (type_name_length + 1) + str_length;
1601 
1602       i_stop = g_ascii_strtoull(str + 1,
1603 				NULL,
1604 				10);
1605 
1606       play = start_play;
1607       recall = start_recall;
1608 
1609       for(i = 0; i <= i_stop; i++){
1610 	play = ags_recall_template_find_type(play, recall_type);
1611 	recall = ags_recall_template_find_type(recall, recall_type);
1612 
1613 	if(i + 1 < i_stop){
1614 	  if(play != NULL){
1615 	    play = play->next;
1616 	  }
1617 
1618 	  if(recall != NULL){
1619 	    recall = recall->next;
1620 	  }
1621 	}
1622       }
1623 
1624       if(play != NULL){
1625 	AgsRecall *current;
1626 
1627 	GList *retval;
1628 
1629 	current = play->data;
1630 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1631 							 osc_connection,
1632 							 current,
1633 							 message, message_size,
1634 							 type_tag,
1635 							 path, path_offset);
1636 
1637 	if(start_response != NULL){
1638 	  start_response = g_list_concat(start_response,
1639 					 retval);
1640 	}else{
1641 	  start_response = retval;
1642 	}
1643       }
1644 
1645       if(recall != NULL){
1646 	AgsRecall *current;
1647 
1648 	GList *retval;
1649 
1650 	current = recall->data;
1651 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1652 							 osc_connection,
1653 							 current,
1654 							 message, message_size,
1655 							 type_tag,
1656 							 path, path_offset);
1657 
1658 	if(start_response != NULL){
1659 	  start_response = g_list_concat(start_response,
1660 					 retval);
1661 	}else{
1662 	  start_response = retval;
1663 	}
1664       }
1665     }else if(ags_regexec(&range_access_regex, str, max_matches, match_arr, 0) == 0){
1666       gchar *endptr;
1667 
1668       guint i;
1669       guint i_start, i_stop;
1670 
1671       path_offset += (type_name_length + 1) + str_length;
1672 
1673       endptr = NULL;
1674       i_start = g_ascii_strtoull(str + 1,
1675 				 &endptr,
1676 				 10);
1677 
1678       i_stop = g_ascii_strtoull(endptr + 1,
1679 				NULL,
1680 				10);
1681 
1682       play = start_play;
1683       recall = start_recall;
1684 
1685       for(i = 0; i <= i_stop; i++){
1686 	play = ags_recall_template_find_type(play, recall_type);
1687 	recall = ags_recall_template_find_type(recall, recall_type);
1688 
1689 	if(i >= i_start){
1690 	  if(play != NULL){
1691 	    AgsRecall *current;
1692 
1693 	    GList *retval;
1694 
1695 	    current = play->data;
1696 	    retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1697 							     osc_connection,
1698 							     current,
1699 							     message, message_size,
1700 							     type_tag,
1701 							     path, path_offset);
1702 
1703 	    if(start_response != NULL){
1704 	      start_response = g_list_concat(start_response,
1705 					     retval);
1706 	    }else{
1707 	      start_response = retval;
1708 	    }
1709 	  }
1710 
1711 	  if(recall != NULL){
1712 	    AgsRecall *current;
1713 
1714 	    GList *retval;
1715 
1716 	    current = recall->data;
1717 	    retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1718 							     osc_connection,
1719 							     current,
1720 							     message, message_size,
1721 							     type_tag,
1722 							     path, path_offset);
1723 
1724 	    if(start_response != NULL){
1725 	      start_response = g_list_concat(start_response,
1726 					     retval);
1727 	    }else{
1728 	      start_response = retval;
1729 	    }
1730 	  }
1731 	}
1732 
1733 	if(i + 1 < i_stop){
1734 	  if(play != NULL){
1735 	    play = play->next;
1736 	  }
1737 
1738 	  if(recall != NULL){
1739 	    recall = recall->next;
1740 	  }
1741 	}
1742       }
1743     }else if(ags_regexec(&voluntary_access_regex, str, index_max_matches, match_arr, 0) == 0){
1744       path_offset += (type_name_length + 1) + str_length;
1745 
1746       play = start_play;
1747       recall = start_recall;
1748 
1749       play = ags_recall_template_find_type(play, recall_type);
1750       recall = ags_recall_template_find_type(recall, recall_type);
1751 
1752       if(play != NULL){
1753 	AgsRecall *current;
1754 
1755 	current = play->data;
1756 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
1757 								 osc_connection,
1758 								 current,
1759 								 message, message_size,
1760 								 type_tag,
1761 								 path, path_offset);
1762       }
1763 
1764       if(recall != NULL){
1765 	AgsRecall *current;
1766 
1767 	current = recall->data;
1768 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
1769 								 osc_connection,
1770 								 current,
1771 								 message, message_size,
1772 								 type_tag,
1773 								 path, path_offset);
1774       }
1775 
1776       if(play == NULL && recall == NULL){
1777 	osc_response = ags_osc_response_new();
1778 	start_response = g_list_prepend(start_response,
1779 					osc_response);
1780 
1781 	ags_osc_response_set_flags(osc_response,
1782 				   AGS_OSC_RESPONSE_OK);
1783 
1784 	g_list_free_full(start_play,
1785 			 g_object_unref);
1786 	g_list_free_full(start_recall,
1787 			 g_object_unref);
1788 
1789 	return(start_response);
1790       }
1791     }else if(ags_regexec(&more_access_regex, str, index_max_matches, match_arr, 0) == 0){
1792       path_offset += (type_name_length + 1) + str_length;
1793 
1794       play = start_play;
1795       recall = start_recall;
1796 
1797       play = ags_recall_template_find_type(play, recall_type);
1798       recall = ags_recall_template_find_type(recall, recall_type);
1799 
1800       if(play == NULL && recall == NULL){
1801 	osc_response = ags_osc_response_new();
1802 	start_response = g_list_prepend(start_response,
1803 					osc_response);
1804 
1805 	ags_osc_response_set_flags(osc_response,
1806 				   AGS_OSC_RESPONSE_ERROR);
1807 
1808 	g_object_set(osc_response,
1809 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
1810 		     NULL);
1811 
1812 	g_list_free_full(start_play,
1813 			 g_object_unref);
1814 	g_list_free_full(start_recall,
1815 			 g_object_unref);
1816 
1817 	return(start_response);
1818       }
1819 
1820       if(play != NULL){
1821 	AgsRecall *current;
1822 
1823 	current = play->data;
1824 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
1825 								 osc_connection,
1826 								 current,
1827 								 message, message_size,
1828 								 type_tag,
1829 								 path, path_offset);
1830       }
1831 
1832       if(recall != NULL){
1833 	AgsRecall *current;
1834 
1835 	GList *retval;
1836 
1837 	current = recall->data;
1838 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1839 							 osc_connection,
1840 							 current,
1841 							 message, message_size,
1842 							 type_tag,
1843 							 path, path_offset);
1844 
1845 	if(start_response != NULL){
1846 	  start_response = g_list_concat(start_response,
1847 					 retval);
1848 	}else{
1849 	  start_response = retval;
1850 	}
1851       }
1852 
1853       while(play != NULL || recall != NULL){
1854 	play = ags_recall_template_find_type(play, recall_type);
1855 	recall = ags_recall_template_find_type(recall, recall_type);
1856 
1857 	if(play != NULL){
1858 	  AgsRecall *current;
1859 
1860 	  GList *retval;
1861 
1862 	  current = play->data;
1863 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1864 							   osc_connection,
1865 							   current,
1866 							   message, message_size,
1867 							   type_tag,
1868 							   path, path_offset);
1869 
1870 	  start_response = g_list_concat(start_response,
1871 					 retval);
1872 	}
1873 
1874 	if(recall != NULL){
1875 	  AgsRecall *current;
1876 
1877 	  GList *retval;
1878 
1879 	  current = recall->data;
1880 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1881 							   osc_connection,
1882 							   current,
1883 							   message, message_size,
1884 							   type_tag,
1885 							   path, path_offset);
1886 
1887 	  start_response = g_list_concat(start_response,
1888 					 retval);
1889 	}
1890 
1891 	if(play != NULL){
1892 	  play = play->next;
1893 	}
1894 
1895 	if(recall != NULL){
1896 	  recall = recall->next;
1897 	}
1898       }
1899     }else if(ags_regexec(&wildcard_access_regex, str, index_max_matches, match_arr, 0) == 0){
1900       path_offset += (type_name_length + 1) + str_length;
1901 
1902       play = start_play;
1903       recall = start_recall;
1904 
1905       while(play != NULL || recall != NULL){
1906 	play = ags_recall_template_find_type(play, recall_type);
1907 	recall = ags_recall_template_find_type(recall, recall_type);
1908 
1909 	if(play != NULL){
1910 	  AgsRecall *current;
1911 
1912 	  GList *retval;
1913 
1914 	  current = play->data;
1915 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1916 							   osc_connection,
1917 							   current,
1918 							   message, message_size,
1919 							   type_tag,
1920 							   path, path_offset);
1921 
1922 	  if(start_response != NULL){
1923 	    start_response = g_list_concat(start_response,
1924 					   retval);
1925 	  }else{
1926 	    start_response = retval;
1927 	  }
1928 	}
1929 
1930 	if(recall != NULL){
1931 	  AgsRecall *current;
1932 
1933 	  GList *retval;
1934 
1935 	  current = recall->data;
1936 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
1937 							   osc_connection,
1938 							   current,
1939 							   message, message_size,
1940 							   type_tag,
1941 							   path, path_offset);
1942 
1943 	  if(start_response != NULL){
1944 	    start_response = g_list_concat(start_response,
1945 					   retval);
1946 	  }else{
1947 	    start_response = retval;
1948 	  }
1949 	}
1950 
1951 	if(play != NULL){
1952 	  play = play->next;
1953 	}
1954 
1955 	if(recall != NULL){
1956 	  recall = recall->next;
1957 	}
1958       }
1959     }else{
1960       osc_response = ags_osc_response_new();
1961       start_response = g_list_prepend(start_response,
1962 				      osc_response);
1963 
1964       ags_osc_response_set_flags(osc_response,
1965 				 AGS_OSC_RESPONSE_ERROR);
1966 
1967       g_object_set(osc_response,
1968 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_MALFORMED_REQUEST,
1969 		   NULL);
1970 
1971       g_list_free_full(start_play,
1972 		       g_object_unref);
1973       g_list_free_full(start_recall,
1974 		       g_object_unref);
1975 
1976       return(start_response);
1977     }
1978 
1979     g_list_free_full(start_play,
1980 		     g_object_unref);
1981     g_list_free_full(start_recall,
1982 		     g_object_unref);
1983   }
1984 
1985   return(start_response);
1986 }
1987 
1988 gpointer
ags_osc_node_controller_get_data_channel(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,AgsChannel * channel,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)1989 ags_osc_node_controller_get_data_channel(AgsOscNodeController *osc_node_controller,
1990 					 AgsOscConnection *osc_connection,
1991 					 AgsChannel *channel,
1992 					 unsigned char *message, guint message_size,
1993 					 gchar *type_tag,
1994 					 gchar *path, guint path_offset)
1995 {
1996   AgsAudio *audio;
1997 
1998   AgsOscResponse *osc_response;
1999 
2000   AgsApplicationContext *application_context;
2001 
2002   GList *start_response;
2003   GList *start_list;
2004 
2005   unsigned char *packet;
2006   gchar *current_path;
2007 
2008   guint real_packet_size;
2009   guint packet_size;
2010   gint nth_audio;
2011   gint nth_channel;
2012 
2013   if(!AGS_IS_CHANNEL(channel)){
2014     return(NULL);
2015   }
2016 
2017   start_response = NULL;
2018 
2019   application_context = ags_application_context_get_instance();
2020 
2021   real_packet_size = 0;
2022   packet_size = 0;
2023 
2024   if(!strncmp(path + path_offset,
2025 	      ":",
2026 	      1)){
2027     guint length;
2028 
2029     g_object_get(channel,
2030 		 "audio", &audio,
2031 		 "line", &nth_channel,
2032 		 NULL);
2033 
2034     g_object_unref(audio);
2035 
2036     /* get nth audio */
2037     start_list = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
2038 
2039     nth_audio = g_list_index(start_list,
2040 			     audio);
2041 
2042     g_list_free_full(start_list,
2043 		     g_object_unref);
2044 
2045     osc_response = ags_osc_response_new();
2046     start_response = g_list_prepend(start_response,
2047 				    osc_response);
2048 
2049     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
2050     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
2051 
2052     g_object_set(osc_response,
2053 		 "packet", packet,
2054 		 "packet-size", packet_size,
2055 		 NULL);
2056 
2057     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
2058 
2059     path_offset += 1;
2060 
2061     if(!strncmp(path + path_offset,
2062 		"buffer-size",
2063 		12)){
2064       guint buffer_size;
2065 
2066       /* create current path */
2067       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]/%s[%d]:buffer-size",
2068 				     nth_audio,
2069 				     ((AGS_IS_OUTPUT(channel)) ? "AgsOutput": "AgsInput"),
2070 				     nth_channel);
2071 
2072       /* message path */
2073       packet_size = 4;
2074 
2075       ags_osc_buffer_util_put_string(packet + packet_size,
2076 				     "/node", -1);
2077 
2078       /* message type tag */
2079       packet_size += 8;
2080 
2081       ags_osc_buffer_util_put_string(packet + packet_size,
2082 				     ",si", -1);
2083 
2084       /* node path */
2085       packet_size += 4;
2086 
2087       length = strlen(current_path);
2088 
2089       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
2090 	ags_osc_response_set_flags(osc_response,
2091 				   AGS_OSC_RESPONSE_ERROR);
2092 
2093 	g_object_set(osc_response,
2094 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
2095 		     NULL);
2096 
2097 	return(start_response);
2098       }
2099 
2100       ags_osc_buffer_util_put_string(packet + packet_size,
2101 				     current_path, -1);
2102 
2103       /* node argument */
2104       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
2105 
2106       g_object_get(channel,
2107 		   "buffer-size", &buffer_size,
2108 		   NULL);
2109       ags_osc_buffer_util_put_int32(packet + packet_size,
2110 				    buffer_size);
2111 
2112       packet_size += 4;
2113 
2114       /* packet size */
2115       ags_osc_buffer_util_put_int32(packet,
2116 				    packet_size);
2117     }else if(!strncmp(path + path_offset,
2118 		      "samplerate",
2119 		      11)){
2120       guint samplerate;
2121 
2122       /* create current path */
2123       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]/%s[%d]:samplerate",
2124 				     nth_audio,
2125 				     ((AGS_IS_OUTPUT(channel)) ? "AgsOutput": "AgsInput"),
2126 				     nth_channel);
2127 
2128       /* message path */
2129       packet_size = 4;
2130 
2131       ags_osc_buffer_util_put_string(packet + packet_size,
2132 				     "/node", -1);
2133 
2134       /* message type tag */
2135       packet_size += 8;
2136 
2137       ags_osc_buffer_util_put_string(packet + packet_size,
2138 				     ",si", -1);
2139 
2140       /* node path */
2141       packet_size += 4;
2142 
2143       length = strlen(current_path);
2144 
2145       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
2146 	ags_osc_response_set_flags(osc_response,
2147 				   AGS_OSC_RESPONSE_ERROR);
2148 
2149 	g_object_set(osc_response,
2150 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
2151 		     NULL);
2152 
2153 	return(start_response);
2154       }
2155 
2156       ags_osc_buffer_util_put_string(packet + packet_size,
2157 				     current_path, -1);
2158 
2159       /* node argument */
2160       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
2161 
2162       g_object_get(channel,
2163 		   "samplerate", &samplerate,
2164 		   NULL);
2165       ags_osc_buffer_util_put_int32(packet + packet_size,
2166 				    samplerate);
2167 
2168       packet_size += 4;
2169 
2170       /* packet size */
2171       ags_osc_buffer_util_put_int32(packet,
2172 				    packet_size);
2173     }else if(!strncmp(path + path_offset,
2174 		      "format",
2175 		      7)){
2176       guint format;
2177 
2178       /* create current path */
2179       current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]/%s[%d]:format",
2180 				     nth_audio,
2181 				     ((AGS_IS_OUTPUT(channel)) ? "AgsOutput": "AgsInput"),
2182 				     nth_channel);
2183 
2184       /* message path */
2185       packet_size = 4;
2186 
2187       ags_osc_buffer_util_put_string(packet + packet_size,
2188 				     "/node", -1);
2189 
2190       /* message type tag */
2191       packet_size += 8;
2192 
2193       ags_osc_buffer_util_put_string(packet + packet_size,
2194 				     ",si", -1);
2195 
2196       /* node path */
2197       packet_size += 4;
2198 
2199       length = strlen(current_path);
2200 
2201       if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 4 > real_packet_size){
2202 	ags_osc_response_set_flags(osc_response,
2203 				   AGS_OSC_RESPONSE_ERROR);
2204 
2205 	g_object_set(osc_response,
2206 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
2207 		     NULL);
2208 
2209 	return(start_response);
2210       }
2211 
2212       ags_osc_buffer_util_put_string(packet + packet_size,
2213 				     current_path, -1);
2214 
2215       /* node argument */
2216       packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
2217 
2218       g_object_get(channel,
2219 		   "format", &format,
2220 		   NULL);
2221       ags_osc_buffer_util_put_int32(packet + packet_size,
2222 				    format);
2223 
2224       packet_size += 4;
2225 
2226       /* packet size */
2227       ags_osc_buffer_util_put_int32(packet,
2228 				    packet_size);
2229     }else{
2230       ags_osc_response_set_flags(osc_response,
2231 				 AGS_OSC_RESPONSE_ERROR);
2232 
2233       g_object_set(osc_response,
2234 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
2235 		   NULL);
2236 
2237       return(start_response);
2238     }
2239 
2240     g_object_set(osc_response,
2241 		 "packet-size", packet_size,
2242 		 NULL);
2243   }else{
2244     GType recall_type;
2245 
2246     GList *start_play, *play;
2247     GList *start_recall, *recall;
2248 
2249     regmatch_t match_arr[3];
2250 
2251     gchar *type_name;
2252     gchar *str;
2253 
2254     guint type_name_length;
2255     guint str_length;
2256 
2257     static regex_t recall_regex;
2258     static regex_t single_access_regex;
2259     static regex_t range_access_regex;
2260     static regex_t voluntary_access_regex;
2261     static regex_t more_access_regex;
2262     static regex_t wildcard_access_regex;
2263 
2264     static gboolean regex_compiled = FALSE;
2265 
2266     static const gchar *recall_pattern = "^\\/([a-zA-Z]+)(\\/|\\[[0-9]+\\]|\\[[0-9]+\\-[0-9]+\\]|\\[\\?\\]|\\[\\+\\]|\\[\\*\\]|:)";
2267     static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
2268     static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
2269     static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
2270     static const gchar *more_access_pattern = "^\\[(\\+)\\]";
2271     static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
2272 
2273     static const size_t max_matches = 3;
2274     static const size_t index_max_matches = 2;
2275 
2276     /* compile regex */
2277     g_mutex_lock(&regex_mutex);
2278 
2279     if(!regex_compiled){
2280       regex_compiled = TRUE;
2281 
2282       ags_regcomp(&recall_regex, recall_pattern, REG_EXTENDED);
2283 
2284       ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
2285       ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
2286       ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
2287       ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
2288       ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
2289     }
2290 
2291     g_mutex_unlock(&regex_mutex);
2292 
2293     if(ags_regexec(&recall_regex, path + path_offset, max_matches, match_arr, 0) == 0){
2294       type_name_length = match_arr[1].rm_eo - match_arr[1].rm_so;
2295       type_name = g_strndup(path + path_offset + 1,
2296 			    type_name_length);
2297 
2298       str_length = match_arr[2].rm_eo - match_arr[2].rm_so;
2299       str = g_strndup(path + path_offset + 1 + type_name_length,
2300 		      str_length);
2301     }else{
2302       osc_response = ags_osc_response_new();
2303       start_response = g_list_prepend(start_response,
2304 				      osc_response);
2305 
2306       ags_osc_response_set_flags(osc_response,
2307 				 AGS_OSC_RESPONSE_ERROR);
2308 
2309       g_object_set(osc_response,
2310 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_PATH,
2311 		   NULL);
2312 
2313       return(start_response);
2314     }
2315 
2316     recall_type = g_type_from_name(type_name);
2317 
2318     g_object_get(channel,
2319 		 "play", &start_play,
2320 		 "recall", &start_recall,
2321 		 NULL);
2322 
2323     if(ags_regexec(&single_access_regex, str, index_max_matches, match_arr, 0) == 0){
2324       guint i;
2325       guint i_stop;
2326 
2327       path_offset += (type_name_length + 1) + str_length;
2328 
2329       i_stop = g_ascii_strtoull(str + 1,
2330 				NULL,
2331 				10);
2332 
2333       play = start_play;
2334       recall = start_recall;
2335 
2336       for(i = 0; i <= i_stop; i++){
2337 	play = ags_recall_template_find_type(play, recall_type);
2338 	recall = ags_recall_template_find_type(recall, recall_type);
2339 
2340 	if(i + 1 < i_stop){
2341 	  if(play != NULL){
2342 	    play = play->next;
2343 	  }
2344 
2345 	  if(recall != NULL){
2346 	    recall = recall->next;
2347 	  }
2348 	}
2349       }
2350 
2351       if(play != NULL){
2352 	AgsRecall *current;
2353 
2354 	GList *retval;
2355 
2356 	current = play->data;
2357 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2358 							 osc_connection,
2359 							 current,
2360 							 message, message_size,
2361 							 type_tag,
2362 							 path, path_offset);
2363 
2364 	if(start_response != NULL){
2365 	  start_response = g_list_concat(start_response,
2366 					 retval);
2367 	}else{
2368 	  start_response = retval;
2369 	}
2370       }
2371 
2372       if(recall != NULL){
2373 	AgsRecall *current;
2374 
2375 	GList *retval;
2376 
2377 	current = recall->data;
2378 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2379 							 osc_connection,
2380 							 current,
2381 							 message, message_size,
2382 							 type_tag,
2383 							 path, path_offset);
2384 
2385 	if(start_response != NULL){
2386 	  start_response = g_list_concat(start_response,
2387 					 retval);
2388 	}else{
2389 	  start_response = retval;
2390 	}
2391       }
2392     }else if(ags_regexec(&range_access_regex, str, max_matches, match_arr, 0) == 0){
2393       gchar *endptr;
2394 
2395       guint i;
2396       guint i_start, i_stop;
2397 
2398       path_offset += (type_name_length + 1) + str_length;
2399 
2400       endptr = NULL;
2401       i_start = g_ascii_strtoull(str + 1,
2402 				 &endptr,
2403 				 10);
2404 
2405       i_stop = g_ascii_strtoull(endptr + 1,
2406 				NULL,
2407 				10);
2408 
2409       play = start_play;
2410       recall = start_recall;
2411 
2412       for(i = 0; i <= i_stop; i++){
2413 	play = ags_recall_template_find_type(play, recall_type);
2414 	recall = ags_recall_template_find_type(recall, recall_type);
2415 
2416 	if(i >= i_start){
2417 	  if(play != NULL){
2418 	    AgsRecall *current;
2419 
2420 	    GList *retval;
2421 
2422 	    current = play->data;
2423 	    retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2424 							     osc_connection,
2425 							     current,
2426 							     message, message_size,
2427 							     type_tag,
2428 							     path, path_offset);
2429 
2430 	    if(start_response != NULL){
2431 	      start_response = g_list_concat(start_response,
2432 					     retval);
2433 	    }else{
2434 	      start_response = retval;
2435 	    }
2436 	  }
2437 
2438 	  if(recall != NULL){
2439 	    AgsRecall *current;
2440 
2441 	    GList *retval;
2442 
2443 	    current = recall->data;
2444 	    retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2445 							     osc_connection,
2446 							     current,
2447 							     message, message_size,
2448 							     type_tag,
2449 							     path, path_offset);
2450 
2451 	    if(start_response != NULL){
2452 	      start_response = g_list_concat(start_response,
2453 					     retval);
2454 	    }else{
2455 	      start_response = retval;
2456 	    }
2457 	  }
2458 	}
2459 
2460 	if(i + 1 < i_stop){
2461 	  if(play != NULL){
2462 	    play = play->next;
2463 	  }
2464 
2465 	  if(recall != NULL){
2466 	    recall = recall->next;
2467 	  }
2468 	}
2469       }
2470     }else if(ags_regexec(&voluntary_access_regex, str, index_max_matches, match_arr, 0) == 0){
2471       path_offset += (type_name_length + 1) + str_length;
2472 
2473       play = start_play;
2474       recall = start_recall;
2475 
2476       play = ags_recall_template_find_type(play, recall_type);
2477       recall = ags_recall_template_find_type(recall, recall_type);
2478 
2479       if(play != NULL){
2480 	AgsRecall *current;
2481 
2482 	current = play->data;
2483 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
2484 								 osc_connection,
2485 								 current,
2486 								 message, message_size,
2487 								 type_tag,
2488 								 path, path_offset);
2489       }
2490 
2491       if(recall != NULL){
2492 	AgsRecall *current;
2493 
2494 	current = recall->data;
2495 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
2496 								 osc_connection,
2497 								 current,
2498 								 message, message_size,
2499 								 type_tag,
2500 								 path, path_offset);
2501       }
2502 
2503       if(play == NULL && recall == NULL){
2504 	osc_response = ags_osc_response_new();
2505 	start_response = g_list_prepend(start_response,
2506 					osc_response);
2507 
2508 	ags_osc_response_set_flags(osc_response,
2509 				   AGS_OSC_RESPONSE_OK);
2510 
2511 	g_list_free_full(start_play,
2512 			 g_object_unref);
2513 	g_list_free_full(start_recall,
2514 			 g_object_unref);
2515 
2516 	return(start_response);
2517       }
2518     }else if(ags_regexec(&more_access_regex, str, index_max_matches, match_arr, 0) == 0){
2519       path_offset += (type_name_length + 1) + str_length;
2520 
2521       play = start_play;
2522       recall = start_recall;
2523 
2524       play = ags_recall_template_find_type(play, recall_type);
2525       recall = ags_recall_template_find_type(recall, recall_type);
2526 
2527       if(play == NULL && recall == NULL){
2528 	osc_response = ags_osc_response_new();
2529 	start_response = g_list_prepend(start_response,
2530 					osc_response);
2531 
2532 	ags_osc_response_set_flags(osc_response,
2533 				   AGS_OSC_RESPONSE_ERROR);
2534 
2535 	g_object_set(osc_response,
2536 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
2537 		     NULL);
2538 
2539 	g_list_free_full(start_play,
2540 			 g_object_unref);
2541 	g_list_free_full(start_recall,
2542 			 g_object_unref);
2543 
2544 	return(start_response);
2545       }
2546 
2547       if(play != NULL){
2548 	AgsRecall *current;
2549 
2550 	current = play->data;
2551 	start_response = ags_osc_node_controller_get_data_recall(osc_node_controller,
2552 								 osc_connection,
2553 								 current,
2554 								 message, message_size,
2555 								 type_tag,
2556 								 path, path_offset);
2557       }
2558 
2559       if(recall != NULL){
2560 	AgsRecall *current;
2561 
2562 	GList *retval;
2563 
2564 	current = recall->data;
2565 	retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2566 							 osc_connection,
2567 							 current,
2568 							 message, message_size,
2569 							 type_tag,
2570 							 path, path_offset);
2571 
2572 	if(start_response != NULL){
2573 	  start_response = g_list_concat(start_response,
2574 					 retval);
2575 	}else{
2576 	  start_response = retval;
2577 	}
2578       }
2579 
2580       while(play != NULL || recall != NULL){
2581 	play = ags_recall_template_find_type(play, recall_type);
2582 	recall = ags_recall_template_find_type(recall, recall_type);
2583 
2584 	if(play != NULL){
2585 	  AgsRecall *current;
2586 
2587 	  GList *retval;
2588 
2589 	  current = play->data;
2590 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2591 							   osc_connection,
2592 							   current,
2593 							   message, message_size,
2594 							   type_tag,
2595 							   path, path_offset);
2596 
2597 	  start_response = g_list_concat(start_response,
2598 					 retval);
2599 	}
2600 
2601 	if(recall != NULL){
2602 	  AgsRecall *current;
2603 
2604 	  GList *retval;
2605 
2606 	  current = recall->data;
2607 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2608 							   osc_connection,
2609 							   current,
2610 							   message, message_size,
2611 							   type_tag,
2612 							   path, path_offset);
2613 
2614 	  start_response = g_list_concat(start_response,
2615 					 retval);
2616 	}
2617 
2618 	if(play != NULL){
2619 	  play = play->next;
2620 	}
2621 
2622 	if(recall != NULL){
2623 	  recall = recall->next;
2624 	}
2625       }
2626     }else if(ags_regexec(&wildcard_access_regex, str, index_max_matches, match_arr, 0) == 0){
2627       path_offset += (type_name_length + 1) + str_length;
2628 
2629       play = start_play;
2630       recall = start_recall;
2631 
2632       while(play != NULL || recall != NULL){
2633 	play = ags_recall_template_find_type(play, recall_type);
2634 	recall = ags_recall_template_find_type(recall, recall_type);
2635 
2636 	if(play != NULL){
2637 	  AgsRecall *current;
2638 
2639 	  GList *retval;
2640 
2641 	  current = play->data;
2642 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2643 							   osc_connection,
2644 							   current,
2645 							   message, message_size,
2646 							   type_tag,
2647 							   path, path_offset);
2648 
2649 	  if(start_response != NULL){
2650 	    start_response = g_list_concat(start_response,
2651 					   retval);
2652 	  }else{
2653 	    start_response = retval;
2654 	  }
2655 	}
2656 
2657 	if(recall != NULL){
2658 	  AgsRecall *current;
2659 
2660 	  GList *retval;
2661 
2662 	  current = recall->data;
2663 	  retval = ags_osc_node_controller_get_data_recall(osc_node_controller,
2664 							   osc_connection,
2665 							   current,
2666 							   message, message_size,
2667 							   type_tag,
2668 							   path, path_offset);
2669 
2670 	  if(start_response != NULL){
2671 	    start_response = g_list_concat(start_response,
2672 					   retval);
2673 	  }else{
2674 	    start_response = retval;
2675 	  }
2676 	}
2677 
2678 	if(play != NULL){
2679 	  play = play->next;
2680 	}
2681 
2682 	if(recall != NULL){
2683 	  recall = recall->next;
2684 	}
2685       }
2686     }else{
2687       osc_response = ags_osc_response_new();
2688       start_response = g_list_prepend(start_response,
2689 				      osc_response);
2690 
2691       ags_osc_response_set_flags(osc_response,
2692 				 AGS_OSC_RESPONSE_ERROR);
2693 
2694       g_object_set(osc_response,
2695 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_MALFORMED_REQUEST,
2696 		   NULL);
2697 
2698       g_list_free_full(start_play,
2699 		       g_object_unref);
2700       g_list_free_full(start_recall,
2701 		       g_object_unref);
2702 
2703       return(start_response);
2704     }
2705 
2706     g_list_free_full(start_play,
2707 		     g_object_unref);
2708     g_list_free_full(start_recall,
2709 		     g_object_unref);
2710   }
2711 
2712   return(start_response);
2713 }
2714 
2715 gpointer
ags_osc_node_controller_get_data_recall(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,AgsRecall * recall,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)2716 ags_osc_node_controller_get_data_recall(AgsOscNodeController *osc_node_controller,
2717 					AgsOscConnection *osc_connection,
2718 					AgsRecall *recall,
2719 					unsigned char *message, guint message_size,
2720 					gchar *type_tag,
2721 					gchar *path, guint path_offset)
2722 {
2723   AgsOscResponse *osc_response;
2724 
2725   AgsTaskLauncher *task_launcher;
2726 
2727   AgsApplicationContext *application_context;
2728 
2729   GList *start_response;
2730 
2731   unsigned char *packet;
2732 
2733   guint path_length;
2734   guint real_packet_size;
2735   guint packet_size;
2736 
2737   if(!AGS_IS_RECALL(recall)){
2738     return(NULL);
2739   }
2740 
2741   start_response = NULL;
2742 
2743   application_context = ags_application_context_get_instance();
2744 
2745   task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
2746 
2747   real_packet_size = 0;
2748   packet_size = 0;
2749 
2750   if(!strncmp(path + path_offset,
2751 	      ":",
2752 	      1)){
2753     guint length;
2754 
2755     osc_response = ags_osc_response_new();
2756     start_response = g_list_prepend(start_response,
2757 				    osc_response);
2758 
2759     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
2760     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
2761 
2762     g_object_set(osc_response,
2763 		 "packet", packet,
2764 		 "packet-size", packet_size,
2765 		 NULL);
2766 
2767     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
2768 
2769     path_length = 4 * (guint) ceil((double) (strlen(path) + 1) / 4.0);
2770     path_offset += 1;
2771 
2772     ags_osc_response_set_flags(osc_response,
2773 			       AGS_OSC_RESPONSE_ERROR);
2774 
2775     g_object_set(osc_response,
2776 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
2777 		 NULL);
2778 
2779     g_object_unref(task_launcher);
2780 
2781     return(start_response);
2782   }else if(!strncmp(path + path_offset,
2783 		    "/AgsPort",
2784 		    8)){
2785     GList *start_port, *port;
2786 
2787     regmatch_t match_arr[3];
2788 
2789     static regex_t single_access_regex;
2790     static regex_t range_access_regex;
2791     static regex_t voluntary_access_regex;
2792     static regex_t more_access_regex;
2793     static regex_t wildcard_access_regex;
2794 
2795     static gboolean regex_compiled = FALSE;
2796 
2797     static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
2798     static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
2799     static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
2800     static const gchar *more_access_pattern = "^\\[(\\+)\\]";
2801     static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
2802 
2803     static const size_t max_matches = 3;
2804     static const size_t index_max_matches = 2;
2805 
2806     path_offset += 8;
2807 
2808     /* compile regex */
2809     g_mutex_lock(&regex_mutex);
2810 
2811     if(!regex_compiled){
2812       regex_compiled = TRUE;
2813 
2814       ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
2815       ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
2816       ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
2817       ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
2818       ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
2819     }
2820 
2821     g_mutex_unlock(&regex_mutex);
2822 
2823     g_object_get(recall,
2824 		 "port", &start_port,
2825 		 NULL);
2826 
2827     port = start_port;
2828 
2829     if(ags_regexec(&single_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
2830       AgsPort *current;
2831 
2832       gchar *endptr;
2833 
2834       guint i_stop;
2835 
2836       endptr = NULL;
2837       i_stop = g_ascii_strtoull(path + path_offset + 1,
2838 				&endptr,
2839 				10);
2840 
2841       current = g_list_nth_data(start_port,
2842 				i_stop);
2843 
2844       path_offset += ((endptr + 1) - (path + path_offset));
2845 
2846       start_response = ags_osc_node_controller_get_data_port(osc_node_controller,
2847 							     osc_connection,
2848 							     recall,
2849 							     current,
2850 							     message, message_size,
2851 							     type_tag,
2852 							     path, path_offset);
2853     }else if(ags_regexec(&range_access_regex, path + path_offset, max_matches, match_arr, 0) == 0){
2854       gchar *endptr;
2855 
2856       guint i;
2857       guint i_start, i_stop;
2858 
2859       endptr = NULL;
2860       i_start = g_ascii_strtoull(path + path_offset + 1,
2861 				 &endptr,
2862 				 10);
2863 
2864       i_stop = g_ascii_strtoull(endptr + 1,
2865 				&endptr,
2866 				10);
2867 
2868       path_offset += ((endptr + 1) - (path + path_offset));
2869 
2870       port = g_list_nth(start_port,
2871 			i_start);
2872 
2873       for(i = i_start; i <= i_stop; i++){
2874 	GList *retval;
2875 
2876 	retval = ags_osc_node_controller_get_data_port(osc_node_controller,
2877 						       osc_connection,
2878 						       recall,
2879 						       port->data,
2880 						       message, message_size,
2881 						       type_tag,
2882 						       path, path_offset);
2883 
2884 	if(start_response != NULL){
2885 	  start_response = g_list_concat(start_response,
2886 					 retval);
2887 	}else{
2888 	  start_response = retval;
2889 	}
2890 
2891 	port = port->next;
2892       }
2893     }else if(ags_regexec(&voluntary_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
2894       path_offset += 3;
2895 
2896       if(start_port != NULL){
2897 	GList *retval;
2898 
2899 	retval = ags_osc_node_controller_get_data_port(osc_node_controller,
2900 						       osc_connection,
2901 						       recall,
2902 						       start_port->data,
2903 						       message, message_size,
2904 						       type_tag,
2905 						       path, path_offset);
2906       }else{
2907 	osc_response = ags_osc_response_new();
2908 	start_response = g_list_prepend(start_response,
2909 					osc_response);
2910 
2911 	ags_osc_response_set_flags(osc_response,
2912 				   AGS_OSC_RESPONSE_OK);
2913 
2914 	g_object_unref(task_launcher);
2915 
2916 	return(start_response);
2917       }
2918     }else if(ags_regexec(&more_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
2919       path_offset += 3;
2920 
2921       if(start_port == NULL){
2922 	osc_response = ags_osc_response_new();
2923 	start_response = g_list_prepend(start_response,
2924 					osc_response);
2925 
2926 	ags_osc_response_set_flags(osc_response,
2927 				   AGS_OSC_RESPONSE_ERROR);
2928 
2929 	g_object_set(osc_response,
2930 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
2931 		     NULL);
2932 
2933 	g_object_unref(task_launcher);
2934 
2935 	return(start_response);
2936       }
2937 
2938       port = start_port;
2939 
2940       while(port != NULL){
2941 	GList *retval;
2942 
2943 	retval = ags_osc_node_controller_get_data_port(osc_node_controller,
2944 						       osc_connection,
2945 						       recall,
2946 						       port->data,
2947 						       message, message_size,
2948 						       type_tag,
2949 						       path, path_offset);
2950 
2951 	if(start_response != NULL){
2952 	  start_response = g_list_concat(start_response,
2953 					 retval);
2954 	}else{
2955 	  start_response = retval;
2956 	}
2957 
2958 	port = port->next;
2959       }
2960     }else if(ags_regexec(&wildcard_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
2961       path_offset += 3;
2962 
2963       if(start_port == NULL){
2964 	osc_response = ags_osc_response_new();
2965 	start_response = g_list_prepend(start_response,
2966 					osc_response);
2967 
2968 	ags_osc_response_set_flags(osc_response,
2969 				   AGS_OSC_RESPONSE_OK);
2970 
2971 	g_object_unref(task_launcher);
2972 
2973 	return(start_response);
2974       }
2975 
2976       while(port != NULL){
2977 	GList *retval;
2978 
2979 	retval = ags_osc_node_controller_get_data_port(osc_node_controller,
2980 						       osc_connection,
2981 						       recall,
2982 						       port->data,
2983 						       message, message_size,
2984 						       type_tag,
2985 						       path, path_offset);
2986 
2987 	if(start_response != NULL){
2988 	  start_response = g_list_concat(start_response,
2989 					 retval);
2990 	}else{
2991 	  start_response = retval;
2992 	}
2993 
2994 	port = port->next;
2995       }
2996     }else if(path[path_offset] == '[' &&
2997 	     path[path_offset + 1] == '"'){
2998       AgsPort *current;
2999 
3000       gchar *port_specifier;
3001       gchar *offset;
3002 
3003       guint length;
3004 
3005       if((offset = strchr(path + path_offset + 2, '"')) == NULL){
3006 	osc_response = ags_osc_response_new();
3007 	start_response = g_list_prepend(start_response,
3008 					osc_response);
3009 
3010 	ags_osc_response_set_flags(osc_response,
3011 				   AGS_OSC_RESPONSE_ERROR);
3012 
3013 	g_object_set(osc_response,
3014 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3015 		     NULL);
3016 
3017 	g_list_free_full(start_port,
3018 			 g_object_unref);
3019 
3020 	g_object_unref(task_launcher);
3021 
3022 	return(start_response);
3023       }
3024 
3025       length = offset - (path + path_offset + 2);
3026 
3027       port_specifier = (gchar *) malloc((length + 1) * sizeof(gchar));
3028       memcpy(port_specifier, path + path_offset + 2, (length) * sizeof(gchar));
3029       port_specifier[length] = '\0';
3030 
3031       current = NULL;
3032       port = ags_port_find_specifier(start_port,
3033 				     port_specifier);
3034 
3035       if(port != NULL){
3036 	current = port->data;
3037       }
3038 
3039       path_offset += (length + 4);
3040       start_response  = ags_osc_node_controller_get_data_port(osc_node_controller,
3041 							      osc_connection,
3042 							      recall,
3043 							      current,
3044 							      message, message_size,
3045 							      type_tag,
3046 							      path, path_offset);
3047     }else{
3048       osc_response = ags_osc_response_new();
3049       start_response = g_list_prepend(start_response,
3050 				      osc_response);
3051 
3052       ags_osc_response_set_flags(osc_response,
3053 				 AGS_OSC_RESPONSE_ERROR);
3054 
3055       g_object_set(osc_response,
3056 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
3057 		   NULL);
3058 
3059       g_list_free_full(start_port,
3060 		       g_object_unref);
3061 
3062       g_object_unref(task_launcher);
3063 
3064       return(start_response);
3065     }
3066 
3067     g_list_free_full(start_port,
3068 		     g_object_unref);
3069   }else{
3070     osc_response = ags_osc_response_new();
3071     start_response = g_list_prepend(start_response,
3072 				    osc_response);
3073 
3074     ags_osc_response_set_flags(osc_response,
3075 			       AGS_OSC_RESPONSE_ERROR);
3076 
3077     g_object_set(osc_response,
3078 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
3079 		 NULL);
3080 
3081     g_object_unref(task_launcher);
3082 
3083     return(start_response);
3084   }
3085 
3086   g_object_unref(task_launcher);
3087 
3088   return(start_response);
3089 }
3090 
3091 gpointer
ags_osc_node_controller_get_data_port(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,AgsRecall * parent,AgsPort * port,unsigned char * message,guint message_size,gchar * type_tag,gchar * path,guint path_offset)3092 ags_osc_node_controller_get_data_port(AgsOscNodeController *osc_node_controller,
3093 				      AgsOscConnection *osc_connection,
3094 				      AgsRecall *parent,
3095 				      AgsPort *port,
3096 				      unsigned char *message, guint message_size,
3097 				      gchar *type_tag,
3098 				      gchar *path, guint path_offset)
3099 {
3100   AgsAudio *audio;
3101   AgsChannel *channel;
3102 
3103   AgsOscResponse *osc_response;
3104 
3105   AgsApplicationContext *application_context;
3106 
3107   GList *start_response;
3108   GList *start_list;
3109 
3110   unsigned char *packet;
3111   gchar *current_path;
3112   gchar *specifier;
3113 
3114   guint real_packet_size;
3115   guint packet_size;
3116   gint nth_audio;
3117   gint nth_channel;
3118 
3119   if(!AGS_IS_PORT(port)){
3120     return(NULL);
3121   }
3122 
3123   start_response = NULL;
3124 
3125   application_context = ags_application_context_get_instance();
3126 
3127   real_packet_size = 0;
3128   packet_size = 0;
3129 
3130   if(!strncmp(path + path_offset,
3131 	      ":",
3132 	      1)){
3133     guint length;
3134 
3135     audio = NULL;
3136     channel = NULL;
3137 
3138     if(AGS_IS_RECALL_CHANNEL(parent)){
3139       g_object_get(parent,
3140 		   "source", &channel,
3141 		   NULL);
3142 
3143       g_object_get(channel,
3144 		   "audio", &audio,
3145 		   "line", &nth_channel,
3146 		   NULL);
3147 
3148       g_object_unref(channel);
3149 
3150       g_object_unref(audio);
3151     }else if(AGS_IS_RECALL_AUDIO(parent)){
3152       g_object_get(parent,
3153 		   "audio", &audio,
3154 		   NULL);
3155 
3156       g_object_unref(audio);
3157     }
3158 
3159     /* get nth audio */
3160     start_list = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
3161 
3162     nth_audio = g_list_index(start_list,
3163 			     audio);
3164 
3165     g_list_free_full(start_list,
3166 		     g_object_unref);
3167 
3168     osc_response = ags_osc_response_new();
3169     start_response = g_list_prepend(start_response,
3170 				    osc_response);
3171 
3172     packet = (unsigned char *) malloc(AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
3173     memset(packet, 0, AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE * sizeof(unsigned char));
3174 
3175     g_object_set(osc_response,
3176 		 "packet", packet,
3177 		 "packet-size", packet_size,
3178 		 NULL);
3179 
3180     real_packet_size = AGS_OSC_RESPONSE_DEFAULT_CHUNK_SIZE;
3181 
3182     path_offset += 1;
3183 
3184     if(!strncmp(path + path_offset,
3185 		"value",
3186 		6)){
3187       GType port_value_type;
3188 
3189       guint port_value_length;
3190       gboolean port_value_is_pointer;
3191 
3192       GRecMutex *port_mutex;
3193 
3194       /* get port mutex */
3195       port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
3196 
3197       /* create current path */
3198       g_rec_mutex_lock(port_mutex);
3199 
3200       specifier = g_strdup(port->specifier);
3201 
3202       g_rec_mutex_unlock(port_mutex);
3203 
3204       if(channel != NULL){
3205 	current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]/%s[%d]/%s/AgsPort[%s]:value",
3206 				       nth_audio,
3207 				       ((AGS_IS_OUTPUT(channel)) ? "AgsOutput": "AgsInput"),
3208 				       nth_channel,
3209 				       G_OBJECT_TYPE_NAME(parent),
3210 				       specifier);
3211       }else{
3212 	current_path = g_strdup_printf("/AgsSoundProvider/AgsAudio[%d]/%s/AgsPort[%s]:value",
3213 				       nth_audio,
3214 				       G_OBJECT_TYPE_NAME(parent),
3215 				       specifier);
3216       }
3217 
3218       g_free(specifier);
3219 
3220       /* message path */
3221       packet_size = 4;
3222 
3223       ags_osc_buffer_util_put_string(packet + packet_size,
3224 				     "/node", -1);
3225 
3226       packet_size += 8;
3227 
3228       /* check array type */
3229       g_object_get(port,
3230 		   "port-value-is-pointer", &port_value_is_pointer,
3231 		   "port-value-type", &port_value_type,
3232 		   "port-value-length", &port_value_length,
3233 		   NULL);
3234 
3235       if(port_value_is_pointer){
3236 	gchar *type_tag;
3237 
3238 	guint i;
3239 
3240 	/* message type tag */
3241 	if(packet_size + (4 * (guint) ceil((double) (port_value_length + 5) / 4.0)) > real_packet_size){
3242 	  ags_osc_response_set_flags(osc_response,
3243 				     AGS_OSC_RESPONSE_ERROR);
3244 
3245 	  g_object_set(osc_response,
3246 		       "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3247 		       NULL);
3248 
3249 	  return(start_response);
3250 	}
3251 
3252 	type_tag = packet + packet_size; // (gchar *) malloc((port_value_length + 5) * sizeof(gchar));
3253 
3254 	type_tag[0] = ',';
3255 	type_tag[1] = 's';
3256 	type_tag[2] = '[';
3257 	type_tag[port_value_length + 4] = ']';
3258 
3259 	if(port_value_type == G_TYPE_BOOLEAN){
3260 	  g_rec_mutex_lock(port_mutex);
3261 
3262 	  for(i = 0; i < port_value_length; i++){
3263 	    gboolean is_active;
3264 
3265 	    is_active = port->port_value.ags_port_boolean_ptr[i];
3266 
3267 	    if(is_active){
3268 	      packet[packet_size + 3 + i] = 'T';
3269 	    }else{
3270 	      packet[packet_size + 3 + i] = 'F';
3271 	    }
3272 	  }
3273 
3274 	  g_rec_mutex_unlock(port_mutex);
3275 
3276 	  /* node path */
3277 	  packet_size += (4 * (guint) ceil((double) (port_value_length + 5) / 4.0));
3278 
3279 	  length = strlen(current_path);
3280 
3281 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3282 	    ags_osc_response_set_flags(osc_response,
3283 				       AGS_OSC_RESPONSE_ERROR);
3284 
3285 	    g_object_set(osc_response,
3286 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3287 			 NULL);
3288 
3289 	    return(start_response);
3290 	  }
3291 
3292 	  ags_osc_buffer_util_put_string(packet + packet_size,
3293 					 current_path, -1);
3294 
3295 	  /* node argument */
3296 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3297 
3298 	  /* packet size */
3299 	  ags_osc_buffer_util_put_int32(packet,
3300 					packet_size);
3301 	}else if(port_value_type == G_TYPE_INT64){
3302 	  for(i = 0; i < port_value_length; i++){
3303 	    packet[packet_size + 3 + i] = 'h';
3304 	  }
3305 
3306 	  /* node path */
3307 	  packet_size += (4 * (guint) ceil((double) (port_value_length + 5) / 4.0));
3308 
3309 	  length = strlen(current_path);
3310 
3311 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3312 	    ags_osc_response_set_flags(osc_response,
3313 				       AGS_OSC_RESPONSE_ERROR);
3314 
3315 	    g_object_set(osc_response,
3316 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3317 			 NULL);
3318 
3319 	    return(start_response);
3320 	  }
3321 
3322 	  ags_osc_buffer_util_put_string(packet + packet_size,
3323 					 current_path, -1);
3324 
3325 	  /* node argument */
3326 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3327 
3328 	  if(packet_size + (4 * (guint) ceil((double) (port_value_length * 8) / 4.0)) > real_packet_size){
3329 	    ags_osc_response_set_flags(osc_response,
3330 				       AGS_OSC_RESPONSE_ERROR);
3331 
3332 	    g_object_set(osc_response,
3333 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3334 			 NULL);
3335 
3336 	    return(start_response);
3337 	  }
3338 
3339 	  g_rec_mutex_lock(port_mutex);
3340 
3341 	  for(i = 0; i < port_value_length; i++){
3342 	    gint64 value;
3343 
3344 	    value = port->port_value.ags_port_int_ptr[i];
3345 
3346 	    ags_osc_buffer_util_put_int64(packet + packet_size + 3 + (i * 8),
3347 					  value);
3348 	  }
3349 
3350 	  g_rec_mutex_unlock(port_mutex);
3351 
3352 	  /* packet size */
3353 	  ags_osc_buffer_util_put_int32(packet,
3354 					packet_size);
3355 	}else if(port_value_type == G_TYPE_UINT64){
3356 	  for(i = 0; i < port_value_length; i++){
3357 	    packet[packet_size + 3 + i] = 'h';
3358 	  }
3359 
3360 	  /* node path */
3361 	  packet_size += (4 * (guint) ceil((double) (port_value_length + 5) / 4.0));
3362 
3363 	  length = strlen(current_path);
3364 
3365 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3366 	    ags_osc_response_set_flags(osc_response,
3367 				       AGS_OSC_RESPONSE_ERROR);
3368 
3369 	    g_object_set(osc_response,
3370 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3371 			 NULL);
3372 
3373 	    return(start_response);
3374 	  }
3375 
3376 	  ags_osc_buffer_util_put_string(packet + packet_size,
3377 					 current_path, -1);
3378 
3379 	  /* node argument */
3380 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3381 
3382 	  if(packet_size + (4 * (guint) ceil((double) (port_value_length * 8) / 4.0)) > real_packet_size){
3383 	    ags_osc_response_set_flags(osc_response,
3384 				       AGS_OSC_RESPONSE_ERROR);
3385 
3386 	    g_object_set(osc_response,
3387 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3388 			 NULL);
3389 
3390 	    return(start_response);
3391 	  }
3392 
3393 	  g_rec_mutex_lock(port_mutex);
3394 
3395 	  for(i = 0; i < port_value_length; i++){
3396 	    guint64 value;
3397 
3398 	    value = port->port_value.ags_port_uint_ptr[i];
3399 
3400 	    //FIXME:JK: unsafe sign
3401 	    ags_osc_buffer_util_put_int64(packet + packet_size + 3 + (i * 8),
3402 					  value);
3403 	  }
3404 
3405 	  g_rec_mutex_unlock(port_mutex);
3406 
3407 	  /* packet size */
3408 	  ags_osc_buffer_util_put_int32(packet,
3409 					packet_size);
3410 	}else if(port_value_type == G_TYPE_FLOAT){
3411 	  for(i = 0; i < port_value_length; i++){
3412 	    packet[packet_size + 3 + i] = 'f';
3413 	  }
3414 
3415 	  /* node path */
3416 	  packet_size += (4 * (guint) ceil((double) (port_value_length + 5) / 4.0));
3417 
3418 	  length = strlen(current_path);
3419 
3420 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3421 	    ags_osc_response_set_flags(osc_response,
3422 				       AGS_OSC_RESPONSE_ERROR);
3423 
3424 	    g_object_set(osc_response,
3425 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3426 			 NULL);
3427 
3428 	    return(start_response);
3429 	  }
3430 
3431 	  ags_osc_buffer_util_put_string(packet + packet_size,
3432 					 current_path, -1);
3433 
3434 	  /* node argument */
3435 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3436 
3437 	  if(packet_size + (4 * (guint) ceil((double) (port_value_length * 4) / 4.0)) > real_packet_size){
3438 	    ags_osc_response_set_flags(osc_response,
3439 				       AGS_OSC_RESPONSE_ERROR);
3440 
3441 	    g_object_set(osc_response,
3442 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3443 			 NULL);
3444 
3445 	    return(start_response);
3446 	  }
3447 
3448 	  g_rec_mutex_lock(port_mutex);
3449 
3450 	  for(i = 0; i < port_value_length; i++){
3451 	    gfloat value;
3452 
3453 	    value = port->port_value.ags_port_float_ptr[i];
3454 
3455 	    ags_osc_buffer_util_put_float(packet + packet_size + 3 + (i * 4),
3456 					  value);
3457 	  }
3458 
3459 	  g_rec_mutex_unlock(port_mutex);
3460 
3461 	  /* packet size */
3462 	  ags_osc_buffer_util_put_int32(packet,
3463 					packet_size);
3464 	}else if(port_value_type == G_TYPE_DOUBLE){
3465 	  for(i = 0; i < port_value_length; i++){
3466 	    packet[packet_size + 3 + i] = 'd';
3467 	  }
3468 
3469 	  /* node path */
3470 	  packet_size += (4 * (guint) ceil((double) (port_value_length + 5) / 4.0));
3471 
3472 	  length = strlen(current_path);
3473 
3474 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3475 	    ags_osc_response_set_flags(osc_response,
3476 				       AGS_OSC_RESPONSE_ERROR);
3477 
3478 	    g_object_set(osc_response,
3479 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3480 			 NULL);
3481 
3482 	    return(start_response);
3483 	  }
3484 
3485 	  ags_osc_buffer_util_put_string(packet + packet_size,
3486 					 current_path, -1);
3487 
3488 	  /* node argument */
3489 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3490 
3491 	  if(packet_size + (4 * (guint) ceil((double) (port_value_length * 8) / 4.0)) > real_packet_size){
3492 	    ags_osc_response_set_flags(osc_response,
3493 				       AGS_OSC_RESPONSE_ERROR);
3494 
3495 	    g_object_set(osc_response,
3496 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3497 			 NULL);
3498 
3499 	    return(start_response);
3500 	  }
3501 
3502 	  g_rec_mutex_lock(port_mutex);
3503 
3504 	  for(i = 0; i < port_value_length; i++){
3505 	    gdouble value;
3506 
3507 	    value = port->port_value.ags_port_double_ptr[i];
3508 
3509 	    ags_osc_buffer_util_put_double(packet + packet_size + 3 + (i * 8),
3510 					   value);
3511 	  }
3512 
3513 	  g_rec_mutex_unlock(port_mutex);
3514 
3515 	  /* packet size */
3516 	  ags_osc_buffer_util_put_int32(packet,
3517 					packet_size);
3518 	}
3519       }else{
3520 	if(port_value_type == G_TYPE_BOOLEAN){
3521 	  gboolean is_active;
3522 
3523 	  /* message type tag */
3524 	  g_rec_mutex_lock(port_mutex);
3525 
3526 	  is_active = port->port_value.ags_port_boolean;
3527 
3528 	  g_rec_mutex_unlock(port_mutex);
3529 
3530 	  if(is_active){
3531 	    ags_osc_buffer_util_put_string(packet + packet_size,
3532 					   ",sT", -1);
3533 	  }else{
3534 	    ags_osc_buffer_util_put_string(packet + packet_size,
3535 					   ",sF", -1);
3536 	  }
3537 
3538 	  /* node path */
3539 	  packet_size += 4;
3540 
3541 	  length = strlen(current_path);
3542 
3543 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) > real_packet_size){
3544 	    ags_osc_response_set_flags(osc_response,
3545 				       AGS_OSC_RESPONSE_ERROR);
3546 
3547 	    g_object_set(osc_response,
3548 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3549 			 NULL);
3550 
3551 	    return(start_response);
3552 	  }
3553 
3554 	  ags_osc_buffer_util_put_string(packet + packet_size,
3555 					 current_path, -1);
3556 
3557 	  /* node argument */
3558 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3559 
3560 	  /* packet size */
3561 	  ags_osc_buffer_util_put_int32(packet,
3562 					packet_size);
3563 	}else if(port_value_type == G_TYPE_INT64){
3564 	  gint64 value;
3565 
3566 	  /* message type tag */
3567 	  g_rec_mutex_lock(port_mutex);
3568 
3569 	  value = port->port_value.ags_port_int;
3570 
3571 	  g_rec_mutex_unlock(port_mutex);
3572 
3573 	  ags_osc_buffer_util_put_string(packet + packet_size,
3574 					 ",sh", -1);
3575 
3576 	  /* node path */
3577 	  packet_size += 4;
3578 
3579 	  length = strlen(current_path);
3580 
3581 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 8 > real_packet_size){
3582 	    ags_osc_response_set_flags(osc_response,
3583 				       AGS_OSC_RESPONSE_ERROR);
3584 
3585 	    g_object_set(osc_response,
3586 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3587 			 NULL);
3588 
3589 	    return(start_response);
3590 	  }
3591 
3592 	  ags_osc_buffer_util_put_string(packet + packet_size,
3593 					 current_path, -1);
3594 
3595 	  /* node argument */
3596 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3597 
3598 	  ags_osc_buffer_util_put_int64(packet + packet_size,
3599 					value);
3600 
3601 	  packet_size += 8;
3602 
3603 	  /* packet size */
3604 	  ags_osc_buffer_util_put_int32(packet,
3605 					packet_size);
3606 	}else if(port_value_type == G_TYPE_UINT64){
3607 	  guint64 value;
3608 
3609 	  /* message type tag */
3610 	  g_rec_mutex_lock(port_mutex);
3611 
3612 	  value = port->port_value.ags_port_uint;
3613 
3614 	  g_rec_mutex_unlock(port_mutex);
3615 
3616 	  ags_osc_buffer_util_put_string(packet + packet_size,
3617 					 ",sh", -1);
3618 
3619 	  /* node path */
3620 	  packet_size += 4;
3621 
3622 	  length = strlen(current_path);
3623 
3624 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 8 > real_packet_size){
3625 	    ags_osc_response_set_flags(osc_response,
3626 				       AGS_OSC_RESPONSE_ERROR);
3627 
3628 	    g_object_set(osc_response,
3629 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3630 			 NULL);
3631 
3632 	    return(start_response);
3633 	  }
3634 
3635 	  ags_osc_buffer_util_put_string(packet + packet_size,
3636 					 current_path, -1);
3637 
3638 	  /* node argument */
3639 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3640 
3641 	  //FIXME:JK: unsafe sign
3642 	  ags_osc_buffer_util_put_int64(packet + packet_size,
3643 					value);
3644 
3645 	  packet_size += 8;
3646 
3647 	  /* packet size */
3648 	  ags_osc_buffer_util_put_int32(packet,
3649 					packet_size);
3650 	}else if(port_value_type == G_TYPE_FLOAT){
3651 	  gfloat value;
3652 
3653 	  /* message type tag */
3654 	  g_rec_mutex_lock(port_mutex);
3655 
3656 	  value = port->port_value.ags_port_float;
3657 
3658 	  g_rec_mutex_unlock(port_mutex);
3659 
3660 	  ags_osc_buffer_util_put_string(packet + packet_size,
3661 					 ",sf", -1);
3662 
3663 	  /* node path */
3664 	  packet_size += 4;
3665 
3666 	  length = strlen(current_path);
3667 
3668 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 8 > real_packet_size){
3669 	    ags_osc_response_set_flags(osc_response,
3670 				       AGS_OSC_RESPONSE_ERROR);
3671 
3672 	    g_object_set(osc_response,
3673 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3674 			 NULL);
3675 
3676 	    return(start_response);
3677 	  }
3678 
3679 	  ags_osc_buffer_util_put_string(packet + packet_size,
3680 					 current_path, -1);
3681 
3682 	  /* node argument */
3683 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3684 
3685 	  ags_osc_buffer_util_put_float(packet + packet_size,
3686 					value);
3687 
3688 	  packet_size += 4;
3689 
3690 	  /* packet size */
3691 	  ags_osc_buffer_util_put_int32(packet,
3692 					packet_size);
3693 	}else if(port_value_type == G_TYPE_DOUBLE){
3694 	  gdouble value;
3695 
3696 	  /* message type tag */
3697 	  g_rec_mutex_lock(port_mutex);
3698 
3699 	  value = port->port_value.ags_port_double;
3700 
3701 	  g_rec_mutex_unlock(port_mutex);
3702 
3703 	  ags_osc_buffer_util_put_string(packet + packet_size,
3704 					 ",sd", -1);
3705 
3706 	  /* node path */
3707 	  packet_size += 4;
3708 
3709 	  length = strlen(current_path);
3710 
3711 	  if(packet_size + (4 * (guint) ceil((double) (length + 1) / 4.0)) + 8 > real_packet_size){
3712 	    ags_osc_response_set_flags(osc_response,
3713 				       AGS_OSC_RESPONSE_ERROR);
3714 
3715 	    g_object_set(osc_response,
3716 			 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
3717 			 NULL);
3718 
3719 	    return(start_response);
3720 	  }
3721 
3722 	  ags_osc_buffer_util_put_string(packet + packet_size,
3723 					 current_path, -1);
3724 
3725 	  /* node argument */
3726 	  packet_size += (4 * (guint) ceil((double) (length + 1) / 4.0));
3727 
3728 	  ags_osc_buffer_util_put_double(packet + packet_size,
3729 					 value);
3730 
3731 	  packet_size += 8;
3732 
3733 	  /* packet size */
3734 	  ags_osc_buffer_util_put_int32(packet,
3735 					packet_size);
3736 	}
3737       }
3738 
3739       g_object_set(osc_response,
3740 		   "packet-size", packet_size,
3741 		   NULL);
3742     }
3743   }
3744 
3745   return(start_response);
3746 }
3747 
3748 gpointer
ags_osc_node_controller_real_get_data(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,unsigned char * message,guint message_size)3749 ags_osc_node_controller_real_get_data(AgsOscNodeController *osc_node_controller,
3750 				      AgsOscConnection *osc_connection,
3751 				      unsigned char *message, guint message_size)
3752 {
3753   AgsOscResponse *osc_response;
3754 
3755   AgsApplicationContext *application_context;
3756 
3757   GList *start_response;
3758 
3759   gchar *type_tag;
3760   gchar *path;
3761 
3762   guint path_offset;
3763   gboolean success;
3764 
3765   start_response = NULL;
3766 
3767   /* read type tag */
3768   ags_osc_buffer_util_get_string(message + 8,
3769 				 &type_tag, NULL);
3770 
3771   success = (type_tag != NULL &&
3772 	     !strncmp(type_tag, ",s", 2)) ? TRUE: FALSE;
3773 
3774   if(!success){
3775     osc_response = ags_osc_response_new();
3776     start_response = g_list_prepend(start_response,
3777 				    osc_response);
3778 
3779     ags_osc_response_set_flags(osc_response,
3780 			       AGS_OSC_RESPONSE_ERROR);
3781 
3782     g_object_set(osc_response,
3783 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_MALFORMED_REQUEST,
3784 		 NULL);
3785 
3786     if(type_tag != NULL){
3787       free(type_tag);
3788     }
3789 
3790     return(start_response);
3791   }
3792 
3793   /* read argument */
3794   ags_osc_buffer_util_get_string(message + 8 + (4 * (guint) ceil((gdouble) (strlen(type_tag) + 1) / 4.0)),
3795 				 &path, NULL);
3796 
3797   if(path == NULL){
3798     osc_response = ags_osc_response_new();
3799     start_response = g_list_prepend(start_response,
3800 				    osc_response);
3801 
3802     ags_osc_response_set_flags(osc_response,
3803 			       AGS_OSC_RESPONSE_ERROR);
3804 
3805     g_object_set(osc_response,
3806 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_MALFORMED_REQUEST,
3807 		 NULL);
3808 
3809     free(type_tag);
3810 
3811     return(start_response);
3812   }
3813 
3814   /* create packet */
3815   application_context = ags_application_context_get_instance();
3816 
3817   path_offset = 0;
3818 
3819   if(!strncmp(path,
3820 	      "/AgsSoundProvider",
3821 	      17)){
3822     path_offset = 17;
3823 
3824     if(!strncmp(path + path_offset,
3825 		"/AgsSoundcard",
3826 		13)){
3827       GList *start_soundcard, *soundcard;
3828 
3829       regmatch_t match_arr[2];
3830 
3831       static regex_t single_access_regex;
3832       static regex_t range_access_regex;
3833       static regex_t voluntary_access_regex;
3834       static regex_t more_access_regex;
3835       static regex_t wildcard_access_regex;
3836 
3837       static gboolean regex_compiled = FALSE;
3838 
3839       static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
3840       static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
3841       static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
3842       static const gchar *more_access_pattern = "^\\[(\\+)\\]";
3843       static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
3844 
3845       static const size_t max_matches = 2;
3846       static const size_t index_max_matches = 1;
3847 
3848       path_offset += 13;
3849 
3850       /* compile regex */
3851       g_mutex_lock(&regex_mutex);
3852 
3853       if(!regex_compiled){
3854 	regex_compiled = TRUE;
3855 
3856 	ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
3857 	ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
3858 	ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
3859 	ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
3860 	ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
3861       }
3862 
3863       g_mutex_unlock(&regex_mutex);
3864 
3865       soundcard =
3866 	start_soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
3867 
3868       if(ags_regexec(&single_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
3869 	GObject *current;
3870 
3871 	gchar *endptr;
3872 
3873 	guint i_stop;
3874 
3875 	endptr = NULL;
3876 	i_stop = g_ascii_strtoull(path + path_offset + 1,
3877 				  &endptr,
3878 				  10);
3879 
3880 	current = g_list_nth_data(start_soundcard,
3881 				  i_stop);
3882 
3883 	path_offset += ((endptr + 1) - (path + path_offset));
3884 
3885 	start_response = ags_osc_node_controller_get_data_soundcard(osc_node_controller,
3886 								    osc_connection,
3887 								    current,
3888 								    message, message_size,
3889 								    type_tag,
3890 								    path, path_offset);
3891       }else if(ags_regexec(&range_access_regex, path + path_offset, max_matches, match_arr, 0) == 0){
3892 	gchar *endptr;
3893 
3894 	guint i;
3895 	guint i_start, i_stop;
3896 
3897 	endptr = NULL;
3898 	i_start = g_ascii_strtoull(path + path_offset + 1,
3899 				   &endptr,
3900 				   10);
3901 
3902 	i_stop = g_ascii_strtoull(endptr + 1,
3903 				  &endptr,
3904 				  10);
3905 
3906 	path_offset += ((endptr + 1) - (path + path_offset));
3907 
3908 	soundcard = g_list_nth(start_soundcard,
3909 			       i_start);
3910 
3911 	for(i = i_start; i <= i_stop; i++){
3912 	  GList *retval;
3913 
3914 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
3915 							    osc_connection,
3916 							    soundcard->data,
3917 							    message, message_size,
3918 							    type_tag,
3919 							    path, path_offset);
3920 
3921 	  if(start_response != NULL){
3922 	    start_response = g_list_concat(start_response,
3923 					   retval);
3924 	  }else{
3925 	    start_response = retval;
3926 	  }
3927 
3928 	  soundcard = soundcard->next;
3929 	}
3930       }else if(ags_regexec(&voluntary_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
3931 	path_offset += 3;
3932 
3933 	if(start_soundcard != NULL){
3934 	  GList *retval;
3935 
3936 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
3937 							    osc_connection,
3938 							    start_soundcard->data,
3939 							    message, message_size,
3940 							    type_tag,
3941 							    path, path_offset);
3942 	}else{
3943 	  osc_response = ags_osc_response_new();
3944 	  start_response = g_list_prepend(start_response,
3945 					  osc_response);
3946 
3947 	  ags_osc_response_set_flags(osc_response,
3948 				     AGS_OSC_RESPONSE_OK);
3949 
3950 	  free(type_tag);
3951 	  free(path);
3952 
3953 	  return(start_response);
3954 	}
3955       }else if(ags_regexec(&more_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
3956 	path_offset += 3;
3957 
3958 	if(start_soundcard == NULL){
3959 	  osc_response = ags_osc_response_new();
3960 	  start_response = g_list_prepend(start_response,
3961 					  osc_response);
3962 
3963 	  ags_osc_response_set_flags(osc_response,
3964 				     AGS_OSC_RESPONSE_ERROR);
3965 
3966 	  g_object_set(osc_response,
3967 		       "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
3968 		       NULL);
3969 
3970 	  g_list_free_full(start_soundcard,
3971 			   g_object_unref);
3972 
3973 	  free(type_tag);
3974 	  free(path);
3975 
3976 	  return(start_response);
3977 	}
3978 
3979 	soundcard = start_soundcard;
3980 
3981 	while(soundcard != NULL){
3982 	  GList *retval;
3983 
3984 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
3985 							    osc_connection,
3986 							    soundcard->data,
3987 							    message, message_size,
3988 							    type_tag,
3989 							    path, path_offset);
3990 
3991 	  if(start_response != NULL){
3992 	    start_response = g_list_concat(start_response,
3993 					   retval);
3994 	  }else{
3995 	    start_response = retval;
3996 	  }
3997 
3998 	  soundcard = soundcard->next;
3999 	}
4000       }else if(ags_regexec(&wildcard_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4001 	path_offset += 3;
4002 
4003 	if(start_soundcard == NULL){
4004 	  osc_response = ags_osc_response_new();
4005 	  start_response = g_list_prepend(start_response,
4006 					  osc_response);
4007 
4008 	  ags_osc_response_set_flags(osc_response,
4009 				     AGS_OSC_RESPONSE_OK);
4010 
4011 	  free(type_tag);
4012 	  free(path);
4013 
4014 	  return(start_response);
4015 	}
4016 
4017 	while(soundcard != NULL){
4018 	  GList *retval;
4019 
4020 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
4021 							    osc_connection,
4022 							    soundcard->data,
4023 							    message, message_size,
4024 							    type_tag,
4025 							    path, path_offset);
4026 
4027 	  if(start_response != NULL){
4028 	    start_response = g_list_concat(start_response,
4029 					   retval);
4030 	  }else{
4031 	    start_response = retval;
4032 	  }
4033 
4034 	  soundcard = soundcard->next;
4035 	}
4036       }else{
4037 	osc_response = ags_osc_response_new();
4038 	start_response = g_list_prepend(start_response,
4039 					osc_response);
4040 
4041 	ags_osc_response_set_flags(osc_response,
4042 				   AGS_OSC_RESPONSE_ERROR);
4043 
4044 	g_object_set(osc_response,
4045 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4046 		     NULL);
4047 
4048 	g_list_free_full(start_soundcard,
4049 			 g_object_unref);
4050 
4051 	free(type_tag);
4052 	free(path);
4053 
4054 	return(start_response);
4055       }
4056 
4057       g_list_free_full(start_soundcard,
4058 		       g_object_unref);
4059     }else if(!strncmp(path + path_offset,
4060 		      "/AgsSequencer",
4061 		      13)){
4062       GList *start_sequencer, *sequencer;
4063 
4064       regmatch_t match_arr[2];
4065 
4066       static regex_t single_access_regex;
4067       static regex_t range_access_regex;
4068       static regex_t voluntary_access_regex;
4069       static regex_t more_access_regex;
4070       static regex_t wildcard_access_regex;
4071 
4072       static gboolean regex_compiled = FALSE;
4073 
4074       static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
4075       static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
4076       static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
4077       static const gchar *more_access_pattern = "^\\[(\\+)\\]";
4078       static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
4079 
4080       static const size_t max_matches = 2;
4081       static const size_t index_max_matches = 1;
4082 
4083       path_offset += 13;
4084 
4085       /* compile regex */
4086       g_mutex_lock(&regex_mutex);
4087 
4088       if(!regex_compiled){
4089 	regex_compiled = TRUE;
4090 
4091 	ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
4092 	ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
4093 	ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
4094 	ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
4095 	ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
4096       }
4097 
4098       g_mutex_unlock(&regex_mutex);
4099 
4100       sequencer =
4101 	start_sequencer = ags_sound_provider_get_sequencer(AGS_SOUND_PROVIDER(application_context));
4102 
4103       if(ags_regexec(&single_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4104 	GObject *current;
4105 
4106 	gchar *endptr;
4107 
4108 	guint i_stop;
4109 
4110 	endptr = NULL;
4111 	i_stop = g_ascii_strtoull(path + path_offset + 1,
4112 				  &endptr,
4113 				  10);
4114 
4115 	current = g_list_nth_data(start_sequencer,
4116 				  i_stop);
4117 
4118 	path_offset += ((endptr + 1) - (path + path_offset));
4119 
4120 	start_response = ags_osc_node_controller_get_data_sequencer(osc_node_controller,
4121 								    osc_connection,
4122 								    current,
4123 								    message, message_size,
4124 								    type_tag,
4125 								    path, path_offset);
4126       }else if(ags_regexec(&range_access_regex, path + path_offset, max_matches, match_arr, 0) == 0){
4127 	gchar *endptr;
4128 
4129 	guint i;
4130 	guint i_start, i_stop;
4131 
4132 	endptr = NULL;
4133 	i_start = g_ascii_strtoull(path + path_offset + 1,
4134 				   &endptr,
4135 				   10);
4136 
4137 	i_stop = g_ascii_strtoull(endptr + 1,
4138 				  &endptr,
4139 				  10);
4140 
4141 	path_offset += ((endptr + 1) - (path + path_offset));
4142 
4143 	sequencer = g_list_nth(start_sequencer,
4144 			       i_start);
4145 
4146 	for(i = i_start; i <= i_stop; i++){
4147 	  GList *retval;
4148 
4149 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
4150 							    osc_connection,
4151 							    sequencer->data,
4152 							    message, message_size,
4153 							    type_tag,
4154 							    path, path_offset);
4155 
4156 	  if(start_response != NULL){
4157 	    start_response = g_list_concat(start_response,
4158 					   retval);
4159 	  }else{
4160 	    start_response = retval;
4161 	  }
4162 
4163 	  sequencer = sequencer->next;
4164 	}
4165       }else if(ags_regexec(&voluntary_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4166 	path_offset += 3;
4167 
4168 	if(start_sequencer != NULL){
4169 	  GList *retval;
4170 
4171 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
4172 							    osc_connection,
4173 							    start_sequencer->data,
4174 							    message, message_size,
4175 							    type_tag,
4176 							    path, path_offset);
4177 	}else{
4178 	  osc_response = ags_osc_response_new();
4179 	  start_response = g_list_prepend(start_response,
4180 					  osc_response);
4181 
4182 	  ags_osc_response_set_flags(osc_response,
4183 				     AGS_OSC_RESPONSE_OK);
4184 
4185 	  free(type_tag);
4186 	  free(path);
4187 
4188 	  return(start_response);
4189 	}
4190       }else if(ags_regexec(&more_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4191 	path_offset += 3;
4192 
4193 	if(start_sequencer == NULL){
4194 	  osc_response = ags_osc_response_new();
4195 	  start_response = g_list_prepend(start_response,
4196 					  osc_response);
4197 
4198 	  ags_osc_response_set_flags(osc_response,
4199 				     AGS_OSC_RESPONSE_ERROR);
4200 
4201 	  g_object_set(osc_response,
4202 		       "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4203 		       NULL);
4204 
4205 	  free(type_tag);
4206 	  free(path);
4207 
4208 	  return(start_response);
4209 	}
4210 
4211 	sequencer = start_sequencer;
4212 
4213 	while(sequencer != NULL){
4214 	  GList *retval;
4215 
4216 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
4217 							    osc_connection,
4218 							    sequencer->data,
4219 							    message, message_size,
4220 							    type_tag,
4221 							    path, path_offset);
4222 
4223 	  if(start_response != NULL){
4224 	    start_response = g_list_concat(start_response,
4225 					   retval);
4226 	  }else{
4227 	    start_response = retval;
4228 	  }
4229 
4230 	  sequencer = sequencer->next;
4231 	}
4232       }else if(ags_regexec(&wildcard_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4233 	path_offset += 3;
4234 
4235 	if(start_sequencer == NULL){
4236 	  osc_response = ags_osc_response_new();
4237 	  start_response = g_list_prepend(start_response,
4238 					  osc_response);
4239 
4240 	  ags_osc_response_set_flags(osc_response,
4241 				     AGS_OSC_RESPONSE_OK);
4242 
4243 	  free(type_tag);
4244 	  free(path);
4245 
4246 	  return(start_response);
4247 	}
4248 
4249 	while(sequencer != NULL){
4250 	  GList *retval;
4251 
4252 	  retval = ags_osc_node_controller_get_data_channel(osc_node_controller,
4253 							    osc_connection,
4254 							    sequencer->data,
4255 							    message, message_size,
4256 							    type_tag,
4257 							    path, path_offset);
4258 
4259 	  if(start_response != NULL){
4260 	    start_response = g_list_concat(start_response,
4261 					   retval);
4262 	  }else{
4263 	    start_response = retval;
4264 	  }
4265 
4266 	  sequencer = sequencer->next;
4267 	}
4268       }else{
4269 	osc_response = ags_osc_response_new();
4270 	start_response = g_list_prepend(start_response,
4271 					osc_response);
4272 
4273 	ags_osc_response_set_flags(osc_response,
4274 				   AGS_OSC_RESPONSE_ERROR);
4275 
4276 	g_object_set(osc_response,
4277 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4278 		     NULL);
4279 
4280 	g_list_free_full(start_sequencer,
4281 			 g_object_unref);
4282 
4283 	free(type_tag);
4284 	free(path);
4285 
4286 	return(start_response);
4287       }
4288 
4289       g_list_free_full(start_sequencer,
4290 		       g_object_unref);
4291     }else if(!strncmp(path + path_offset,
4292 		      "/AgsAudio",
4293 		      9)){
4294       GList *start_audio, *audio;
4295 
4296       regmatch_t match_arr[2];
4297 
4298       static regex_t single_access_regex;
4299       static regex_t range_access_regex;
4300       static regex_t voluntary_access_regex;
4301       static regex_t more_access_regex;
4302       static regex_t wildcard_access_regex;
4303 
4304       static gboolean regex_compiled = FALSE;
4305 
4306       static const gchar *single_access_pattern = "^\\[([0-9]+)\\]";
4307       static const gchar *range_access_pattern = "^\\[([0-9]+)\\-([0-9]+)\\]";
4308       static const gchar *voluntary_access_pattern = "^\\[(\\?)\\]";
4309       static const gchar *more_access_pattern = "^\\[(\\+)\\]";
4310       static const gchar *wildcard_access_pattern = "^\\[(\\*)\\]";
4311 
4312       static const size_t max_matches = 2;
4313       static const size_t index_max_matches = 1;
4314 
4315       path_offset += 9;
4316 
4317       /* compile regex */
4318       g_mutex_lock(&regex_mutex);
4319 
4320       if(!regex_compiled){
4321 	regex_compiled = TRUE;
4322 
4323 	ags_regcomp(&single_access_regex, single_access_pattern, REG_EXTENDED);
4324 	ags_regcomp(&range_access_regex, range_access_pattern, REG_EXTENDED);
4325 	ags_regcomp(&voluntary_access_regex, voluntary_access_pattern, REG_EXTENDED);
4326 	ags_regcomp(&more_access_regex, more_access_pattern, REG_EXTENDED);
4327 	ags_regcomp(&wildcard_access_regex, wildcard_access_pattern, REG_EXTENDED);
4328       }
4329 
4330       g_mutex_unlock(&regex_mutex);
4331 
4332       audio =
4333 	start_audio = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
4334 
4335       if(ags_regexec(&single_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4336 	AgsAudio *current;
4337 
4338 	gchar *endptr;
4339 
4340 	guint i_stop;
4341 
4342 	endptr = NULL;
4343 	i_stop = g_ascii_strtoull(path + path_offset + 1,
4344 				  &endptr,
4345 				  10);
4346 
4347 	current = g_list_nth_data(start_audio,
4348 				  i_stop);
4349 
4350 	path_offset += ((endptr + 1) - (path + path_offset));
4351 
4352 	start_response = ags_osc_node_controller_get_data_audio(osc_node_controller,
4353 								osc_connection,
4354 								current,
4355 								message, message_size,
4356 								type_tag,
4357 								path, path_offset);
4358       }else if(ags_regexec(&range_access_regex, path + path_offset, max_matches, match_arr, 0) == 0){
4359 	gchar *endptr;
4360 
4361 	guint i;
4362 	guint i_start, i_stop;
4363 
4364 	endptr = NULL;
4365 	i_start = g_ascii_strtoull(path + path_offset + 1,
4366 				   &endptr,
4367 				   10);
4368 
4369 	i_stop = g_ascii_strtoull(endptr + 1,
4370 				  &endptr,
4371 				  10);
4372 
4373 	path_offset += ((endptr + 1) - (path + path_offset));
4374 
4375 	audio = g_list_nth(start_audio,
4376 			   i_start);
4377 
4378 	for(i = i_start; i <= i_stop; i++){
4379 	  GList *retval;
4380 
4381 	  retval = ags_osc_node_controller_get_data_audio(osc_node_controller,
4382 							  osc_connection,
4383 							  audio->data,
4384 							  message, message_size,
4385 							  type_tag,
4386 							  path, path_offset);
4387 
4388 	  if(start_response != NULL){
4389 	    start_response = g_list_concat(start_response,
4390 					   retval);
4391 	  }else{
4392 	    start_response = retval;
4393 	  }
4394 
4395 	  audio = audio->next;
4396 	}
4397       }else if(ags_regexec(&voluntary_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4398 	path_offset += 3;
4399 
4400 	if(start_audio != NULL){
4401 	  GList *retval;
4402 
4403 	  retval = ags_osc_node_controller_get_data_audio(osc_node_controller,
4404 							  osc_connection,
4405 							  start_audio->data,
4406 							  message, message_size,
4407 							  type_tag,
4408 							  path, path_offset);
4409 	}else{
4410 	  osc_response = ags_osc_response_new();
4411 	  start_response = g_list_prepend(start_response,
4412 					  osc_response);
4413 
4414 	  ags_osc_response_set_flags(osc_response,
4415 				     AGS_OSC_RESPONSE_OK);
4416 
4417 	  free(type_tag);
4418 	  free(path);
4419 
4420 	  return(start_response);
4421 	}
4422       }else if(ags_regexec(&more_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4423 	path_offset += 3;
4424 
4425 	if(start_audio == NULL){
4426 	  osc_response = ags_osc_response_new();
4427 	  start_response = g_list_prepend(start_response,
4428 					  osc_response);
4429 
4430 	  ags_osc_response_set_flags(osc_response,
4431 				     AGS_OSC_RESPONSE_ERROR);
4432 
4433 	  g_object_set(osc_response,
4434 		       "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4435 		       NULL);
4436 
4437 	  free(type_tag);
4438 	  free(path);
4439 
4440 	  return(start_response);
4441 	}
4442 
4443 	audio = start_audio;
4444 
4445 	while(audio != NULL){
4446 	  GList *retval;
4447 
4448 	  retval = ags_osc_node_controller_get_data_audio(osc_node_controller,
4449 							  osc_connection,
4450 							  audio->data,
4451 							  message, message_size,
4452 							  type_tag,
4453 							  path, path_offset);
4454 
4455 	  if(start_response != NULL){
4456 	    start_response = g_list_concat(start_response,
4457 					   retval);
4458 	  }else{
4459 	    start_response = retval;
4460 	  }
4461 
4462 	  audio = audio->next;
4463 	}
4464       }else if(ags_regexec(&wildcard_access_regex, path + path_offset, index_max_matches, match_arr, 0) == 0){
4465 	path_offset += 3;
4466 
4467 	if(start_audio == NULL){
4468 	  osc_response = ags_osc_response_new();
4469 	  start_response = g_list_prepend(start_response,
4470 					  osc_response);
4471 
4472 	  ags_osc_response_set_flags(osc_response,
4473 				     AGS_OSC_RESPONSE_OK);
4474 
4475 	  free(type_tag);
4476 	  free(path);
4477 
4478 	  return(start_response);
4479 	}
4480 
4481 	while(audio != NULL){
4482 	  GList *retval;
4483 
4484 	  retval = ags_osc_node_controller_get_data_audio(osc_node_controller,
4485 							  osc_connection,
4486 							  audio->data,
4487 							  message, message_size,
4488 							  type_tag,
4489 							  path, path_offset);
4490 
4491 	  if(start_response != NULL){
4492 	    start_response = g_list_concat(start_response,
4493 					   retval);
4494 	  }else{
4495 	    start_response = retval;
4496 	  }
4497 
4498 	  audio = audio->next;
4499 	}
4500       }else if(path[path_offset] == '[' &&
4501 	       path[path_offset + 1] == '"'){
4502 	AgsAudio *current;
4503 
4504 	gchar *audio_name;
4505 	gchar *offset;
4506 
4507 	guint length;
4508 
4509 	if((offset = strchr(path + path_offset + 2, '"')) == NULL){
4510 	  osc_response = ags_osc_response_new();
4511 	  start_response = g_list_prepend(start_response,
4512 					  osc_response);
4513 
4514 	  ags_osc_response_set_flags(osc_response,
4515 				     AGS_OSC_RESPONSE_ERROR);
4516 
4517 	  g_object_set(osc_response,
4518 		       "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_CHUNK_SIZE_EXCEEDED,
4519 		       NULL);
4520 
4521 	  g_list_free_full(start_audio,
4522 			   g_object_unref);
4523 
4524 	  free(type_tag);
4525 	  free(path);
4526 
4527 	  return(start_response);
4528 	}
4529 
4530 	length = offset - (path + path_offset + 2);
4531 
4532 	audio_name = (gchar *) malloc((length + 1) * sizeof(gchar));
4533 	memcpy(audio_name, path + path_offset + 2, (length) * sizeof(gchar));
4534 	audio_name[length] = '\0';
4535 
4536 	current = NULL;
4537 	audio = ags_audio_find_name(start_audio,
4538 				    audio_name);
4539 
4540 	if(audio != NULL){
4541 	  current = audio->data;
4542 	}
4543 
4544 	path_offset += (length + 4);
4545 	start_response = ags_osc_node_controller_get_data_audio(osc_node_controller,
4546 								osc_connection,
4547 								current,
4548 								message, message_size,
4549 								type_tag,
4550 								path, path_offset);
4551       }else{
4552 	osc_response = ags_osc_response_new();
4553 	start_response = g_list_prepend(start_response,
4554 					osc_response);
4555 
4556 	ags_osc_response_set_flags(osc_response,
4557 				   AGS_OSC_RESPONSE_ERROR);
4558 
4559 	g_object_set(osc_response,
4560 		     "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4561 		     NULL);
4562 
4563 	g_list_free_full(start_audio,
4564 			 g_object_unref);
4565 
4566 	free(type_tag);
4567 	free(path);
4568 
4569 	return(start_response);
4570       }
4571 
4572       g_list_free_full(start_audio,
4573 		       g_object_unref);
4574     }else{
4575       osc_response = ags_osc_response_new();
4576       start_response = g_list_prepend(start_response,
4577 				      osc_response);
4578 
4579       ags_osc_response_set_flags(osc_response,
4580 				 AGS_OSC_RESPONSE_ERROR);
4581 
4582       g_object_set(osc_response,
4583 		   "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_UNKNOWN_ARGUMENT,
4584 		   NULL);
4585 
4586       free(type_tag);
4587       free(path);
4588 
4589       return(start_response);
4590     }
4591   }
4592 
4593   if(start_response == NULL){
4594     osc_response = ags_osc_response_new();
4595     start_response = g_list_prepend(start_response,
4596 				    osc_response);
4597 
4598     ags_osc_response_set_flags(osc_response,
4599 			       AGS_OSC_RESPONSE_ERROR);
4600 
4601     g_object_set(osc_response,
4602 		 "error-message", AGS_OSC_RESPONSE_ERROR_MESSAGE_SERVER_FAILURE,
4603 		 NULL);
4604 
4605     free(type_tag);
4606     free(path);
4607 
4608     return(start_response);
4609   }
4610 
4611   free(type_tag);
4612   free(path);
4613 
4614   return(start_response);
4615 }
4616 
4617 /**
4618  * ags_osc_node_controller_get_data:
4619  * @osc_node_controller: the #AgsOscNodeController
4620  * @osc_connection: the #AgsOscConnection
4621  * @message: the message received
4622  * @message_size: the message size
4623  *
4624  * Get node.
4625  *
4626  * Returns: the #GList-struct containing #AgsOscResponse
4627  *
4628  * Since: 3.0.0
4629  */
4630 gpointer
ags_osc_node_controller_get_data(AgsOscNodeController * osc_node_controller,AgsOscConnection * osc_connection,unsigned char * message,guint message_size)4631 ags_osc_node_controller_get_data(AgsOscNodeController *osc_node_controller,
4632 				 AgsOscConnection *osc_connection,
4633 				 unsigned char *message, guint message_size)
4634 {
4635   gpointer osc_response;
4636 
4637   g_return_val_if_fail(AGS_IS_OSC_NODE_CONTROLLER(osc_node_controller), NULL);
4638 
4639   g_object_ref((GObject *) osc_node_controller);
4640   g_signal_emit(G_OBJECT(osc_node_controller),
4641 		osc_node_controller_signals[GET_DATA], 0,
4642 		osc_connection,
4643 		message, message_size,
4644 		&osc_response);
4645   g_object_unref((GObject *) osc_node_controller);
4646 
4647   return(osc_response);
4648 }
4649 
4650 /**
4651  * ags_osc_node_controller_new:
4652  *
4653  * Instantiate new #AgsOscNodeController
4654  *
4655  * Returns: the #AgsOscNodeController
4656  *
4657  * Since: 3.0.0
4658  */
4659 AgsOscNodeController*
ags_osc_node_controller_new()4660 ags_osc_node_controller_new()
4661 {
4662   AgsOscNodeController *osc_node_controller;
4663 
4664   osc_node_controller = (AgsOscNodeController *) g_object_new(AGS_TYPE_OSC_NODE_CONTROLLER,
4665 							      NULL);
4666 
4667   return(osc_node_controller);
4668 }
4669