diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2007-04-10 21:37:24 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2007-04-10 21:37:24 +0000 |
commit | b8a407aa8470ad8d92d9142edb41c17548b0cb2c (patch) | |
tree | 1510d97fe928944432a7fea1ac56b6f24760c5e2 | |
parent | f895f6df807b623b2cdd041e9666b01b7f266eb7 (diff) |
Add first step of ALSA plugin integration
-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); |