--- libcheese/cheese-camera-device-monitor.c.orig 2010-08-16 23:00:43.000000000 +0200 +++ libcheese/cheese-camera-device-monitor.c 2010-08-18 09:51:48.000000000 +0200 @@ -24,24 +24,11 @@ #endif #include +#include #include +#include #include - -#ifdef HAVE_UDEV - #define G_UDEV_API_IS_SUBJECT_TO_CHANGE 1 - #include -#else - #include - #include - #include - #if USE_SYS_VIDEOIO_H > 0 - #include - #include - #elif defined (__sun) - #include - #include - #endif /* USE_SYS_VIDEOIO_H */ -#endif +#include #include "cheese-camera-device-monitor.h" #include "cheese-marshal.h" @@ -54,9 +41,9 @@ * #CheeseCameraDeviceMonitor provides a basic interface for * video4linux device enumeration and hotplugging. * - * It uses either GUdev or some platform specific code to list video + * It uses either HAL or some platform specific code to list video * devices. It is also capable (right now in linux only, with the - * udev backend) to monitor device plugging and emit a + * hal backend) to monitor device plugging and emit a * CheeseCameraDeviceMonitor::added or * CheeseCameraDeviceMonitor::removed signal when an event happens. */ @@ -80,11 +67,9 @@ enum CheeseCameraDeviceMonitorError typedef struct { -#ifdef HAVE_UDEV - GUdevClient *client; -#else + DBusConnection *connection; + LibHalContext *hal_ctx; guint filler; -#endif /* HAVE_UDEV */ } CheeseCameraDeviceMonitorPrivate; enum @@ -102,111 +87,77 @@ cheese_camera_device_monitor_error_quark return g_quark_from_static_string ("cheese-camera-error-quark"); } -#ifdef HAVE_UDEV -static void -cheese_camera_device_monitor_added (CheeseCameraDeviceMonitor *monitor, - GUdevDevice *udevice) +cheese_camera_device_monitor_handle_udi (CheeseCameraDeviceMonitor *monitor, + const char *udi) { - const char *device_file; - const char *product_name; - const char *vendor; - const char *product; - const char *bus; - gint vendor_id = 0; - gint product_id = 0; + CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); + char *device_file; + char *product_name; + char *capstr; gint v4l_version = 0; + DBusError error; - const gchar *devpath = g_udev_device_get_property (udevice, "DEVPATH"); + GST_INFO ("Checking hal device '%s'", udi); - GST_INFO ("Checking udev device '%s'", devpath); + dbus_error_init (&error); - bus = g_udev_device_get_property (udevice, "ID_BUS"); - if (g_strcmp0 (bus, "usb") == 0) - { - vendor = g_udev_device_get_property (udevice, "ID_VENDOR_ID"); - if (vendor != NULL) - vendor_id = g_ascii_strtoll (vendor, NULL, 16); - product = g_udev_device_get_property (udevice, "ID_MODEL_ID"); - if (product != NULL) - product_id = g_ascii_strtoll (product, NULL, 16); - if (vendor_id == 0 || product_id == 0) - { - GST_WARNING ("Error getting vendor and product id"); - } - else - { - GST_INFO ("Found device %04x:%04x, getting capabilities...", vendor_id, product_id); - } - } - else + product_name = libhal_device_get_property_string (priv->hal_ctx, udi, "info.product", &error); + if (dbus_error_is_set (&error)) { - GST_INFO ("Not an usb device, skipping vendor and model id retrieval"); + GST_WARNING ("error getting product name: %s: %s", error.name, error.message); + dbus_error_free (&error); + return; } - device_file = g_udev_device_get_device_file (udevice); - if (device_file == NULL) + device_file = libhal_device_get_property_string (priv->hal_ctx, udi, "video4linux.device", &error); + if (dbus_error_is_set (&error)) { - GST_WARNING ("Error getting V4L device"); - return; + GST_WARNING ("error getting V4L device for %s: %s: %s", udi, error.name, error.message); + dbus_error_free (&error); + libhal_free_string (product_name); } - /* vbi devices support capture capability too, but cannot be used, - * so detect them by device name */ - if (strstr (device_file, "vbi")) + if (g_access (device_file, (R_OK | W_OK)) == -1) { - GST_INFO ("Skipping vbi device: %s", device_file); + GST_WARNING ("Device %s does not have proper permissions. Permissions must be 0666", device_file); + libhal_free_string (product_name); + libhal_free_string (device_file); return; } - v4l_version = g_udev_device_get_property_as_int (udevice, "ID_V4L_VERSION"); - if (v4l_version == 2 || v4l_version == 1) + capstr = libhal_device_get_property_string (priv->hal_ctx, udi, "video4linux.version", &error); + if (dbus_error_is_set (&error)) { - const char *caps; - - caps = g_udev_device_get_property (udevice, "ID_V4L_CAPABILITIES"); - if (caps == NULL || strstr (caps, ":capture:") == NULL) - { - GST_WARNING ("Device %s seems to not have the capture capability, (radio tuner?)" - "Removing it from device list.", device_file); - return; - } - product_name = g_udev_device_get_property (udevice, "ID_V4L_PRODUCT"); - } - else if (v4l_version == 0) - { - GST_ERROR ("Fix your udev installation to include v4l_id, ignoring %s", device_file); + GST_WARNING ("error getting V4L version for %s: %s: %s", udi, error.name, error.message); + dbus_error_free (&error); + libhal_free_string (product_name); + libhal_free_string (device_file); return; } - else - { - g_assert_not_reached (); - } + + v4l_version = atoi (capstr); + libhal_free_string (capstr); g_signal_emit (monitor, monitor_signals[ADDED], 0, - devpath, + udi, device_file, product_name, v4l_version); } static void -cheese_camera_device_monitor_removed (CheeseCameraDeviceMonitor *monitor, - GUdevDevice *udevice) -{ - g_signal_emit (monitor, monitor_signals[REMOVED], 0, - g_udev_device_get_property (udevice, "DEVPATH")); -} +cheese_camera_device_monitor_removed (LibHalContext *ctx, + const char *udi) + { + CheeseCameraDeviceMonitor *monitor; + void *data; -static void -cheese_camera_device_monitor_uevent_cb (GUdevClient *client, - const gchar *action, - GUdevDevice *udevice, - CheeseCameraDeviceMonitor *monitor) -{ - if (g_str_equal (action, "remove")) - cheese_camera_device_monitor_removed (monitor, udevice); - else if (g_str_equal (action, "add")) - cheese_camera_device_monitor_added (monitor, udevice); + data = libhal_ctx_get_user_data (ctx); + g_assert (data); + + monitor = CHEESE_CAMERA_DEVICE_MONITOR (data); + + g_signal_emit (monitor, monitor_signals[REMOVED], 0, udi); } /** @@ -222,115 +173,85 @@ void cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor) { CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); - GList *devices, *l; - gint i = 0; + int i; + int num_udis = 0; + char **udis; + DBusError error; - if (priv->client == NULL) - return; + GST_INFO ("Probing devices with HAL..."); - GST_INFO ("Probing devices with udev..."); + if (priv->hal_ctx == NULL) + return; - devices = g_udev_client_query_by_subsystem (priv->client, "video4linux"); + dbus_error_init (&error); - /* Initialize camera structures */ - for (l = devices; l != NULL; l = l->next) + udis = libhal_find_device_by_capability (priv->hal_ctx, "video4linux", &num_udis, &error); + + if (dbus_error_is_set (&error)) { - cheese_camera_device_monitor_added (monitor, l->data); - g_object_unref (l->data); - i++; + GST_WARNING ("libhal_find_device_by_capability: %s: %s", error.name, error.message); + dbus_error_free (&error); + return; } - g_list_free (devices); + + /* Initialize camera structures */ + for (i = 0; i < num_udis; i++) + cheese_camera_device_monitor_handle_udi (monitor, udis[i]); + libhal_free_string_array (udis); if (i == 0) GST_WARNING ("No device found"); } -#else /* HAVE_UDEV */ -void -cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor) +static void +cheese_camera_device_monitor_added (LibHalContext *ctx, const char *udi) { - #if 0 - CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); - struct v4l2_capability v2cap; - struct video_capability v1cap; - int fd, ok; - - if ((fd = open (device_path, O_RDONLY | O_NONBLOCK)) < 0) - { - g_warning ("Failed to open %s: %s", device_path, strerror (errno)); - return; - } - ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap); - if (ok < 0) - { - ok = ioctl (fd, VIDIOCGCAP, &v1cap); - if (ok < 0) - { - g_warning ("Error while probing v4l capabilities for %s: %s", - device_path, strerror (errno)); - close (fd); - return; - } - g_print ("Detected v4l device: %s\n", v1cap.name); - g_print ("Device type: %d\n", v1cap.type); - gstreamer_src = "v4lsrc"; - product_name = v1cap.name; - } - else - { - guint cap = v2cap.capabilities; - g_print ("Detected v4l2 device: %s\n", v2cap.card); - g_print ("Driver: %s, version: %d\n", v2cap.driver, v2cap.version); - - /* g_print ("Bus info: %s\n", v2cap.bus_info); */ /* Doesn't seem anything useful */ - g_print ("Capabilities: 0x%08X\n", v2cap.capabilities); - if (!(cap & V4L2_CAP_VIDEO_CAPTURE)) - { - g_print ("Device %s seems to not have the capture capability, (radio tuner?)\n" - "Removing it from device list.\n", device_path); - close (fd); - return; - } - gstreamer_src = "v4l2src"; - product_name = (char *) v2cap.card; - } - close (fd); + CheeseCameraDeviceMonitor *monitor; + char **caps; + guint i; + void *data; - GList *devices, *l; + data = libhal_ctx_get_user_data (ctx); + g_assert (data); - g_print ("Probing devices with udev...\n"); + monitor = CHEESE_CAMERA_DEVICE_MONITOR (data); - if (priv->client == NULL) + caps = libhal_device_get_property_strlist (ctx, udi, "info.capabilities", NULL); + if (caps == NULL) return; - devices = g_udev_client_query_by_subsystem (priv->client, "video4linux"); - - /* Initialize camera structures */ - for (l = devices; l != NULL; l = l->next) + for (i = 0; caps[i] != NULL; i++) { - cheese_camera_device_monitor_added (monitor, l->data); - g_object_unref (l->data); + if (g_strcmp0 (caps[i], "video4linux") == 0) + { + cheese_camera_device_monitor_handle_udi (monitor, udi); + break; + } } - g_list_free (devices); - #endif -} -#endif /* HAVE_UDEV */ + libhal_free_string_array (caps); +} static void cheese_camera_device_monitor_finalize (GObject *object) { -#ifdef HAVE_UDEV CheeseCameraDeviceMonitor *monitor; monitor = CHEESE_CAMERA_DEVICE_MONITOR (object); CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); - if (priv->client != NULL) + if (priv->connection != NULL) { - g_object_unref (priv->client); - priv->client = NULL; + dbus_connection_unref (priv->connection); + priv->connection = NULL; } -#endif /* HAVE_UDEV */ + if (priv->hal_ctx != NULL) + { + libhal_ctx_set_device_added (priv->hal_ctx, NULL); + libhal_ctx_set_device_removed (priv->hal_ctx, NULL); + libhal_ctx_free (priv->hal_ctx); + priv->hal_ctx = NULL; + } + G_OBJECT_CLASS (cheese_camera_device_monitor_parent_class)->finalize (object); } @@ -385,14 +306,52 @@ cheese_camera_device_monitor_class_init static void cheese_camera_device_monitor_init (CheeseCameraDeviceMonitor *monitor) { -#ifdef HAVE_UDEV - CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); - const gchar *const subsystems[] = {"video4linux", NULL}; - - priv->client = g_udev_client_new (subsystems); - g_signal_connect (G_OBJECT (priv->client), "uevent", - G_CALLBACK (cheese_camera_device_monitor_uevent_cb), monitor); -#endif /* HAVE_UDEV */ + CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor); + LibHalContext *hal_ctx; + DBusError error; + + dbus_error_init (&error); + + priv->connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + dbus_connection_set_exit_on_disconnect (priv->connection, FALSE); + + hal_ctx = libhal_ctx_new (); + if (hal_ctx == NULL) + { + GST_WARNING ("Could not create libhal context"); + dbus_error_free (&error); + return; + } + + if (!libhal_ctx_set_dbus_connection (hal_ctx, priv->connection)) + { + GST_WARNING ("libhal_ctx_set_dbus_connection: %s: %s", error.name, error.message); + dbus_error_free (&error); + return; + } + + if (!libhal_ctx_init (hal_ctx, &error)) + { + if (dbus_error_is_set (&error)) + { + GST_WARNING ("libhal_ctx_init: %s: %s", error.name, error.message); + dbus_error_free (&error); + } + GST_WARNING ("Could not initialise connection to hald.\n" + "Normally this means the HAL daemon (hald) is not running or not ready"); + return; + } + + dbus_connection_setup_with_g_main (priv->connection, NULL); + + if (!libhal_ctx_set_user_data (hal_ctx, monitor)) + GST_WARNING ("Failed to set user data on HAL context"); + if (!libhal_ctx_set_device_added (hal_ctx, cheese_camera_device_monitor_added)) + GST_WARNING ("Failed to connect to device added signal from HAL"); + if (!libhal_ctx_set_device_removed (hal_ctx, cheese_camera_device_monitor_removed)) + GST_WARNING ("Failed to connect to device removed signal from HAL"); + + priv->hal_ctx = hal_ctx; } /**