summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/ctl_bluetooth.c222
-rw-r--r--audio/ipc.h34
-rw-r--r--audio/pcm_bluetooth.c24
3 files changed, 195 insertions, 85 deletions
diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c
index 4d73c788..411d7e00 100644
--- a/audio/ctl_bluetooth.c
+++ b/audio/ctl_bluetooth.c
@@ -33,7 +33,11 @@
#include "ipc.h"
+#ifdef ENABLE_DEBUG
#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
+#endif
#define BLUETOOTH_MINVOL 0
#define BLUETOOTH_MAXVOL 15
@@ -53,15 +57,24 @@ static const char *vol_devices[2] = {
[BLUETOOTH_CAPTURE] = "Capture volume",
};
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->sock >= 0)
+ close(data->sock);
+
+ free(data);
+}
+
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);
+ bluetooth_exit(data);
}
static int bluetooth_elem_count(snd_ctl_ext_t *ext)
@@ -125,48 +138,140 @@ static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
return 0;
}
+static int bluetooth_send_ctl(struct bluetooth_data *data,
+ struct ipc_packet *pkt, int len)
+{
+ int ret;
+
+ ret = send(data->sock, pkt, len, MSG_NOSIGNAL);
+ if (ret <= 0) {
+ SYSERR("Unable to request new volume value to server");
+ return -errno;
+ }
+
+ ret = recv(data->sock, pkt, len, 0);
+ if (ret <= 0) {
+ SYSERR("Unable to receive new volume value from server");
+ return -errno;
+ }
+
+ if(pkt->type != PKT_TYPE_CTL_RSP) {
+ SNDERR("Unexpected packet type %d received", pkt->type);
+ return -EINVAL;
+ }
+
+ if(pkt->length != sizeof(struct ipc_data_ctl)) {
+ SNDERR("Unexpected packet length %d received", pkt->length);
+ return -EINVAL;
+ }
+
+ 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;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ int len, ret;
DBG("ext %p key %ld", ext, key);
- len = write(data->sock, buf, sizeof(buf));
-
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
*value = 0;
- return 0;
+ pkt->type = PKT_TYPE_CTL_REQ;
+ pkt->length = sizeof(struct ipc_data_ctl);
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ ctl->mode = key;
+
+ if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+ goto done;
+
+ *value = ctl->key;
+done:
+ free(pkt);
+ return ret;
}
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;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ long current;
+ int len, ret;
DBG("ext %p key %ld", ext, key);
- len = write(data->sock, buf, sizeof(buf));
+ if ((ret = bluetooth_read_integer(ext, key, &current)) < 0)
+ return ret;
- return 0;
+ if (*value == current)
+ return 0;
+
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
+
+ pkt->length = sizeof(struct ipc_data_ctl);
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ ctl->mode = key;
+
+ while (*value != current) {
+ pkt->type = PKT_TYPE_CTL_REQ;
+ ctl->key = (*value > current) ? CTL_KEY_VOL_UP : CTL_KEY_VOL_DOWN;
+
+ if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+ break;
+
+ current = ctl->key;
+ }
+
+ free(pkt);
+ return ret;
}
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;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ int len, ret;
- //DBG("ext %p id %p", ext, id);
+ DBG("ext %p id %p", ext, id);
- len = recv(data->sock, buf, sizeof(buf), MSG_DONTWAIT);
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
- return 0;
+ ret = recv(data->sock, pkt, len, MSG_DONTWAIT);
+ if (ret <= 0)
+ return -errno;
+
+ if(pkt->type != PKT_TYPE_CTL_NTFY) {
+ SNDERR("Unexpected packet type %d received!", pkt->type);
+ return -EAGAIN;
+ }
+
+ if(pkt->length != sizeof(struct ipc_data_ctl)) {
+ SNDERR("Unexpected packet length %d received", pkt->length);
+ return -EAGAIN;
+ }
+
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl->mode == BLUETOOTH_PLAYBACK ?
+ vol_devices[BLUETOOTH_PLAYBACK] :
+ vol_devices[BLUETOOTH_CAPTURE]);
+ *event_mask = SND_CTL_EVENT_MASK_VALUE;
+
+ return 1;
}
static snd_ctl_ext_callback_t bluetooth_callback = {
@@ -181,69 +286,60 @@ static snd_ctl_ext_callback_t bluetooth_callback = {
.read_event = bluetooth_read_event,
};
-SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
+static int bluetooth_init(struct bluetooth_data *data)
{
- snd_config_iterator_t iter, next;
- struct bluetooth_data *data;
- struct sockaddr_un addr;
- unsigned int id;
- int sk, err;
-
- DBG("Bluetooth Control plugin");
-
- 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;
+ int sk, err, id;
+ struct sockaddr_un addr = {
+ AF_UNIX, IPC_SOCKET_NAME
+ };
- if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
- continue;
+ if (!data)
+ return -EINVAL;
- SNDERR("Unknown field %s", id);
+ memset(data, 0, sizeof(struct bluetooth_data));
- return -EINVAL;
- }
+ data->sock = -1;
id = abs(getpid() * rand());
- sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
- if (sk < 0) {
+ if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ err = -errno;
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",
- IPC_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", IPC_SOCKET_NAME);
-
+ DBG("Connecting to address: %s", addr.sun_path + 1);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
SNDERR("Can't connect socket");
close(sk);
- return -errno;
+ return err;
}
- data = malloc(sizeof(*data));
+ data->sock = sk;
+
+ return 0;
+}
+
+SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
+{
+ struct bluetooth_data *data;
+ int err;
+
+ DBG("Bluetooth Control plugin");
+
+ data = malloc(sizeof(struct bluetooth_data));
+ memset(data, 0, sizeof(struct bluetooth_data));
if (!data) {
- close(sk);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto error;
}
- memset(data, 0, sizeof(*data));
+ err = bluetooth_init(data);
+ if (err < 0)
+ goto error;
- data->sock = sk;
+ memset(data, 0, sizeof(*data));
data->ext.version = SND_CTL_EXT_VERSION;
data->ext.card_idx = -1;
@@ -255,7 +351,7 @@ SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
data->ext.callback = &bluetooth_callback;
- data->ext.poll_fd = sk;
+ data->ext.poll_fd = data->sock;
data->ext.private_data = data;
err = snd_ctl_ext_create(&data->ext, name, mode);
@@ -267,9 +363,7 @@ SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
return 0;
error:
- close(sk);
-
- free(data);
+ bluetooth_exit(data);
return err;
}
diff --git a/audio/ipc.h b/audio/ipc.h
index 409abfda..d340d15e 100644
--- a/audio/ipc.h
+++ b/audio/ipc.h
@@ -44,6 +44,7 @@
#define PKT_TYPE_STATUS_RSP 3
#define PKT_TYPE_CTL_REQ 4
#define PKT_TYPE_CTL_RSP 5
+#define PKT_TYPE_CTL_NTFY 6
/* Errors codes */
#define PKT_ERROR_NONE 0
@@ -83,21 +84,26 @@ struct ipc_data_status {
uint8_t status; /* Stream status */
} __attribute__ ((packed));
+#define CTL_MODE_PLAYBACK 0
+#define CTL_MODE_CAPTURE 1
+#define CTL_MODE_GENERAL 2
+
/* Supported control operations */
-#define DATA_CTL_POWER 0x40
-#define DATA_CTL_VOL_UP 0x41
-#define DATA_CTL_VOL_DOWN 0x42
-#define DATA_CTL_MUTE 0x43
-#define DATA_CTL_PLAY 0x44
-#define DATA_CTL_STOP 0x45
-#define DATA_CTL_PAUSE 0x46
-#define DATA_CTL_RECORD 0x47
-#define DATA_CTL_REWIND 0x48
-#define DATA_CTL_FAST_FORWARD 0x49
-#define DATA_CTL_EJECT 0x4A
-#define DATA_CTL_FORWARD 0x4B
-#define DATA_CTL_BACKWARD 0x4C
+#define CTL_KEY_POWER 0x40
+#define CTL_KEY_VOL_UP 0x41
+#define CTL_KEY_VOL_DOWN 0x42
+#define CTL_KEY_MUTE 0x43
+#define CTL_KEY_PLAY 0x44
+#define CTL_KEY_STOP 0x45
+#define CTL_KEY_PAUSE 0x46
+#define CTL_KEY_RECORD 0x47
+#define CTL_KEY_REWIND 0x48
+#define CTL_KEY_FAST_FORWARD 0x49
+#define CTL_KEY_EJECT 0x4A
+#define CTL_KEY_FORWARD 0x4B
+#define CTL_KEY_BACKWARD 0x4C
struct ipc_data_ctl {
- uint8_t operation; /* Operation ID */
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
} __attribute__ ((packed));
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index d588bcfd..16c99f06 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -84,14 +84,27 @@ static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
return data->hw_ptr;
}
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->sock >= 0)
+ close(data->sock);
+
+ if (data->buffer)
+ free(data->buffer);
+
+ free(data);
+}
+
static int bluetooth_close(snd_pcm_ioplug_t *io)
{
struct bluetooth_data *data = io->private_data;
DBG("bluetooth_close %p", io);
- free(data->buffer);
- free(data);
+ bluetooth_exit(data);
return 0;
}
@@ -517,6 +530,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
data = malloc(sizeof(struct bluetooth_data));
+ memset(data, 0, sizeof(struct bluetooth_data));
if (!data) {
err = -ENOMEM;
goto error;
@@ -552,11 +566,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
return 0;
error:
- if (data) {
- if (data->sock >= 0)
- close(data->sock);
- free(data);
- }
+ bluetooth_exit(data);
return err;
}