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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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(®ex_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