diff options
-rw-r--r-- | audio/ctl_bluetooth.c | 222 | ||||
-rw-r--r-- | audio/ipc.h | 34 | ||||
-rw-r--r-- | audio/pcm_bluetooth.c | 24 |
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, ¤t)) < 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; } |