2012-03-12 15:56:36

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v0 0/3] audio: enabling both Headset and Gateway

From: Mikel Astiz <[email protected]>

When both Gateway and Headset are enabled, special care must be taken to avoid inconsistent states.

This affects the audio device driver, which needs to handle partial driver unloading (proposed in patch 2/3).

If this approach is accepted, other drivers that support multiple profiles (such as HDP and proximity monitor driver) should consider if they need to handle these transitions.

Mikel Astiz (3):
audio: fix omitting headset records if AG found
Add device driver support for partial unloading
audio: add partial unloading to audio driver

audio/manager.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++---
src/device.c | 15 +++++++++++--
src/device.h | 1 +
3 files changed, 68 insertions(+), 7 deletions(-)

--
1.7.7.6



2012-03-12 15:56:39

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v0 3/3] audio: add partial unloading to audio driver

From: Mikel Astiz <[email protected]>

This solves the issue fully unloading the driver when one of the
supported profiles is not found in the reverse discovery process.

This can be easily reproduced when both Headset and Gateway are enabled.
When a new phone is paired, the incoming connection can be handled by
the gateway server, which assumes the remote device is a HFP headset,
and installs the HFP_HS_UUID. Once the reverse discovery information is
available, this uuid must be removed, but not the whole driver.
---
audio/manager.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 44 insertions(+), 1 deletions(-)

diff --git a/audio/manager.c b/audio/manager.c
index ab97314..ad32446 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -799,6 +799,49 @@ static int audio_probe(struct btd_device *device, GSList *uuids)
return 0;
}

+static int device_part_count(struct audio_device *dev)
+{
+ int count = 0;
+
+ count += dev->headset ? 1 : 0;
+ count += dev->gateway ? 1 : 0;
+ count += dev->sink ? 1 : 0;
+ count += dev->source ? 1 : 0;
+ count += dev->control ? 1 : 0;
+ count += dev->target ? 1 : 0;
+
+ return count;
+}
+
+static int audio_partial_remove(struct btd_device *device, const char *uuid)
+{
+ struct audio_device *dev;
+ const char *path;
+ int part_count;
+
+ path = device_get_path(device);
+
+ DBG("%s: remove uuid %s", path, uuid);
+
+ dev = manager_find_device(path, NULL, NULL, NULL, FALSE);
+ if (!dev)
+ return 0;
+
+ part_count = device_part_count(dev);
+
+ if ((dev->headset != NULL) && !g_strcmp0(uuid, HSP_HS_UUID)) {
+ headset_unregister(dev);
+ return part_count - 1;
+ }
+
+ if ((dev->gateway != NULL) && !g_strcmp0(uuid, HFP_AG_UUID)) {
+ gateway_unregister(dev);
+ return part_count - 1;
+ }
+
+ return part_count;
+}
+
static void audio_remove(struct btd_device *device)
{
struct audio_device *dev;
@@ -813,7 +856,6 @@ static void audio_remove(struct btd_device *device)
devices = g_slist_remove(devices, dev);

audio_device_unregister(dev);
-
}

static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
@@ -1115,6 +1157,7 @@ static struct btd_device_driver audio_driver = {
ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID,
AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID),
.probe = audio_probe,
+ .partial_remove = audio_partial_remove,
.remove = audio_remove,
};

--
1.7.7.6


2012-03-12 15:56:38

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v0 2/3] Add device driver support for partial unloading

From: Mikel Astiz <[email protected]>

A driver that supports several profiles (uuid) should not necessarily be
completely unloaded just because one of its profiles has been removed.

This patch adds a new callback that a driver can implement, where
partial removals are handled. The return value of this callback will
tell the core if the driver should be entirely removed (in that case, 0
is returned).
---
src/device.c | 15 ++++++++++++---
src/device.h | 1 +
2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/device.c b/src/device.c
index dfc8e59..a38dbe7 100644
--- a/src/device.c
+++ b/src/device.c
@@ -497,6 +497,17 @@ static void driver_remove(struct btd_device_driver *driver,
device->drivers = g_slist_remove(device->drivers, driver);
}

+static void driver_partial_remove(struct btd_device_driver *driver,
+ struct btd_device *device,
+ const char *uuid)
+{
+ if (driver->partial_remove != NULL)
+ if (driver->partial_remove(device, uuid) > 0)
+ return;
+
+ driver_remove(driver, device);
+}
+
static gboolean do_disconnect(gpointer user_data)
{
struct btd_device *device = user_data;
@@ -1349,9 +1360,7 @@ static void device_remove_drivers(struct btd_device *device, GSList *uuids)
DBG("UUID %s was removed from device %s",
*uuid, dstaddr);

- driver->remove(device);
- device->drivers = g_slist_remove(device->drivers,
- driver);
+ driver_partial_remove(driver, device, *uuid);
break;
}
}
diff --git a/src/device.h b/src/device.h
index 7cb9bb2..ef4909b 100644
--- a/src/device.h
+++ b/src/device.h
@@ -107,6 +107,7 @@ struct btd_device_driver {
const char *name;
const char **uuids;
int (*probe) (struct btd_device *device, GSList *uuids);
+ int (*partial_remove) (struct btd_device *device, const char *uuid);
void (*remove) (struct btd_device *device);
};

--
1.7.7.6


2012-03-12 15:56:37

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v0 1/3] audio: fix omitting headset records if AG found

From: Mikel Astiz <[email protected]>

During pairing both records can be registered, when an incoming
connection is handled by the gateway server (hf_io_cb). In any case only
the AG record should be left, and thus the headset record must be either
omitted or removed.

Without this patch, both device->headset and device->gateway can be set.
The first point where this causes trouble is inside sco_server_cb, where
the state of the headset is checked (disconnected) and the incoming SCO
request is refused.
---
audio/manager.c | 14 +++++++++++---
1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/audio/manager.c b/audio/manager.c
index 68a0a56..ab97314 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -182,7 +182,9 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
switch (uuid16) {
case HEADSET_SVCLASS_ID:
DBG("Found Headset record");
- if (device->headset)
+ if (device->gateway)
+ DBG("Omitting record because Handsfree AG exists");
+ else if (device->headset)
headset_update(device, uuid16, uuidstr);
else
device->headset = headset_init(device, uuid16,
@@ -193,7 +195,9 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
break;
case HANDSFREE_SVCLASS_ID:
DBG("Found Handsfree record");
- if (device->headset)
+ if (device->gateway)
+ DBG("Omitting record because Handsfree AG exists");
+ else if (device->headset)
headset_update(device, uuid16, uuidstr);
else
device->headset = headset_init(device, uuid16,
@@ -201,8 +205,12 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
break;
case HANDSFREE_AGW_SVCLASS_ID:
DBG("Found Handsfree AG record");
- if (enabled.gateway && (device->gateway == NULL))
+ if (enabled.gateway && (device->gateway == NULL)) {
device->gateway = gateway_init(device);
+
+ if (device->headset != NULL)
+ headset_unregister(device);
+ }
break;
case AUDIO_SINK_SVCLASS_ID:
DBG("Found Audio Sink");
--
1.7.7.6