diff options
| -rw-r--r-- | audio/Makefile.am | 6 | ||||
| -rw-r--r-- | audio/ctl_bluetooth.c | 4 | ||||
| -rw-r--r-- | audio/ipc.h | 43 | ||||
| -rw-r--r-- | audio/manager.c | 1 | ||||
| -rw-r--r-- | audio/pcm_bluetooth.c | 227 | 
5 files changed, 275 insertions, 6 deletions
| diff --git a/audio/Makefile.am b/audio/Makefile.am index fe5931b1..6bf33050 100644 --- a/audio/Makefile.am +++ b/audio/Makefile.am @@ -10,7 +10,7 @@ servicedir = $(libdir)/bluetooth  service_PROGRAMS = bluetoothd-service-audio -bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.c +bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.c ipc.h  bluetoothd_service_audio_LDADD = $(top_builddir)/common/libhelper.a \  				@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ @@ -21,11 +21,11 @@ alsadir = $(libdir)/alsa-lib  alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_bluetooth.la -libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c +libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c ipc.h  libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version -export-dynamic  libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @ALSA_LIBS@ -libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c +libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c ipc.h  libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version -export-dynamic  libasound_module_ctl_bluetooth_la_LIBADD = @ALSA_LIBS@   endif diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c index 4e55058e..037cfb09 100644 --- a/audio/ctl_bluetooth.c +++ b/audio/ctl_bluetooth.c @@ -193,7 +193,7 @@ SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)  	unsigned int id;  	int sk, err; -	DBG(""); +	DBG("Bluetooth Control plugin");  	snd_config_for_each(iter, next, conf) {  		snd_config_t *n = snd_config_iterator_entry(iter); @@ -270,6 +270,8 @@ SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)  	return 0;  error: +	close(sk); +  	free(data);  	return err; diff --git a/audio/ipc.h b/audio/ipc.h new file mode 100644 index 00000000..5b545844 --- /dev/null +++ b/audio/ipc.h @@ -0,0 +1,43 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org> + * + * + *  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 + * + */ + +#include <stdint.h> + +#define IPC_TYPE_CONNECT  0x0001 + +struct ipc_hdr { +	uint16_t id; +	uint16_t type; +	uint16_t seqnum; +	uint16_t length; +} __attribute__ ((packed)); + +struct ipc_connect_cmd { +	uint8_t src[6]; +	uint8_t dst[6]; +	uint16_t uuid; +} __attribute__ ((packed)); + +struct ipc_connect_evt { +	uint16_t id; +} __attribute__ ((packed)); diff --git a/audio/manager.c b/audio/manager.c index 28ae615e..e48d7a7a 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -43,6 +43,7 @@  #include "dbus.h"  #include "logging.h" +#include "ipc.h"  #include "headset.h"  #include "manager.h" diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index b9f4f02c..d3e457ae 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -25,14 +25,237 @@  #include <config.h>  #endif +#include <sys/socket.h> +#include <sys/un.h> +  #include <alsa/asoundlib.h>  #include <alsa/pcm_external.h> +#include "ipc.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" + +struct bluetooth_data { +	snd_pcm_ioplug_t io; +	snd_pcm_sframes_t hw_ptr; +	int sock; +}; + +static int bluetooth_start(snd_pcm_ioplug_t *io) +{ +	DBG("io %p", io); + +	return 0; +} + +static int bluetooth_stop(snd_pcm_ioplug_t *io) +{ +	DBG("io %p", io); + +	return 0; +} + +static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io) +{ +	struct bluetooth_data *data = io->private_data; + +	//DBG("io %p", io); + +	//DBG("hw_ptr=%lu", data->hw_ptr); + +	return data->hw_ptr; +} + +static int bluetooth_close(snd_pcm_ioplug_t *io) +{ +	struct bluetooth_data *data = io->private_data; + +	DBG("io %p", io); + +	free(data); + +	return 0; +} + +static snd_pcm_ioplug_callback_t bluetooth_playback_callback = { +	.start		= bluetooth_start, +	.stop		= bluetooth_stop, +	.pointer	= bluetooth_pointer, +	.close		= bluetooth_close, +#if 0 +	.hw_params	= bluetooth_hw_params, +	.prepare	= bluetooth_prepare, +	.transfer	= bluetooth_write, +#endif +}; + +static snd_pcm_ioplug_callback_t bluetooth_capture_callback = { +	.start		= bluetooth_start, +	.stop		= bluetooth_stop, +	.pointer	= bluetooth_pointer, +	.close		= bluetooth_close, +#if 0 +	.hw_params	= bluetooth_hw_params, +	.prepare	= bluetooth_prepare, +	.transfer	= bluetooth_read, +#endif +}; + +#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0])) + +static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io) +{ +	snd_pcm_access_t access_list[] = { +		SND_PCM_ACCESS_RW_INTERLEAVED, +		/* Mmap access is really useless fo this driver, but we +		 * support it because some pieces of software out there +		 * insist on using it */ +		SND_PCM_ACCESS_MMAP_INTERLEAVED +	}; +	unsigned int format_list[] = { +		SND_PCM_FORMAT_S16_LE +	}; +	int err; + +	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, +					ARRAY_NELEMS(access_list), access_list); +	if (err < 0) +		return err; + +	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, +					ARRAY_NELEMS(format_list), format_list); +	if (err < 0) +		return err; + +	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1); +	if (err < 0) +		return err; + +	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000); +	if (err < 0) +		return err; + +	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48); +	if (err < 0) +		return err; + +	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200); +	if (err < 0) +		return err; + +	return 0; +} +  SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)  { -	printf("Bluetooth PCM plugin\n"); +	snd_config_iterator_t iter, next; +	struct bluetooth_data *data; +	struct sockaddr_un addr; +	unsigned int id; +	int sk, err; + +	DBG("Bluetooth PCM plugin (%s)", +		stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"); + +	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; + +		if (strcmp(id, "bdaddr") == 0) { +			const char *str; +			if (snd_config_get_string(n, &str) < 0) { +				SNDERR("Invalid type for %s", id); +				return -EINVAL; +			} +			printf("bdaddr %s\n", str); +			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->io.version = SND_PCM_IOPLUG_VERSION; +	data->io.name = "Bluetooth Audio"; +	data->io.mmap_rw =  0;		/* No direct mmap communication */ + +	data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? +		&bluetooth_playback_callback : &bluetooth_capture_callback; +	data->io.poll_fd = sk; +	data->io.poll_events = POLLIN; +	data->io.private_data = data; + +	err = snd_pcm_ioplug_create(&data->io, name, stream, mode); +	if (err < 0) +		goto error; + +	err = bluetooth_hw_constraint(&data->io); +	if (err < 0) { +		snd_pcm_ioplug_delete(&data->io); +		goto error;  +	} + +	*pcmp = data->io.pcm; + +	return 0; + +error: +	close(sk); + +	free(data); -	return -EIO; +	return err;  }  SND_PCM_PLUGIN_SYMBOL(bluetooth); | 
