summaryrefslogblamecommitdiffstats
path: root/multimedia/cheese/files/patch-libcheese_cheese-camera-device-monitor.c
blob: 995cb5d50cbbc0dbcf0defb1f1da88b3074a2b5f (plain) (tree)


















                                                                                           

  




                                                                                          
 


























                                                                     
  











                                                               
    


                                                                  

    
                                                
    





                                                                  

    













                                                                                
    







































































































                                                                                                         


            
                                                  
    
                                                          
      





















                                                                                 
      





















                                                                               


            




                                                                         
 













                                                                                       
 









                                                                                   

  
--- libcheese/cheese-camera-device-monitor.c.orig   2012-08-22 21:04:40.000000000 +0200
+++ libcheese/cheese-camera-device-monitor.c    2013-09-22 23:12:35.072353163 +0200
@@ -33,6 +33,14 @@
   #include <fcntl.h>
   #include <unistd.h>
   #include <sys/ioctl.h>
+  #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+    #include <errno.h>
+    #include <sys/param.h>
+    #include <sys/types.h>
+    #include <sys/socket.h>
+    #include <sys/un.h>
+    #include <linux/videodev.h>
+  #endif
   #if USE_SYS_VIDEOIO_H > 0
     #include <sys/types.h>
     #include <sys/videoio.h>
@@ -302,6 +310,220 @@
   g_list_free (devices);
 }
 
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static void cheese_camera_device_monitor_init_event (CheeseCameraDeviceMonitor *monitor);
+static gboolean cheese_camera_device_monitor_is_camera (const char *devname);
+ 
+static gboolean cheese_camera_device_monitor_event_inited = FALSE;
+
+static gboolean
+cheese_camera_device_monitor_is_camera (const char *devname){
+  gboolean is_camera = FALSE;
+  int fd;
+  struct v4l2_capability v2cap;
+  g_return_val_if_fail (devname != NULL, FALSE);
+
+  fd = open (devname, O_RDONLY);
+  if (fd < 0)
+  {
+    GST_WARNING("Failed to query: %s", devname);
+    return FALSE;
+  }
+  else{
+     if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0)
+     {
+       is_camera = ((v2cap.capabilities & 0x00000001)==1);
+     }
+     else{
+       GST_WARNING("Failed to get product name for %s: %s", devname,
+                g_strerror (errno));
+     }
+  }
+
+  close (fd);
+
+  return is_camera;
+}
+
+static char *
+cheese_camera_device_monitor_get_product (const char *devname)
+{
+  int fd;
+  struct v4l2_capability v2cap;
+  char *product = NULL;
+
+  g_return_val_if_fail (devname != NULL, NULL);
+
+  fd = open (devname, O_RDONLY);
+  if (fd < 0)
+  {
+    GST_WARNING("Failed to get product name for %s: %s", devname,
+                g_strerror (errno));
+    return NULL;
+  }
+
+  if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0)
+  {
+    product = g_strdup ((const char *) v2cap.card);
+  }
+  else
+  {
+    GST_WARNING("Failed to get product name for %s: %s", devname,
+                g_strerror (errno));
+  }
+
+  close (fd);
+
+  return product;
+}
+
+static void
+cheese_camera_device_monitor_process_event (const char *event,
+                                            CheeseCameraDeviceMonitor *monitor)
+{
+  g_return_if_fail (event != NULL);
+
+  GST_INFO ("Received devd event: %s", event);
+
+  switch (event[0])
+  {
+    case '!':
+            {
+              GRegex *rex;
+              GMatchInfo *info;
+
+              rex = g_regex_new ("subsystem=CDEV type=(CREATE|DESTROY) cdev=(video[0-9]+)", 0, 0, NULL);
+              if (g_regex_match (rex, event, 0, &info))
+              {
+                char *devname, *type, *vdev, *product = NULL;
+                CheeseCameraDevice *device;
+                GError *error = NULL;
+
+                type = g_match_info_fetch (info, 1);
+                vdev = g_match_info_fetch (info, 2);
+
+                devname = g_strdup_printf ("/dev/%s", vdev);
+
+                if (g_strcmp0 (type, "DESTROY") == 0)
+                {
+                  g_signal_emit (monitor, monitor_signals[REMOVED], 0,
+                                 devname);
+                }
+                else
+                {
+                  if(cheese_camera_device_monitor_is_camera (devname))
+                  {
+                    product = cheese_camera_device_monitor_get_product (devname);
+                    if (product == NULL)
+                      product = g_strdup ("WebCamd Device");
+                    device = cheese_camera_device_new (devname, devname,
+                                                       product,
+                                                       2,
+                                                       &error);
+                    if (device == NULL)
+                      GST_WARNING ("Device initialization for %s failed: %s",
+                                   devname,
+                                   (error != NULL) ? error->message : "Unknown reason");
+                    g_signal_emit (monitor, monitor_signals[ADDED], 0, device);
+                  }
+
+                  g_free (product);
+                }
+                g_free (devname);
+                g_free (vdev);
+                g_free (type);
+              }
+              g_match_info_free (info);
+              g_regex_unref (rex);
+              break;
+            }
+    default:
+            break;
+  }
+}
+
+static gboolean
+cheese_camera_device_monitor_event_cb (GIOChannel *source,
+                                       GIOCondition condition,
+                                       gpointer user_data)
+{
+  char *event;
+  gsize terminator;
+  GIOStatus status;
+  CheeseCameraDeviceMonitor *monitor;
+
+  monitor = (CheeseCameraDeviceMonitor *) user_data;
+
+  status = g_io_channel_read_line (source, &event, NULL, &terminator, NULL);
+  if (status == G_IO_STATUS_NORMAL)
+  {
+    event[terminator] = 0;
+    cheese_camera_device_monitor_process_event (event, monitor);
+    g_free (event);
+  }
+  else
+  {
+    if (cheese_camera_device_monitor_event_inited)
+    {
+      int fd;
+
+      cheese_camera_device_monitor_init_event (monitor);
+      fd = g_io_channel_unix_get_fd (source);
+      g_io_channel_shutdown (source, FALSE, NULL);
+      close (fd);
+
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+void
+cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor)
+{
+  GDir *dir;
+  GError *error = NULL;
+  const char *fname;
+
+  dir = g_dir_open ("/dev", 0, &error);
+  if (dir == NULL)
+  {
+    GST_WARNING ("Failed to open /dev for reading: %s",
+                 (error != NULL) ? error->message : "Unknown error");
+    return;
+  }
+
+  while ((fname = g_dir_read_name (dir)) != NULL)
+  {
+    if ( strncmp (fname, "video", strlen ("video")) == 0)
+    {
+      char *devname, *product;
+
+      devname = g_strdup_printf ("/dev/%s", fname);
+      if (cheese_camera_device_monitor_is_camera (devname))
+      {
+        CheeseCameraDevice *device;
+        GError *derr = NULL;
+
+        product = cheese_camera_device_monitor_get_product (devname);
+        if (product == NULL)
+          product = g_strdup ("WebCamd Device");
+
+        device = cheese_camera_device_new (devname, devname, product, 2, &derr);
+        if (device == NULL)
+          GST_WARNING ("Device initialization for %s failed: %s", devname,
+                       (derr != NULL) ? derr->message : "Unknown reason");
+
+        g_signal_emit (monitor, monitor_signals[ADDED], 0, device);
+
+        g_free (product);
+      }
+      g_free (devname);
+    }
+  }
+  g_dir_close (dir);
+}
 #else /* HAVE_UDEV */
 void
 cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor)
@@ -430,6 +652,42 @@
   g_type_class_add_private (klass, sizeof (CheeseCameraDeviceMonitorPrivate));
 }
 
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static void
+cheese_camera_device_monitor_init_event (CheeseCameraDeviceMonitor *monitor)
+{
+  int event_fd;
+  struct sockaddr_un addr;
+
+  event_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (event_fd < 0)
+  {
+    GST_WARNING ("Failed to create devd socket: %s", g_strerror (errno));
+    cheese_camera_device_monitor_event_inited = FALSE;
+    return;
+  }
+
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, "/var/run/devd.pipe", sizeof (addr.sun_path));
+  if (connect (event_fd, (struct sockaddr *) &addr, sizeof (addr)) == 0)
+  {
+    GIOChannel *channel;
+
+    channel = g_io_channel_unix_new (event_fd);
+    g_io_add_watch (channel, G_IO_IN, cheese_camera_device_monitor_event_cb, monitor);
+    g_io_channel_unref (channel);
+    cheese_camera_device_monitor_event_inited = TRUE;
+  }
+  else
+  {
+    GST_WARNING("Failed to connect to /var/run/devd.pipe: %s",
+                g_strerror (errno));
+    close (event_fd);
+    cheese_camera_device_monitor_event_inited = FALSE;
+  }
+}
+#endif
+
 static void
 cheese_camera_device_monitor_init (CheeseCameraDeviceMonitor *monitor)
 {
@@ -440,6 +698,8 @@
   priv->client = g_udev_client_new (subsystems);
   g_signal_connect (G_OBJECT (priv->client), "uevent",
                     G_CALLBACK (cheese_camera_device_monitor_uevent_cb), monitor);
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+  cheese_camera_device_monitor_init_event (monitor);
 #endif /* HAVE_UDEV */
 }