access: srt: add support stream encryption
[vlc.git] / modules / services_discovery / pulse.c
blob2c0771d2006dfdbd87e101306e08d29c3706677b
1 /**
2 * @file pulse.c
3 * @brief List of PulseAudio sources for VLC media player
4 */
5 /*****************************************************************************
6 * Copyright © 2011 Rémi Denis-Courmont
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 #include <search.h>
28 #include <assert.h>
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_services_discovery.h>
33 #include <pulse/pulseaudio.h>
34 #include "audio_output/vlcpulse.h"
36 static int Open (vlc_object_t *);
37 static void Close (vlc_object_t *);
39 VLC_SD_PROBE_HELPER("pulse", N_("Audio capture"), SD_CAT_DEVICES);
41 vlc_module_begin ()
42 set_shortname (N_("Audio capture"))
43 set_description (N_("Audio capture (PulseAudio)"))
44 set_category (CAT_PLAYLIST)
45 set_subcategory (SUBCAT_PLAYLIST_SD)
46 set_capability ("services_discovery", 0)
47 set_callbacks (Open, Close)
48 add_shortcut ("pulse", "pa", "pulseaudio", "audio")
50 VLC_SD_PROBE_SUBMODULE
51 vlc_module_end ()
53 struct services_discovery_sys_t
55 void *root;
56 pa_context *context;
57 pa_threaded_mainloop *mainloop;
60 static void SourceCallback(pa_context *, const pa_source_info *, int, void *);
61 static void ContextCallback(pa_context *, pa_subscription_event_type_t,
62 uint32_t, void *);
64 static int Open (vlc_object_t *obj)
66 services_discovery_t *sd = (services_discovery_t *)obj;
67 pa_operation *op;
68 pa_context *ctx;
70 services_discovery_sys_t *sys = malloc (sizeof (*sys));
71 if (unlikely(sys == NULL))
72 return VLC_ENOMEM;
74 ctx = vlc_pa_connect (obj, &sys->mainloop);
75 if (ctx == NULL)
77 free (sys);
78 return VLC_EGENERIC;
81 sd->p_sys = sys;
82 sd->description = _("Audio capture");
83 sys->context = ctx;
84 sys->root = NULL;
86 /* Subscribe for source events */
87 const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SOURCE;
88 pa_threaded_mainloop_lock (sys->mainloop);
89 pa_context_set_subscribe_callback (ctx, ContextCallback, sd);
90 op = pa_context_subscribe (ctx, mask, NULL, NULL);
91 if (likely(op != NULL))
92 pa_operation_unref (op);
94 /* Enumerate existing sources */
95 op = pa_context_get_source_info_list (ctx, SourceCallback, sd);
96 if (likely(op != NULL))
98 //while (pa_operation_get_state (op) == PA_OPERATION_RUNNING)
99 // pa_threaded_mainloop_wait (sys->mainloop);
100 pa_operation_unref (op);
102 pa_threaded_mainloop_unlock (sys->mainloop);
103 return VLC_SUCCESS;
105 error:
106 pa_threaded_mainloop_unlock (sys->mainloop);
107 vlc_pa_disconnect (obj, ctx, sys->mainloop);
108 free (sys);
109 return VLC_EGENERIC;*/
112 struct device
114 uint32_t index;
115 input_item_t *item;
116 services_discovery_t *sd;
119 static void DestroySource (void *data)
121 struct device *d = data;
123 services_discovery_RemoveItem (d->sd, d->item);
124 input_item_Release (d->item);
125 free (d);
129 * Compares two devices (to support binary search).
131 static int cmpsrc (const void *a, const void *b)
133 const uint32_t *pa = a, *pb = b;
134 uint32_t idxa = *pa, idxb = *pb;
136 return (idxa != idxb) ? ((idxa < idxb) ? -1 : +1) : 0;
140 * Adds a source.
142 static int AddSource (services_discovery_t *sd, const pa_source_info *info)
144 services_discovery_sys_t *sys = sd->p_sys;
146 msg_Dbg (sd, "adding %s (%s)", info->name, info->description);
148 char *mrl;
149 if (unlikely(asprintf (&mrl, "pulse://%s", info->name) == -1))
150 return -1;
152 input_item_t *item = input_item_NewCard (mrl, info->description);
153 free (mrl);
154 if (unlikely(item == NULL))
155 return -1;
157 struct device *d = malloc (sizeof (*d));
158 if (unlikely(d == NULL))
160 input_item_Release (item);
161 return -1;
163 d->index = info->index;
164 d->item = item;
166 struct device **dp = tsearch (d, &sys->root, cmpsrc);
167 if (dp == NULL) /* Out-of-memory */
169 free (d);
170 input_item_Release (item);
171 return -1;
173 if (*dp != d) /* Update existing source */
175 free (d);
176 d = *dp;
177 input_item_SetURI (d->item, item->psz_uri);
178 input_item_SetName (d->item, item->psz_name);
179 input_item_Release (item);
180 return 0;
183 const char *card = pa_proplist_gets(info->proplist, "device.product.name");
184 services_discovery_AddItemCat(sd, item,
185 (card != NULL) ? card : N_("Generic"));
186 d->sd = sd;
187 return 0;
190 static void SourceCallback(pa_context *ctx, const pa_source_info *i, int eol,
191 void *userdata)
193 services_discovery_t *sd = userdata;
195 if (eol)
196 return;
197 AddSource (sd, i);
198 (void) ctx;
202 * Removes a source (if present) by index.
204 static void RemoveSource (services_discovery_t *sd, uint32_t idx)
206 services_discovery_sys_t *sys = sd->p_sys;
208 struct device **dp = tfind (&idx, &sys->root, cmpsrc);
209 if (dp == NULL)
210 return;
212 struct device *d = *dp;
213 tdelete (d, &sys->root, cmpsrc);
214 DestroySource (d);
217 static void ContextCallback(pa_context *ctx, pa_subscription_event_type_t type,
218 uint32_t idx, void *userdata)
220 services_discovery_t *sd = userdata;
221 pa_operation *op;
223 assert ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)
224 == PA_SUBSCRIPTION_EVENT_SOURCE);
225 switch (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK)
227 case PA_SUBSCRIPTION_EVENT_NEW:
228 case PA_SUBSCRIPTION_EVENT_CHANGE:
229 op = pa_context_get_source_info_by_index(ctx, idx, SourceCallback, sd);
230 if (likely(op != NULL))
231 pa_operation_unref(op);
232 break;
234 case PA_SUBSCRIPTION_EVENT_REMOVE:
235 RemoveSource (sd, idx);
236 break;
240 static void Close (vlc_object_t *obj)
242 services_discovery_t *sd = (services_discovery_t *)obj;
243 services_discovery_sys_t *sys = sd->p_sys;
245 vlc_pa_disconnect (obj, sys->context, sys->mainloop);
246 tdestroy (sys->root, DestroySource);
247 free (sys);