summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/Makefile.am6
-rw-r--r--audio/ctl_bluetooth.c4
-rw-r--r--audio/ipc.h43
-rw-r--r--audio/manager.c1
-rw-r--r--audio/pcm_bluetooth.c227
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);