summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/audio-api.txt36
-rw-r--r--audio/headset.c288
-rw-r--r--audio/headset.h6
-rw-r--r--audio/main.c2
-rw-r--r--audio/manager.c282
-rw-r--r--audio/manager.h32
6 files changed, 396 insertions, 250 deletions
diff --git a/audio/audio-api.txt b/audio/audio-api.txt
index 26b4d46a..1f71c14e 100644
--- a/audio/audio-api.txt
+++ b/audio/audio-api.txt
@@ -2,14 +2,13 @@ Bluetooth audio service API description
***************************************
Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
-Audio Manager hierarchy
-=======================
+org.bluez.audio.Manager interface
+=================================
-Interface org.bluez.audio.Manager
Object path /org/bluez/audio
Methods array{string} ListHeadsets()
@@ -49,11 +48,20 @@ Signals void HeadsetCreated(string path)
Sent when the default headset has changed.
-Audio Headset hierarchy
-=======================
+org.bluez.audio.Device interface
+================================
-Interface org.bluez.audio.Headset
-Object path /org/bluez/audio/headset*
+Object path(s) /org/bluez/audio/device*
+
+Methods string GetAddress()
+
+ Returns the Bluetooth address of the remote device.
+
+
+org.bluez.audio.Headset interface
+=================================
+
+Object path(s) /org/bluez/audio/device*
Methods void Connect()
@@ -111,3 +119,15 @@ Signals void AnswerRequested()
void MicrophoneGainChanged(uint16 gain)
The microphone gain changed.
+
+
+org.bluez.audio.Source interface
+================================
+
+Object path(s) /org/bluez/audio/device*
+
+
+org.bluez.audio.Sink interface
+==============================
+
+Object path(s) /org/bluez/audio/device*
diff --git a/audio/headset.c b/audio/headset.c
index 5d991fb4..72fc3bfb 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -67,8 +67,7 @@ typedef enum {
} headset_event_t;
typedef enum {
- HEADSET_STATE_UNAUTHORIZED,
- HEADSET_STATE_DISCONNECTED,
+ HEADSET_STATE_DISCONNECTED = 0,
HEADSET_STATE_CONNECT_IN_PROGRESS,
HEADSET_STATE_CONNECTED,
HEADSET_STATE_PLAY_IN_PROGRESS,
@@ -82,9 +81,6 @@ struct pending_connect {
};
struct headset {
- char object_path[128];
- bdaddr_t bda;
-
GIOChannel *rfcomm;
GIOChannel *sco;
@@ -110,8 +106,6 @@ static GIOChannel *hs_server = NULL;
static uint32_t hs_record_id = 0;
-static GSList *headsets = NULL;
-
static DBusConnection *connection = NULL;
static void pending_connect_free(struct pending_connect *c)
@@ -169,13 +163,6 @@ static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg)
return error_reply(conn, msg, "org.bluez.audio.Error.Failed", "Failed");
}
-static gint headset_bda_cmp(gconstpointer headset, gconstpointer bda)
-{
- const struct headset *hs = headset;
-
- return bacmp(&hs->bda, bda);
-}
-
static gboolean headset_close_output(struct headset *hs)
{
assert(hs != NULL);
@@ -269,7 +256,7 @@ static gboolean headset_open_input(struct headset *hs, const char *input)
}
#endif
-static void hs_signal_gain_setting(struct headset *hs, const char *buf)
+static void hs_signal_gain_setting(audio_device_t *device, const char *buf)
{
const char *name;
dbus_uint16_t gain;
@@ -293,7 +280,7 @@ static void hs_signal_gain_setting(struct headset *hs, const char *buf)
gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE, name,
DBUS_TYPE_UINT16, &gain,
DBUS_TYPE_INVALID);
@@ -321,8 +308,10 @@ static headset_event_t parse_headset_event(const char *buf, char *rsp, int rsp_l
return HEADSET_EVENT_UNKNOWN;
}
-static void close_sco(struct headset *hs)
+static void close_sco(audio_device_t *device)
{
+ struct headset *hs = device->headset;
+
g_io_channel_close(hs->sco);
g_io_channel_unref(hs->sco);
hs->sco = NULL;
@@ -334,15 +323,15 @@ static void close_sco(struct headset *hs)
headset_close_input(hs);
assert(hs->rfcomm);
hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE, "Stopped",
DBUS_TYPE_INVALID);
}
-
static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
- struct headset *hs)
+ audio_device_t *device)
{
+ struct headset *hs = device->headset;
unsigned char buf[BUF_SIZE];
char *cr, rsp[BUF_SIZE];
gsize bytes_read = 0;
@@ -387,7 +376,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
switch (parse_headset_event(&hs->buf[hs->data_start], rsp, sizeof(rsp))) {
case HEADSET_EVENT_GAIN:
- hs_signal_gain_setting(hs, &hs->buf[hs->data_start] + 2);
+ hs_signal_gain_setting(device, &hs->buf[hs->data_start] + 2);
break;
case HEADSET_EVENT_KEYPRESS:
@@ -396,7 +385,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
hs->ring_timer = 0;
}
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE,
"AnswerRequested",
DBUS_TYPE_INVALID);
@@ -432,17 +421,17 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
failed:
if (hs->sco)
- close_sco(hs);
- hs_disconnect(NULL, NULL, hs);
+ close_sco(device);
+ hs_disconnect(NULL, NULL, device);
return FALSE;
}
-static void send_cancel_auth(struct headset *hs)
+static void send_cancel_auth(audio_device_t *device)
{
DBusMessage *cancel;
char addr[18], *address = addr;
- const char *uuid = "";
+ const char *uuid = HSP_AG_UUID;
cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",
"org.bluez.Database",
@@ -452,7 +441,7 @@ static void send_cancel_auth(struct headset *hs)
return;
}
- ba2str(&hs->bda, addr);
+ ba2str(&device->bda, addr);
dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,
DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
@@ -462,7 +451,8 @@ static void send_cancel_auth(struct headset *hs)
static void auth_callback(DBusPendingCall *call, void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusError err;
@@ -471,7 +461,7 @@ static void auth_callback(DBusPendingCall *call, void *data)
error("Access denied: %s", err.message);
if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
debug("Canceling authorization request");
- send_cancel_auth(hs);
+ send_cancel_auth(device);
}
dbus_error_free(&err);
g_io_channel_close(hs->rfcomm);
@@ -481,14 +471,15 @@ static void auth_callback(DBusPendingCall *call, void *data)
char hs_address[18];
g_io_add_watch(hs->rfcomm, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, hs);
+ (GIOFunc) rfcomm_io_cb, device);
- ba2str(&hs->bda, hs_address);
+ ba2str(&device->bda, hs_address);
- debug("Accepted connection from %s for %s", hs_address, hs->object_path);
+ debug("Accepted headset connection from %s for %s", hs_address,
+ device->object_path);
hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE,
"Connected",
DBUS_TYPE_INVALID);
@@ -499,7 +490,8 @@ static void auth_callback(DBusPendingCall *call, void *data)
static gboolean audio_input_to_sco_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
char buf[1024];
gsize bytes_read;
gsize bytes_written, total_bytes_written;
@@ -536,7 +528,8 @@ failed:
static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
char buf[1024];
gsize bytes_read;
gsize bytes_written, total_bytes_written;
@@ -579,13 +572,14 @@ static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond
disconn:
error("Audio connection got disconnected");
if (hs->sco)
- close_sco(hs);
+ close_sco(device);
return FALSE;
}
static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
- struct headset *hs)
+ audio_device_t *device)
{
+ struct headset *hs = device->headset;
int ret, sk, err, flags;
socklen_t len;
DBusMessage *reply;
@@ -611,7 +605,7 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
goto failed;
}
- debug("SCO socket opened for headset %s", hs->object_path);
+ debug("SCO socket opened for headset %s", device->object_path);
hs->sco = chan;
hs->pending_connect->io = NULL;
@@ -629,13 +623,13 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
/* FIXME: do we allow both? pull & push model at the same time on sco && audio_input? */
if (hs->audio_input)
g_io_add_watch(hs->audio_input, G_IO_IN | G_IO_NVAL,
- audio_input_to_sco_cb, hs);
+ audio_input_to_sco_cb, device);
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
hs->state = HEADSET_STATE_PLAYING;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE,
"Playing", DBUS_TYPE_INVALID);
@@ -654,8 +648,10 @@ failed:
return FALSE;
}
-static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct headset *hs)
+static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,
+ audio_device_t *device)
{
+ struct headset *hs = device->headset;
char hs_address[18];
int sk, ret, err;
socklen_t len;
@@ -682,19 +678,19 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct he
goto failed;
}
- ba2str(&hs->bda, hs_address);
+ ba2str(&device->bda, hs_address);
hs->rfcomm = chan;
hs->pending_connect->io = NULL;
hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE,
"Connected", DBUS_TYPE_INVALID);
debug("Connected to %s", hs_address);
g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, hs);
+ (GIOFunc) rfcomm_io_cb, device);
if (hs->pending_connect->msg) {
DBusMessage *reply;
@@ -721,8 +717,9 @@ failed:
return FALSE;
}
-static int rfcomm_connect(struct headset *hs, int *err)
+static int rfcomm_connect(audio_device_t *device, int *err)
{
+ struct headset *hs = device->headset;
struct sockaddr_rc addr;
char address[18];
int sk;
@@ -730,7 +727,7 @@ static int rfcomm_connect(struct headset *hs, int *err)
assert(hs != NULL && hs->pending_connect != NULL &&
hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
- ba2str(&hs->bda, address);
+ ba2str(&device->bda, address);
debug("Connecting to %s channel %d", address, hs->pending_connect->ch);
@@ -761,7 +758,7 @@ static int rfcomm_connect(struct headset *hs, int *err)
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, &hs->bda);
+ bacpy(&addr.rc_bdaddr, &device->bda);
addr.rc_channel = hs->pending_connect->ch;
hs->pending_connect->io = g_io_channel_unix_new(sk);
@@ -781,10 +778,10 @@ static int rfcomm_connect(struct headset *hs, int *err)
debug("Connect in progress");
g_io_add_watch(hs->pending_connect->io, G_IO_OUT | G_IO_NVAL,
- (GIOFunc) rfcomm_connect_cb, hs);
+ (GIOFunc) rfcomm_connect_cb, device);
} else {
debug("Connect succeeded with first try");
- rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, hs);
+ rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, device);
}
return 0;
@@ -986,7 +983,8 @@ static void get_record_reply(DBusPendingCall *call, void *data)
sdp_record_t *record = NULL;
sdp_list_t *protos, *classes = NULL;
uuid_t uuid;
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
struct pending_connect *c;
assert(hs != NULL && hs->pending_connect && !hs->rfcomm);
@@ -1053,7 +1051,7 @@ static void get_record_reply(DBusPendingCall *call, void *data)
goto failed_not_supported;
}
- if (rfcomm_connect(hs, &err) < 0) {
+ if (rfcomm_connect(device, &err) < 0) {
error("Unable to connect");
if (c->msg)
err_connect_failed(connection, c->msg, err);
@@ -1064,7 +1062,7 @@ static void get_record_reply(DBusPendingCall *call, void *data)
sdp_record_free(record);
dbus_message_unref(reply);
- finish_sdp_transaction(&hs->bda);
+ finish_sdp_transaction(&device->bda);
return;
@@ -1081,13 +1079,14 @@ failed:
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
hs->state = HEADSET_STATE_DISCONNECTED;
- finish_sdp_transaction(&hs->bda);
+ finish_sdp_transaction(&device->bda);
}
static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
if (!hs || !hs->sco)
@@ -1109,7 +1108,7 @@ static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg,
hs->state = HEADSET_STATE_CONNECTED;
}
- close_sco(hs);
+ close_sco(device);
if (reply)
send_message_and_unref(connection, reply);
@@ -1120,7 +1119,8 @@ static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg,
static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply;
dbus_bool_t playing;
@@ -1146,7 +1146,8 @@ static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg,
static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
char hs_address[18];
@@ -1179,10 +1180,10 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
hs->state = HEADSET_STATE_DISCONNECTED;
- ba2str(&hs->bda, hs_address);
- info("Disconnected from %s, %s", &hs_address, hs->object_path);
+ ba2str(&device->bda, hs_address);
+ info("Disconnected from %s, %s", hs_address, device->object_path);
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(connection, device->object_path,
AUDIO_HEADSET_INTERFACE,
"Disconnected", DBUS_TYPE_INVALID);
@@ -1198,7 +1199,8 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply;
dbus_bool_t connected;
@@ -1226,7 +1228,8 @@ static void get_handles_reply(DBusPendingCall *call, void *data)
DBusMessage *msg = NULL, *reply;
DBusPendingCall *pending;
DBusError derr;
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
struct pending_connect *c;
char address[18], *addr_ptr = address;
dbus_uint32_t *array = NULL;
@@ -1288,7 +1291,7 @@ static void get_handles_reply(DBusPendingCall *call, void *data)
goto failed;
}
- ba2str(&hs->bda, address);
+ ba2str(&device->bda, address);
handle = array[0];
@@ -1303,7 +1306,7 @@ static void get_handles_reply(DBusPendingCall *call, void *data)
goto failed;
}
- dbus_pending_call_set_notify(pending, get_record_reply, hs, NULL);
+ dbus_pending_call_set_notify(pending, get_record_reply, device, NULL);
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
dbus_message_unref(reply);
@@ -1321,7 +1324,8 @@ static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
DBusPendingCall *pending;
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
const char *hs_svc = "hsp";
const char *addr_ptr;
char hs_address[18];
@@ -1352,7 +1356,7 @@ static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
- ba2str(&hs->bda, hs_address);
+ ba2str(&device->bda, hs_address);
addr_ptr = hs_address;
dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
DBUS_TYPE_STRING, &hs_svc,
@@ -1367,22 +1371,23 @@ static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
return err_connect_failed(connection, msg, EIO);
}
- dbus_pending_call_set_notify(pending, get_handles_reply, hs, NULL);
+ dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL);
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
return DBUS_HANDLER_RESULT_HANDLED;;
}
-static GIOError headset_send_ring(struct headset *hs)
+static GIOError headset_send_ring(audio_device_t *device)
{
+ struct headset *hs = device->headset;
const char *ring_str = "\r\nRING\r\n";
GIOError err;
gsize total_written, written, count;
assert(hs != NULL);
if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) {
- error("the headset %s is not connected", hs->object_path);
+ error("the headset %s is not connected", device->object_path);
return G_IO_ERROR_UNKNOWN;
}
@@ -1402,11 +1407,11 @@ static GIOError headset_send_ring(struct headset *hs)
static gboolean ring_timer_cb(gpointer data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
- assert(hs != NULL);
+ assert(device != NULL);
- if (headset_send_ring(hs) != G_IO_ERROR_NONE)
+ if (headset_send_ring(device) != G_IO_ERROR_NONE)
error("Sending RING failed");
return TRUE;
@@ -1415,7 +1420,8 @@ static gboolean ring_timer_cb(gpointer data)
static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
assert(hs != NULL);
@@ -1434,12 +1440,12 @@ static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg,
goto done;
}
- if (headset_send_ring(hs) != G_IO_ERROR_NONE) {
+ if (headset_send_ring(device) != G_IO_ERROR_NONE) {
dbus_message_unref(reply);
return err_failed(connection, msg);
}
- hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, hs);
+ hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);
done:
if (reply)
@@ -1451,7 +1457,8 @@ done:
static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
if (hs->state < HEADSET_STATE_CONNECTED)
@@ -1481,7 +1488,8 @@ done:
static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ audio_device_t *device = data;
+ struct headset *hs = device->headset;
struct sockaddr_sco addr;
struct pending_connect *c;
int sk, err;
@@ -1537,7 +1545,7 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, &hs->bda);
+ bacpy(&addr.sco_bdaddr, &device->bda);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
if (!(errno == EAGAIN || errno == EINPROGRESS)) {
@@ -1549,10 +1557,10 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,
debug("Connect in progress");
g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL,
- (GIOFunc) sco_connect_cb, hs);
+ (GIOFunc) sco_connect_cb, device);
} else {
debug("Connect succeeded with first try");
- sco_connect_cb(c->io, G_IO_OUT, hs);
+ sco_connect_cb(c->io, G_IO_OUT, device);
}
hs->pending_connect = c;
@@ -1589,93 +1597,15 @@ static DBusSignalVTable headset_signals[] = {
{ NULL, NULL }
};
-static struct headset *headset_add_internal(const bdaddr_t *bda)
-{
- static int headset_uid = 0;
- struct headset *hs;
- GSList *match;
-
- match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
- if (match)
- return match->data;
-
- hs = g_try_new0(struct headset, 1);
- if (!hs) {
- error("Allocating new hs connection struct failed!");
- return NULL;
- }
-
- snprintf(hs->object_path, sizeof(hs->object_path),
- HEADSET_PATH_BASE "%d", headset_uid++);
-
- if (!dbus_connection_create_object_path(connection, hs->object_path,
- hs, NULL)) {
- error("D-Bus failed to register %s path", hs->object_path);
- g_free(hs);
- return NULL;
- }
-
- if (!dbus_connection_register_interface(connection, hs->object_path,
- AUDIO_HEADSET_INTERFACE,
- headset_methods,
- headset_signals, NULL)) {
- error("Failed to register %s interface to %s",
- AUDIO_HEADSET_INTERFACE, hs->object_path);
- dbus_connection_destroy_object_path(connection,
- hs->object_path);
- g_free(hs);
- return NULL;
- }
-
- bacpy(&hs->bda, bda);
-
- headsets = g_slist_append(headsets, hs);
-
- return hs;
-}
-
-const char *headset_add(const bdaddr_t *bda)
-{
- struct headset *hs;
-
- hs = headset_add_internal(bda);
- if (!hs)
- return NULL;
-
- return hs->object_path;
-}
-
-const char *headset_get(const bdaddr_t *bda)
+headset_t *headset_init(const char *object_path)
{
- GSList *match;
- struct headset *hs;
-
- match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
- if (!match)
+ if (!dbus_connection_register_interface(connection, object_path,
+ AUDIO_HEADSET_INTERFACE,
+ headset_methods,
+ headset_signals, NULL))
return NULL;
- hs = match->data;
-
- return hs->object_path;
-}
-
-void headset_remove(const char *path)
-{
- struct headset *hs;
-
- if (!dbus_connection_get_object_user_data(connection, path,
- (void *) &hs))
- return;
-
- if (hs->state > HEADSET_STATE_DISCONNECTED)
- hs_disconnect(NULL, NULL, hs);
-
- if (!dbus_connection_destroy_object_path(connection, path))
- error("D-Bus failed to unregister %s path", path);
-
- headsets = g_slist_remove(headsets, hs);
-
- g_free(hs);
+ return g_new0(headset_t, 1);
}
static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
@@ -1684,11 +1614,11 @@ static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *
struct sockaddr_rc addr;
socklen_t size;
char hs_address[18], *address = hs_address;
- const char *uuid = "";
- struct headset *hs = NULL;
+ const char *uuid = HSP_AG_UUID;
+ audio_device_t *device;
+ struct headset *hs;
DBusMessage *auth;
DBusPendingCall *pending;
- GSList *match;
if (cond & G_IO_NVAL)
return FALSE;
@@ -1709,19 +1639,13 @@ static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *
return TRUE;
}
- match = g_slist_find_custom(headsets, &addr.rc_bdaddr, headset_bda_cmp);
- if (!match) {
- hs = headset_add_internal(&addr.rc_bdaddr);
- if (!hs) {
- error("Unable to create a new headset object");
- close(cli_sk);
- return TRUE;
- }
-
- manager_add_headset(hs->object_path);
+ device = manager_headset_connected(&addr.rc_bdaddr);
+ if (!device) {
+ close(cli_sk);
+ return TRUE;
}
- else
- hs = match->data;
+
+ hs = device->headset;
if (hs->state > HEADSET_STATE_DISCONNECTED || hs->rfcomm) {
debug("Refusing new connection since one already exists");
@@ -1743,7 +1667,7 @@ static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *
goto failed;
}
- ba2str(&hs->bda, hs_address);
+ ba2str(&device->bda, hs_address);
dbus_message_append_args(auth, DBUS_TYPE_STRING, &address,
DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
@@ -1753,7 +1677,7 @@ static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *
goto failed;
}
- dbus_pending_call_set_notify(pending, auth_callback, hs, NULL);
+ dbus_pending_call_set_notify(pending, auth_callback, device, NULL);
dbus_pending_call_unref(pending);
dbus_message_unref(auth);
@@ -1820,7 +1744,7 @@ static GIOChannel *server_socket(uint8_t *channel)
return io;
}
-int headset_init(DBusConnection *conn)
+int headset_server_init(DBusConnection *conn)
{
uint8_t chan = DEFAULT_HS_AG_CHANNEL;
diff --git a/audio/headset.h b/audio/headset.h
index ae5119fc..de8e8a38 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -31,13 +31,15 @@
#define BUF_SIZE 1024
+typedef struct headset headset_t;
+
const char *headset_get(const bdaddr_t *bda);
const char *headset_add(const bdaddr_t *bda);
-void headset_remove(const char *path);
+headset_t *headset_init(const char *path);
-int headset_init(DBusConnection *conn);
+int headset_server_init(DBusConnection *conn);
void headset_exit(void);
diff --git a/audio/main.c b/audio/main.c
index 2188e6e7..5c44df9b 100644
--- a/audio/main.c
+++ b/audio/main.c
@@ -78,7 +78,7 @@ int main(int argc, char *argv[])
exit(1);
}
- if (headset_init(conn) < 0) {
+ if (headset_server_init(conn) < 0) {
error("Headset initialization failed!");
exit(1);
}
diff --git a/audio/manager.c b/audio/manager.c
index 5d381972..682158c2 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -56,9 +56,9 @@
static DBusConnection *connection = NULL;
-static char *default_hs = NULL;
+static audio_device_t *default_hs = NULL;
-static GSList *headsets = NULL;
+static GSList *devices = NULL;
static int unix_sock = -1;
@@ -116,85 +116,242 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
return TRUE;
}
-void manager_add_headset(const char *path)
+static audio_device_t *find_device(bdaddr_t *bda)
{
- char *my_path = g_strdup(path);
+ GSList *l;
+
+ for (l = devices; l != NULL; l = l->next) {
+ audio_device_t *device = l->data;
+ if (bacmp(&device->bda, bda) == 0)
+ return device;
+ }
+
+ return NULL;
+}
+
+static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ audio_device_t *device = data;
+ DBusMessage *reply;
+ char address[18], *ptr = address;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
- headsets = g_slist_append(headsets, my_path);
+ ba2str(&device->bda, address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable device_methods[] = {
+ { "GetAddress", device_get_address, "", "s" },
+ { NULL, NULL, NULL, NULL }
+};
+
+static audio_device_t *add_device(bdaddr_t *bda)
+{
+ static int device_id = 0;
+ audio_device_t *device;
+
+ device = g_new0(audio_device_t, 1);
+
+ bacpy(&device->bda, bda);
+
+ snprintf(device->object_path, sizeof(device->object_path) - 1,
+ "%s/device%d", AUDIO_MANAGER_PATH, device_id++);
+
+ if (!dbus_connection_create_object_path(connection, device->object_path,
+ device, NULL)) {
+ error("D-Bus failed to register %s path", device->object_path);
+ g_free(device);
+ return NULL;
+ }
+
+ if (!dbus_connection_register_interface(connection, device->object_path,
+ AUDIO_DEVICE_INTERFACE,
+ device_methods, NULL, NULL)) {
+ error("Failed to register %s interface to %s",
+ AUDIO_DEVICE_INTERFACE, device->object_path);
+ dbus_connection_destroy_object_path(connection,
+ device->object_path);
+ g_free(device);
+ return NULL;
+ }
+
+ devices = g_slist_append(devices, device);
+
+ return device;
+}
+
+static void remove_device(audio_device_t *device)
+{
+ devices = g_slist_remove(devices, device);
+ dbus_connection_destroy_object_path(connection, device->object_path);
+ g_free(device->headset);
+ g_free(device);
+}
+
+audio_device_t *manager_headset_connected(bdaddr_t *bda)
+{
+ audio_device_t *device;
+ const char *path;
+
+ device = find_device(bda);
+ if (device && device->headset)
+ return device;
+
+ if (!device)
+ device = add_device(bda);
+
+ if (!device)
+ return NULL;
+
+ if (!device->headset)
+ device->headset = headset_init(device->object_path);
+
+ if (!device->headset)
+ return NULL;
+
+ path = device->object_path;
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"HeadsetCreated",
- DBUS_TYPE_STRING, &my_path,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
if (!default_hs) {
- default_hs = my_path;
+ default_hs = device;
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &my_path,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
}
-}
-static void manager_remove_headset(char *path)
-{
- headset_remove(path);
- g_free(path);
+ return device;
}
-static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_create_device(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- const char *hs_path;
const char *address;
bdaddr_t bda;
- DBusMessage *reply;
+ audio_device_t *device;
DBusError derr;
+ DBusMessageIter iter, array_iter;
dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&derr)) {
err_invalid_args(connection, msg, derr.message);
+ dbus_error_free(&derr);
return DBUS_HANDLER_RESULT_HANDLED;
}
+
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+ if (device) {
+ const char *iface, *path = device->object_path;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &path);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "s", &array_iter);
+ if (device->headset) {
+ iface = AUDIO_HEADSET_INTERFACE;
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &iface);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return send_message_and_unref(conn, reply);
+ }
+
+ device = add_device(&bda);
+ /*
+ resolve_services(conn, device, msg);
+ */
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path, *address;
+ bdaddr_t bda;
+ DBusMessage *reply;
+ DBusError derr;
+ audio_device_t *device;
+
+ dbus_error_init(&derr);
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
if (dbus_error_is_set(&derr)) {
err_invalid_args(connection, msg, derr.message);
dbus_error_free(&derr);
return DBUS_HANDLER_RESULT_HANDLED;
}
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+ if (!device)
+ device = add_device(&bda);
+
+ if (!device)
+ return error_reply(connection, msg,
+ "org.bluez.audio.Error.Failed",
+ "Unable to create new audio device");
+
+ device->headset = headset_init(device->object_path);
+ if (!device->headset)
+ return error_reply(connection, msg,
+ "org.bluez.audio.Error.Failed",
+ "Unable to init Headset interface");
+
+ path = device->object_path;
+
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- str2ba(address, &bda);
-
- hs_path = headset_get(&bda);
- if (!hs_path) {
- hs_path = headset_add(&bda);
- if (!hs_path)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.Failed",
- "Unable to create new headset object");
- manager_add_headset(hs_path);
- }
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &hs_path,
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
+static gint device_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const audio_device_t *device = a;
+ const char *path = b;
+
+ return strcmp(device->object_path, path);
+}
+
static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *msg,
void *data)
{
DBusError derr;
DBusMessage *reply;
GSList *match;
- char *path;
+ const char *path;
+ audio_device_t *device;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -209,7 +366,7 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
return error_reply(connection, msg,
"org.bluez.audio.Error.DoesNotExist",
@@ -219,19 +376,24 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- path = match->data;
+ device = match->data;
- headsets = g_slist_remove(headsets, path);
+ remove_device(device);
- if (default_hs == path) {
+ if (default_hs == device) {
const char *param;
+ GSList *l;
+
+ default_hs = NULL;
- if (!headsets)
- default_hs = NULL;
- else
- default_hs = headsets->data;
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
- param = default_hs ? default_hs : "";
+ if (device->headset)
+ default_hs = device;
+ }
+
+ param = default_hs ? default_hs->object_path : "";
dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
@@ -246,10 +408,6 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
- headset_remove(path);
-
- g_free(path);
-
return send_message_and_unref(connection, reply);
}
@@ -270,9 +428,18 @@ static DBusHandlerResult am_list_headsets(DBusConnection *conn, DBusMessage *msg
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &array_iter);
- for (l = headsets; l != NULL; l = l->next)
+ for (l = devices; l != NULL; l = l->next) {
+ audio_device_t *device = l->data;
+ const char *path;
+
+ if (!device->headset)
+ continue;
+
+ path = device->object_path;
+
dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_STRING, &l->data);
+ DBUS_TYPE_STRING, &path);
+ }
dbus_message_iter_close_container(&iter, &array_iter);
@@ -283,6 +450,7 @@ static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessag
void *data)
{
DBusMessage *reply;
+ const char *path;
if (!default_hs)
return error_reply(connection, msg,
@@ -293,7 +461,9 @@ static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessag
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_hs,
+ path = default_hs->object_path;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
@@ -320,7 +490,7 @@ static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMes
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
return error_reply(connection, msg,
"org.bluez.audio.Error.DoesNotExist",
@@ -332,16 +502,20 @@ static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMes
default_hs = match->data;
+ path = default_hs->object_path;
+
dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &default_hs,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
static DBusMethodVTable manager_methods[] = {
+ { "CreateDevice", am_create_device,
+ "s", "sas" },
{ "CreateHeadset", am_create_headset,
"s", "s" },
{ "RemoveHeadset", am_remove_headset,
@@ -425,11 +599,9 @@ void audio_exit(void)
unix_sock = -1;
- if (headsets) {
- g_slist_foreach(headsets, (GFunc) manager_remove_headset, NULL);
- g_slist_free(headsets);
- headsets = NULL;
- }
+ g_slist_foreach(devices, (GFunc) remove_device, NULL);
+ g_slist_free(devices);
+ devices = NULL;
dbus_connection_unref(connection);
diff --git a/audio/manager.h b/audio/manager.h
index 6356ab1c..9fd98d65 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -30,9 +30,37 @@
#define AUDIO_MANAGER_PATH "/org/bluez/audio"
#define AUDIO_MANAGER_INTERFACE "org.bluez.audio.Manager"
-#define HEADSET_PATH_BASE AUDIO_MANAGER_PATH "/headset"
+#define AUDIO_DEVICE_INTERFACE "org.bluez.audio.Device"
-void manager_add_headset(const char *path);
+#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805F9B34FB"
+
+#define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
+#define HSP_AG_UUID "00001112-0000-1000-8000-00805F9B34FB"
+
+#define HFP_HS_UUID "0000111E-0000-1000-8000-00805F9B34FB"
+#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"
+
+#define ADVANCED_AUDIO_UUID "0000110D-0000-1000-8000-00805F9B34FB"
+
+#define A2DP_SOURCE_UUID "0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID "0000110B-0000-1000-8000-00805F9B34FB"
+
+#define AVRCP_REMOTE_UUID "0000110E-0000-1000-8000-00805F9B34FB"
+#define AVRCP_TARGET_UUID "0000110C-0000-1000-8000-00805F9B34FB"
+
+typedef struct audio_device {
+ char object_path[128];
+ bdaddr_t bda;
+
+ headset_t *headset;
+/*
+ sink_t *sink;
+ source_t *source;
+ control_t *control;
+*/
+} audio_device_t;
+
+audio_device_t *manager_headset_connected(bdaddr_t *bda);
int audio_init(DBusConnection *conn);