feat(ble_audio): Support running ISO & LE Audio with Bluedroid Host

This commit is contained in:
Liu Linyan
2026-06-04 15:41:36 +08:00
parent 77f5214ab0
commit 91fc8d3905
223 changed files with 14714 additions and 2347 deletions
@@ -13,6 +13,49 @@
#define CONFIG_LITTLE_ENDIAN 1
#define CONFIG_BT_CONN_TX_USER_DATA_SIZE 8
#if CONFIG_BT_BLUEDROID_ENABLED
#define CONFIG_BT_ISO_EXT_ADV CONFIG_BT_BLE_50_EXTEND_ADV_EN
#define CONFIG_BT_ISO_PER_ADV CONFIG_BT_BLE_50_PERIODIC_ADV_EN
/* Bluedroid host does not expose ext-adv/periodic-sync slot counts;
* keep using the controller-side limits as the source of truth. */
#if CONFIG_BT_ISO_EXT_ADV
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES
#else /* CONFIG_BT_ISO_EXT_ADV */
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET 0
#endif /* CONFIG_BT_ISO_EXT_ADV */
#if CONFIG_BT_ISO_PER_ADV
#define CONFIG_BT_PER_ADV_SYNC_MAX CONFIG_BT_LE_MAX_PERIODIC_SYNCS
#else /* CONFIG_BT_ISO_PER_ADV */
#define CONFIG_BT_PER_ADV_SYNC_MAX 0
#endif /* CONFIG_BT_ISO_PER_ADV */
#if CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
#else /* CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER */
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER 0
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER 0
#endif /* CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER */
#define CONFIG_BT_MAX_CONN CONFIG_BT_ACL_CONNECTIONS
#define CONFIG_BT_SMP CONFIG_BT_BLE_SMP_ENABLE
#define CONFIG_BT_MAX_PAIRED CONFIG_BT_SMP_MAX_BONDS
#if CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_CIS_MAX_COUNT + CONFIG_BT_BLE_ISO_BIS_MAX_COUNT, "Too large ISO channels");
#elif CONFIG_BT_ISO_UNICAST && !CONFIG_BT_ISO_BROADCAST
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_CIS_MAX_COUNT, "Too large ISO channels");
#elif !CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_BIS_MAX_COUNT, "Too large ISO channels");
#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels");
#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
#else /* CONFIG_BT_BLUEDROID_ENABLED */
#define CONFIG_BT_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS
#define CONFIG_BT_SMP CONFIG_BT_NIMBLE_SECURITY_ENABLE
#define CONFIG_BT_MAX_PAIRED CONFIG_BT_NIMBLE_MAX_BONDS
@@ -46,3 +89,5 @@ _Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_BIS, "Too large IS
#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels");
#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
@@ -28,6 +28,7 @@ extern "C" {
/* Mutex */
#define K_MUTEX_FOREVER portMAX_DELAY
#define K_MUTEX_SHORT (5000 / portTICK_PERIOD_MS)
struct k_mutex {
SemaphoreHandle_t handle;
@@ -99,6 +100,94 @@ static inline int k_mutex_unlock(struct k_mutex *mutex)
return 0;
}
/* Semaphore */
#define K_SEM_FOREVER portMAX_DELAY
#define K_SEM_SHORT (5000 / portTICK_PERIOD_MS)
struct k_sem {
SemaphoreHandle_t handle;
int result;
};
static inline void k_sem_create(struct k_sem *sem)
{
assert(sem);
assert(sem->handle == NULL);
sem->handle = xSemaphoreCreateBinary();
assert(sem->handle);
sem->result = 0;
}
static inline void k_sem_delete(struct k_sem *sem)
{
assert(sem);
assert(sem->handle);
vSemaphoreDelete(sem->handle);
sem->handle = NULL;
}
/* Inline log helper with a fixed tag, mirroring K_MUTEX_LOG_ERR. The sem
* helpers are inlined across many TUs, not all of which call
* LOG_MODULE_REGISTER, so we cannot reference the per-TU __iso_log_tag.
* Hardcode the "ISO_SEM" tag and keep the same level gating. */
#if CONFIG_BT_ISO_NO_LOG || (CONFIG_BT_ISO_LOG_LEVEL < BT_ISO_LOG_ERROR)
#define K_SEM_LOG_ERR(fmt, args...)
#else
#define K_SEM_LOG_ERR(fmt, args...) BT_ISO_LOGE("ISO_SEM", fmt, ## args)
#endif
static inline int k_sem_take(struct k_sem *sem, uint32_t timeout)
{
assert(sem);
assert(sem->handle);
/* Do NOT touch sem->result here. The producer may have already written
* it and called k_sem_give before this take ran (BTU/HCI cb on a
* higher-priority task). Clearing now would race-overwrite the
* producer's value. Caller must k_sem_reset() before initiating the
* async op that will produce the result. */
if (xSemaphoreTake(sem->handle, timeout) == pdTRUE) {
return 0;
}
#if !CONFIG_BT_ISO_NO_LOG && (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR)
K_SEM_LOG_ERR("TakeFail[self=%s]", pcTaskGetName(NULL));
#else
K_SEM_LOG_ERR("TakeFail");
#endif
return -EIO;
}
static inline int k_sem_give(struct k_sem *sem)
{
assert(sem);
assert(sem->handle);
if (xSemaphoreGive(sem->handle) != pdTRUE) {
K_SEM_LOG_ERR("GiveFail");
return -EIO;
}
return 0;
}
/* Discard any pending give. Used by callers that reuse the same sem across
* cmd/response cycles where a previous cycle timed out — without this, a
* late give from the timed-out cycle would unblock the next take and the
* caller would see uninitialized response data. */
static inline void k_sem_reset(struct k_sem *sem)
{
assert(sem);
assert(sem->handle);
xQueueReset(sem->handle);
sem->result = 0;
}
/* Timer */
typedef uint32_t k_timeout_t;