1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2019 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/audio/recall/ags_play_channel_run_master.h>
21
22 #include <ags/audio/ags_audio.h>
23 #include <ags/audio/ags_recycling.h>
24 #include <ags/audio/ags_recall_id.h>
25 #include <ags/audio/ags_recall_container.h>
26
27 #include <ags/audio/recall/ags_play_channel.h>
28 #include <ags/audio/recall/ags_play_recycling.h>
29 #include <ags/audio/recall/ags_stream_channel_run.h>
30
31 #include <stdlib.h>
32 #include <stdio.h>
33
34 #include <ags/i18n.h>
35
36 void ags_play_channel_run_master_class_init(AgsPlayChannelRunMasterClass *play_channel_run_master);
37 void ags_play_channel_run_master_connectable_interface_init(AgsConnectableInterface *connectable);
38 void ags_play_channel_run_master_init(AgsPlayChannelRunMaster *play_channel_run_master);
39 void ags_play_channel_run_master_set_property(GObject *gobject,
40 guint prop_id,
41 const GValue *value,
42 GParamSpec *param_spec);
43 void ags_play_channel_run_master_get_property(GObject *gobject,
44 guint prop_id,
45 GValue *value,
46 GParamSpec *param_spec);
47 void ags_play_channel_run_master_dispose(GObject *gobject);
48 void ags_play_channel_run_master_finalize(GObject *gobject);
49
50 void ags_play_channel_run_master_connect(AgsConnectable *connectable);
51 void ags_play_channel_run_master_disconnect(AgsConnectable *connectable);
52 void ags_play_channel_run_master_connect_connection(AgsConnectable *connectable,
53 GObject *connection);
54 void ags_play_channel_run_master_disconnect_connection(AgsConnectable *connectable,
55 GObject *connection);
56
57 void ags_play_channel_run_master_run_init_pre(AgsRecall *recall);
58 void ags_play_channel_run_master_resolve_dependency(AgsRecall *recall);
59
60 void ags_play_channel_run_master_remap_child_source(AgsPlayChannelRunMaster *play_channel_run_master,
61 AgsRecycling *old_start_region, AgsRecycling *old_end_region,
62 AgsRecycling *new_start_region, AgsRecycling *new_end_region);
63 void ags_play_channel_run_master_remap_dependencies(AgsPlayChannelRunMaster *play_channel_run_master,
64 AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
65 AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region);
66
67 void ags_play_channel_run_master_source_recycling_changed_callback(AgsChannel *channel,
68 AgsRecycling *old_start_region, AgsRecycling *old_end_region,
69 AgsRecycling *new_start_region, AgsRecycling *new_end_region,
70 AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
71 AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
72 AgsPlayChannelRunMaster *play_channel_run_master);
73
74 void ags_play_channel_run_master_stream_channel_done_callback(AgsRecall *recall,
75 AgsPlayChannelRunMaster *play_channel_run_master);
76
77 /**
78 * SECTION:ags_play_channel_run_master
79 * @short_description: plays channel as toplevel
80 * @title: AgsPlayChannelRunMaster
81 * @section_id:
82 * @include: ags/audio/recall/ags_play_channel_master.h
83 *
84 * The #AgsPlayChannelRunMaster class plays the channel within toplevel context.
85 */
86
87 enum{
88 PROP_0,
89 PROP_STREAM_CHANNEL_RUN,
90 };
91
92 static gpointer ags_play_channel_run_master_parent_class = NULL;
93 static AgsConnectableInterface *ags_play_channel_run_master_parent_connectable_interface;
94
95 GType
ags_play_channel_run_master_get_type()96 ags_play_channel_run_master_get_type()
97 {
98 static volatile gsize g_define_type_id__volatile = 0;
99
100 if(g_once_init_enter (&g_define_type_id__volatile)){
101 GType ags_type_play_channel_run_master = 0;
102
103 static const GTypeInfo ags_play_channel_run_master_info = {
104 sizeof (AgsPlayChannelRunMasterClass),
105 NULL, /* base_init */
106 NULL, /* base_finalize */
107 (GClassInitFunc) ags_play_channel_run_master_class_init,
108 NULL, /* class_finalize */
109 NULL, /* class_data */
110 sizeof (AgsPlayChannelRunMaster),
111 0, /* n_preallocs */
112 (GInstanceInitFunc) ags_play_channel_run_master_init,
113 };
114
115 static const GInterfaceInfo ags_connectable_interface_info = {
116 (GInterfaceInitFunc) ags_play_channel_run_master_connectable_interface_init,
117 NULL, /* interface_finalize */
118 NULL, /* interface_data */
119 };
120
121 ags_type_play_channel_run_master = g_type_register_static(AGS_TYPE_RECALL_CHANNEL_RUN,
122 "AgsPlayChannelRunMaster",
123 &ags_play_channel_run_master_info,
124 0);
125
126 g_type_add_interface_static(ags_type_play_channel_run_master,
127 AGS_TYPE_CONNECTABLE,
128 &ags_connectable_interface_info);
129
130 g_once_init_leave(&g_define_type_id__volatile, ags_type_play_channel_run_master);
131 }
132
133 return g_define_type_id__volatile;
134 }
135
136 void
ags_play_channel_run_master_class_init(AgsPlayChannelRunMasterClass * play_channel_run_master)137 ags_play_channel_run_master_class_init(AgsPlayChannelRunMasterClass *play_channel_run_master)
138 {
139 GObjectClass *gobject;
140 AgsRecallClass *recall;
141 GParamSpec *param_spec;
142
143 ags_play_channel_run_master_parent_class = g_type_class_peek_parent(play_channel_run_master);
144
145 /* GObjectClass */
146 gobject = (GObjectClass *) play_channel_run_master;
147
148 gobject->set_property = ags_play_channel_run_master_set_property;
149 gobject->get_property = ags_play_channel_run_master_get_property;
150
151 gobject->dispose = ags_play_channel_run_master_dispose;
152 gobject->finalize = ags_play_channel_run_master_finalize;
153
154 /* properties */
155 /**
156 * AgsPlayChannelRunMaster:stream-channel-run: (type GList(AgsStreamChannelRun)) (transfer full)
157 *
158 * The assigned stream channel run.
159 *
160 * Since: 3.0.0
161 */
162 param_spec = g_param_spec_pointer("stream-channel-run",
163 i18n_pspec("assigned AgsStreamChannelRun"),
164 i18n_pspec("an assigned AgsStreamChannelRun"),
165 G_PARAM_READABLE | G_PARAM_WRITABLE);
166 g_object_class_install_property(gobject,
167 PROP_STREAM_CHANNEL_RUN,
168 param_spec);
169
170 /* AgsRecallClass */
171 recall = (AgsRecallClass *) play_channel_run_master;
172
173 recall->run_init_pre = ags_play_channel_run_master_run_init_pre;
174 recall->resolve_dependency = ags_play_channel_run_master_resolve_dependency;
175 }
176
177 void
ags_play_channel_run_master_connectable_interface_init(AgsConnectableInterface * connectable)178 ags_play_channel_run_master_connectable_interface_init(AgsConnectableInterface *connectable)
179 {
180 ags_play_channel_run_master_parent_connectable_interface = g_type_interface_peek_parent(connectable);
181
182 connectable->connect = ags_play_channel_run_master_connect;
183 connectable->disconnect = ags_play_channel_run_master_disconnect;
184
185 connectable->connect_connection = ags_play_channel_run_master_connect_connection;
186 connectable->disconnect_connection = ags_play_channel_run_master_disconnect_connection;
187 }
188
189 void
ags_play_channel_run_master_init(AgsPlayChannelRunMaster * play_channel_run_master)190 ags_play_channel_run_master_init(AgsPlayChannelRunMaster *play_channel_run_master)
191 {
192 AGS_RECALL(play_channel_run_master)->name = "ags-play";
193 AGS_RECALL(play_channel_run_master)->version = AGS_RECALL_DEFAULT_VERSION;
194 AGS_RECALL(play_channel_run_master)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
195 AGS_RECALL(play_channel_run_master)->xml_type = "ags-play-channel-run-master";
196 AGS_RECALL(play_channel_run_master)->port = NULL;
197
198 AGS_RECALL(play_channel_run_master)->behaviour_flags |= (AGS_SOUND_BEHAVIOUR_PERSISTENT);
199 AGS_RECALL(play_channel_run_master)->child_type = AGS_TYPE_PLAY_RECYCLING;
200
201 play_channel_run_master->flags = 0;
202
203 play_channel_run_master->stream_channel_run = NULL;
204 }
205
206 void
ags_play_channel_run_master_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)207 ags_play_channel_run_master_set_property(GObject *gobject,
208 guint prop_id,
209 const GValue *value,
210 GParamSpec *param_spec)
211 {
212 AgsPlayChannelRunMaster *play_channel_run_master;
213
214 GRecMutex *recall_mutex;
215
216 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(gobject);
217
218 /* get recall mutex */
219 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_channel_run_master);
220
221 switch(prop_id){
222 case PROP_STREAM_CHANNEL_RUN:
223 {
224 AgsStreamChannelRun *stream_channel_run;
225
226 gboolean is_template;
227
228 stream_channel_run = (AgsStreamChannelRun *) g_value_get_pointer(value);
229
230 g_rec_mutex_lock(recall_mutex);
231
232 if(stream_channel_run == NULL ||
233 g_list_find(play_channel_run_master->stream_channel_run,
234 stream_channel_run) != NULL){
235 g_rec_mutex_unlock(recall_mutex);
236
237 return;
238 }
239
240 if(stream_channel_run != NULL){
241 g_object_ref(G_OBJECT(stream_channel_run));
242 }
243
244 play_channel_run_master->stream_channel_run = g_list_prepend(play_channel_run_master->stream_channel_run,
245 stream_channel_run);
246
247 g_rec_mutex_unlock(recall_mutex);
248
249 if(ags_recall_test_flags((AgsRecall *) stream_channel_run, AGS_RECALL_TEMPLATE)){
250 is_template = TRUE;
251 }else{
252 is_template = FALSE;
253 }
254
255 if(is_template){
256 ags_recall_add_recall_dependency((AgsRecall *) play_channel_run_master,
257 ags_recall_dependency_new((GObject *) stream_channel_run));
258 }else{
259 if(ags_connectable_is_connected(AGS_CONNECTABLE(play_channel_run_master))){
260 ags_connectable_connect_connection(AGS_CONNECTABLE(play_channel_run_master),
261 (GObject *) stream_channel_run);
262 }
263 }
264 }
265 break;
266 default:
267 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
268 break;
269 }
270 }
271
272 void
ags_play_channel_run_master_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)273 ags_play_channel_run_master_get_property(GObject *gobject,
274 guint prop_id,
275 GValue *value,
276 GParamSpec *param_spec)
277 {
278 AgsPlayChannelRunMaster *play_channel_run_master;
279
280 GRecMutex *recall_mutex;
281
282 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(gobject);
283
284 /* get recall mutex */
285 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_channel_run_master);
286
287 switch(prop_id){
288 case PROP_STREAM_CHANNEL_RUN:
289 {
290 g_rec_mutex_lock(recall_mutex);
291
292 g_value_set_pointer(value,
293 g_list_copy_deep(play_channel_run_master->stream_channel_run,
294 (GCopyFunc) g_object_ref,
295 NULL));
296
297 g_rec_mutex_unlock(recall_mutex);
298 }
299 break;
300 default:
301 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
302 break;
303 }
304 }
305
306 void
ags_play_channel_run_master_dispose(GObject * gobject)307 ags_play_channel_run_master_dispose(GObject *gobject)
308 {
309 AgsPlayChannelRunMaster *play_channel_run_master;
310
311 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(gobject);
312
313 /* stream channel run */
314 if(play_channel_run_master->stream_channel_run != NULL){
315 g_list_free_full(play_channel_run_master->stream_channel_run,
316 g_object_unref);
317
318 play_channel_run_master->stream_channel_run = NULL;
319 }
320
321 /* call parent */
322 G_OBJECT_CLASS(ags_play_channel_run_master_parent_class)->dispose(gobject);
323 }
324
325 void
ags_play_channel_run_master_finalize(GObject * gobject)326 ags_play_channel_run_master_finalize(GObject *gobject)
327 {
328 AgsPlayChannelRunMaster *play_channel_run_master;
329
330 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(gobject);
331
332 /* stream channel run */
333 if(play_channel_run_master->stream_channel_run != NULL){
334 g_list_free_full(play_channel_run_master->stream_channel_run,
335 g_object_unref);
336 }
337
338 /* call parent */
339 G_OBJECT_CLASS(ags_play_channel_run_master_parent_class)->finalize(gobject);
340 }
341
342 void
ags_play_channel_run_master_connect(AgsConnectable * connectable)343 ags_play_channel_run_master_connect(AgsConnectable *connectable)
344 {
345 AgsChannel *channel;
346 AgsPlayChannelRunMaster *play_channel_run_master;
347
348 GList *list_start, *list;
349
350 if(ags_connectable_is_connected(connectable)){
351 return;
352 }
353
354 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(connectable);
355
356 /* call parent */
357 ags_play_channel_run_master_parent_connectable_interface->connect(connectable);
358
359 /* source */
360 g_object_get(play_channel_run_master,
361 "source", &channel,
362 NULL);
363
364 g_signal_connect(channel, "recycling-changed",
365 G_CALLBACK(ags_play_channel_run_master_source_recycling_changed_callback), play_channel_run_master);
366
367 /* connection */
368 g_object_get(play_channel_run_master,
369 "stream-channel-run", &list_start,
370 NULL);
371
372 list = list_start;
373
374 while(list != NULL){
375 ags_connectable_connect_connection(connectable,
376 (GObject *) list->data);
377
378 list = list->next;
379 }
380
381 /* unref */
382 g_object_unref(channel);
383
384 g_list_free_full(list_start,
385 g_object_unref);
386 }
387
388 void
ags_play_channel_run_master_disconnect(AgsConnectable * connectable)389 ags_play_channel_run_master_disconnect(AgsConnectable *connectable)
390 {
391 AgsChannel *channel;
392 AgsPlayChannelRunMaster *play_channel_run_master;
393
394 GList *list_start, *list;
395
396 if(!ags_connectable_is_connected(connectable)){
397 return;
398 }
399
400 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(connectable);
401
402 ags_play_channel_run_master_parent_connectable_interface->disconnect(connectable);
403
404 /* source */
405 g_object_get(play_channel_run_master,
406 "source", &channel,
407 NULL);
408
409 g_object_disconnect(channel,
410 "any_signal::recycling-changed",
411 G_CALLBACK(ags_play_channel_run_master_source_recycling_changed_callback),
412 play_channel_run_master,
413 NULL);
414
415 /* connection */
416 g_object_get(play_channel_run_master,
417 "stream-channel-run", &list_start,
418 NULL);
419
420 list = list_start;
421
422 while(list != NULL){
423 ags_connectable_disconnect_connection(connectable,
424 (GObject *) list->data);
425
426 list = list->next;
427 }
428
429 /* unref */
430 g_object_unref(channel);
431
432 g_list_free_full(list_start,
433 g_object_unref);
434 }
435
436 void
ags_play_channel_run_master_connect_connection(AgsConnectable * connectable,GObject * connection)437 ags_play_channel_run_master_connect_connection(AgsConnectable *connectable,
438 GObject *connection)
439 {
440 AgsPlayChannelRunMaster *play_channel_run_master;
441
442 GList *list_start;
443
444 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(connectable);
445
446 if(connection == NULL){
447 return;
448 }
449
450 g_object_get(play_channel_run_master,
451 "stream-channel-run", &list_start,
452 NULL);
453
454 if(g_list_find(list_start, connection) != NULL){
455 g_signal_connect(connection, "done",
456 G_CALLBACK(ags_play_channel_run_master_stream_channel_done_callback), play_channel_run_master);
457 }
458
459 g_list_free_full(list_start,
460 g_object_unref);
461 }
462
463 void
ags_play_channel_run_master_disconnect_connection(AgsConnectable * connectable,GObject * connection)464 ags_play_channel_run_master_disconnect_connection(AgsConnectable *connectable,
465 GObject *connection)
466 {
467 AgsPlayChannelRunMaster *play_channel_run_master;
468
469 GList *list_start;
470
471 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(connectable);
472
473 if(connection == NULL){
474 return;
475 }
476
477 g_object_get(play_channel_run_master,
478 "stream-channel-run", &list_start,
479 NULL);
480
481 if(g_list_find(list_start, connection) != NULL){
482 g_object_disconnect(connection,
483 "any_signal::done",
484 G_CALLBACK(ags_play_channel_run_master_stream_channel_done_callback),
485 play_channel_run_master,
486 NULL);
487 }
488
489 g_list_free_full(list_start,
490 g_object_unref);
491 }
492
493 void
ags_play_channel_run_master_run_init_pre(AgsRecall * recall)494 ags_play_channel_run_master_run_init_pre(AgsRecall *recall)
495 {
496 AgsChannel *channel;
497 AgsRecycling *first_recycling, *last_recycling;
498 AgsPlayChannelRunMaster *play_channel_run_master;
499
500 void (*parent_class_run_init_pre)(AgsRecall *recall);
501
502 GRecMutex *recall_mutex;
503
504 play_channel_run_master = AGS_PLAY_CHANNEL_RUN_MASTER(recall);
505
506 /* get recall mutex */
507 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(recall);
508
509 /* get parent class */
510 parent_class_run_init_pre = AGS_RECALL_CLASS(ags_play_channel_run_master_parent_class)->run_init_pre;
511
512 /* call parent */
513 parent_class_run_init_pre(recall);
514
515 /* remap */
516 g_object_get(play_channel_run_master,
517 "source", &channel,
518 NULL);
519
520 g_object_get(channel,
521 "first-recycling", &first_recycling,
522 "last-recycling", &last_recycling,
523 NULL);
524
525 ags_play_channel_run_master_remap_dependencies(play_channel_run_master,
526 NULL, NULL,
527 first_recycling, last_recycling);
528
529 g_object_unref(channel);
530
531 g_object_unref(first_recycling);
532 g_object_unref(last_recycling);
533 }
534
535 void
ags_play_channel_run_master_resolve_dependency(AgsRecall * recall)536 ags_play_channel_run_master_resolve_dependency(AgsRecall *recall)
537 {
538 AgsRecall *template;
539 AgsRecallContainer *recall_container;
540 AgsRecallID *recall_id;
541 AgsRecallDependency *recall_dependency;
542 AgsStreamChannelRun *stream_channel_run;
543
544 GObject *dependency;
545
546 GList *list_start, *list;
547
548 guint i, i_stop;
549
550 /* get some fields */
551 g_object_get(recall,
552 "recall-container", &recall_container,
553 NULL);
554
555 g_object_get(recall_container,
556 "recall-channel-run", &list_start,
557 NULL);
558
559 list = ags_recall_find_template(list_start);
560
561 if(list == NULL){
562 g_warning("AgsRecallClass::resolve - missing dependency");
563
564 g_object_unref(recall_container);
565
566 g_list_free_full(list_start,
567 g_object_unref);
568
569 return;
570 }
571
572 template = AGS_RECALL(list->data);
573 g_list_free_full(list_start,
574 g_object_unref);
575
576 g_object_get(template,
577 "recall-dependency", &list_start,
578 NULL);
579
580 g_object_get(recall,
581 "recall-id", &recall_id,
582 NULL);
583
584 /* prepare to resolve */
585 stream_channel_run = NULL;
586
587 list = list_start;
588
589 for(i = 0; list != NULL;){
590 recall_dependency = AGS_RECALL_DEPENDENCY(list->data);
591
592 g_object_get(recall_dependency,
593 "dependency", &dependency,
594 NULL);
595
596 if(AGS_IS_STREAM_CHANNEL_RUN(dependency)){
597 stream_channel_run = (AgsStreamChannelRun *) ags_recall_dependency_resolve(recall_dependency,
598 recall_id);
599
600 g_object_set(G_OBJECT(recall),
601 "stream-channel-run", stream_channel_run,
602 NULL);
603
604 i++;
605 }
606
607 g_object_unref(dependency);
608
609 list = list->next;
610 }
611
612 /* unref */
613 g_object_unref(recall_container);
614
615 g_list_free_full(list_start,
616 g_object_unref);
617
618 g_object_unref(recall_id);
619 }
620
621 void
ags_play_channel_run_master_remap_dependencies(AgsPlayChannelRunMaster * play_channel_run_master,AgsRecycling * old_start_region,AgsRecycling * old_end_region,AgsRecycling * new_start_region,AgsRecycling * new_end_region)622 ags_play_channel_run_master_remap_dependencies(AgsPlayChannelRunMaster *play_channel_run_master,
623 AgsRecycling *old_start_region, AgsRecycling *old_end_region,
624 AgsRecycling *new_start_region, AgsRecycling *new_end_region)
625 {
626 AgsChannel *current;
627 AgsRecycling *recycling, *next_recycling;
628 AgsRecycling *end_recycling;
629 AgsRecallID *recall_id;
630 AgsRecyclingContext *recycling_context;
631
632 GRecMutex *recall_mutex;
633
634 if(!AGS_IS_PLAY_CHANNEL_RUN_MASTER(play_channel_run_master)){
635 return;
636 }
637
638 /* get recall mutex */
639 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_channel_run_master);
640
641 /* get recycling context */
642 g_object_get(play_channel_run_master,
643 "recall-id", &recall_id,
644 NULL);
645
646 recycling_context = NULL;
647
648 if(recall_id != NULL){
649 g_object_get(recall_id,
650 "recycling-context", &recycling_context,
651 NULL);
652 }
653
654 /* remove old */
655 if(old_start_region != NULL){
656 GList *list_start, *list;
657
658 current = NULL;
659
660 recycling = old_start_region;
661 g_object_ref(recycling);
662
663 end_recycling = ags_recycling_next(old_end_region);
664
665 next_recycling = NULL;
666
667 while(recycling != end_recycling){
668 AgsChannel *tmp_channel;
669
670 g_object_get(recycling,
671 "channel", &tmp_channel,
672 NULL);
673
674 if(current != tmp_channel){
675 current = tmp_channel;
676
677 g_object_get(play_channel_run_master,
678 "recall-dependency", &list_start,
679 NULL);
680
681 list = list_start;
682
683 while((list = ags_recall_dependency_find_dependency_by_provider(list,
684 (GObject *) current)) != NULL){
685 GObject *dependency;
686
687 GList *start_stream_channel_run;
688
689 g_object_get(list->data,
690 "dependency", &dependency,
691 NULL);
692
693 /* remove dependency */
694 ags_recall_remove_recall_dependency((AgsRecall *) play_channel_run_master,
695 list->data);
696
697 /* remove stream channel run */
698 g_object_get(play_channel_run_master,
699 "stream-channel-run", &start_stream_channel_run,
700 NULL);
701
702 if(g_list_find(start_stream_channel_run,
703 dependency) != NULL){
704 g_rec_mutex_lock(recall_mutex);
705
706 play_channel_run_master->stream_channel_run = g_list_remove(play_channel_run_master->stream_channel_run,
707 dependency);
708
709 g_rec_mutex_unlock(recall_mutex);
710
711 g_object_unref(dependency);
712 }
713
714 g_list_free_full(start_stream_channel_run,
715 g_object_unref);
716
717 g_object_unref(dependency);
718
719 /* iterate */
720 list = list->next;
721 }
722
723 g_list_free_full(list_start,
724 g_object_unref);
725 }
726
727 /* unref */
728 g_object_unref(tmp_channel);
729
730 /* iterate */
731 next_recycling = ags_recycling_next(recycling);
732
733 g_object_unref(recycling);
734
735 recycling = next_recycling;
736 }
737
738 /* unref */
739 if(end_recycling != NULL){
740 g_object_unref(end_recycling);
741 }
742
743 if(next_recycling != NULL){
744 g_object_unref(next_recycling);
745 }
746 }
747
748 /* add new */
749 if(new_start_region != NULL){
750 AgsRecallContainer *recall_container;
751 AgsPlayChannelRunMaster *current_master;
752
753 GList *list_start, *list;
754 GList *master_start, *master;
755
756 current = NULL;
757
758 recycling = new_start_region;
759 g_object_ref(recycling);
760
761 end_recycling = ags_recycling_next(new_end_region);
762
763 next_recycling = NULL;
764
765 while(recycling != end_recycling){
766 AgsChannel *tmp_channel;
767
768 g_object_get(recycling,
769 "channel", &tmp_channel,
770 NULL);
771
772 if(current != tmp_channel){
773 current = tmp_channel;
774
775 g_object_get(current,
776 "play", &list_start,
777 NULL);
778
779 list = list_start;
780
781 while((list = ags_recall_find_type_with_recycling_context(list, AGS_TYPE_STREAM_CHANNEL_RUN, (GObject *) recycling_context)) != NULL){
782 g_object_set(play_channel_run_master,
783 "stream-channel-run", list->data,
784 NULL);
785
786 g_object_get(play_channel_run_master,
787 "recall-container", &recall_container,
788 NULL);
789
790 g_object_get(recall_container,
791 "recall-channel-run", &master_start,
792 NULL);
793
794 master = master_start;
795
796 while(master != NULL){
797 current_master = AGS_PLAY_CHANNEL_RUN_MASTER(master->data);
798
799 if(!ags_recall_test_flags((AgsRecall *) current_master, AGS_RECALL_TEMPLATE)){
800 g_object_set(G_OBJECT(current_master),
801 "stream-channel-run", AGS_STREAM_CHANNEL_RUN(list->data),
802 NULL);
803 }
804
805 /* iterate */
806 master = master->next;
807 }
808
809 g_object_unref(recall_container);
810
811 g_list_free_full(master_start,
812 g_object_unref);
813
814 /* iterate */
815 list = list->next;
816 }
817
818 g_list_free_full(list_start,
819 g_object_unref);
820 }
821
822 /* unref */
823 g_object_unref(tmp_channel);
824
825 /* iterate */
826 next_recycling = ags_recycling_next(recycling);
827
828 g_object_unref(recycling);
829
830 recycling = next_recycling;
831 }
832
833 /* unref */
834 if(end_recycling != NULL){
835 g_object_unref(end_recycling);
836 }
837
838 if(next_recycling != NULL){
839 g_object_unref(next_recycling);
840 }
841 }
842
843 /* unref */
844 if(recall_id != NULL){
845 g_object_unref(recall_id);
846 }
847
848 if(recycling_context != NULL){
849 g_object_unref(recycling_context);
850 }
851 }
852
853 void
ags_play_channel_run_master_source_recycling_changed_callback(AgsChannel * channel,AgsRecycling * old_start_region,AgsRecycling * old_end_region,AgsRecycling * new_start_region,AgsRecycling * new_end_region,AgsRecycling * old_start_changed_region,AgsRecycling * old_end_changed_region,AgsRecycling * new_start_changed_region,AgsRecycling * new_end_changed_region,AgsPlayChannelRunMaster * play_channel_run_master)854 ags_play_channel_run_master_source_recycling_changed_callback(AgsChannel *channel,
855 AgsRecycling *old_start_region, AgsRecycling *old_end_region,
856 AgsRecycling *new_start_region, AgsRecycling *new_end_region,
857 AgsRecycling *old_start_changed_region, AgsRecycling *old_end_changed_region,
858 AgsRecycling *new_start_changed_region, AgsRecycling *new_end_changed_region,
859 AgsPlayChannelRunMaster *play_channel_run_master)
860 {
861 if(ags_recall_test_flags((AgsRecall *) play_channel_run_master, AGS_RECALL_TEMPLATE)){
862 ags_play_channel_run_master_remap_dependencies(play_channel_run_master,
863 old_start_changed_region, old_end_changed_region,
864 new_start_changed_region, new_end_changed_region);
865 }
866 }
867
868 void
ags_play_channel_run_master_stream_channel_done_callback(AgsRecall * recall,AgsPlayChannelRunMaster * play_channel_run_master)869 ags_play_channel_run_master_stream_channel_done_callback(AgsRecall *recall,
870 AgsPlayChannelRunMaster *play_channel_run_master)
871 {
872 GRecMutex *recall_mutex;
873
874 /* get recall mutex */
875 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_channel_run_master);
876
877 /* remove stream channel run */
878 g_rec_mutex_lock(recall_mutex);
879
880 play_channel_run_master->stream_channel_run = g_list_remove(play_channel_run_master->stream_channel_run,
881 recall);
882 g_object_unref(recall);
883
884 g_rec_mutex_unlock(recall_mutex);
885 }
886
887 /**
888 * ags_play_channel_master_run_new:
889 * @source: the #AgsChannel
890 *
891 * Create a new instance of #AgsPlayChannelRunMaster
892 *
893 * Returns: the new #AgsPlayChannelRunMaster
894 *
895 * Since: 3.0.0
896 */
897 AgsPlayChannelRunMaster*
ags_play_channel_run_master_new(AgsChannel * source)898 ags_play_channel_run_master_new(AgsChannel *source)
899 {
900 AgsPlayChannelRunMaster *play_channel_run_master;
901
902 play_channel_run_master = (AgsPlayChannelRunMaster *) g_object_new(AGS_TYPE_PLAY_CHANNEL_RUN_MASTER,
903 "source", source,
904 NULL);
905
906 return(play_channel_run_master);
907 }
908