2022-01-07 17:23:45 +01:00
|
|
|
/* @file
|
|
|
|
* @brief Bluetooth PACS
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2020 Intel Corporation
|
|
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 09:58:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/sys/byteorder.h>
|
2022-04-12 16:11:18 +02:00
|
|
|
#include <zephyr/sys/check.h>
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/device.h>
|
|
|
|
#include <zephyr/init.h>
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
|
|
#include <zephyr/bluetooth/conn.h>
|
|
|
|
#include <zephyr/bluetooth/gatt.h>
|
|
|
|
#include <zephyr/bluetooth/audio/audio.h>
|
|
|
|
#include <zephyr/bluetooth/audio/capabilities.h>
|
2022-01-07 17:23:45 +01:00
|
|
|
#include "../host/conn_internal.h"
|
|
|
|
|
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_PACS)
|
|
|
|
#define LOG_MODULE_NAME bt_pacs
|
|
|
|
#include "common/log.h"
|
|
|
|
|
2022-07-25 09:56:23 +02:00
|
|
|
#include "audio_internal.h"
|
2022-01-07 17:23:45 +01:00
|
|
|
#include "pacs_internal.h"
|
|
|
|
#include "unicast_server.h"
|
|
|
|
|
2022-01-31 11:28:59 +01:00
|
|
|
#define PAC_NOTIFY_TIMEOUT K_MSEC(10)
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
#define PACS_LOCATION(_name, _work_handler) \
|
|
|
|
struct pacs_location _name = { \
|
|
|
|
.work = Z_WORK_DELAYABLE_INITIALIZER(_work_handler), \
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pacs_location {
|
|
|
|
struct k_work_delayable work;
|
|
|
|
uint32_t location;
|
|
|
|
};
|
|
|
|
|
2022-10-18 14:46:12 +02:00
|
|
|
static sys_slist_t snks;
|
|
|
|
static sys_slist_t srcs;
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK)
|
|
|
|
static uint16_t snk_available_contexts;
|
|
|
|
static const uint16_t snk_supported_contexts = CONFIG_BT_PACS_SNK_CONTEXT;
|
|
|
|
#else
|
|
|
|
static const uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
|
|
|
static const uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
|
|
|
#endif /* CONFIG_BT_PAC_SNK */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_PAC_SRC)
|
|
|
|
static uint16_t src_available_contexts;
|
|
|
|
static const uint16_t src_supported_contexts = CONFIG_BT_PACS_SRC_CONTEXT;
|
|
|
|
#else
|
|
|
|
static const uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
|
|
|
static const uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
|
|
|
#endif /* CONFIG_BT_PAC_SRC */
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 14:46:12 +02:00
|
|
|
NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, CONFIG_BT_L2CAP_TX_MTU);
|
2022-04-12 16:11:18 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
static ssize_t pac_data_add(struct net_buf_simple *buf, size_t count,
|
|
|
|
struct bt_codec_data *data)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
2022-10-20 09:47:34 +02:00
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
struct bt_pac_ltv *ltv;
|
2022-01-07 17:23:45 +01:00
|
|
|
struct bt_data *d = &data[i].data;
|
2022-10-20 09:47:34 +02:00
|
|
|
const size_t ltv_len = sizeof(*ltv) + d->data_len;
|
|
|
|
|
|
|
|
if (net_buf_simple_tailroom(buf) < ltv_len) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
ltv = net_buf_simple_add(buf, sizeof(*ltv));
|
|
|
|
ltv->len = d->data_len + sizeof(ltv->type);
|
|
|
|
ltv->type = d->type;
|
2022-01-07 17:23:45 +01:00
|
|
|
net_buf_simple_add_mem(buf, d->data, d->data_len);
|
2022-09-26 17:40:23 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
len += ltv_len;
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
2022-10-20 09:47:34 +02:00
|
|
|
|
|
|
|
return len;
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 22:37:32 +02:00
|
|
|
struct pac_records_build_data {
|
|
|
|
struct bt_pacs_read_rsp *rsp;
|
|
|
|
struct net_buf_simple *buf;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool build_pac_records(const struct bt_audio_capability *capability, void *user_data)
|
2022-10-18 14:46:12 +02:00
|
|
|
{
|
2022-10-18 22:37:32 +02:00
|
|
|
struct pac_records_build_data *data = user_data;
|
2022-10-20 09:47:34 +02:00
|
|
|
struct bt_codec *codec = capability->codec;
|
2022-10-18 22:37:32 +02:00
|
|
|
struct net_buf_simple *buf = data->buf;
|
2022-10-20 09:47:34 +02:00
|
|
|
struct net_buf_simple_state state;
|
|
|
|
struct bt_pac_ltv_data *cc, *meta;
|
2022-10-18 22:37:32 +02:00
|
|
|
struct bt_pac *pac;
|
2022-10-20 09:47:34 +02:00
|
|
|
ssize_t len;
|
2022-10-18 14:46:12 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
net_buf_simple_save(buf, &state);
|
|
|
|
|
|
|
|
if (net_buf_simple_tailroom(buf) < sizeof(*pac)) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2022-10-18 14:46:12 +02:00
|
|
|
|
2022-10-18 22:37:32 +02:00
|
|
|
pac = net_buf_simple_add(buf, sizeof(*pac));
|
|
|
|
pac->codec.id = codec->id;
|
|
|
|
pac->codec.cid = sys_cpu_to_le16(codec->cid);
|
|
|
|
pac->codec.vid = sys_cpu_to_le16(codec->vid);
|
2022-10-18 14:46:12 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
if (net_buf_simple_tailroom(buf) < sizeof(*cc)) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc = net_buf_simple_add(buf, sizeof(*cc));
|
2022-10-18 22:37:32 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
len = pac_data_add(buf, codec->data_count, codec->data);
|
|
|
|
if (len < 0 || len > UINT8_MAX) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc->len = len;
|
2022-10-18 14:46:12 +02:00
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
if (net_buf_simple_tailroom(buf) < sizeof(*meta)) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2022-10-18 22:37:32 +02:00
|
|
|
|
|
|
|
meta = net_buf_simple_add(buf, sizeof(*meta));
|
|
|
|
|
2022-10-20 09:47:34 +02:00
|
|
|
len = pac_data_add(buf, codec->meta_count, codec->meta);
|
|
|
|
if (len < 0 || len > UINT8_MAX) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta->len = len;
|
2022-10-18 22:37:32 +02:00
|
|
|
|
|
|
|
data->rsp->num_pac++;
|
|
|
|
|
|
|
|
return true;
|
2022-10-20 09:47:34 +02:00
|
|
|
|
|
|
|
fail:
|
|
|
|
__ASSERT(true, "No space for %p", capability);
|
|
|
|
|
|
|
|
net_buf_simple_restore(buf, &state);
|
|
|
|
|
|
|
|
return false;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
2022-03-29 17:55:51 +02:00
|
|
|
static void get_pac_records(struct bt_conn *conn, enum bt_audio_dir dir,
|
2022-01-31 14:28:59 +01:00
|
|
|
struct net_buf_simple *buf)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
2022-10-18 22:37:32 +02:00
|
|
|
struct pac_records_build_data data;
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
/* Reset if buffer before using */
|
2022-01-31 14:28:59 +01:00
|
|
|
net_buf_simple_reset(buf);
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 22:37:32 +02:00
|
|
|
data.rsp = net_buf_simple_add(buf, sizeof(*data.rsp));
|
|
|
|
data.rsp->num_pac = 0;
|
|
|
|
data.buf = buf;
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 22:37:32 +02:00
|
|
|
bt_audio_foreach_capability(dir, build_pac_records, &data);
|
2022-01-31 14:28:59 +01:00
|
|
|
}
|
|
|
|
|
2022-05-19 16:52:44 +02:00
|
|
|
static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
|
|
|
|
2022-05-19 16:52:44 +02:00
|
|
|
|
|
|
|
static ssize_t available_contexts_read(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr, void *buf,
|
|
|
|
uint16_t len, uint16_t offset)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
struct bt_pacs_context context = {
|
|
|
|
.snk = sys_cpu_to_le16(snk_available_contexts),
|
|
|
|
.src = sys_cpu_to_le16(src_available_contexts),
|
|
|
|
};
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
|
|
|
|
sizeof(context));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void supported_context_cfg_changed(const struct bt_gatt_attr *attr,
|
|
|
|
uint16_t value)
|
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t supported_context_read(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr,
|
|
|
|
void *buf, uint16_t len, uint16_t offset)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
struct bt_pacs_context context = {
|
|
|
|
.snk = sys_cpu_to_le16(snk_supported_contexts),
|
|
|
|
.src = sys_cpu_to_le16(src_supported_contexts),
|
|
|
|
};
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
|
|
|
|
sizeof(context));
|
|
|
|
}
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
static void available_contexts_notify(struct k_work *work);
|
|
|
|
static K_WORK_DELAYABLE_DEFINE(available_contexts_work, available_contexts_notify);
|
|
|
|
|
|
|
|
static int set_available_contexts(uint16_t contexts, uint16_t *available,
|
|
|
|
const uint16_t supported)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (contexts & ~supported) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contexts == *available) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*available = contexts;
|
|
|
|
|
|
|
|
err = k_work_reschedule(&available_contexts_work, PAC_NOTIFY_TIMEOUT);
|
|
|
|
if (err < 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK)
|
2022-10-18 23:52:06 +02:00
|
|
|
static void pac_notify(struct k_work *work);
|
2022-09-01 11:17:08 +02:00
|
|
|
static K_WORK_DELAYABLE_DEFINE(snks_work, pac_notify);
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
|
|
|
void *buf, uint16_t len, uint16_t offset)
|
|
|
|
{
|
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
2022-09-22 14:07:57 +02:00
|
|
|
get_pac_records(conn, BT_AUDIO_DIR_SINK, &read_buf);
|
|
|
|
|
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
|
|
|
|
read_buf.len);
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
static inline int set_snk_available_contexts(uint16_t contexts)
|
|
|
|
{
|
|
|
|
return set_available_contexts(contexts, &snk_available_contexts,
|
|
|
|
snk_supported_contexts);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int set_snk_available_contexts(uint16_t contexts)
|
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK */
|
2022-10-18 22:58:34 +02:00
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
2022-10-18 23:52:06 +02:00
|
|
|
static void pac_notify_snk_loc(struct k_work *work);
|
|
|
|
static PACS_LOCATION(snk_location, pac_notify_snk_loc);
|
2022-04-13 21:10:18 +02:00
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
static ssize_t snk_loc_read(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr, void *buf,
|
|
|
|
uint16_t len, uint16_t offset)
|
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
uint32_t location = sys_cpu_to_le32(snk_location.location);
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
|
|
|
|
sizeof(location));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
static int set_snk_location(enum bt_audio_location audio_location)
|
|
|
|
{
|
|
|
|
if (audio_location == snk_location.location) {
|
|
|
|
return 0;
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
snk_location.location = audio_location;
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
k_work_reschedule(&snk_location.work, PAC_NOTIFY_TIMEOUT);
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int set_snk_location(enum bt_audio_location location)
|
2022-10-18 14:46:12 +02:00
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
return -ENOTSUP;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK_LOC */
|
2022-10-18 14:46:12 +02:00
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
|
2022-01-07 17:23:45 +01:00
|
|
|
static ssize_t snk_loc_write(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr, const void *data,
|
|
|
|
uint16_t len, uint16_t offset, uint8_t flags)
|
|
|
|
{
|
2022-02-08 14:43:43 +01:00
|
|
|
int err;
|
|
|
|
enum bt_audio_location location;
|
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
if (offset) {
|
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
|
|
|
|
}
|
|
|
|
|
2022-02-08 14:43:43 +01:00
|
|
|
if (len != sizeof(location)) {
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
|
2022-02-08 14:43:43 +01:00
|
|
|
location = (enum bt_audio_location)sys_get_le32(data);
|
|
|
|
if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
|
|
|
|
BT_DBG("Invalid location value: 0x%08X", location);
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
err = set_snk_location(location);
|
2022-02-08 14:43:43 +01:00
|
|
|
if (err != 0) {
|
|
|
|
BT_DBG("write_location returned %d", err);
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
2022-04-13 21:10:18 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_PAC_SRC)
|
2022-09-01 11:17:08 +02:00
|
|
|
static K_WORK_DELAYABLE_DEFINE(srcs_work, pac_notify);
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
|
|
|
void *buf, uint16_t len, uint16_t offset)
|
|
|
|
{
|
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
2022-09-22 14:07:57 +02:00
|
|
|
get_pac_records(conn, BT_AUDIO_DIR_SOURCE, &read_buf);
|
|
|
|
|
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
|
|
|
|
read_buf.len);
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
static inline int set_src_available_contexts(uint16_t contexts)
|
|
|
|
{
|
|
|
|
return set_available_contexts(contexts, &src_available_contexts,
|
|
|
|
src_supported_contexts);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int set_src_available_contexts(uint16_t contexts)
|
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC */
|
2022-10-18 22:58:34 +02:00
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SRC_LOC)
|
2022-10-18 23:52:06 +02:00
|
|
|
static void pac_notify_src_loc(struct k_work *work);
|
|
|
|
static PACS_LOCATION(src_location, pac_notify_src_loc);
|
2022-04-13 21:10:18 +02:00
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
static ssize_t src_loc_read(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr, void *buf,
|
|
|
|
uint16_t len, uint16_t offset)
|
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
uint32_t location = sys_cpu_to_le32(src_location.location);
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
BT_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len,
|
|
|
|
offset);
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
|
|
|
|
sizeof(location));
|
|
|
|
}
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
|
|
|
{
|
|
|
|
BT_DBG("attr %p value 0x%04x", attr, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_src_location(enum bt_audio_location audio_location)
|
|
|
|
{
|
|
|
|
if (audio_location == src_location.location) {
|
|
|
|
return 0;
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
src_location.location = audio_location;
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
k_work_reschedule(&src_location.work, PAC_NOTIFY_TIMEOUT);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int set_src_location(enum bt_audio_location location)
|
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC_LOC */
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-07-22 16:13:15 +08:00
|
|
|
#if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
|
2022-01-07 17:23:45 +01:00
|
|
|
static ssize_t src_loc_write(struct bt_conn *conn,
|
|
|
|
const struct bt_gatt_attr *attr, const void *data,
|
|
|
|
uint16_t len, uint16_t offset, uint8_t flags)
|
|
|
|
{
|
2022-02-08 14:43:43 +01:00
|
|
|
int err;
|
|
|
|
uint32_t location;
|
|
|
|
|
2022-01-07 17:23:45 +01:00
|
|
|
if (offset) {
|
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
|
|
|
|
}
|
|
|
|
|
2022-02-08 14:43:43 +01:00
|
|
|
if (len != sizeof(location)) {
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
|
2022-02-08 14:43:43 +01:00
|
|
|
location = (enum bt_audio_location)sys_get_le32(data);
|
|
|
|
if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
|
|
|
|
BT_DBG("Invalid location value: 0x%08X", location);
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
err = set_src_location(location);
|
2022-02-08 14:43:43 +01:00
|
|
|
if (err != 0) {
|
|
|
|
BT_DBG("write_location returned %d", err);
|
2022-08-23 14:55:23 +02:00
|
|
|
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
2022-07-22 16:13:15 +08:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
|
2022-01-07 17:23:45 +01:00
|
|
|
|
|
|
|
BT_GATT_SERVICE_DEFINE(pacs_svc,
|
|
|
|
BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
|
|
|
|
#if defined(CONFIG_BT_PAC_SNK)
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SNK,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
snk_read, NULL, NULL),
|
|
|
|
BT_AUDIO_CCC(snk_cfg_changed),
|
2022-10-18 22:18:55 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
2022-07-11 15:28:03 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
|
|
|
|
snk_loc_read, snk_loc_write, NULL),
|
2022-10-18 22:18:55 +02:00
|
|
|
#else
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
snk_loc_read, NULL, NULL),
|
2022-06-13 09:36:47 +08:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CCC(snk_loc_cfg_changed),
|
2022-10-18 22:18:55 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK_LOC */
|
2022-01-07 17:23:45 +01:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK */
|
|
|
|
#if defined(CONFIG_BT_PAC_SRC)
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SRC,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
src_read, NULL, NULL),
|
|
|
|
BT_AUDIO_CCC(src_cfg_changed),
|
2022-10-18 22:18:55 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SRC_LOC)
|
2022-07-11 15:28:03 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
|
2022-08-17 14:25:26 +02:00
|
|
|
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
|
2022-07-25 09:56:23 +02:00
|
|
|
src_loc_read, src_loc_write, NULL),
|
2022-10-18 22:18:55 +02:00
|
|
|
#else
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
src_loc_read, NULL, NULL),
|
2022-06-13 09:36:47 +08:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CCC(src_loc_cfg_changed),
|
2022-10-18 22:18:55 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC_LOC */
|
2022-07-11 15:28:03 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC */
|
2022-07-25 09:56:23 +02:00
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
available_contexts_read, NULL, NULL),
|
|
|
|
BT_AUDIO_CCC(available_context_cfg_changed),
|
|
|
|
BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT,
|
|
|
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
|
|
BT_GATT_PERM_READ_ENCRYPT,
|
|
|
|
supported_context_read, NULL, NULL),
|
|
|
|
BT_AUDIO_CCC(supported_context_cfg_changed)
|
2022-01-07 17:23:45 +01:00
|
|
|
);
|
|
|
|
|
2022-03-29 17:55:51 +02:00
|
|
|
static struct k_work_delayable *bt_pacs_get_work(enum bt_audio_dir dir)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
2022-03-29 17:55:51 +02:00
|
|
|
switch (dir) {
|
2022-01-07 17:23:45 +01:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK)
|
2022-03-29 18:20:10 +02:00
|
|
|
case BT_AUDIO_DIR_SINK:
|
2022-01-07 17:23:45 +01:00
|
|
|
return &snks_work;
|
|
|
|
#endif /* CONFIG_BT_PAC_SNK */
|
|
|
|
#if defined(CONFIG_BT_PAC_SRC)
|
2022-03-29 18:20:10 +02:00
|
|
|
case BT_AUDIO_DIR_SOURCE:
|
2022-01-07 17:23:45 +01:00
|
|
|
return &srcs_work;
|
2022-06-13 09:36:47 +08:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC */
|
2022-03-29 17:55:51 +02:00
|
|
|
default:
|
|
|
|
return NULL;
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
|
|
|
static void pac_notify_snk_loc(struct k_work *work)
|
2022-02-08 14:43:43 +01:00
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work);
|
|
|
|
uint32_t location_le = sys_cpu_to_le32(location->location);
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK_LOC, pacs_svc.attrs, &location_le,
|
|
|
|
sizeof(location_le));
|
|
|
|
if (err != 0 && err != -ENOTCONN) {
|
|
|
|
BT_WARN("PACS notify_loc failed: %d", err);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SNK_LOC */
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
#if defined(CONFIG_BT_PAC_SRC_LOC)
|
|
|
|
static void pac_notify_src_loc(struct k_work *work)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work);
|
|
|
|
uint32_t location_le = sys_cpu_to_le32(location->location);
|
2022-01-31 11:28:59 +01:00
|
|
|
int err;
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC_LOC, pacs_svc.attrs, &location_le,
|
|
|
|
sizeof(location_le));
|
2022-06-24 10:28:17 +02:00
|
|
|
if (err != 0 && err != -ENOTCONN) {
|
|
|
|
BT_WARN("PACS notify_loc failed: %d", err);
|
2022-01-31 11:28:59 +01:00
|
|
|
}
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
2022-10-18 23:52:06 +02:00
|
|
|
#endif /* CONFIG_BT_PAC_SRC_LOC */
|
2022-01-07 17:23:45 +01:00
|
|
|
|
2022-04-13 21:10:18 +02:00
|
|
|
static void pac_notify(struct k_work *work)
|
2022-02-08 14:43:43 +01:00
|
|
|
{
|
2022-06-24 10:51:56 +02:00
|
|
|
int err = 0;
|
2022-02-08 14:43:43 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_PAC_SNK)
|
2022-04-13 21:10:18 +02:00
|
|
|
if (work == &snks_work.work) {
|
2022-10-20 10:19:44 +02:00
|
|
|
get_pac_records(NULL, BT_AUDIO_DIR_SINK, &read_buf);
|
|
|
|
|
2022-06-24 10:51:56 +02:00
|
|
|
err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK,
|
|
|
|
pacs_svc.attrs, read_buf.data,
|
|
|
|
read_buf.len);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_PAC_SNK */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_PAC_SRC)
|
2022-04-13 21:10:18 +02:00
|
|
|
if (work == &srcs_work.work) {
|
2022-10-20 10:19:44 +02:00
|
|
|
get_pac_records(NULL, BT_AUDIO_DIR_SOURCE, &read_buf);
|
|
|
|
|
2022-06-24 10:51:56 +02:00
|
|
|
err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC,
|
|
|
|
pacs_svc.attrs, read_buf.data,
|
|
|
|
read_buf.len);
|
2022-02-08 14:43:43 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_PAC_SRC */
|
|
|
|
|
2022-06-24 10:28:17 +02:00
|
|
|
if (err != 0 && err != -ENOTCONN) {
|
2022-02-08 14:43:43 +01:00
|
|
|
BT_WARN("PACS notify failed: %d", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-18 14:46:12 +02:00
|
|
|
static void bt_pacs_capabilities_changed(enum bt_audio_dir dir)
|
2022-01-07 17:23:45 +01:00
|
|
|
{
|
|
|
|
struct k_work_delayable *work;
|
|
|
|
|
2022-03-29 17:55:51 +02:00
|
|
|
work = bt_pacs_get_work(dir);
|
2022-01-07 17:23:45 +01:00
|
|
|
if (!work) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-31 11:28:59 +01:00
|
|
|
k_work_reschedule(work, PAC_NOTIFY_TIMEOUT);
|
2022-01-07 17:23:45 +01:00
|
|
|
}
|
2022-02-08 14:43:43 +01:00
|
|
|
|
2022-05-19 16:52:44 +02:00
|
|
|
static void available_contexts_notify(struct k_work *work)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
struct bt_pacs_context context = {
|
|
|
|
.snk = sys_cpu_to_le16(snk_available_contexts),
|
|
|
|
.src = sys_cpu_to_le16(src_available_contexts),
|
|
|
|
};
|
2022-05-19 16:52:44 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_AVAILABLE_CONTEXT, pacs_svc.attrs,
|
|
|
|
&context, sizeof(context));
|
2022-06-24 10:28:17 +02:00
|
|
|
if (err != 0 && err != -ENOTCONN) {
|
2022-05-19 16:52:44 +02:00
|
|
|
BT_WARN("Available Audio Contexts notify failed: %d", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 11:50:38 +02:00
|
|
|
bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
if (dir == BT_AUDIO_DIR_SOURCE) {
|
|
|
|
return (context & src_available_contexts) == context;
|
2022-07-15 11:21:25 +02:00
|
|
|
}
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
if (dir == BT_AUDIO_DIR_SINK) {
|
|
|
|
return (context & snk_available_contexts) == context;
|
2022-04-05 11:50:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2022-10-18 14:46:12 +02:00
|
|
|
|
|
|
|
static sys_slist_t *bt_audio_capability_get(enum bt_audio_dir dir)
|
|
|
|
{
|
|
|
|
switch (dir) {
|
|
|
|
case BT_AUDIO_DIR_SINK:
|
|
|
|
return &snks;
|
|
|
|
case BT_AUDIO_DIR_SOURCE:
|
|
|
|
return &srcs;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_audio_foreach_capability(enum bt_audio_dir dir, bt_audio_foreach_capability_func_t func,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct bt_audio_capability *cap;
|
|
|
|
sys_slist_t *lst;
|
|
|
|
|
|
|
|
CHECKIF(func == NULL) {
|
|
|
|
BT_ERR("func is NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lst = bt_audio_capability_get(dir);
|
|
|
|
if (!lst) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(lst, cap, _node) {
|
|
|
|
if (!func(cap, user_data)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Register Audio Capability */
|
|
|
|
int bt_audio_capability_register(enum bt_audio_dir dir, struct bt_audio_capability *cap)
|
|
|
|
{
|
|
|
|
sys_slist_t *lst;
|
|
|
|
|
|
|
|
if (!cap || !cap->codec) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
lst = bt_audio_capability_get(dir);
|
|
|
|
if (!lst) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("cap %p dir 0x%02x codec 0x%02x codec cid 0x%04x "
|
|
|
|
"codec vid 0x%04x", cap, dir, cap->codec->id,
|
|
|
|
cap->codec->cid, cap->codec->vid);
|
|
|
|
|
|
|
|
sys_slist_append(lst, &cap->_node);
|
|
|
|
|
|
|
|
bt_pacs_capabilities_changed(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unregister Audio Capability */
|
|
|
|
int bt_audio_capability_unregister(enum bt_audio_dir dir, struct bt_audio_capability *cap)
|
|
|
|
{
|
|
|
|
sys_slist_t *lst;
|
|
|
|
|
|
|
|
if (!cap) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
lst = bt_audio_capability_get(dir);
|
|
|
|
if (!lst) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("cap %p dir 0x%02x", cap, dir);
|
|
|
|
|
|
|
|
if (!sys_slist_find_and_remove(lst, &cap->_node)) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_pacs_capabilities_changed(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
int bt_audio_capability_set_location(enum bt_audio_dir dir, enum bt_audio_location location)
|
2022-10-18 14:46:12 +02:00
|
|
|
{
|
2022-10-18 23:52:06 +02:00
|
|
|
switch (dir) {
|
|
|
|
case BT_AUDIO_DIR_SINK:
|
|
|
|
return set_snk_location(location);
|
|
|
|
case BT_AUDIO_DIR_SOURCE:
|
|
|
|
return set_src_location(location);
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
2022-10-18 23:52:06 +02:00
|
|
|
return -EINVAL;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int bt_audio_capability_set_available_contexts(enum bt_audio_dir dir,
|
|
|
|
enum bt_audio_context contexts)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
switch (dir) {
|
|
|
|
case BT_AUDIO_DIR_SINK:
|
|
|
|
return set_snk_available_contexts(contexts);
|
|
|
|
case BT_AUDIO_DIR_SOURCE:
|
|
|
|
return set_src_available_contexts(contexts);
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
return -EINVAL;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
enum bt_audio_context bt_audio_capability_get_available_contexts(enum bt_audio_dir dir)
|
|
|
|
{
|
2022-10-18 22:58:34 +02:00
|
|
|
switch (dir) {
|
|
|
|
case BT_AUDIO_DIR_SINK:
|
|
|
|
return snk_available_contexts;
|
|
|
|
case BT_AUDIO_DIR_SOURCE:
|
|
|
|
return src_available_contexts;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|
|
|
|
|
2022-10-18 22:58:34 +02:00
|
|
|
return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
2022-10-18 14:46:12 +02:00
|
|
|
}
|