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