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/pulse/ags_pulse_server.h>
21 #include <ags/audio/pulse/ags_pulse_client.h>
22 #include <ags/audio/pulse/ags_pulse_port.h>
23
24 #include <ags/audio/pulse/ags_pulse_devout.h>
25 #include <ags/audio/pulse/ags_pulse_devin.h>
26
27 #include <string.h>
28
29 #include <errno.h>
30
31 #include <ags/i18n.h>
32
33 void ags_pulse_server_class_init(AgsPulseServerClass *pulse_server);
34 void ags_pulse_server_connectable_interface_init(AgsConnectableInterface *connectable);
35 void ags_pulse_server_sound_server_interface_init(AgsSoundServerInterface *sound_server);
36 void ags_pulse_server_init(AgsPulseServer *pulse_server);
37 void ags_pulse_server_set_property(GObject *gobject,
38 guint prop_id,
39 const GValue *value,
40 GParamSpec *param_spec);
41 void ags_pulse_server_get_property(GObject *gobject,
42 guint prop_id,
43 GValue *value,
44 GParamSpec *param_spec);
45 void ags_pulse_server_dispose(GObject *gobject);
46 void ags_pulse_server_finalize(GObject *gobject);
47
48 AgsUUID* ags_pulse_server_get_uuid(AgsConnectable *connectable);
49 gboolean ags_pulse_server_has_resource(AgsConnectable *connectable);
50 gboolean ags_pulse_server_is_ready(AgsConnectable *connectable);
51 void ags_pulse_server_add_to_registry(AgsConnectable *connectable);
52 void ags_pulse_server_remove_from_registry(AgsConnectable *connectable);
53 xmlNode* ags_pulse_server_list_resource(AgsConnectable *connectable);
54 xmlNode* ags_pulse_server_xml_compose(AgsConnectable *connectable);
55 void ags_pulse_server_xml_parse(AgsConnectable *connectable,
56 xmlNode *node);
57 gboolean ags_pulse_server_is_connected(AgsConnectable *connectable);
58 void ags_pulse_server_connect(AgsConnectable *connectable);
59 void ags_pulse_server_disconnect(AgsConnectable *connectable);
60
61 void ags_pulse_server_set_url(AgsSoundServer *sound_server,
62 gchar *url);
63 gchar* ags_pulse_server_get_url(AgsSoundServer *sound_server);
64 void ags_pulse_server_set_ports(AgsSoundServer *sound_server,
65 guint *ports, guint port_count);
66 guint* ags_pulse_server_get_ports(AgsSoundServer *sound_server,
67 guint *port_count);
68 void ags_pulse_server_set_soundcard(AgsSoundServer *sound_server,
69 gchar *client_uuid,
70 GList *soundcard);
71 GList* ags_pulse_server_get_soundcard(AgsSoundServer *sound_server,
72 gchar *client_uuid);
73 void ags_pulse_server_set_sequencer(AgsSoundServer *sound_server,
74 gchar *client_uuid,
75 GList *sequencer);
76 GList* ags_pulse_server_get_sequencer(AgsSoundServer *sound_server,
77 gchar *client_uuid);
78 GObject* ags_pulse_server_register_soundcard(AgsSoundServer *sound_server,
79 gboolean is_output);
80 void ags_pulse_server_unregister_soundcard(AgsSoundServer *sound_server,
81 GObject *soundcard);
82 GObject* ags_pulse_server_register_sequencer(AgsSoundServer *sound_server,
83 gboolean is_output);
84 void ags_pulse_server_unregister_sequencer(AgsSoundServer *sound_server,
85 GObject *sequencer);
86
87 void* ags_pulse_server_do_poll_loop(void *ptr);
88
89 /**
90 * SECTION:ags_pulse_server
91 * @short_description: pulseaudio instance
92 * @title: AgsPulseServer
93 * @section_id:
94 * @include: ags/audio/pulse/ags_pulse_server.h
95 *
96 * The #AgsPulseServer is an object to represent a running pulseaudio instance.
97 */
98
99 enum{
100 PROP_0,
101 PROP_URL,
102 PROP_DEFAULT_SOUNDCARD,
103 PROP_DEFAULT_PULSE_CLIENT,
104 PROP_PULSE_CLIENT,
105 };
106
107 static gpointer ags_pulse_server_parent_class = NULL;
108
109 GType
ags_pulse_server_get_type()110 ags_pulse_server_get_type()
111 {
112 static volatile gsize g_define_type_id__volatile = 0;
113
114 if(g_once_init_enter (&g_define_type_id__volatile)){
115 GType ags_type_pulse_server = 0;
116
117 static const GTypeInfo ags_pulse_server_info = {
118 sizeof(AgsPulseServerClass),
119 NULL, /* base_init */
120 NULL, /* base_finalize */
121 (GClassInitFunc) ags_pulse_server_class_init,
122 NULL, /* class_finalize */
123 NULL, /* class_data */
124 sizeof(AgsPulseServer),
125 0, /* n_preallocs */
126 (GInstanceInitFunc) ags_pulse_server_init,
127 };
128
129 static const GInterfaceInfo ags_connectable_interface_info = {
130 (GInterfaceInitFunc) ags_pulse_server_connectable_interface_init,
131 NULL, /* interface_finalize */
132 NULL, /* interface_data */
133 };
134
135 static const GInterfaceInfo ags_sound_server_interface_info = {
136 (GInterfaceInitFunc) ags_pulse_server_sound_server_interface_init,
137 NULL, /* interface_finalize */
138 NULL, /* interface_data */
139 };
140
141 ags_type_pulse_server = g_type_register_static(G_TYPE_OBJECT,
142 "AgsPulseServer",
143 &ags_pulse_server_info,
144 0);
145
146 g_type_add_interface_static(ags_type_pulse_server,
147 AGS_TYPE_CONNECTABLE,
148 &ags_connectable_interface_info);
149
150 g_type_add_interface_static(ags_type_pulse_server,
151 AGS_TYPE_SOUND_SERVER,
152 &ags_sound_server_interface_info);
153
154 g_once_init_leave(&g_define_type_id__volatile, ags_type_pulse_server);
155 }
156
157 return g_define_type_id__volatile;
158 }
159
160 void
ags_pulse_server_class_init(AgsPulseServerClass * pulse_server)161 ags_pulse_server_class_init(AgsPulseServerClass *pulse_server)
162 {
163 GObjectClass *gobject;
164
165 GParamSpec *param_spec;
166
167 ags_pulse_server_parent_class = g_type_class_peek_parent(pulse_server);
168
169 /* GObjectClass */
170 gobject = (GObjectClass *) pulse_server;
171
172 gobject->set_property = ags_pulse_server_set_property;
173 gobject->get_property = ags_pulse_server_get_property;
174
175 gobject->dispose = ags_pulse_server_dispose;
176 gobject->finalize = ags_pulse_server_finalize;
177
178 /* properties */
179 /**
180 * AgsPulseServer:url:
181 *
182 * The assigned URL.
183 *
184 * Since: 3.0.0
185 */
186 param_spec = g_param_spec_string("url",
187 i18n_pspec("the URL"),
188 i18n_pspec("The URL"),
189 NULL,
190 G_PARAM_READABLE | G_PARAM_WRITABLE);
191 g_object_class_install_property(gobject,
192 PROP_URL,
193 param_spec);
194
195 /**
196 * AgsPulseServer:default-soundcard:
197 *
198 * The default soundcard.
199 *
200 * Since: 3.0.0
201 */
202 param_spec = g_param_spec_object("default-soundcard",
203 i18n_pspec("default soundcard"),
204 i18n_pspec("The default soundcard"),
205 G_TYPE_OBJECT,
206 G_PARAM_READABLE | G_PARAM_WRITABLE);
207 g_object_class_install_property(gobject,
208 PROP_DEFAULT_SOUNDCARD,
209 param_spec);
210
211 /**
212 * AgsPulseServer:default-pulse-client:
213 *
214 * The default pulse client.
215 *
216 * Since: 3.0.0
217 */
218 param_spec = g_param_spec_object("default-pulse-client",
219 i18n_pspec("default pulse client"),
220 i18n_pspec("The default pulse client"),
221 AGS_TYPE_PULSE_CLIENT,
222 G_PARAM_READABLE | G_PARAM_WRITABLE);
223 g_object_class_install_property(gobject,
224 PROP_DEFAULT_PULSE_CLIENT,
225 param_spec);
226
227 /**
228 * AgsPulseServer:pulse-client: (type GList(AgsPulseClient)) (transfer full)
229 *
230 * The pulse client list.
231 *
232 * Since: 3.0.0
233 */
234 param_spec = g_param_spec_pointer("pulse-client",
235 i18n_pspec("pulse client list"),
236 i18n_pspec("The pulse client list"),
237 G_PARAM_READABLE | G_PARAM_WRITABLE);
238 g_object_class_install_property(gobject,
239 PROP_PULSE_CLIENT,
240 param_spec);
241 }
242
243 void
ags_pulse_server_connectable_interface_init(AgsConnectableInterface * connectable)244 ags_pulse_server_connectable_interface_init(AgsConnectableInterface *connectable)
245 {
246 connectable->get_uuid = ags_pulse_server_get_uuid;
247 connectable->has_resource = ags_pulse_server_has_resource;
248
249 connectable->is_ready = ags_pulse_server_is_ready;
250 connectable->add_to_registry = ags_pulse_server_add_to_registry;
251 connectable->remove_from_registry = ags_pulse_server_remove_from_registry;
252
253 connectable->list_resource = ags_pulse_server_list_resource;
254 connectable->xml_compose = ags_pulse_server_xml_compose;
255 connectable->xml_parse = ags_pulse_server_xml_parse;
256
257 connectable->is_connected = ags_pulse_server_is_connected;
258 connectable->connect = ags_pulse_server_connect;
259 connectable->disconnect = ags_pulse_server_disconnect;
260
261 connectable->connect_connection = NULL;
262 connectable->disconnect_connection = NULL;
263 }
264
265 void
ags_pulse_server_sound_server_interface_init(AgsSoundServerInterface * sound_server)266 ags_pulse_server_sound_server_interface_init(AgsSoundServerInterface *sound_server)
267 {
268 sound_server->set_url = ags_pulse_server_set_url;
269 sound_server->get_url = ags_pulse_server_get_url;
270 sound_server->set_ports = ags_pulse_server_set_ports;
271 sound_server->get_ports = ags_pulse_server_get_ports;
272 sound_server->set_soundcard = ags_pulse_server_set_soundcard;
273 sound_server->get_soundcard = ags_pulse_server_get_soundcard;
274 sound_server->set_sequencer = ags_pulse_server_set_sequencer;
275 sound_server->get_sequencer = ags_pulse_server_get_sequencer;
276 sound_server->register_soundcard = ags_pulse_server_register_soundcard;
277 sound_server->unregister_soundcard = ags_pulse_server_unregister_soundcard;
278 sound_server->register_sequencer = ags_pulse_server_register_sequencer;
279 sound_server->unregister_sequencer = ags_pulse_server_unregister_sequencer;
280 }
281
282 void
ags_pulse_server_init(AgsPulseServer * pulse_server)283 ags_pulse_server_init(AgsPulseServer *pulse_server)
284 {
285 /* flags */
286 pulse_server->flags = 0;
287
288 /* server mutex */
289 g_rec_mutex_init(&(pulse_server->obj_mutex));
290
291 g_atomic_int_set(&(pulse_server->running),
292 TRUE);
293
294 pulse_server->thread = NULL;
295
296 /* uuid */
297 pulse_server->uuid = ags_uuid_alloc();
298 ags_uuid_generate(pulse_server->uuid);
299
300 #ifdef AGS_WITH_PULSE
301 pulse_server->main_loop = NULL;
302 pulse_server->main_loop_api = NULL;
303 #else
304 pulse_server->main_loop = NULL;
305 pulse_server->main_loop_api = NULL;
306 #endif
307
308 pulse_server->url = NULL;
309
310 pulse_server->port = NULL;
311 pulse_server->port_count = 0;
312
313 pulse_server->n_soundcards = 0;
314 pulse_server->n_sequencers = 0;
315
316 pulse_server->default_soundcard = NULL;
317
318 pulse_server->default_client = NULL;
319 pulse_server->client = NULL;
320 }
321
322 void
ags_pulse_server_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)323 ags_pulse_server_set_property(GObject *gobject,
324 guint prop_id,
325 const GValue *value,
326 GParamSpec *param_spec)
327 {
328 AgsPulseServer *pulse_server;
329
330 GRecMutex *pulse_server_mutex;
331
332 pulse_server = AGS_PULSE_SERVER(gobject);
333
334 /* get pulse server mutex */
335 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
336
337 switch(prop_id){
338 case PROP_URL:
339 {
340 gchar *url;
341
342 url = g_value_get_string(value);
343
344 g_rec_mutex_lock(pulse_server_mutex);
345
346 if(pulse_server->url == url){
347 g_rec_mutex_unlock(pulse_server_mutex);
348
349 return;
350 }
351
352 if(pulse_server->url != NULL){
353 g_free(pulse_server->url);
354 }
355
356 pulse_server->url = g_strdup(url);
357
358 g_rec_mutex_unlock(pulse_server_mutex);
359 }
360 break;
361 case PROP_DEFAULT_SOUNDCARD:
362 {
363 GObject *default_soundcard;
364
365 default_soundcard = (GObject *) g_value_get_object(value);
366
367 g_rec_mutex_lock(pulse_server_mutex);
368
369 if(pulse_server->default_soundcard == (GObject *) default_soundcard){
370 g_rec_mutex_unlock(pulse_server_mutex);
371
372 return;
373 }
374
375 if(pulse_server->default_soundcard != NULL){
376 g_object_unref(G_OBJECT(pulse_server->default_soundcard));
377 }
378
379 if(default_soundcard != NULL){
380 g_object_ref(G_OBJECT(default_soundcard));
381 }
382
383 pulse_server->default_soundcard = (GObject *) default_soundcard;
384
385 g_rec_mutex_unlock(pulse_server_mutex);
386 }
387 break;
388 case PROP_DEFAULT_PULSE_CLIENT:
389 {
390 AgsPulseClient *default_client;
391
392 default_client = (AgsPulseClient *) g_value_get_object(value);
393
394 g_rec_mutex_lock(pulse_server_mutex);
395
396 if(pulse_server->default_client == (GObject *) default_client){
397 g_rec_mutex_unlock(pulse_server_mutex);
398
399 return;
400 }
401
402 if(pulse_server->default_client != NULL){
403 g_object_unref(G_OBJECT(pulse_server->default_client));
404 }
405
406 if(default_client != NULL){
407 g_object_ref(G_OBJECT(default_client));
408 }
409
410 pulse_server->default_client = (GObject *) default_client;
411
412 g_rec_mutex_unlock(pulse_server_mutex);
413 }
414 break;
415 case PROP_PULSE_CLIENT:
416 {
417 GObject *client;
418
419 client = (GObject *) g_value_get_pointer(value);
420
421 g_rec_mutex_lock(pulse_server_mutex);
422
423 if(!AGS_IS_PULSE_CLIENT(client) ||
424 g_list_find(pulse_server->client, client) != NULL){
425 g_rec_mutex_unlock(pulse_server_mutex);
426
427 return;
428 }
429
430 g_object_ref(G_OBJECT(client));
431 pulse_server->client = g_list_prepend(pulse_server->client,
432 client);
433
434 g_rec_mutex_unlock(pulse_server_mutex);
435 }
436 break;
437 default:
438 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
439 break;
440 }
441 }
442
443 void
ags_pulse_server_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)444 ags_pulse_server_get_property(GObject *gobject,
445 guint prop_id,
446 GValue *value,
447 GParamSpec *param_spec)
448 {
449 AgsPulseServer *pulse_server;
450
451 GRecMutex *pulse_server_mutex;
452
453 pulse_server = AGS_PULSE_SERVER(gobject);
454
455 /* get pulse server mutex */
456 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
457
458 switch(prop_id){
459 case PROP_URL:
460 {
461 g_rec_mutex_lock(pulse_server_mutex);
462
463 g_value_set_string(value, pulse_server->url);
464
465 g_rec_mutex_unlock(pulse_server_mutex);
466 }
467 break;
468 case PROP_DEFAULT_SOUNDCARD:
469 {
470 g_rec_mutex_lock(pulse_server_mutex);
471
472 g_value_set_object(value, pulse_server->default_soundcard);
473
474 g_rec_mutex_unlock(pulse_server_mutex);
475 }
476 break;
477 case PROP_DEFAULT_PULSE_CLIENT:
478 {
479 g_rec_mutex_lock(pulse_server_mutex);
480
481 g_value_set_object(value, pulse_server->default_client);
482
483 g_rec_mutex_unlock(pulse_server_mutex);
484 }
485 break;
486 case PROP_PULSE_CLIENT:
487 {
488 g_rec_mutex_lock(pulse_server_mutex);
489
490 g_value_set_pointer(value,
491 g_list_copy_deep(pulse_server->client,
492 (GCopyFunc) g_object_ref,
493 NULL));
494
495 g_rec_mutex_unlock(pulse_server_mutex);
496 }
497 break;
498 default:
499 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
500 break;
501 }
502 }
503
504 void
ags_pulse_server_dispose(GObject * gobject)505 ags_pulse_server_dispose(GObject *gobject)
506 {
507 AgsPulseServer *pulse_server;
508
509 GList *list;
510
511 pulse_server = AGS_PULSE_SERVER(gobject);
512
513 /* default soundcard */
514 if(pulse_server->default_soundcard != NULL){
515 g_object_unref(G_OBJECT(pulse_server->default_soundcard));
516
517 pulse_server->default_soundcard = NULL;
518 }
519
520 /* default client */
521 if(pulse_server->default_client != NULL){
522 g_object_unref(G_OBJECT(pulse_server->default_client));
523
524 pulse_server->default_client = NULL;
525 }
526
527 /* client */
528 if(pulse_server->client != NULL){
529 list = pulse_server->client;
530
531 while(list != NULL){
532 g_object_run_dispose(G_OBJECT(list->data));
533
534 list = list->next;
535 }
536
537 g_list_free_full(pulse_server->client,
538 g_object_unref);
539
540 pulse_server->client = NULL;
541 }
542
543 /* call parent */
544 G_OBJECT_CLASS(ags_pulse_server_parent_class)->dispose(gobject);
545 }
546
547 void
ags_pulse_server_finalize(GObject * gobject)548 ags_pulse_server_finalize(GObject *gobject)
549 {
550 AgsPulseServer *pulse_server;
551
552 pulse_server = AGS_PULSE_SERVER(gobject);
553
554 /* url */
555 g_free(pulse_server->url);
556
557 /* default soundcard */
558 if(pulse_server->default_soundcard != NULL){
559 g_object_unref(G_OBJECT(pulse_server->default_soundcard));
560 }
561
562 /* default client */
563 if(pulse_server->default_client != NULL){
564 g_object_unref(G_OBJECT(pulse_server->default_client));
565 }
566
567 /* client */
568 if(pulse_server->client != NULL){
569 g_list_free_full(pulse_server->client,
570 g_object_unref);
571 }
572
573 /* call parent */
574 G_OBJECT_CLASS(ags_pulse_server_parent_class)->finalize(gobject);
575 }
576
577 AgsUUID*
ags_pulse_server_get_uuid(AgsConnectable * connectable)578 ags_pulse_server_get_uuid(AgsConnectable *connectable)
579 {
580 AgsPulseServer *pulse_server;
581
582 AgsUUID *ptr;
583
584 GRecMutex *pulse_server_mutex;
585
586 pulse_server = AGS_PULSE_SERVER(connectable);
587
588 /* get pulse server signal mutex */
589 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
590
591 /* get UUID */
592 g_rec_mutex_lock(pulse_server_mutex);
593
594 ptr = pulse_server->uuid;
595
596 g_rec_mutex_unlock(pulse_server_mutex);
597
598 return(ptr);
599 }
600
601 gboolean
ags_pulse_server_has_resource(AgsConnectable * connectable)602 ags_pulse_server_has_resource(AgsConnectable *connectable)
603 {
604 return(FALSE);
605 }
606
607 gboolean
ags_pulse_server_is_ready(AgsConnectable * connectable)608 ags_pulse_server_is_ready(AgsConnectable *connectable)
609 {
610 AgsPulseServer *pulse_server;
611
612 gboolean is_ready;
613
614 pulse_server = AGS_PULSE_SERVER(connectable);
615
616 /* check is added */
617 is_ready = ags_pulse_server_test_flags(pulse_server, AGS_PULSE_SERVER_ADDED_TO_REGISTRY);
618
619 return(is_ready);
620 }
621
622 void
ags_pulse_server_add_to_registry(AgsConnectable * connectable)623 ags_pulse_server_add_to_registry(AgsConnectable *connectable)
624 {
625 AgsPulseServer *pulse_server;
626
627 if(ags_connectable_is_ready(connectable)){
628 return;
629 }
630
631 pulse_server = AGS_PULSE_SERVER(connectable);
632
633 ags_pulse_server_set_flags(pulse_server, AGS_PULSE_SERVER_ADDED_TO_REGISTRY);
634 }
635
636 void
ags_pulse_server_remove_from_registry(AgsConnectable * connectable)637 ags_pulse_server_remove_from_registry(AgsConnectable *connectable)
638 {
639 AgsPulseServer *pulse_server;
640
641 if(!ags_connectable_is_ready(connectable)){
642 return;
643 }
644
645 pulse_server = AGS_PULSE_SERVER(connectable);
646
647 ags_pulse_server_unset_flags(pulse_server, AGS_PULSE_SERVER_ADDED_TO_REGISTRY);
648 }
649
650 xmlNode*
ags_pulse_server_list_resource(AgsConnectable * connectable)651 ags_pulse_server_list_resource(AgsConnectable *connectable)
652 {
653 xmlNode *node;
654
655 node = NULL;
656
657 //TODO:JK: implement me
658
659 return(node);
660 }
661
662 xmlNode*
ags_pulse_server_xml_compose(AgsConnectable * connectable)663 ags_pulse_server_xml_compose(AgsConnectable *connectable)
664 {
665 xmlNode *node;
666
667 node = NULL;
668
669 //TODO:JK: implement me
670
671 return(node);
672 }
673
674 void
ags_pulse_server_xml_parse(AgsConnectable * connectable,xmlNode * node)675 ags_pulse_server_xml_parse(AgsConnectable *connectable,
676 xmlNode *node)
677 {
678 //TODO:JK: implement me
679 }
680
681 gboolean
ags_pulse_server_is_connected(AgsConnectable * connectable)682 ags_pulse_server_is_connected(AgsConnectable *connectable)
683 {
684 AgsPulseServer *pulse_server;
685
686 gboolean is_connected;
687
688 pulse_server = AGS_PULSE_SERVER(connectable);
689
690 /* check is connected */
691 is_connected = ags_pulse_server_test_flags(pulse_server, AGS_PULSE_SERVER_CONNECTED);
692
693 return(is_connected);
694 }
695
696 void
ags_pulse_server_connect(AgsConnectable * connectable)697 ags_pulse_server_connect(AgsConnectable *connectable)
698 {
699 AgsPulseServer *pulse_server;
700
701 GList *list_start, *list;
702
703 GRecMutex *pulse_server_mutex;
704
705 if(ags_connectable_is_connected(connectable)){
706 return;
707 }
708
709 pulse_server = AGS_PULSE_SERVER(connectable);
710
711 ags_pulse_server_set_flags(pulse_server, AGS_PULSE_SERVER_CONNECTED);
712
713 /* get pulse server mutex */
714 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
715
716 list =
717 list_start = g_list_copy(pulse_server->client);
718
719 while(list != NULL){
720 ags_connectable_connect(AGS_CONNECTABLE(list->data));
721
722 list = list->next;
723 }
724
725 g_list_free(list_start);
726 }
727
728 void
ags_pulse_server_disconnect(AgsConnectable * connectable)729 ags_pulse_server_disconnect(AgsConnectable *connectable)
730 {
731 AgsPulseServer *pulse_server;
732
733 GList *list_start, *list;
734
735 GRecMutex *pulse_server_mutex;
736
737 if(!ags_connectable_is_connected(connectable)){
738 return;
739 }
740
741 pulse_server = AGS_PULSE_SERVER(connectable);
742
743 ags_pulse_server_unset_flags(pulse_server, AGS_PULSE_SERVER_CONNECTED);
744
745 /* get pulse server mutex */
746 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
747
748 /* client */
749 list =
750 list_start = g_list_copy(pulse_server->client);
751
752 while(list != NULL){
753 ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
754
755 list = list->next;
756 }
757
758 g_list_free(list_start);
759 }
760
761 /**
762 * ags_pulse_server_test_flags:
763 * @pulse_server: the #AgsPulseServer
764 * @flags: the flags
765 *
766 * Test @flags to be set on @pulse_server.
767 *
768 * Returns: %TRUE if flags are set, else %FALSE
769 *
770 * Since: 3.0.0
771 */
772 gboolean
ags_pulse_server_test_flags(AgsPulseServer * pulse_server,guint flags)773 ags_pulse_server_test_flags(AgsPulseServer *pulse_server, guint flags)
774 {
775 gboolean retval;
776
777 GRecMutex *pulse_server_mutex;
778
779 if(!AGS_IS_PULSE_SERVER(pulse_server)){
780 return(FALSE);
781 }
782
783 /* get pulse server mutex */
784 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
785
786 /* test */
787 g_rec_mutex_lock(pulse_server_mutex);
788
789 retval = (flags & (pulse_server->flags)) ? TRUE: FALSE;
790
791 g_rec_mutex_unlock(pulse_server_mutex);
792
793 return(retval);
794 }
795
796 /**
797 * ags_pulse_server_set_flags:
798 * @pulse_server: the #AgsPulseServer
799 * @flags: see #AgsPulseServerFlags-enum
800 *
801 * Enable a feature of @pulse_server.
802 *
803 * Since: 3.0.0
804 */
805 void
ags_pulse_server_set_flags(AgsPulseServer * pulse_server,guint flags)806 ags_pulse_server_set_flags(AgsPulseServer *pulse_server, guint flags)
807 {
808 GRecMutex *pulse_server_mutex;
809
810 if(!AGS_IS_PULSE_SERVER(pulse_server)){
811 return;
812 }
813
814 /* get pulse server mutex */
815 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
816
817 //TODO:JK: add more?
818
819 /* set flags */
820 g_rec_mutex_lock(pulse_server_mutex);
821
822 pulse_server->flags |= flags;
823
824 g_rec_mutex_unlock(pulse_server_mutex);
825 }
826
827 /**
828 * ags_pulse_server_unset_flags:
829 * @pulse_server: the #AgsPulseServer
830 * @flags: see #AgsPulseServerFlags-enum
831 *
832 * Disable a feature of @pulse_server.
833 *
834 * Since: 3.0.0
835 */
836 void
ags_pulse_server_unset_flags(AgsPulseServer * pulse_server,guint flags)837 ags_pulse_server_unset_flags(AgsPulseServer *pulse_server, guint flags)
838 {
839 GRecMutex *pulse_server_mutex;
840
841 if(!AGS_IS_PULSE_SERVER(pulse_server)){
842 return;
843 }
844
845 /* get pulse server mutex */
846 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
847
848 //TODO:JK: add more?
849
850 /* unset flags */
851 g_rec_mutex_lock(pulse_server_mutex);
852
853 pulse_server->flags &= (~flags);
854
855 g_rec_mutex_unlock(pulse_server_mutex);
856 }
857
858 void
ags_pulse_server_set_url(AgsSoundServer * sound_server,gchar * url)859 ags_pulse_server_set_url(AgsSoundServer *sound_server,
860 gchar *url)
861 {
862 AgsPulseServer *pulse_server;
863
864 GRecMutex *pulse_server_mutex;
865
866 pulse_server = AGS_PULSE_SERVER(sound_server);
867
868 /* get pulse server mutex */
869 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
870
871 /* set URL */
872 g_rec_mutex_lock(pulse_server_mutex);
873
874 pulse_server->url = g_strdup(url);
875
876 g_rec_mutex_unlock(pulse_server_mutex);
877 }
878
879 gchar*
ags_pulse_server_get_url(AgsSoundServer * sound_server)880 ags_pulse_server_get_url(AgsSoundServer *sound_server)
881 {
882 AgsPulseServer *pulse_server;
883
884 gchar *url;
885
886 GRecMutex *pulse_server_mutex;
887
888 pulse_server = AGS_PULSE_SERVER(sound_server);
889
890 /* get pulse server mutex */
891 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
892
893 /* set URL */
894 g_rec_mutex_lock(pulse_server_mutex);
895
896 url = pulse_server->url;
897
898 g_rec_mutex_unlock(pulse_server_mutex);
899
900 return(url);
901 }
902
903
904 void
ags_pulse_server_set_ports(AgsSoundServer * sound_server,guint * port,guint port_count)905 ags_pulse_server_set_ports(AgsSoundServer *sound_server,
906 guint *port, guint port_count)
907 {
908 AgsPulseServer *pulse_server;
909
910 GRecMutex *pulse_server_mutex;
911
912 pulse_server = AGS_PULSE_SERVER(sound_server);
913
914 /* get pulse server mutex */
915 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
916
917 /* set ports */
918 g_rec_mutex_lock(pulse_server_mutex);
919
920 pulse_server->port = port;
921 pulse_server->port_count = port_count;
922
923 g_rec_mutex_unlock(pulse_server_mutex);
924 }
925
926 guint*
ags_pulse_server_get_ports(AgsSoundServer * sound_server,guint * port_count)927 ags_pulse_server_get_ports(AgsSoundServer *sound_server,
928 guint *port_count)
929 {
930 AgsPulseServer *pulse_server;
931
932 guint *port;
933
934 GRecMutex *pulse_server_mutex;
935
936 pulse_server = AGS_PULSE_SERVER(sound_server);
937
938 /* get pulse server mutex */
939 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
940
941 /* get ports */
942 g_rec_mutex_lock(pulse_server_mutex);
943
944 if(port_count != NULL){
945 *port_count = AGS_PULSE_SERVER(sound_server)->port_count;
946 }
947
948 port = pulse_server->port;
949
950 g_rec_mutex_unlock(pulse_server_mutex);
951
952 return(port);
953 }
954
955 void
ags_pulse_server_set_soundcard(AgsSoundServer * sound_server,gchar * client_uuid,GList * soundcard)956 ags_pulse_server_set_soundcard(AgsSoundServer *sound_server,
957 gchar *client_uuid,
958 GList *soundcard)
959 {
960 AgsPulseServer *pulse_server;
961 AgsPulseClient *pulse_client;
962
963 GList *list;
964
965 pulse_server = AGS_PULSE_SERVER(sound_server);
966
967 pulse_client = (AgsPulseClient *) ags_pulse_server_find_client(pulse_server,
968 client_uuid);
969
970 if(!AGS_IS_PULSE_CLIENT(pulse_client)){
971 return;
972 }
973
974 //NOTE:JK: soundcard won't removed
975 list = soundcard;
976
977 while(list != NULL){
978 ags_pulse_client_add_device(pulse_client,
979 (GObject *) list->data);
980
981 list = list->next;
982 }
983 }
984
985 GList*
ags_pulse_server_get_soundcard(AgsSoundServer * sound_server,gchar * client_uuid)986 ags_pulse_server_get_soundcard(AgsSoundServer *sound_server,
987 gchar *client_uuid)
988 {
989 AgsPulseServer *pulse_server;
990 AgsPulseClient *pulse_client;
991
992 GList *device_start, *device;
993 GList *list;
994
995 pulse_server = AGS_PULSE_SERVER(sound_server);
996
997 pulse_client = (AgsPulseClient *) ags_pulse_server_find_client(pulse_server,
998 client_uuid);
999
1000 if(!AGS_IS_PULSE_CLIENT(pulse_client)){
1001 return(NULL);
1002 }
1003
1004 g_object_get(pulse_client,
1005 "device", &device_start,
1006 NULL);
1007
1008 device = device_start;
1009 list = NULL;
1010
1011 while(device != NULL){
1012 if(AGS_IS_PULSE_DEVOUT(device->data) ||
1013 AGS_IS_PULSE_DEVIN(device->data)){
1014 list = g_list_prepend(list,
1015 device->data);
1016 g_object_ref(device->data);
1017 }
1018
1019 device = device->next;
1020 }
1021
1022 g_list_free_full(device_start,
1023 g_object_unref);
1024
1025 return(g_list_reverse(list));
1026 }
1027
1028
1029 void
ags_pulse_server_set_sequencer(AgsSoundServer * sound_server,gchar * client_uuid,GList * sequencer)1030 ags_pulse_server_set_sequencer(AgsSoundServer *sound_server,
1031 gchar *client_uuid,
1032 GList *sequencer)
1033 {
1034 AgsPulseServer *pulse_server;
1035 AgsPulseClient *pulse_client;
1036
1037 GList *list;
1038
1039 pulse_server = AGS_PULSE_SERVER(sound_server);
1040
1041 pulse_client = (AgsPulseClient *) ags_pulse_server_find_client(pulse_server,
1042 client_uuid);
1043
1044 if(!AGS_IS_PULSE_CLIENT(pulse_client)){
1045 return;
1046 }
1047
1048 //NOTE:JK: sequencer won't removed
1049 list = sequencer;
1050
1051 while(list != NULL){
1052 ags_pulse_client_add_device(pulse_client,
1053 (GObject *) list->data);
1054
1055 list = list->next;
1056 }
1057 }
1058
1059 GList*
ags_pulse_server_get_sequencer(AgsSoundServer * sound_server,gchar * client_uuid)1060 ags_pulse_server_get_sequencer(AgsSoundServer *sound_server,
1061 gchar *client_uuid)
1062 {
1063 AgsPulseServer *pulse_server;
1064 AgsPulseClient *pulse_client;
1065
1066 GList *device_start, *device;
1067 GList *list;
1068
1069 pulse_server = AGS_PULSE_SERVER(sound_server);
1070
1071 pulse_client = (AgsPulseClient *) ags_pulse_server_find_client(pulse_server,
1072 client_uuid);
1073
1074 if(!AGS_IS_PULSE_CLIENT(pulse_client)){
1075 return(NULL);
1076 }
1077
1078 g_object_get(pulse_client,
1079 "device", &device_start,
1080 NULL);
1081
1082 device = device_start;
1083 list = NULL;
1084
1085 #if 0
1086 while(device != NULL){
1087 if(AGS_IS_PULSE_MIDIIN(device->data)){
1088 list = g_list_prepend(list,
1089 device->data);
1090 g_object_ref(device->data);
1091 }
1092
1093 device = device->next;
1094 }
1095 #endif
1096
1097 g_list_free_full(device_start,
1098 g_object_unref);
1099
1100 return(g_list_reverse(list));
1101 }
1102
1103 GObject*
ags_pulse_server_register_soundcard(AgsSoundServer * sound_server,gboolean is_output)1104 ags_pulse_server_register_soundcard(AgsSoundServer *sound_server,
1105 gboolean is_output)
1106 {
1107 AgsPulseServer *pulse_server;
1108 AgsPulseClient *default_client;
1109 AgsPulsePort *pulse_port;
1110 AgsPulseDevout *pulse_devout;
1111 AgsPulseDevin *pulse_devin;
1112
1113 AgsApplicationContext *application_context;
1114
1115 GObject *soundcard;
1116
1117 #ifdef AGS_WITH_PULSE
1118 pa_context *context;
1119 #else
1120 gpointer context;
1121 #endif
1122
1123 gchar *str;
1124
1125 guint n_soundcards;
1126 gboolean initial_set;
1127 guint i;
1128
1129 GRecMutex *pulse_server_mutex;
1130 GRecMutex *pulse_client_mutex;
1131
1132 pulse_server = AGS_PULSE_SERVER(sound_server);
1133
1134 application_context= ags_application_context_get_instance();
1135
1136 /* get pulse server mutex */
1137 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1138
1139 /* the default client */
1140 initial_set = FALSE;
1141
1142 /* get some fields */
1143 g_rec_mutex_lock(pulse_server_mutex);
1144
1145 if(pulse_server->main_loop == NULL){
1146 #ifdef AGS_WITH_PULSE
1147 pulse_server->main_loop = pa_mainloop_new();
1148 pulse_server->main_loop_api = pa_mainloop_get_api(pulse_server->main_loop);
1149 #else
1150 pulse_server->main_loop = NULL;
1151 pulse_server->main_loop_api = NULL;
1152 #endif
1153 }
1154
1155 default_client = (AgsPulseClient *) pulse_server->default_client;
1156
1157 n_soundcards = pulse_server->n_soundcards;
1158
1159 g_rec_mutex_unlock(pulse_server_mutex);
1160
1161 /* the default client */
1162 if(default_client == NULL){
1163 default_client = ags_pulse_client_new((GObject *) pulse_server);
1164
1165 g_object_set(pulse_server,
1166 "default-pulse-client", default_client,
1167 NULL);
1168 ags_pulse_server_add_client(pulse_server,
1169 (GObject *) default_client);
1170
1171 ags_pulse_client_open((AgsPulseClient *) default_client,
1172 "ags-default-client");
1173 initial_set = TRUE;
1174 }
1175
1176 /* get pulse client mutex */
1177 pulse_client_mutex = AGS_PULSE_CLIENT_GET_OBJ_MUTEX(default_client);
1178
1179 /* get context */
1180 g_rec_mutex_lock(pulse_client_mutex);
1181
1182 context = default_client->context;
1183
1184 g_rec_mutex_unlock(pulse_client_mutex);
1185
1186 if(context == NULL){
1187 g_warning("ags_pulse_server.c - can't open pulseaudio client");
1188 }
1189
1190 /* the soundcard */
1191 soundcard = NULL;
1192
1193 /* the soundcard */
1194 if(is_output){
1195 pulse_devout = ags_pulse_devout_new();
1196 soundcard = (GObject *) pulse_devout;
1197
1198 str = g_strdup_printf("ags-pulse-devout-%d",
1199 n_soundcards);
1200
1201 g_object_set(AGS_PULSE_DEVOUT(pulse_devout),
1202 "pulse-client", default_client,
1203 "device", str,
1204 NULL);
1205 g_free(str);
1206
1207 /* register ports */
1208 pulse_port = ags_pulse_port_new((GObject *) default_client);
1209
1210 str = g_strdup_printf("ags-soundcard%d",
1211 n_soundcards);
1212
1213 g_object_set(pulse_port,
1214 "pulse-devout", pulse_devout,
1215 NULL);
1216 ags_pulse_client_add_port(default_client,
1217 (GObject *) pulse_port);
1218
1219 g_object_set(pulse_devout,
1220 "pulse-port", pulse_port,
1221 NULL);
1222
1223 pulse_devout->port_name = (gchar **) malloc(2 * sizeof(gchar *));
1224 pulse_devout->port_name[0] = g_strdup(str);
1225 pulse_devout->port_name[1] = NULL;
1226
1227 ags_pulse_port_register(pulse_port,
1228 str,
1229 TRUE, FALSE,
1230 TRUE);
1231
1232 ags_pulse_devout_realloc_buffer(pulse_devout);
1233
1234 g_object_set(default_client,
1235 "device", pulse_devout,
1236 NULL);
1237
1238 /* increment n-soundcards */
1239 g_rec_mutex_lock(pulse_server_mutex);
1240
1241 pulse_server->n_soundcards += 1;
1242
1243 g_rec_mutex_unlock(pulse_server_mutex);
1244 }else{
1245 pulse_devin = ags_pulse_devin_new();
1246 soundcard = (GObject *) pulse_devin;
1247
1248 str = g_strdup_printf("ags-pulse-devin-%d",
1249 pulse_server->n_soundcards);
1250
1251 g_object_set(AGS_PULSE_DEVIN(pulse_devin),
1252 "pulse-client", default_client,
1253 "device", str,
1254 NULL);
1255 g_free(str);
1256
1257 /* register ports */
1258 str = g_strdup_printf("ags-soundcard%d",
1259 n_soundcards);
1260
1261 #ifdef AGS_DEBUG
1262 g_message("%s", str);
1263 #endif
1264
1265 pulse_port = ags_pulse_port_new((GObject *) default_client);
1266 g_object_set(pulse_port,
1267 "pulse-devin", pulse_devin,
1268 NULL);
1269 ags_pulse_client_add_port(default_client,
1270 (GObject *) pulse_port);
1271
1272 g_object_set(pulse_devin,
1273 "pulse-port", pulse_port,
1274 NULL);
1275
1276 pulse_devin->port_name = (gchar **) malloc(2 * sizeof(gchar *));
1277 pulse_devin->port_name[0] = g_strdup(str);
1278 pulse_devin->port_name[1] = NULL;
1279
1280 ags_pulse_port_register(pulse_port,
1281 str,
1282 TRUE, FALSE,
1283 TRUE);
1284
1285 ags_pulse_devin_realloc_buffer(pulse_devin);
1286
1287 g_object_set(default_client,
1288 "device", pulse_devin,
1289 NULL);
1290
1291 /* increment n-soundcards */
1292 g_rec_mutex_lock(pulse_server_mutex);
1293
1294 pulse_server->n_soundcards += 1;
1295
1296 g_rec_mutex_unlock(pulse_server_mutex);
1297 }
1298
1299 return((GObject *) soundcard);
1300 }
1301
1302 void
ags_pulse_server_unregister_soundcard(AgsSoundServer * sound_server,GObject * soundcard)1303 ags_pulse_server_unregister_soundcard(AgsSoundServer *sound_server,
1304 GObject *soundcard)
1305 {
1306 AgsPulseServer *pulse_server;
1307 AgsPulseClient *default_client;
1308
1309 GList *list_start, *list;
1310 GList *port;
1311
1312 GRecMutex *pulse_server_mutex;
1313
1314 pulse_server = AGS_PULSE_SERVER(sound_server);
1315
1316 /* get pulse server mutex */
1317 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1318
1319 /* the default client */
1320 g_object_get(pulse_server,
1321 "default-pulse-client", &default_client,
1322 NULL);
1323
1324 if(default_client == NULL){
1325 g_warning("GSequencer - no pulse client");
1326
1327 return;
1328 }
1329
1330 if(AGS_IS_PULSE_DEVOUT(soundcard)){
1331 g_object_get(soundcard,
1332 "pulse-port", &list_start,
1333 NULL);
1334
1335 list = list_start;
1336
1337 while(list != NULL){
1338 ags_pulse_port_unregister(list->data);
1339 ags_pulse_client_remove_port(default_client,
1340 list->data);
1341
1342 list = list->next;
1343 }
1344
1345 g_list_free_full(list_start,
1346 g_object_unref);
1347 }else if(AGS_IS_PULSE_DEVIN(soundcard)){
1348 g_object_get(soundcard,
1349 "pulse-port", &list_start,
1350 NULL);
1351
1352 list = list_start;
1353
1354 while(list != NULL){
1355 ags_pulse_port_unregister(list->data);
1356 ags_pulse_client_remove_port(default_client,
1357 list->data);
1358
1359 list = list->next;
1360 }
1361
1362 g_list_free_full(list_start,
1363 g_object_unref);
1364 }
1365
1366 ags_pulse_client_remove_device(default_client,
1367 soundcard);
1368
1369 g_object_get(default_client,
1370 "port", &port,
1371 NULL);
1372
1373 if(port == NULL){
1374 /* reset n-soundcards */
1375 g_rec_mutex_lock(pulse_server_mutex);
1376
1377 pulse_server->n_soundcards = 0;
1378
1379 g_rec_mutex_unlock(pulse_server_mutex);
1380 }
1381
1382 g_object_unref(default_client);
1383
1384 g_list_free_full(port,
1385 g_object_unref);
1386 }
1387
1388 GObject*
ags_pulse_server_register_sequencer(AgsSoundServer * sound_server,gboolean is_output)1389 ags_pulse_server_register_sequencer(AgsSoundServer *sound_server,
1390 gboolean is_output)
1391 {
1392 g_message("GSequencer - can't register pulseaudio sequencer");
1393
1394 return(NULL);
1395 }
1396
1397 void
ags_pulse_server_unregister_sequencer(AgsSoundServer * sound_server,GObject * sequencer)1398 ags_pulse_server_unregister_sequencer(AgsSoundServer *sound_server,
1399 GObject *sequencer)
1400 {
1401 g_message("GSequencer - can't unregister pulseaudio sequencer");
1402 }
1403
1404 /**
1405 * ags_pulse_server_register_default_soundcard:
1406 * @pulse_server: the #AgsPulseServer
1407 *
1408 * Register default soundcard.
1409 *
1410 * Returns: the instantiated #AgsPulseDevout
1411 *
1412 * Since: 3.0.0
1413 */
1414 GObject*
ags_pulse_server_register_default_soundcard(AgsPulseServer * pulse_server)1415 ags_pulse_server_register_default_soundcard(AgsPulseServer *pulse_server)
1416 {
1417 AgsPulseClient *default_client;
1418 AgsPulseDevout *pulse_devout;
1419 AgsPulsePort *pulse_port;
1420
1421 AgsApplicationContext *application_context;
1422
1423 #ifdef AGS_WITH_PULSE
1424 pa_context *context;
1425 #else
1426 gpointer context;
1427 #endif
1428
1429 gchar *str;
1430
1431 guint i;
1432
1433 GRecMutex *pulse_server_mutex;
1434 GRecMutex *pulse_client_mutex;
1435
1436 if(!AGS_IS_PULSE_SERVER(pulse_server)){
1437 return(NULL);
1438 }
1439
1440 application_context = ags_application_context_get_instance();
1441
1442 /* get pulse server mutex */
1443 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1444
1445 /* get some fields */
1446 g_rec_mutex_lock(pulse_server_mutex);
1447
1448 default_client = (AgsPulseClient *) pulse_server->default_client;
1449
1450 g_rec_mutex_unlock(pulse_server_mutex);
1451
1452 /* the default client */
1453 if(default_client == NULL){
1454 default_client = ags_pulse_client_new((GObject *) pulse_server);
1455
1456 g_object_set(pulse_server,
1457 "default-pulse-client", default_client,
1458 NULL);
1459 ags_pulse_server_add_client(pulse_server,
1460 (GObject *) default_client);
1461
1462 ags_pulse_client_open((AgsPulseClient *) default_client,
1463 "ags-default-client");
1464 }
1465
1466 /* get pulse client mutex */
1467 pulse_client_mutex = AGS_PULSE_CLIENT_GET_OBJ_MUTEX(default_client);
1468
1469 /* get context */
1470 g_rec_mutex_lock(pulse_client_mutex);
1471
1472 context = default_client->context;
1473
1474 g_rec_mutex_unlock(pulse_client_mutex);
1475
1476 if(context == NULL){
1477 g_warning("ags_pulse_server.c - can't open pulseaudio client");
1478 }
1479
1480 /* the soundcard */
1481 pulse_devout = ags_pulse_devout_new();
1482
1483 g_object_set(AGS_PULSE_DEVOUT(pulse_devout),
1484 "pulse-client", default_client,
1485 "device", "ags-default-devout",
1486 NULL);
1487
1488 /* register ports */
1489 str = g_strdup_printf("ags-default-soundcard");
1490
1491 #ifdef AGS_DEBUG
1492 g_message("%s", str);
1493 #endif
1494
1495 pulse_port = ags_pulse_port_new((GObject *) default_client);
1496 g_object_set(pulse_port,
1497 "pulse-devout", pulse_devout,
1498 NULL);
1499 ags_pulse_client_add_port(default_client,
1500 (GObject *) pulse_port);
1501
1502 g_object_set(pulse_devout,
1503 "pulse-port", pulse_port,
1504 NULL);
1505
1506 pulse_devout->port_name = (gchar **) malloc(2 * sizeof(gchar *));
1507 pulse_devout->port_name[0] = g_strdup(str);
1508 pulse_devout->port_name[1] = NULL;
1509
1510 ags_pulse_port_register(pulse_port,
1511 str,
1512 TRUE, FALSE,
1513 TRUE);
1514
1515 g_free(str);
1516
1517 g_object_set(default_client,
1518 "device", pulse_devout,
1519 NULL);
1520
1521 return((GObject *) pulse_devout);
1522 }
1523
1524 /**
1525 * ags_pulse_server_find_url:
1526 * @pulse_server: (element-type AgsAudio.PulseServer) (transfer none): the #GList-struct containing #AgsPulseServer
1527 * @url: the url to find
1528 *
1529 * Find #AgsPulseServer by url.
1530 *
1531 * Returns: (element-type AgsAudio.PulseServer) (transfer none): the #GList-struct containing a #AgsPulseServer matching @url or %NULL
1532 *
1533 * Since: 3.0.0
1534 */
1535 GList*
ags_pulse_server_find_url(GList * pulse_server,gchar * url)1536 ags_pulse_server_find_url(GList *pulse_server,
1537 gchar *url)
1538 {
1539 GList *retval;
1540
1541 GRecMutex *pulse_server_mutex;
1542
1543 retval = NULL;
1544
1545 while(pulse_server != NULL){
1546 /* get pulse server mutex */
1547 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server->data);
1548
1549 /* check URL */
1550 g_rec_mutex_lock(pulse_server_mutex);
1551
1552 if(!g_ascii_strcasecmp(AGS_PULSE_SERVER(pulse_server->data)->url,
1553 url)){
1554 retval = pulse_server;
1555
1556 g_rec_mutex_unlock(pulse_server_mutex);
1557
1558 break;
1559 }
1560
1561 g_rec_mutex_unlock(pulse_server_mutex);
1562
1563 pulse_server = pulse_server->next;
1564 }
1565
1566 return(retval);
1567 }
1568
1569 /**
1570 * ags_pulse_server_find_client:
1571 * @pulse_server: the #AgsPulseServer
1572 * @client_uuid: the uuid to find
1573 *
1574 * Find #AgsPulseClient by uuid.
1575 *
1576 * Returns: (transfer none): the #AgsPulseClient found or %NULL
1577 *
1578 * Since: 3.0.0
1579 */
1580 GObject*
ags_pulse_server_find_client(AgsPulseServer * pulse_server,gchar * client_uuid)1581 ags_pulse_server_find_client(AgsPulseServer *pulse_server,
1582 gchar *client_uuid)
1583 {
1584 AgsPulseClient *retval;
1585
1586 GList *list_start, *list;
1587
1588 GRecMutex *pulse_server_mutex;
1589 GRecMutex *pulse_client_mutex;
1590
1591 if(!AGS_IS_PULSE_SERVER(pulse_server)){
1592 return(NULL);
1593 }
1594
1595 /* get pulse server mutex */
1596 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1597
1598 /* get some fields */
1599 g_rec_mutex_lock(pulse_server_mutex);
1600
1601 list =
1602 list_start = g_list_copy(pulse_server->client);
1603
1604 g_rec_mutex_unlock(pulse_server_mutex);
1605
1606 retval = NULL;
1607
1608 while(list != NULL){
1609 /* get pulse client mutex */
1610 pulse_client_mutex = AGS_PULSE_CLIENT_GET_OBJ_MUTEX(list->data);
1611
1612 /* check client UUID */
1613 g_rec_mutex_lock(pulse_client_mutex);
1614
1615 if(!g_ascii_strcasecmp(AGS_PULSE_CLIENT(list->data)->client_uuid,
1616 client_uuid)){
1617 retval = list->data;
1618
1619 g_rec_mutex_unlock(pulse_client_mutex);
1620
1621 break;
1622 }
1623
1624 g_rec_mutex_unlock(pulse_client_mutex);
1625
1626 list = list->next;
1627 }
1628
1629 g_list_free(list_start);
1630
1631 return((GObject *) retval);
1632 }
1633
1634 /**
1635 * ags_pulse_server_find_port:
1636 * @pulse_server: the #AgsPulseServer
1637 * @port_uuid: the uuid to find
1638 *
1639 * Find #AgsPulsePort by uuid.
1640 *
1641 * Returns: (transfer none): the #AgsPulsePort found or %NULL
1642 *
1643 * Since: 3.0.0
1644 */
1645 GObject*
ags_pulse_server_find_port(AgsPulseServer * pulse_server,gchar * port_uuid)1646 ags_pulse_server_find_port(AgsPulseServer *pulse_server,
1647 gchar *port_uuid)
1648 {
1649 GList *client_start, *client;
1650 GList *port_start, *port;
1651
1652 gboolean success;
1653
1654 GRecMutex *pulse_port_mutex;
1655
1656 g_object_get(pulse_server,
1657 "pulse-client", &client_start,
1658 NULL);
1659
1660 client = client_start;
1661
1662 while(client != NULL){
1663 g_object_get(pulse_server,
1664 "pulse-port", &port_start,
1665 NULL);
1666
1667 port = port_start;
1668
1669 while(port != NULL){
1670 /* get pulse port mutex */
1671 pulse_port_mutex = AGS_PULSE_PORT_GET_OBJ_MUTEX(port->data);
1672
1673 /* check port UUID */
1674 g_rec_mutex_lock(pulse_port_mutex);
1675
1676 success = (!g_ascii_strcasecmp(AGS_PULSE_PORT(port->data)->port_uuid,
1677 port_uuid)) ? TRUE: FALSE;
1678
1679 g_rec_mutex_unlock(pulse_port_mutex);
1680
1681 if(success){
1682 AgsPulsePort *retval;
1683
1684 retval = port->data;
1685
1686 g_list_free_full(client_start,
1687 g_object_unref);
1688 g_list_free_full(port_start,
1689 g_object_unref);
1690
1691 return(retval);
1692 }
1693
1694 /* iterate */
1695 port = port->next;
1696 }
1697
1698 g_list_free_full(port_start,
1699 g_object_unref);
1700
1701 /* iterate */
1702 client = client->next;
1703 }
1704
1705 g_list_free_full(client_start,
1706 g_object_unref);
1707
1708 return(NULL);
1709 }
1710
1711 /**
1712 * ags_pulse_server_add_client:
1713 * @pulse_server: the #AgsPulseServer
1714 * @pulse_client: the #AgsPulseClient to add
1715 *
1716 * Add @pulse_client to @pulse_server
1717 *
1718 * Since: 3.0.0
1719 */
1720 void
ags_pulse_server_add_client(AgsPulseServer * pulse_server,GObject * pulse_client)1721 ags_pulse_server_add_client(AgsPulseServer *pulse_server,
1722 GObject *pulse_client)
1723 {
1724 GRecMutex *pulse_server_mutex;
1725
1726 if(!AGS_IS_PULSE_SERVER(pulse_server) ||
1727 !AGS_IS_PULSE_CLIENT(pulse_client)){
1728 return;
1729 }
1730
1731 /* get pulse server mutex */
1732 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1733
1734 /* get some fields */
1735 g_rec_mutex_lock(pulse_server_mutex);
1736
1737 if(g_list_find(pulse_server->client, pulse_client) == NULL){
1738 g_object_ref(pulse_client);
1739 pulse_server->client = g_list_prepend(pulse_server->client,
1740 pulse_client);
1741 }
1742
1743 g_rec_mutex_unlock(pulse_server_mutex);
1744 }
1745
1746 /**
1747 * ags_pulse_server_remove_client:
1748 * @pulse_server: the #AgsPulseServer
1749 * @pulse_client: the #AgsPulseClient to remove
1750 *
1751 * Remove @pulse_client to @pulse_server
1752 *
1753 * Since: 3.0.0
1754 */
1755 void
ags_pulse_server_remove_client(AgsPulseServer * pulse_server,GObject * pulse_client)1756 ags_pulse_server_remove_client(AgsPulseServer *pulse_server,
1757 GObject *pulse_client)
1758 {
1759 GRecMutex *pulse_server_mutex;
1760
1761 if(!AGS_IS_PULSE_SERVER(pulse_server) ||
1762 !AGS_IS_PULSE_CLIENT(pulse_client)){
1763 return;
1764 }
1765
1766 /* get pulse server mutex */
1767 pulse_server_mutex = AGS_PULSE_SERVER_GET_OBJ_MUTEX(pulse_server);
1768
1769 /* get some fields */
1770 g_rec_mutex_lock(pulse_server_mutex);
1771
1772 if(g_list_find(pulse_server->client, pulse_client) != NULL){
1773 pulse_server->client = g_list_remove(pulse_server->client,
1774 pulse_client);
1775 g_object_unref(pulse_client);
1776 }
1777
1778 g_rec_mutex_unlock(pulse_server_mutex);
1779 }
1780
1781 /**
1782 * ags_pulse_server_connect_client:
1783 * @pulse_server: the #AgsPulseServer
1784 *
1785 * Connect all clients.
1786 *
1787 * Since: 3.0.0
1788 */
1789 void
ags_pulse_server_connect_client(AgsPulseServer * pulse_server)1790 ags_pulse_server_connect_client(AgsPulseServer *pulse_server)
1791 {
1792 GList *client_start, *client;
1793
1794 gchar *client_name;
1795
1796 GRecMutex *pulse_client_mutex;
1797
1798 if(!AGS_IS_PULSE_SERVER(pulse_server)){
1799 return;
1800 }
1801
1802 g_object_get(pulse_server,
1803 "pulse-client", &client_start,
1804 NULL);
1805
1806 client = client_start;
1807
1808 while(client != NULL){
1809 /* client name */
1810 g_object_get(client->data,
1811 "client-name", &client_name,
1812 NULL);
1813
1814 /* open */
1815 ags_pulse_client_open((AgsPulseClient *) client->data,
1816 client_name);
1817 ags_pulse_client_activate(client->data);
1818
1819 /* iterate */
1820 client = client->next;
1821 }
1822
1823 g_list_free_full(client_start,
1824 g_object_unref);
1825 }
1826
1827 /**
1828 * ags_pulse_server_disconnect_client:
1829 * @pulse_server: the #AgsPulseServer
1830 *
1831 * Disconnect all clients.
1832 *
1833 * Since: 3.0.0
1834 */
1835 void
ags_pulse_server_disconnect_client(AgsPulseServer * pulse_server)1836 ags_pulse_server_disconnect_client(AgsPulseServer *pulse_server)
1837 {
1838 GList *client_start, *client;
1839
1840 if(!AGS_IS_PULSE_SERVER(pulse_server)){
1841 return;
1842 }
1843
1844 g_object_get(pulse_server,
1845 "pulse-client", &client_start,
1846 NULL);
1847
1848 client = client_start;
1849
1850 while(client != NULL){
1851 /* close */
1852 ags_pulse_client_deactivate(client->data);
1853
1854 ags_pulse_client_close((AgsPulseClient *) client->data);
1855
1856 /* iterate */
1857 client = client->next;
1858 }
1859
1860 g_list_free_full(client_start,
1861 g_object_unref);
1862 }
1863
1864
1865 void*
ags_pulse_server_do_poll_loop(void * ptr)1866 ags_pulse_server_do_poll_loop(void *ptr)
1867 {
1868 AgsPulseServer *pulse_server;
1869
1870 #ifdef AGS_WITH_RT
1871 AgsPriority *priority;
1872
1873 struct sched_param param;
1874
1875 gchar *str;
1876 #endif
1877
1878 pulse_server = (AgsPulseServer *) ptr;
1879
1880 /* Declare ourself as a real time task */
1881 #ifdef AGS_WITH_RT
1882 priority = ags_priority_get_instance();
1883
1884 /* Declare ourself as a real time task */
1885 param.sched_priority = 45;
1886
1887 str = ags_priority_get_value(priority,
1888 AGS_PRIORITY_RT_THREAD,
1889 AGS_PRIORITY_KEY_AUDIO);
1890
1891 if(str != NULL){
1892 param.sched_priority = (int) g_ascii_strtoull(str,
1893 NULL,
1894 10);
1895 }
1896
1897 if(str == NULL ||
1898 ((!g_ascii_strncasecmp(str,
1899 "0",
1900 2)) != TRUE)){
1901 if(sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
1902 perror("sched_setscheduler failed");
1903 }
1904 }
1905
1906 g_free(str);
1907 #endif
1908
1909 #ifdef AGS_WITH_PULSE
1910 pa_mainloop_run(pulse_server->main_loop,
1911 NULL);
1912 #endif
1913
1914 g_thread_exit(NULL);
1915
1916 return(NULL);
1917 }
1918
1919 void
ags_pulse_server_start_poll(AgsPulseServer * pulse_server)1920 ags_pulse_server_start_poll(AgsPulseServer *pulse_server)
1921 {
1922 pulse_server->thread = g_thread_new("Advanced Gtk+ Sequencer - pulseaudio server",
1923 ags_pulse_server_do_poll_loop,
1924 pulse_server);
1925 }
1926
1927 /**
1928 * ags_pulse_server_new:
1929 * @url: the URL as string
1930 *
1931 * Create a new instance of #AgsPulseServer.
1932 *
1933 * Returns: the new #AgsPulseServer
1934 *
1935 * Since: 3.0.0
1936 */
1937 AgsPulseServer*
ags_pulse_server_new(gchar * url)1938 ags_pulse_server_new(gchar *url)
1939 {
1940 AgsPulseServer *pulse_server;
1941
1942 pulse_server = (AgsPulseServer *) g_object_new(AGS_TYPE_PULSE_SERVER,
1943 "url", url,
1944 NULL);
1945
1946 return(pulse_server);
1947 }
1948