3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
#include <sys/socket.h>
31
#include <alsa/asoundlib.h>
32
#include <alsa/control_external.h>
34
#include <bluetooth/bluetooth.h>
39
#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
41
#define DBG(fmt, arg...)
44
#define BLUETOOTH_MINVOL 0
45
#define BLUETOOTH_MAXVOL 15
47
struct bluetooth_data {
57
static const char *vol_devices[2] = {
58
[BLUETOOTH_PLAYBACK] = "Playback volume",
59
[BLUETOOTH_CAPTURE] = "Capture volume",
62
static void bluetooth_exit(struct bluetooth_data *data)
68
bt_audio_service_close(data->sock);
73
static void bluetooth_close(snd_ctl_ext_t *ext)
75
struct bluetooth_data *data = ext->private_data;
82
static int bluetooth_elem_count(snd_ctl_ext_t *ext)
89
static int bluetooth_elem_list(snd_ctl_ext_t *ext,
90
unsigned int offset, snd_ctl_elem_id_t *id)
92
DBG("ext %p offset %d id %p", ext, offset, id);
94
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
99
snd_ctl_elem_id_set_name(id, vol_devices[offset]);
104
static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext,
105
const snd_ctl_elem_id_t *id)
107
const char *name = snd_ctl_elem_id_get_name(id);
110
DBG("ext %p id %p name '%s'", ext, id, name);
112
for (i = 0; i < 2; i++)
113
if (strcmp(name, vol_devices[i]) == 0)
116
return SND_CTL_EXT_KEY_NOT_FOUND;
119
static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
120
int *type, unsigned int *acc, unsigned int *count)
122
DBG("ext %p key %ld", ext, key);
124
*type = SND_CTL_ELEM_TYPE_INTEGER;
125
*acc = SND_CTL_EXT_ACCESS_READWRITE;
131
static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
132
long *imin, long *imax, long *istep)
134
DBG("ext %p key %ld", ext, key);
137
*imin = BLUETOOTH_MINVOL;
138
*imax = BLUETOOTH_MAXVOL;
143
static int bluetooth_send_ctl(struct bluetooth_data *data,
144
uint8_t mode, uint8_t key, struct bt_control_rsp *ctl_rsp)
147
struct bt_control_req *ctl_req = (void *) ctl_rsp;
150
memset(ctl_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
151
ctl_req->h.msg_type = BT_CONTROL_REQ;
152
ctl_req->mode = mode;
155
ret = send(data->sock, ctl_req, BT_AUDIO_IPC_PACKET_SIZE, MSG_NOSIGNAL);
157
SYSERR("Unable to request new volume value to server");
161
ret = recv(data->sock, ctl_rsp, BT_AUDIO_IPC_PACKET_SIZE, 0);
163
SNDERR("Unable to receive new volume value from server");
167
type = bt_audio_strmsg(ctl_rsp->rsp_h.msg_h.msg_type);
169
SNDERR("Bogus message type %d "
170
"received from audio service",
171
ctl_rsp->rsp_h.msg_h.msg_type);
175
if (ctl_rsp->rsp_h.msg_h.msg_type != BT_CONTROL_RSP) {
176
SNDERR("Unexpected message %s received", type);
180
if (ctl_rsp->rsp_h.posix_errno != 0) {
181
SNDERR("BT_CONTROL failed : %s (%d)",
182
strerror(ctl_rsp->rsp_h.posix_errno),
183
ctl_rsp->rsp_h.posix_errno);
184
return -ctl_rsp->rsp_h.posix_errno;
190
static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
193
struct bluetooth_data *data = ext->private_data;
195
char buf[BT_AUDIO_IPC_PACKET_SIZE];
196
struct bt_control_rsp *rsp = (void *) buf;
198
DBG("ext %p key %ld", ext, key);
200
memset(buf, 0, sizeof(buf));
203
ret = bluetooth_send_ctl(data, key, 0, rsp);
212
static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
215
struct bluetooth_data *data = ext->private_data;
216
char buf[BT_AUDIO_IPC_PACKET_SIZE];
217
struct bt_control_rsp *rsp = (void *) buf;
221
DBG("ext %p key %ld", ext, key);
223
ret = bluetooth_read_integer(ext, key, ¤t);
227
if (*value == current)
230
while (*value != current) {
231
keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP :
232
BT_CONTROL_KEY_VOL_DOWN;
234
ret = bluetooth_send_ctl(data, key, keyvalue, rsp);
244
static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
245
unsigned int *event_mask)
247
struct bluetooth_data *data = ext->private_data;
248
char buf[BT_AUDIO_IPC_PACKET_SIZE];
249
struct bt_control_ind *ind = (void *) buf;
253
DBG("ext %p id %p", ext, id);
255
memset(buf, 0, sizeof(buf));
257
ret = recv(data->sock, ind, BT_AUDIO_IPC_PACKET_SIZE, MSG_DONTWAIT);
258
type = bt_audio_strmsg(ind->h.msg_type);
260
SNDERR("Bogus message type %d "
261
"received from audio service",
266
if (ind->h.msg_type != BT_CONTROL_IND) {
267
SNDERR("Unexpected message %s received", type);
271
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
272
snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ?
273
vol_devices[BLUETOOTH_PLAYBACK] :
274
vol_devices[BLUETOOTH_CAPTURE]);
275
*event_mask = SND_CTL_EVENT_MASK_VALUE;
280
static snd_ctl_ext_callback_t bluetooth_callback = {
281
.close = bluetooth_close,
282
.elem_count = bluetooth_elem_count,
283
.elem_list = bluetooth_elem_list,
284
.find_elem = bluetooth_find_elem,
285
.get_attribute = bluetooth_get_attribute,
286
.get_integer_info = bluetooth_get_integer_info,
287
.read_integer = bluetooth_read_integer,
288
.write_integer = bluetooth_write_integer,
289
.read_event = bluetooth_read_event,
292
static int bluetooth_init(struct bluetooth_data *data)
299
memset(data, 0, sizeof(struct bluetooth_data));
303
sk = bt_audio_service_open();
312
SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
314
struct bluetooth_data *data;
317
DBG("Bluetooth Control plugin");
319
data = malloc(sizeof(struct bluetooth_data));
325
err = bluetooth_init(data);
329
data->ext.version = SND_CTL_EXT_VERSION;
330
data->ext.card_idx = -1;
332
strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1);
333
strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1);
334
strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1);
335
strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1);
336
strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
338
data->ext.callback = &bluetooth_callback;
339
data->ext.poll_fd = data->sock;
340
data->ext.private_data = data;
342
err = snd_ctl_ext_create(&data->ext, name, mode);
346
*handlep = data->ext.handle;
351
bluetooth_exit(data);
356
SND_CTL_PLUGIN_SYMBOL(bluetooth);