2 * Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
3 * Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
4 * Copyright (C) <2007> Sebastian Dröge <slomo@circular-chaos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * this library handles interaction with Hal
34 GST_DEBUG_CATEGORY_EXTERN (hal_debug);
36 #define GST_CAT_DEFAULT hal_debug
38 /* compat for older libhal */
39 #ifndef LIBHAL_FREE_DBUS_ERROR
40 #define LIBHAL_FREE_DBUS_ERROR(e) dbus_error_free (e)
44 * gst_hal_get_alsa_element:
45 * @ctx: a #LibHalContext which should be used for querying HAL.
46 * @udi: a #gchar corresponding to the UDI you want to get.
47 * @device_type: a #GstHalDeviceType specifying the wanted device type.
49 * Get Hal UDI @udi's string value.
51 * Returns: a newly allocated #gchar string containing the appropriate pipeline
52 * for UDI @udi, or NULL in the case of an error..
55 gst_hal_get_alsa_element (LibHalContext * ctx, const gchar * udi,
56 GstHalDeviceType device_type)
58 char *type, *string = NULL;
59 const char *element = NULL;
62 dbus_error_init (&error);
64 if (!libhal_device_query_capability (ctx, udi, "alsa", &error)) {
65 if (dbus_error_is_set (&error)) {
66 GST_DEBUG ("Failed querying %s for alsa capability: %s: %s",
67 udi, error.name, error.message);
68 LIBHAL_FREE_DBUS_ERROR (&error);
70 GST_DEBUG ("UDI %s has no alsa capability", udi);
75 type = libhal_device_get_property_string (ctx, udi, "alsa.type", &error);
77 if (dbus_error_is_set (&error)) {
78 GST_DEBUG ("UDI %s has alsa capabilities but no alsa.type property: %s, %s",
79 udi, error.name, error.message);
80 LIBHAL_FREE_DBUS_ERROR (&error);
83 GST_DEBUG ("UDI %s has empty alsa.type property", udi);
87 if (strcmp (type, "playback") == 0 && device_type == GST_HAL_AUDIOSINK)
89 else if (strcmp (type, "capture") == 0 && device_type == GST_HAL_AUDIOSRC)
92 libhal_free_string (type);
97 card = libhal_device_get_property_int (ctx, udi, "alsa.card", &error);
98 if (dbus_error_is_set (&error)) {
99 GST_DEBUG ("UDI %s has no alsa.card property: %s: %s", udi, error.name,
101 LIBHAL_FREE_DBUS_ERROR (&error);
103 } else if (card == -1) {
104 GST_DEBUG ("UDI %s has no alsa.card property", udi);
108 device = libhal_device_get_property_int (ctx, udi, "alsa.device", &error);
109 if (dbus_error_is_set (&error)) {
110 GST_DEBUG ("UDI %s has no alsa.device property: %s: %s", udi, error.name,
112 LIBHAL_FREE_DBUS_ERROR (&error);
114 } else if (device == -1) {
115 GST_DEBUG ("UDI %s has no alsa.device property", udi);
119 /* This is a bit dodgy, since it makes lots of assumptions about the way
120 * alsa is set up. In any case, only munge the device string for playback */
121 if (strcmp (element, "alsasink") == 0 && device == 0) {
122 /* handle default device specially to use
123 * dmix, dsnoop, and softvol if appropriate */
124 string = g_strdup_printf ("%s device=default:%d", element, card);
127 g_strdup_printf ("%s device=plughw:%d,%d", element, card, device);
135 * gst_hal_get_oss_element:
136 * @ctx: a #LibHalContext which should be used for querying HAL.
137 * @udi: a #gchar corresponding to the UDI you want to get.
138 * @device_type: a #GstHalDeviceType specifying the wanted device type.
140 * Get Hal UDI @udi's string value.
142 * Returns: a newly allocated #gchar string containing the appropriate pipeline
143 * for UDI @udi, or NULL in the case of an error..
146 gst_hal_get_oss_element (LibHalContext * ctx, const gchar * udi,
147 GstHalDeviceType device_type)
149 char *type, *string = NULL;
150 const char *element = NULL;
153 dbus_error_init (&error);
155 if (!libhal_device_query_capability (ctx, udi, "oss", &error)) {
156 if (dbus_error_is_set (&error)) {
157 GST_DEBUG ("Failed querying %s for oss capability: %s: %s", udi,
158 error.name, error.message);
159 LIBHAL_FREE_DBUS_ERROR (&error);
161 GST_DEBUG ("UDI %s has no oss capability", udi);
166 type = libhal_device_get_property_string (ctx, udi, "oss.type", &error);
167 if (dbus_error_is_set (&error)) {
168 GST_DEBUG ("UDI %s has oss capabilities but no oss.type property: %s, %s",
169 udi, error.name, error.message);
170 LIBHAL_FREE_DBUS_ERROR (&error);
173 GST_DEBUG ("UDI %s has empty oss.type property", udi);
177 if (strcmp (type, "pcm") == 0) {
178 if (device_type == GST_HAL_AUDIOSINK)
180 else if (device_type == GST_HAL_AUDIOSRC)
183 libhal_free_string (type);
189 libhal_device_get_property_string (ctx, udi, "oss.device_file", &error);
190 if (dbus_error_is_set (&error)) {
192 ("UDI %s has oss capabilities but no oss.device_file property: %s, %s",
193 udi, error.name, error.message);
194 LIBHAL_FREE_DBUS_ERROR (&error);
196 } else if (!device) {
197 GST_DEBUG ("UDI %s has empty oss.device_file property", udi);
201 string = g_strdup_printf ("%s device=%s", element, device);
202 libhal_free_string (device);
209 * gst_hal_get_string:
210 * @udi: a #gchar corresponding to the UDI you want to get.
211 * @device_type: a #GstHalDeviceType specifying the wanted device type.
213 * Get Hal UDI @udi's string value.
215 * Returns: a newly allocated #gchar string containing the appropriate pipeline
216 * for UDI @udi, or NULL in the case of an error..
219 gst_hal_get_string (const gchar * udi, GstHalDeviceType device_type)
225 /* Don't query HAL for NULL UDIs. Passing NULL as UDI to HAL gives
226 * an assertion failure in D-Bus when running with
227 * DBUS_FATAL_WARNINGS=1. */
231 dbus_error_init (&error);
233 ctx = libhal_ctx_new ();
234 /* Should only happen on OOM */
235 g_return_val_if_fail (ctx != NULL, NULL);
237 if (!libhal_ctx_set_dbus_connection (ctx, dbus_bus_get (DBUS_BUS_SYSTEM,
239 GST_DEBUG ("Unable to set DBus connection: %s: %s", error.name,
241 LIBHAL_FREE_DBUS_ERROR (&error);
245 if (!libhal_ctx_init (ctx, &error)) {
246 GST_DEBUG ("Unable to set init HAL context: %s: %s", error.name,
248 LIBHAL_FREE_DBUS_ERROR (&error);
252 /* Now first check if UDI is an alsa device, then oss and then
253 * check the childs of the given device. If there are alsa and oss
254 * children the first alsa one is used. */
256 string = gst_hal_get_alsa_element (ctx, udi, device_type);
259 string = gst_hal_get_oss_element (ctx, udi, device_type);
263 char **childs = NULL;
265 /* now try if one of the direct subdevices supports ALSA or OSS */
267 libhal_manager_find_device_string_match (ctx, "info.parent", udi,
268 &num_childs, &error);
269 if (dbus_error_is_set (&error)) {
270 GST_DEBUG ("Unable to retrieve childs of %s: %s: %s", udi, error.name,
272 LIBHAL_FREE_DBUS_ERROR (&error);
276 if (childs && num_childs > 0) {
278 char *alsa_string = NULL, *oss_string = NULL;
280 for (i = 0; i < num_childs && !alsa_string; i++) {
281 alsa_string = gst_hal_get_alsa_element (ctx, childs[i], device_type);
284 oss_string = gst_hal_get_oss_element (ctx, childs[i], device_type);
288 string = alsa_string;
290 } else if (oss_string) {
294 libhal_free_string_array (childs);
298 if (!libhal_ctx_shutdown (ctx, &error)) {
299 GST_DEBUG ("Closing connection to HAL failed: %s: %s", error.name,
301 LIBHAL_FREE_DBUS_ERROR (&error);
305 libhal_ctx_free (ctx);
307 if (string == NULL) {
308 GST_WARNING ("Problem finding a HAL audio device for udi %s", udi);
310 GST_INFO ("Using %s", string);
316 /* external functions */
319 * gst_hal_render_bin_from_udi:
320 * @udi: a #gchar string corresponding to a Hal UDI.
322 * Render bin from Hal UDI @udi.
324 * Returns: a #GstElement containing the rendered bin.
327 gst_hal_render_bin_from_udi (const gchar * udi, GstHalDeviceType type)
329 GstElement *bin = NULL;
332 value = gst_hal_get_string (udi, type);
334 bin = gst_parse_bin_from_description (value, TRUE, NULL);
340 * gst_hal_get_audio_sink:
341 * @udi: a #gchar string corresponding to a Hal UDI.
343 * Render audio output bin from GStreamer Hal UDI.
344 * If no device with the specified UDI exists or @udi is NULL,
345 * the default audio sink for the platform is used
346 * (typically alsasink, osssink or sunaudiosink).
348 * Returns: a #GstElement containing the audio output bin, or NULL if
352 gst_hal_get_audio_sink (const gchar * udi)
354 GstElement *ret = NULL;
357 ret = gst_hal_render_bin_from_udi (udi, GST_HAL_AUDIOSINK);
360 ret = gst_element_factory_make (DEFAULT_AUDIOSINK, NULL);
363 GST_ERROR ("Hal audio sink and %s don't work", DEFAULT_AUDIOSINK);
370 * gst_hal_get_audio_src:
371 * @udi: a #gchar string corresponding to a Hal UDI.
373 * Render audio acquisition bin from GStreamer Hal UDI.
374 * If no device with the specified UDI exists or @udi is NULL,
375 * the default audio source for the plaform is used
376 * (typically alsasrc, osssrc or sunaudiosrc).
378 * Returns: a #GstElement containing the audio source bin, or NULL if
382 gst_hal_get_audio_src (const gchar * udi)
384 GstElement *ret = NULL;
387 ret = gst_hal_render_bin_from_udi (udi, GST_HAL_AUDIOSRC);
390 ret = gst_element_factory_make (DEFAULT_AUDIOSRC, NULL);
393 GST_ERROR ("Hal audio src and %s don't work", DEFAULT_AUDIOSRC);