Blame telepathy-account-widgets/tp-account-widgets/cheese-camera-device-monitor.c

Packit 79f644
/* This file is a copy of cheese-camera-device-monitor.c from Tpaw. We
Packit 79f644
 * just renamespaced it to avoid conflicts when linking on libcheese. */
Packit 79f644
/*
Packit 79f644
 * Copyright © 2007,2008 Jaap Haitsma <jaap@haitsma.org>
Packit 79f644
 * Copyright © 2007-2009 daniel g. siegel <dgsiegel@gnome.org>
Packit 79f644
 * Copyright © 2008 Ryan Zeigler <zeiglerr@gmail.com>
Packit 79f644
 * Copyright © 2010 Filippo Argiolas <filippo.argiolas@gmail.com>
Packit 79f644
 *
Packit 79f644
 * This library is free software; you can redistribute it and/or
Packit 79f644
 * modify it under the terms of the GNU Lesser General Public
Packit 79f644
 * License as published by the Free Software Foundation; either
Packit 79f644
 * version 2.1 of the License, or (at your option) any later version.
Packit 79f644
 *
Packit 79f644
 * This library is distributed in the hope that it will be useful,
Packit 79f644
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 79f644
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 79f644
 * Lesser General Public License for more details.
Packit 79f644
 *
Packit 79f644
 * You should have received a copy of the GNU Lesser General Public
Packit 79f644
 * License along with this library; if not, write to the Free Software
Packit 79f644
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 79f644
 */
Packit 79f644
#ifdef HAVE_CONFIG_H
Packit 79f644
  #include "config.h"
Packit 79f644
#endif
Packit 79f644
Packit 79f644
#include <string.h>
Packit 79f644
Packit 79f644
#ifdef HAVE_UDEV
Packit 79f644
  #define G_UDEV_API_IS_SUBJECT_TO_CHANGE 1
Packit 79f644
  #include <gudev/gudev.h>
Packit 79f644
#else
Packit 79f644
  #include <fcntl.h>
Packit 79f644
  #include <unistd.h>
Packit 79f644
  #include <sys/ioctl.h>
Packit 79f644
  #if USE_SYS_VIDEOIO_H > 0
Packit 79f644
    #include <sys/types.h>
Packit 79f644
    #include <sys/videoio.h>
Packit 79f644
  #elif defined (__sun)
Packit 79f644
    #include <sys/types.h>
Packit 79f644
    #include <sys/videodev2.h>
Packit 79f644
  #endif /* USE_SYS_VIDEOIO_H */
Packit 79f644
#endif
Packit 79f644
Packit 79f644
#include "cheese-camera-device-monitor.h"
Packit 79f644
Packit 79f644
/**
Packit 79f644
 * SECTION:cheese-camera-device-monitor
Packit 79f644
 * @short_description: Simple object to enumerate v4l devices
Packit 79f644
 * @include: cheese/cheese-camera-device-monitor.h
Packit 79f644
 *
Packit 79f644
 * #TpawCameraDeviceMonitor provides a basic interface for
Packit 79f644
 * video4linux device enumeration and hotplugging.
Packit 79f644
 *
Packit 79f644
 * It uses either GUdev or some platform specific code to list video
Packit 79f644
 * devices.  It is also capable (right now in linux only, with the
Packit 79f644
 * udev backend) to monitor device plugging and emit a
Packit 79f644
 * TpawCameraDeviceMonitor::added or
Packit 79f644
 * TpawCameraDeviceMonitor::removed signal when an event happens.
Packit 79f644
 */
Packit 79f644
Packit 79f644
G_DEFINE_TYPE (TpawCameraDeviceMonitor, tpaw_camera_device_monitor, G_TYPE_OBJECT)
Packit 79f644
Packit 79f644
#define TPAW_CAMERA_DEVICE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),                               \
Packit 79f644
                                                                                  TPAW_TYPE_CAMERA_DEVICE_MONITOR, \
Packit 79f644
                                                                                  TpawCameraDeviceMonitorPrivate))
Packit 79f644
Packit 79f644
#define TPAW_CAMERA_DEVICE_MONITOR_ERROR tpaw_camera_device_monitor_error_quark ()
Packit 79f644
Packit 79f644
#define DEBUG_FLAG TPAW_DEBUG_OTHER
Packit 79f644
#include "tpaw-debug.h"
Packit 79f644
Packit 79f644
enum TpawCameraDeviceMonitorError
Packit 79f644
{
Packit 79f644
  TPAW_CAMERA_DEVICE_MONITOR_ERROR_UNKNOWN,
Packit 79f644
  TPAW_CAMERA_DEVICE_MONITOR_ERROR_ELEMENT_NOT_FOUND
Packit 79f644
};
Packit 79f644
Packit 79f644
typedef struct
Packit 79f644
{
Packit 79f644
#ifdef HAVE_UDEV
Packit 79f644
  GUdevClient *client;
Packit 79f644
#else
Packit 79f644
  guint filler;
Packit 79f644
#endif /* HAVE_UDEV */
Packit 79f644
} TpawCameraDeviceMonitorPrivate;
Packit 79f644
Packit 79f644
enum
Packit 79f644
{
Packit 79f644
  ADDED,
Packit 79f644
  REMOVED,
Packit 79f644
  LAST_SIGNAL
Packit 79f644
};
Packit 79f644
Packit 79f644
static guint monitor_signals[LAST_SIGNAL];
Packit 79f644
Packit 79f644
#if 0
Packit 79f644
GQuark
Packit 79f644
tpaw_camera_device_monitor_error_quark (void)
Packit 79f644
{
Packit 79f644
  return g_quark_from_static_string ("tpaw-camera-error-quark");
Packit 79f644
}
Packit 79f644
#endif
Packit 79f644
Packit 79f644
#ifdef HAVE_UDEV
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_added (TpawCameraDeviceMonitor *monitor,
Packit 79f644
                                    GUdevDevice               *udevice)
Packit 79f644
{
Packit 79f644
  const char *device_file;
Packit 79f644
  const char *product_name;
Packit 79f644
  const char *vendor;
Packit 79f644
  const char *product;
Packit 79f644
  const char *bus;
Packit 79f644
  gint        vendor_id   = 0;
Packit 79f644
  gint        product_id  = 0;
Packit 79f644
  gint        v4l_version = 0;
Packit 79f644
Packit 79f644
  const gchar *devpath = g_udev_device_get_property (udevice, "DEVPATH");
Packit 79f644
Packit 79f644
  DEBUG ("Checking udev device '%s'", devpath);
Packit 79f644
Packit 79f644
  bus = g_udev_device_get_property (udevice, "ID_BUS");
Packit 79f644
  if (g_strcmp0 (bus, "usb") == 0)
Packit 79f644
  {
Packit 79f644
    vendor = g_udev_device_get_property (udevice, "ID_VENDOR_ID");
Packit 79f644
    if (vendor != NULL)
Packit 79f644
      vendor_id = g_ascii_strtoll (vendor, NULL, 16);
Packit 79f644
    product = g_udev_device_get_property (udevice, "ID_MODEL_ID");
Packit 79f644
    if (product != NULL)
Packit 79f644
      product_id = g_ascii_strtoll (product, NULL, 16);
Packit 79f644
    if (vendor_id == 0 || product_id == 0)
Packit 79f644
    {
Packit 79f644
      DEBUG ("Error getting vendor and product id");
Packit 79f644
    }
Packit 79f644
    else
Packit 79f644
    {
Packit 79f644
      DEBUG ("Found device %04x:%04x, getting capabilities...", vendor_id, product_id);
Packit 79f644
    }
Packit 79f644
  }
Packit 79f644
  else
Packit 79f644
  {
Packit 79f644
    DEBUG ("Not an usb device, skipping vendor and model id retrieval");
Packit 79f644
  }
Packit 79f644
Packit 79f644
  device_file = g_udev_device_get_device_file (udevice);
Packit 79f644
  if (device_file == NULL)
Packit 79f644
  {
Packit 79f644
    DEBUG ("Error getting V4L device");
Packit 79f644
    return;
Packit 79f644
  }
Packit 79f644
Packit 79f644
  /* vbi devices support capture capability too, but cannot be used,
Packit 79f644
   * so detect them by device name */
Packit 79f644
  if (strstr (device_file, "vbi"))
Packit 79f644
  {
Packit 79f644
    DEBUG ("Skipping vbi device: %s", device_file);
Packit 79f644
    return;
Packit 79f644
  }
Packit 79f644
Packit 79f644
  v4l_version = g_udev_device_get_property_as_int (udevice, "ID_V4L_VERSION");
Packit 79f644
  if (v4l_version == 2 || v4l_version == 1)
Packit 79f644
  {
Packit 79f644
    const char *caps;
Packit 79f644
Packit 79f644
    caps = g_udev_device_get_property (udevice, "ID_V4L_CAPABILITIES");
Packit 79f644
    if (caps == NULL || strstr (caps, ":capture:") == NULL)
Packit 79f644
    {
Packit 79f644
      DEBUG ("Device %s seems to not have the capture capability, (radio tuner?)"
Packit 79f644
                   "Removing it from device list.", device_file);
Packit 79f644
      return;
Packit 79f644
    }
Packit 79f644
    product_name = g_udev_device_get_property (udevice, "ID_V4L_PRODUCT");
Packit 79f644
  }
Packit 79f644
  else if (v4l_version == 0)
Packit 79f644
  {
Packit 79f644
    DEBUG ("Fix your udev installation to include v4l_id, ignoring %s", device_file);
Packit 79f644
    return;
Packit 79f644
  }
Packit 79f644
  else
Packit 79f644
  {
Packit 79f644
    g_assert_not_reached ();
Packit 79f644
  }
Packit 79f644
Packit 79f644
  g_signal_emit (monitor, monitor_signals[ADDED], 0,
Packit 79f644
                 devpath,
Packit 79f644
                 device_file,
Packit 79f644
                 product_name,
Packit 79f644
                 v4l_version);
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_removed (TpawCameraDeviceMonitor *monitor,
Packit 79f644
                                      GUdevDevice               *udevice)
Packit 79f644
{
Packit 79f644
  g_signal_emit (monitor, monitor_signals[REMOVED], 0,
Packit 79f644
                 g_udev_device_get_property (udevice, "DEVPATH"));
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_uevent_cb (GUdevClient               *client,
Packit 79f644
                                        const gchar               *action,
Packit 79f644
                                        GUdevDevice               *udevice,
Packit 79f644
                                        TpawCameraDeviceMonitor *monitor)
Packit 79f644
{
Packit 79f644
  if (g_str_equal (action, "remove"))
Packit 79f644
    tpaw_camera_device_monitor_removed (monitor, udevice);
Packit 79f644
  else if (g_str_equal (action, "add"))
Packit 79f644
    tpaw_camera_device_monitor_added (monitor, udevice);
Packit 79f644
}
Packit 79f644
Packit 79f644
/**
Packit 79f644
 * tpaw_camera_device_monitor_coldplug:
Packit 79f644
 * @monitor: a #TpawCameraDeviceMonitor object.
Packit 79f644
 *
Packit 79f644
 * Will actively look for plugged in cameras and emit
Packit 79f644
 * ::added for those new cameras.
Packit 79f644
 * This is only required when your program starts, so as to connect
Packit 79f644
 * to those signals before they are emitted.
Packit 79f644
 */
Packit 79f644
void
Packit 79f644
tpaw_camera_device_monitor_coldplug (TpawCameraDeviceMonitor *monitor)
Packit 79f644
{
Packit 79f644
  TpawCameraDeviceMonitorPrivate *priv = TPAW_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
Packit 79f644
  GList                            *devices, *l;
Packit 79f644
  gint                              i = 0;
Packit 79f644
Packit 79f644
  if (priv->client == NULL)
Packit 79f644
    return;
Packit 79f644
Packit 79f644
  DEBUG ("Probing devices with udev...");
Packit 79f644
Packit 79f644
  devices = g_udev_client_query_by_subsystem (priv->client, "video4linux");
Packit 79f644
Packit 79f644
  /* Initialize camera structures */
Packit 79f644
  for (l = devices; l != NULL; l = l->next)
Packit 79f644
  {
Packit 79f644
    tpaw_camera_device_monitor_added (monitor, l->data);
Packit 79f644
    g_object_unref (l->data);
Packit 79f644
    i++;
Packit 79f644
  }
Packit 79f644
  g_list_free (devices);
Packit 79f644
Packit 79f644
  if (i == 0) DEBUG ("No device found");
Packit 79f644
}
Packit 79f644
Packit 79f644
#else /* HAVE_UDEV */
Packit 79f644
void
Packit 79f644
tpaw_camera_device_monitor_coldplug (TpawCameraDeviceMonitor *monitor)
Packit 79f644
{
Packit 79f644
  #if 0
Packit 79f644
  TpawCameraDeviceMonitorPrivate *priv = TPAW_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
Packit 79f644
  struct v4l2_capability            v2cap;
Packit 79f644
  struct video_capability           v1cap;
Packit 79f644
  int                               fd, ok;
Packit 79f644
Packit 79f644
  if ((fd = open (device_path, O_RDONLY | O_NONBLOCK)) < 0)
Packit 79f644
  {
Packit 79f644
    g_warning ("Failed to open %s: %s", device_path, strerror (errno));
Packit 79f644
    return;
Packit 79f644
  }
Packit 79f644
  ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap);
Packit 79f644
  if (ok < 0)
Packit 79f644
  {
Packit 79f644
    ok = ioctl (fd, VIDIOCGCAP, &v1cap);
Packit 79f644
    if (ok < 0)
Packit 79f644
    {
Packit 79f644
      g_warning ("Error while probing v4l capabilities for %s: %s",
Packit 79f644
                 device_path, strerror (errno));
Packit 79f644
      close (fd);
Packit 79f644
      return;
Packit 79f644
    }
Packit 79f644
    g_print ("Detected v4l device: %s\n", v1cap.name);
Packit 79f644
    g_print ("Device type: %d\n", v1cap.type);
Packit 79f644
    gstreamer_src = "v4lsrc";
Packit 79f644
    product_name  = v1cap.name;
Packit 79f644
  }
Packit 79f644
  else
Packit 79f644
  {
Packit 79f644
    guint cap = v2cap.capabilities;
Packit 79f644
    g_print ("Detected v4l2 device: %s\n", v2cap.card);
Packit 79f644
    g_print ("Driver: %s, version: %d\n", v2cap.driver, v2cap.version);
Packit 79f644
Packit 79f644
    /* g_print ("Bus info: %s\n", v2cap.bus_info); */ /* Doesn't seem anything useful */
Packit 79f644
    g_print ("Capabilities: 0x%08X\n", v2cap.capabilities);
Packit 79f644
    if (!(cap & V4L2_CAP_VIDEO_CAPTURE))
Packit 79f644
    {
Packit 79f644
      g_print ("Device %s seems to not have the capture capability, (radio tuner?)\n"
Packit 79f644
               "Removing it from device list.\n", device_path);
Packit 79f644
      close (fd);
Packit 79f644
      return;
Packit 79f644
    }
Packit 79f644
    gstreamer_src = "v4l2src";
Packit 79f644
    product_name  = (char *) v2cap.card;
Packit 79f644
  }
Packit 79f644
  close (fd);
Packit 79f644
Packit 79f644
  GList *devices, *l;
Packit 79f644
Packit 79f644
  g_print ("Probing devices with udev...\n");
Packit 79f644
Packit 79f644
  if (priv->client == NULL)
Packit 79f644
    return;
Packit 79f644
Packit 79f644
  devices = g_udev_client_query_by_subsystem (priv->client, "video4linux");
Packit 79f644
Packit 79f644
  /* Initialize camera structures */
Packit 79f644
  for (l = devices; l != NULL; l = l->next)
Packit 79f644
  {
Packit 79f644
    tpaw_camera_device_monitor_added (monitor, l->data);
Packit 79f644
    g_object_unref (l->data);
Packit 79f644
  }
Packit 79f644
  g_list_free (devices);
Packit 79f644
  #endif
Packit 79f644
}
Packit 79f644
Packit 79f644
#endif /* HAVE_UDEV */
Packit 79f644
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_finalize (GObject *object)
Packit 79f644
{
Packit 79f644
#ifdef HAVE_UDEV
Packit 79f644
  TpawCameraDeviceMonitor *monitor = TPAW_CAMERA_DEVICE_MONITOR (object);
Packit 79f644
  TpawCameraDeviceMonitorPrivate *priv = TPAW_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
Packit 79f644
Packit 79f644
  if (priv->client != NULL)
Packit 79f644
  {
Packit 79f644
    g_object_unref (priv->client);
Packit 79f644
    priv->client = NULL;
Packit 79f644
  }
Packit 79f644
#endif /* HAVE_UDEV */
Packit 79f644
  G_OBJECT_CLASS (tpaw_camera_device_monitor_parent_class)->finalize (object);
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_class_init (TpawCameraDeviceMonitorClass *klass)
Packit 79f644
{
Packit 79f644
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 79f644
Packit 79f644
  object_class->finalize = tpaw_camera_device_monitor_finalize;
Packit 79f644
Packit 79f644
  /**
Packit 79f644
   * TpawCameraDeviceMonitor::added:
Packit 79f644
   * @device: A private object representing the newly added camera.
Packit 79f644
   * @id: Device unique identifier.
Packit 79f644
   * @device: Device file name  (e.g. /dev/video2).
Packit 79f644
   * @product_name: Device product name (human readable, intended to be displayed in a UI).
Packit 79f644
   * @api_version: Supported video4linux API: 1 for v4l, 2 for v4l2.
Packit 79f644
   *
Packit 79f644
   * The ::added signal is emitted when a camera is added, or on start-up
Packit 79f644
   * after #tpaw_camera_device_monitor_colplug is called.
Packit 79f644
   **/
Packit 79f644
  monitor_signals[ADDED] = g_signal_new ("added", G_OBJECT_CLASS_TYPE (klass),
Packit 79f644
                                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Packit 79f644
                                         G_STRUCT_OFFSET (TpawCameraDeviceMonitorClass, added),
Packit 79f644
                                         NULL, NULL,
Packit 79f644
                                         g_cclosure_marshal_generic,
Packit 79f644
                                         G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
Packit 79f644
Packit 79f644
  /**
Packit 79f644
   * TpawCameraDeviceMonitor::removed:
Packit 79f644
   * @device: A private object representing the newly added camera
Packit 79f644
   * @id: Device unique identifier.
Packit 79f644
   *
Packit 79f644
   * The ::removed signal is emitted when a camera is un-plugged, or
Packit 79f644
   * disabled on the system.
Packit 79f644
   **/
Packit 79f644
  monitor_signals[REMOVED] = g_signal_new ("removed", G_OBJECT_CLASS_TYPE (klass),
Packit 79f644
                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Packit 79f644
                                           G_STRUCT_OFFSET (TpawCameraDeviceMonitorClass, removed),
Packit 79f644
                                           NULL, NULL,
Packit 79f644
                                           g_cclosure_marshal_generic,
Packit 79f644
                                           G_TYPE_NONE, 1, G_TYPE_STRING);
Packit 79f644
Packit 79f644
  g_type_class_add_private (klass, sizeof (TpawCameraDeviceMonitorPrivate));
Packit 79f644
}
Packit 79f644
Packit 79f644
static void
Packit 79f644
tpaw_camera_device_monitor_init (TpawCameraDeviceMonitor *monitor)
Packit 79f644
{
Packit 79f644
#ifdef HAVE_UDEV
Packit 79f644
  TpawCameraDeviceMonitorPrivate *priv         = TPAW_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
Packit 79f644
  const gchar *const                subsystems[] = {"video4linux", NULL};
Packit 79f644
Packit 79f644
  priv->client = g_udev_client_new (subsystems);
Packit 79f644
  g_signal_connect (G_OBJECT (priv->client), "uevent",
Packit 79f644
                    G_CALLBACK (tpaw_camera_device_monitor_uevent_cb), monitor);
Packit 79f644
#endif /* HAVE_UDEV */
Packit 79f644
}
Packit 79f644
Packit 79f644
/**
Packit 79f644
 * tpaw_camera_device_monitor_new:
Packit 79f644
 *
Packit 79f644
 * Returns a new #TpawCameraDeviceMonitor object.
Packit 79f644
 *
Packit 79f644
 * Return value: a new #TpawCameraDeviceMonitor object.
Packit 79f644
 **/
Packit 79f644
TpawCameraDeviceMonitor *
Packit 79f644
tpaw_camera_device_monitor_new (void)
Packit 79f644
{
Packit 79f644
  return g_object_new (TPAW_TYPE_CAMERA_DEVICE_MONITOR, NULL);
Packit 79f644
}
Packit 79f644
Packit 79f644
/*
Packit 79f644
 * vim: sw=2 ts=8 cindent noai bs=2
Packit 79f644
 */