kaffeine-1.0 and webcamd based DVB-T?

Juergen Lock nox at jelal.kn-bremen.de
Wed Aug 25 21:46:45 UTC 2010


On Tue, Aug 24, 2010 at 05:12:10PM -0400, Joe Marcus Clarke wrote:
> On 8/24/10 5:04 PM, Hans Petter Selasky wrote:
> > On Tuesday 24 August 2010 22:21:18 Juergen Lock wrote:
> >> #! /bin/sh
> >> # add PCTV 452e Sat HDTV Pro USB to hal as /dev/dvb/adapter0
> >> hal-device --add usb_device_2304_21f_noserial_dvb_0 <<EOF
> >> dvb.device = '/dev/dvb/adapter0/demux0'  (string)
> >> info.capabilities = {'dvb'} (string list)
> >> info.category = 'dvb'  (string)
> >> info.parent =
> >> '/org/freedesktop/Hal/devices/usb_device_2304_21f_noserial'  (string)
> >> info.product = 'DVB Device'  (string)
> >> info.subsystem = 'dvb'  (string)
> >> EOF
> >> hal-device --add usb_device_2304_21f_noserial_dvb_1 <<EOF
> >> dvb.device = '/dev/dvb/adapter0/dvr0'  (string)
> >> info.capabilities = {'dvb'} (string list)
> >> info.category = 'dvb'  (string)
> >> info.parent =
> >> '/org/freedesktop/Hal/devices/usb_device_2304_21f_noserial'  (string)
> >> info.product = 'DVB Device'  (string)
> >> info.subsystem = 'dvb'  (string)
> >> EOF
> >> hal-device --add usb_device_2304_21f_noserial_dvb_2 <<EOF
> > 
> > Hi,
> > 
> > Could you have changed this into "execve()" calls (man execve) and add these 
> > to webcamd.c whenever cuse_dev_create() is called? Also for /dev/videoX 
> > entries. Then we don't need to patch HAL?
> 
> Yeah, if webcamd can notify hal that new dvb and v4l devices are
> available (and what those devices' capabilities are) then we can remove
> the patches from hal.

Ok I now made that an extra process (so it can open() /dev/videoX
normally and also that way webcamd itself doesn't have to link
libhal and possible problems with fork() and threads are avoided),
webcamd then just feeds it the device nodes on stdin.

 Untested with v4l devices since I don't have one here, and
I also built the helper manually for now and put it into PATH.
And the code can still be cleaned up...

 helper built as:

	cc -o webcamd-hal-helper -Wall webcamd-hal-helper.c $(pkg-config --cflags hal) $(pkg-config --libs hal) -I/usr/local/include

 Patch also at:

	http://people.freebsd.org/~nox/tmp/webcamd-hal.patch

 HTH, :)
	Juergen

Index: webcamd.c
===================================================================
--- webcamd.c	(revision 1621)
+++ webcamd.c	(working copy)
@@ -37,6 +37,11 @@
 
 #include <cuse4bsd.h>
 
+#ifndef HALHELPER
+/* Helper process that feeds webcamd cuse4bsd device nodes into hal */
+#define HALHELPER "webcamd-hal-helper"
+#endif
+
 static cuse_open_t v4b_open;
 static cuse_close_t v4b_close;
 static cuse_read_t v4b_read;
@@ -76,6 +81,9 @@
 static int do_fork = 0;
 static int do_realtime = 1;
 static struct pidfh *local_pid = NULL;
+#ifdef HALHELPER
+static FILE *fp_halhelper = NULL;
+#endif
 
 char	global_fw_prefix[128] = {"/boot/modules"};
 
@@ -309,6 +317,13 @@
 			printf("Creating /dev/");
 			printf(devnames[n / F_V4B_SUBDEV_MAX], temp);
 			printf("\n");
+#ifdef HALHELPER
+			if (fp_halhelper) {
+				fprintf(fp_halhelper, "/dev/");
+				fprintf(fp_halhelper, devnames[n / F_V4B_SUBDEV_MAX], temp);
+				fprintf(fp_halhelper, "\n");
+			}
+#endif
 
 			ndev++;
 		}
@@ -354,6 +369,10 @@
 		pidfile_remove(local_pid);
 		local_pid = NULL;
 	}
+#ifdef HALHELPER
+	if (fp_halhelper)
+		pclose(fp_halhelper);
+#endif
 }
 
 int
@@ -375,6 +394,24 @@
 		pidfile_write(local_pid);
 	}
 
+#ifdef HALHELPER
+	snprintf(buf, sizeof(buf), "%d", bus);
+	setenv("HAL_PROP_USB_BUS_NUMBER", buf, 1);
+	snprintf(buf, sizeof(buf), "%d", addr);
+	setenv("HAL_PROP_USB_PORT_NUMBER", buf, 1);
+	snprintf(buf, sizeof(buf), "%d", 0);
+	setenv("HAL_PROP_USB_INTERFACE_NUMBER", buf, 1);
+
+	if ((fp_halhelper = popen(HALHELPER, "w")) == NULL) {
+		/* XXX */
+		return (EEXIST);
+	}
+	/* Use line buffering */
+	setvbuf(fp_halhelper, (char *)NULL, _IOLBF, 0);
+	/* Keep going if helper exits (e.g. because hal is not running...) */
+	signal(SIGPIPE, SIG_IGN);
+#endif
+
 	printf("Attached ugen%d.%d[%d] to cuse unit %d\n",
 	    bus, addr, index, u_videodev);
 
--- /dev/null	2010-08-25 23:11:00.000000000 +0200
+++ webcamd-hal-helper.c	2010-08-25 22:32:04.000000000 +0200
@@ -0,0 +1,303 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * webcamd-hal-helper.c : Notify hal of webcamd cuse4bsd device nodes
+ *
+ * build as:
+ *	cc -o webcamd-hal-helper -Wall webcamd-hal-helper.c $(pkg-config --cflags hal) $(pkg-config --libs hal) -I/usr/local/include
+ *
+ * Uses code from...
+ *
+ * probe-video4linux.c : Probe video4linux devices
+ * Adapted for FreeBSD by : Joe Marcus Clarke <marcus at FreeBSD.org>
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hal/libhal.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define h_info printf
+#else
+#define h_info(...) /* */
+#endif
+
+typedef struct {
+	char *udi;
+	char *real_udi;
+} new_dev_t;
+
+static char *
+find_usb_udi (LibHalContext *ctx, int bus, int addr)
+{
+	int i, num_devices;
+
+	char **u_devs = libhal_manager_find_device_string_match
+		(ctx, "info.bus", "usb_device", &num_devices, NULL);
+
+	if (!u_devs || !num_devices)
+		return NULL;
+
+	for (i = 0; i < num_devices; ++i) {
+		if (libhal_device_get_property_int(ctx, u_devs[i],
+			"usb_device.bus_number", NULL) == bus &&
+		    libhal_device_get_property_int(ctx, u_devs[i],
+			"usb_device.port_number", NULL) == addr)
+			return u_devs[i];
+	}
+	return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+	int ret = 1;
+	int fd = -1;
+	int bus = -1;
+	int addr = -1;
+	int intf = -1;
+	int dvbindex = 0;
+	char *device_file = NULL;
+	char *busstr;
+	char *addrstr;
+	char *intfstr;
+	struct video_capability v1cap;
+	struct v4l2_capability v2cap;
+
+	DBusError error;
+	DBusConnection *conn;
+	LibHalContext *hal_ctx;
+	LibHalChangeSet *cset;
+
+	busstr = getenv ("HAL_PROP_USB_BUS_NUMBER");
+	if (! busstr)
+		goto out;
+	addrstr = getenv ("HAL_PROP_USB_PORT_NUMBER");
+	if (! addrstr)
+		goto out;
+	intfstr = getenv ("HAL_PROP_USB_INTERFACE_NUMBER");
+	if (! intfstr)
+		goto out;
+
+	bus = atoi (busstr);
+	addr = atoi (addrstr);
+	intf = atoi (intfstr);
+
+	if (intf != 0)
+		goto out;
+
+	dbus_error_init(&error);
+	if (!(conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+		fprintf(stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message);
+		LIBHAL_FREE_DBUS_ERROR (&error);
+		return 2;
+	}
+
+	if (!(hal_ctx = libhal_ctx_new())) return 3;
+	if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) return 4;
+	if (!libhal_ctx_init(hal_ctx, &error)) {
+		if (dbus_error_is_set(&error)) {
+			fprintf (stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
+			dbus_error_free (&error);
+		}
+		fprintf (stderr, "Could not initialise connection to hald.\n"
+				 "Normally this means the HAL daemon (hald) is not running or not ready.\n");
+		return 5;
+	}
+
+	char *hal_udi = find_usb_udi (hal_ctx, bus, addr);
+	if (hal_udi == NULL) {
+		fprintf(stderr, "Device not found in hal: usb bus %d, address %d\n",
+			bus, addr);
+		goto out;
+	}
+
+	char line[0x1000];
+
+	/* give a meaningful process title for ps(1) */
+	setproctitle("%s (bus: %i, addr: %i)", hal_udi, bus, addr);
+
+	while (42) {
+		size_t len;
+
+		device_file = fgets(line, sizeof line, stdin);
+		if (device_file == NULL || !(len = strlen(device_file)) ||
+		    device_file[len - 1] != '\n')
+			break;
+		device_file[len - 1] = '\0';
+
+		if (!strncmp(device_file, "/dev/video", sizeof "/dev/video" - 1)) {
+			cset = libhal_device_new_changeset (hal_udi);
+
+			h_info ("Doing probe-video4linux-hal for %s (udi=%s)\n", device_file, hal_udi);
+
+			fd = open (device_file, O_RDONLY);
+			if (fd < 0) {
+				fprintf(stderr, "Cannot open %s: %s\n", device_file, strerror (errno));
+				goto out;
+			}
+
+			if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) {
+				libhal_changeset_set_property_string (cset,
+								      "video4linux.device", device_file);
+				libhal_changeset_set_property_string (cset,
+								      "info.category", "video4linux");
+				libhal_changeset_set_property_string (cset,
+								      "video4linux.version", "2");
+
+				libhal_changeset_set_property_string (cset,
+								      "info.product", (const char *)v2cap.card);
+
+				libhal_device_add_capability (hal_ctx, hal_udi, "video4linux", NULL);
+				if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_capture", NULL);
+				} if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_output", NULL);
+				} if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_overlay", NULL);
+				} if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.audio", NULL);
+				} if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.tuner", NULL);
+				} if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) {
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.radio", NULL);
+				}
+			} else {
+				h_info (("ioctl VIDIOC_QUERYCAP failed\n"));
+
+				if (ioctl (fd, VIDIOCGCAP, &v1cap) == 0) {
+					libhal_changeset_set_property_string (cset,
+									      "video4linux.device", device_file);
+					libhal_changeset_set_property_string (cset,
+									      "info.category", "video4linux");
+					libhal_changeset_set_property_string (cset,
+									      "video4linux.version", "1");
+
+					libhal_changeset_set_property_string (cset,
+									      "info.product", v1cap.name);
+
+					libhal_device_add_capability (hal_ctx, hal_udi, "video4linux", NULL);
+					if ((v1cap.type & VID_TYPE_CAPTURE) > 0) {
+						libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_capture", NULL);
+					} if ((v1cap.type & VID_TYPE_OVERLAY) > 0) {
+						libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.video_overlay", NULL);
+					} if (v1cap.audios > 0) {
+						libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.audio", NULL);
+					} if ((v1cap.type & VID_TYPE_TUNER) > 0) {
+						libhal_device_add_capability (hal_ctx, hal_udi, "video4linux.tuner", NULL);
+					}
+				} else {
+					h_info (("ioctl VIDIOCGCAP failed; not a v4l device\n"));
+				}
+			}
+
+			libhal_device_commit_changeset (hal_ctx, cset, NULL);
+			libhal_device_free_changeset (cset);
+
+			close (fd);
+		} else if (!strncmp(device_file, "/dev/dvb/adapter", sizeof "/dev/dvb/adapter" - 1)) {
+			char *dvbudi;
+			new_dev_t new_dev;
+
+			if (asprintf(&dvbudi, "%s_dvb_%d", hal_udi, dvbindex++) == -1) {
+				perror("asprintf");
+				goto out;
+			}
+			new_dev.udi = strdup(dvbudi);
+			int dev_exists = libhal_device_exists(hal_ctx, dvbudi, NULL);
+
+			if (dev_exists) {
+				new_dev.real_udi = strdup(new_dev.udi);
+			} else {
+				new_dev.real_udi = libhal_new_device(hal_ctx, &error);
+
+				if (!new_dev.real_udi) {
+					fprintf(stderr, "%s: %s\n", error.name, error.message);
+					LIBHAL_FREE_DBUS_ERROR (&error);
+					free(new_dev.real_udi);
+
+					ret = 22;
+					goto out;
+				}
+
+				//printf("tmp udi: %s\n", new_dev.real_udi);
+			}
+
+			cset = libhal_device_new_changeset (new_dev.real_udi);
+
+			h_info ("Doing add-dvb-hal for %s (udi=%s)\n", device_file, new_dev.udi);
+			libhal_changeset_set_property_string (cset,
+							      "dvb.device", device_file);
+			libhal_changeset_set_property_string (cset,
+							      "info.category", "dvb");
+			libhal_changeset_set_property_string (cset,
+							      "info.parent", hal_udi);
+			libhal_changeset_set_property_string (cset,
+							      "info.product", "DVB Device");
+			libhal_changeset_set_property_string (cset,
+							      "info.subsystem", "dvb");
+			libhal_device_add_capability (hal_ctx, new_dev.real_udi, "dvb", NULL);
+
+			libhal_device_commit_changeset (hal_ctx, cset, NULL);
+			libhal_device_free_changeset (cset);
+
+			if (!dev_exists &&
+			    !libhal_device_commit_to_gdl(hal_ctx, new_dev.real_udi, new_dev.udi, &error)) {
+				fprintf(stderr, "%s: %s\n", error.name, error.message);
+				LIBHAL_FREE_DBUS_ERROR (&error);
+				free(new_dev.real_udi);
+
+				ret = 23;
+				goto out;
+			}
+		} else {
+			printf("Unhandled device %s\n", device_file);
+		}
+	}
+
+	ret = 0;
+
+out:
+	if (fd >= 0)
+		close (fd);
+
+	return ret;
+}


More information about the freebsd-multimedia mailing list