diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2007-04-09 01:14:21 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2007-04-09 01:14:21 +0000 | 
| commit | 67d220c148f13abca61977b3036ea9f356db9205 (patch) | |
| tree | 9dc7371a42bf4336a0914495ead2d51dac138a2c | |
| parent | 353376a06677af64fc6e81d3118adc2e059516b8 (diff) | |
Simple process communication
| -rw-r--r-- | audio/ctl_bluetooth.c | 244 | ||||
| -rw-r--r-- | audio/manager.c | 83 | 
2 files changed, 325 insertions, 2 deletions
| diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c index 511a1b24..4e55058e 100644 --- a/audio/ctl_bluetooth.c +++ b/audio/ctl_bluetooth.c @@ -25,14 +25,254 @@  #include <config.h>  #endif +#include <sys/socket.h> +#include <sys/un.h> +  #include <alsa/asoundlib.h>  #include <alsa/control_external.h> +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg) + +#define SOCKET_NAME "/org/bluez/audio" + +#define BLUETOOTH_MINVOL 0 +#define BLUETOOTH_MAXVOL 15 + +struct bluetooth_data { +	snd_ctl_ext_t ext; +	int sock; +}; + +enum { +	BLUETOOTH_PLAYBACK, +	BLUETOOTH_CAPTURE, +}; + +static const char *vol_devices[2] = { +	[BLUETOOTH_PLAYBACK]	= "Playback volume", +	[BLUETOOTH_CAPTURE]	= "Capture volume", +}; + +static void bluetooth_close(snd_ctl_ext_t *ext) +{ +	struct bluetooth_data *data = ext->private_data; + +	DBG("ext %p", ext); + +	close(data->sock); + +	free(data); +} + +static int bluetooth_elem_count(snd_ctl_ext_t *ext) +{ +	DBG("ext %p", ext); + +	return 2; +} + +static int bluetooth_elem_list(snd_ctl_ext_t *ext, +				unsigned int offset, snd_ctl_elem_id_t *id) +{ +	DBG("ext %p offset %d id %p", ext, offset, id); + +	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); + +	if (offset > 1) +		return -EINVAL; + +	snd_ctl_elem_id_set_name(id, vol_devices[offset]); + +	return 0; +} + +static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext, +						const snd_ctl_elem_id_t *id) +{ +	const char *name = snd_ctl_elem_id_get_name(id); +	int i; + +	DBG("ext %p id %p name '%s'", ext, id, name); + +	for (i = 0; i < 2; i++) +		if (strcmp(name, vol_devices[i]) == 0) +			return i; + +	return SND_CTL_EXT_KEY_NOT_FOUND; +} + +static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, +			int *type, unsigned int *acc, unsigned int *count) +{ +	DBG("ext %p key %td", ext, key); + +	*type  = SND_CTL_ELEM_TYPE_INTEGER; +	*acc   = SND_CTL_EXT_ACCESS_READWRITE; +	*count = 1; + +	return 0; +} + +static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, +					long *imin, long *imax, long *istep) +{ +	DBG("ext %p key %td", ext, key); + +	*istep = 1; +	*imin  = BLUETOOTH_MINVOL; +	*imax  = BLUETOOTH_MAXVOL; + +	return 0; +} + +static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, +								long *value) +{ +	struct bluetooth_data *data = ext->private_data; +	unsigned char buf[] = { 0x00, 0x00 }; +	int len; + +	DBG("ext %p key %td", ext, key); + +	len = write(data->sock, buf, sizeof(buf)); + +	*value = 0; + +	return 0; +} + +static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, +								long *value) +{ +	struct bluetooth_data *data = ext->private_data; +	unsigned char buf[] = { 0xff, 0xff }; +	int len; + +	DBG("ext %p key %td", ext, key); + +	len = write(data->sock, buf, sizeof(buf)); + +	return 0; +} + +static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, +						unsigned int *event_mask) +{ +	struct bluetooth_data *data = ext->private_data; +	unsigned char buf[128]; +	int len; + +	//DBG("ext %p id %p", ext, id); + +	len = recv(data->sock, buf, sizeof(buf), MSG_DONTWAIT); + +	return 0; +} + +static snd_ctl_ext_callback_t bluetooth_callback = { +	.close			= bluetooth_close, +	.elem_count		= bluetooth_elem_count, +	.elem_list		= bluetooth_elem_list, +	.find_elem		= bluetooth_find_elem, +	.get_attribute		= bluetooth_get_attribute, +	.get_integer_info	= bluetooth_get_integer_info, +	.read_integer		= bluetooth_read_integer, +	.write_integer		= bluetooth_write_integer, +	.read_event		= bluetooth_read_event, +}; +  SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)  { -	printf("Bluetooth control plugin\n"); +	snd_config_iterator_t iter, next; +	struct bluetooth_data *data; +	struct sockaddr_un addr; +	unsigned int id; +	int sk, err; + +	DBG(""); + +	snd_config_for_each(iter, next, conf) { +		snd_config_t *n = snd_config_iterator_entry(iter); +		const char *id; + +		if (snd_config_get_id(n, &id) < 0) +			continue; + +		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) +			continue; + +		SNDERR("Unknown field %s", id); + +		return -EINVAL; +	} + +	id = abs(getpid() * rand()); + +	sk = socket(PF_LOCAL, SOCK_DGRAM, 0); +	if (sk < 0) { +		SNDERR("Can't open socket"); +		return -errno; +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.sun_family = AF_UNIX; +	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id); + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		SNDERR("Can't bind socket"); +		close(sk); +		return -errno; +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.sun_family = AF_UNIX; +	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME); + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		SNDERR("Can't connect socket"); +		close(sk); +		return -errno; +	} + +	data = malloc(sizeof(*data)); +	if (!data) { +		close(sk); +		return -ENOMEM; +	} + +	memset(data, 0, sizeof(*data)); + +	data->sock = sk; + +	data->ext.version = SND_CTL_EXT_VERSION; +	data->ext.card_idx = -1; + +	strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1); +	strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1); +	strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1); +	strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1); +	strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1); + +	data->ext.callback = &bluetooth_callback; +	data->ext.poll_fd = sk; +	data->ext.private_data = data; + +	err = snd_ctl_ext_create(&data->ext, name, mode); +	if (err < 0) +		goto error; + +	*handlep = data->ext.handle; + +	return 0; + +error: +	free(data); -	return -EIO; +	return err;  }  SND_CTL_PLUGIN_SYMBOL(bluetooth); diff --git a/audio/manager.c b/audio/manager.c index 32eea81b..a7e3afd9 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -25,14 +25,93 @@  #include <config.h>  #endif +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <glib.h> +  #include <dbus/dbus.h> +#include "dbus.h" +#include "logging.h" +  #include "manager.h" +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +#define SOCKET_NAME "/org/bluez/audio" +  static DBusConnection *connection = NULL; +static int unix_sock = -1; + +static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ +	struct sockaddr_un addr; +	socklen_t addrlen; +	unsigned char buf[128]; +	int sk, len; + +	debug("chan %p cond %td data %p", chan, cond, data); + +	if (cond & G_IO_NVAL) +		return FALSE; + +	if (cond & (G_IO_HUP | G_IO_ERR)) { +		g_io_channel_close(chan); +		return FALSE; +	} + +	sk = g_io_channel_unix_get_fd(chan); + +	memset(&addr, 0, sizeof(addr)); +	addrlen = sizeof(addr); + +	len = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addrlen); + +	debug("path %s len %d", addr.sun_path + 1, len); + +	return TRUE; +} +  int audio_init(DBusConnection *conn)  { +	GIOChannel *io; +	struct sockaddr_un addr; +	int sk; + +	sk = socket(PF_LOCAL, SOCK_DGRAM, 0); +	if (sk < 0) { +		error("Can't create unix socket: %s (%d)", strerror(errno), errno); +		return -1; +	} + +	memset(&addr, 0, sizeof(addr)); +	addr.sun_family = AF_UNIX; +	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME); + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		error("Can't bind unix socket: %s (%d)", strerror(errno), errno); +		close(sk); +		return -1; +	} + +	set_nonblocking(sk); + +	unix_sock = sk; + +	io = g_io_channel_unix_new(sk); + +	g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +							unix_event, NULL); + +	g_io_channel_unref(io); +  	connection = dbus_connection_ref(conn);  	return 0; @@ -40,6 +119,10 @@ int audio_init(DBusConnection *conn)  void audio_exit(void)  { +	close(unix_sock); + +	unix_sock = -1; +  	dbus_connection_unref(connection);  	connection = NULL; | 
