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, &param) == -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