Bluetooth: TBS: Add support for dynamic TBS

The TBS and GTBS instances can now be dynamically registered
and unregistered, which fits better for the use cases of TBS
where specific bearers can come and go depending on the
features of the device.

For example if a SIM card is inserted, then a device can
register a TBS for the provider and remove it again if the
SIM card is removed.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-07-19 14:43:08 +02:00 committed by Anas Nashif
commit 1406c547d6
6 changed files with 467 additions and 134 deletions

View file

@ -126,6 +126,8 @@ extern "C" {
#define BT_TBS_FEATURE_HOLD BIT(0)
/** Join Call Control Point Opcode supported */
#define BT_TBS_FEATURE_JOIN BIT(1)
/** All Control Point Opcodes supported */
#define BT_TBS_FEATURE_ALL (BT_TBS_FEATURE_HOLD | BT_TBS_FEATURE_JOIN)
/** @} */
/**
@ -247,8 +249,6 @@ typedef void (*bt_tbs_call_change_cb)(struct bt_conn *conn,
/**
* @brief Callback function for authorizing a client.
*
* Only used if BT_TBS_AUTHORIZATION is enabled.
*
* @param conn The connection used.
*
* @return true if authorized, false otherwise
@ -462,6 +462,98 @@ int bt_tbs_set_uri_scheme_list(uint8_t bearer_index, const char **uri_list,
*/
void bt_tbs_register_cb(struct bt_tbs_cb *cbs);
struct bt_tbs_register_param {
/** The name of the provider, for example a cellular service provider */
char *provider_name;
/**
* @brief The Uniform Caller Identifier of the bearer
*
* See the Uniform Caller Identifiers table in Bluetooth Assigned Numbers
*/
char *uci;
/**
* The Uniform Resource Identifiers schemes supported by this bearer as an UTF-8 string
*
* See https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for possible values.
* If multiple values are used, these shall be comma separated, e.g. "tel,skype".
*/
char *uri_schemes_supported;
/**
* @brief Whether this bearer shall be registered as a Generic Telephone Bearer server
*
* A GTBS shall be registered before any non-GTBS services. There can only be a single GTBS
* registered.
*/
bool gtbs;
/**
* @brief Whether the application will need to authorize changes to calls
*
* If set to false then the service will automatically accept write requests from clients.
*/
bool authorization_required;
/**
* @brief The technology of the bearer
*
* See the BT_TBS_TECHNOLOGY_* values.
*/
uint8_t technology;
/**
* @brief The optional supported features of the bearer
*
* See the BT_TBS_FEATURE_* values.
*/
uint8_t supported_features;
};
/**
* @brief Register a Telephone Bearer
*
* This will register a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service
* (GTBS)) with the provided parameters.
*
* As per the TBS specification, the GTBS shall be instantiated for the feature, and as such a GTBS
* shall always be registered before any TBS can be registered.
* Similarly, all TBS shall be unregistered before the GTBS can be unregistered with
* bt_tbs_unregister_bearer().
*
* @param param The parameters to initialize the bearer.
* @retval index The bearer index if return value is >= 0
* @retval -EINVAL @p param contains invalid data
* @retval -EALREADY @p param.gtbs is true and GTBS has already been registered
* @retval -EAGAIN @p param.gtbs is false and GTBS has not been registered
* @retval -ENOMEM @p param.gtbs is false and no more TBS can be registered (see
* @kconfig{CONFIG_BT_TBS_BEARER_COUNT})
* @retval -ENOEXEC The service failed to be registered
*/
int bt_tbs_register_bearer(const struct bt_tbs_register_param *param);
/**
* @brief Unregister a Telephone Bearer
*
* This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service
* (GTBS)) with the provided parameters. The bearer shall be registered first by
* bt_tbs_register_bearer() before it can be unregistered.
*
* Similarly, all TBS shall be unregistered before the GTBS can be unregistered with.
*
* @param bearer_index The index of the bearer to unregister.
*
* @retval 0 Success
* @retval -EINVAL @p bearer_index is invalid
* @retval -EALREADY The bearer identified by @p bearer_index is not registered
* @retval -EAGAIN The bearer identified by @p bearer_index is GTBS and there are TBS instances
* registered.
* @retval -ENOEXEC The service failed to be unregistered
*/
int bt_tbs_unregister_bearer(uint8_t bearer_index);
/** @brief Prints all calls of all services to the debug log */
void bt_tbs_dbg_print_calls(void);

View file

@ -22,70 +22,14 @@ config BT_TBS
if BT_TBS
config BT_TBS_PROVIDER_NAME
string "Telephone Bearer Service Provider Name"
default "Unknown"
help
Sets the name of the service provider for the bearer.
config BT_TBS_UCI
string "Telephone Bearer Service Uniform Caller Identifier (UCI)"
default "un000"
help
Sets the UCI of the bearer. See
https://www.bluetooth.com/specifications/assigned-numbers/uniform-caller-identifiers/
for a table of valid UCIs.
config BT_TBS_TECHNOLOGY
int "Telephone Bearer Service Technology"
range 1 10
help
Sets the technology used for the bearer, e.g. GSM, LTE and 5G.
1 : 3G
2 : 4G
3 : LTE
4 : Wi-Fi
5 : 5G
6 : GSM
7 : CDMA
8 : 2G
9 : WCDMA
10: IP
config BT_TBS_URI_SCHEMES_LIST
string "Telephone Bearer Service URI schemes Supported List"
default "tel,skype"
help
Sets a list of URI schemes that are supported by the bearer,
e.g. "tel" or "skype".
Multiple values shall be comma (,) separated, e.g. "tel,skype".
config BT_TBS_SIGNAL_STRENGTH_INTERVAL
int "Telephone Bearer Service Signal Strength Reporting Interval"
default 0
range 0 $(UINT8_MAX)
help
Sets the interval of reporting the signal strength in seconds.
If the value is 0, the signal will not be reported.
config BT_TBS_STATUS_FLAGS
int "Telephone Bearer Service Features and Status value"
default 0
range 0 3
help
Bitfield to set feature and status flags.
Bit 0: In-band ringtone
Bit 1: Silent mode
Bits 2-15: Reserved for future use
config BT_TBS_SUPPORTED_FEATURES
int "Telephone Bearer Service Supported Features"
default 1
range 0 3
help
Bitfield to set supported features of the bearer.
Bit 0: Local Hold and Retrieve
Bit 1: Join calls within Telephone Bearer Service
Bit 0: Local Hold and Retrieve
Bit 1: Join calls within Telephone Bearer Service
config BT_TBS_MAX_CALLS
int "Telephone Bearer Service Maximum Number Of Calls Supported"
@ -108,12 +52,6 @@ config BT_TBS_MAX_SCHEME_LIST_LENGTH
help
Sets the maximum length of the URI scheme list.
config BT_TBS_AUTHORIZATION
bool "TBS authorization requirement"
help
If set to true, then any writable characteristics will require
authorization per connection.
endif # BT_TBS

View file

@ -12,6 +12,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/autoconf.h>
@ -26,7 +27,6 @@
#include "host/shell/bt.h"
static struct bt_conn *tbs_authorized_conn;
static bool cbs_registered;
static bool tbs_authorize_cb(struct bt_conn *conn)
{
@ -59,13 +59,64 @@ static int cmd_tbs_authorize(const struct shell *sh, size_t argc, char *argv[])
return 0;
}
static int cmd_tbs_init(void)
static int cmd_tbs_init(const struct shell *sh, size_t argc, char *argv[])
{
if (!cbs_registered) {
bt_tbs_register_cb(&tbs_cbs);
cbs_registered = true;
static bool registered;
if (registered) {
shell_info(sh, "Already initialized");
return -ENOEXEC;
}
const struct bt_tbs_register_param gtbs_param = {
.provider_name = "Generic TBS",
.uci = "un000",
.uri_schemes_supported = "tel,skype",
.gtbs = true,
.authorization_required = false,
.technology = BT_TBS_TECHNOLOGY_3G,
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
};
int err;
err = bt_tbs_register_bearer(&gtbs_param);
if (err < 0) {
shell_error(sh, "Failed to register GTBS: %d", err);
return -ENOEXEC;
}
shell_info(sh, "Registered GTBS");
for (int i = 0; i < CONFIG_BT_TBS_BEARER_COUNT; i++) {
char prov_name[22]; /* Enough to store "Telephone Bearer #255" */
const struct bt_tbs_register_param tbs_param = {
.provider_name = prov_name,
.uci = "un000",
.uri_schemes_supported = "tel,skype",
.gtbs = false,
.authorization_required = false,
/* Set different technologies per bearer */
.technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1,
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
};
snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i);
err = bt_tbs_register_bearer(&tbs_param);
if (err < 0) {
shell_error(sh, "Failed to register TBS[%d]: %d", i, err);
return -ENOEXEC;
}
shell_info(sh, "Registered TBS[%d] with index %u", i, (uint8_t)err);
}
bt_tbs_register_cb(&tbs_cbs);
registered = true;
return 0;
}

View file

@ -26,6 +26,7 @@
#include <zephyr/net_buf.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/check.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/types.h>
@ -65,6 +66,8 @@ struct tbs_inst {
const struct bt_gatt_attr *attrs;
/** Service Attribute count */
size_t attr_count;
bool authorization_required;
};
static struct tbs_inst svc_insts[CONFIG_BT_TBS_BEARER_COUNT];
@ -82,6 +85,11 @@ static uint8_t held_calls_cnt;
static struct bt_tbs_cb *tbs_cbs;
static bool inst_is_registered(const struct tbs_inst *inst)
{
return inst->attrs != NULL;
}
static bool inst_is_gtbs(const struct tbs_inst *inst)
{
if (CONFIG_BT_TBS_BEARER_COUNT > 0) {
@ -109,15 +117,19 @@ static uint8_t inst_index(const struct tbs_inst *inst)
static struct tbs_inst *inst_lookup_index(uint8_t index)
{
struct tbs_inst *inst = NULL;
if (index == BT_TBS_GTBS_INDEX) {
return &gtbs_inst;
inst = &gtbs_inst;
} else if (ARRAY_SIZE(svc_insts) > 0U && index < ARRAY_SIZE(svc_insts)) {
inst = &svc_insts[index];
}
if (ARRAY_SIZE(svc_insts) > 0U && index < ARRAY_SIZE(svc_insts)) {
return &svc_insts[index];
if (inst == NULL || !inst_is_registered(inst)) {
return NULL;
}
return NULL;
return inst;
}
static struct bt_tbs_call *lookup_call_in_inst(struct tbs_inst *inst, uint8_t call_index)
@ -213,9 +225,9 @@ static struct tbs_inst *lookup_inst_by_call_index(uint8_t call_index)
return NULL;
}
static bool is_authorized(struct bt_conn *conn)
static bool is_authorized(const struct tbs_inst *inst, struct bt_conn *conn)
{
if (IS_ENABLED(CONFIG_BT_TBS_AUTHORIZATION)) {
if (inst->authorization_required) {
if (tbs_cbs != NULL && tbs_cbs->authorize != NULL) {
return tbs_cbs->authorize(conn);
} else {
@ -636,12 +648,8 @@ static ssize_t read_signal_strength_interval(struct bt_conn *conn, const struct
{
const struct tbs_inst *inst = BT_AUDIO_CHRC_USER_DATA(attr);
if (!is_authorized(conn)) {
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
}
LOG_DBG("Index %u: Signal strength interval 0x%02x", inst_index(inst),
inst->signal_strength_interval);
LOG_DBG("Index %u: Signal strength interval 0x%02x",
inst_index(inst), inst->signal_strength_interval);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &inst->signal_strength_interval,
sizeof(inst->signal_strength_interval));
@ -655,7 +663,7 @@ static ssize_t write_signal_strength_interval(struct bt_conn *conn, const struct
struct net_buf_simple net_buf;
uint8_t signal_strength_interval;
if (!is_authorized(conn)) {
if (!is_authorized(inst, conn)) {
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
}
@ -1115,7 +1123,7 @@ static ssize_t write_call_cp(struct bt_conn *conn, const struct bt_gatt_attr *at
uint8_t call_index = 0;
const bool is_gtbs = inst_is_gtbs(inst);
if (!is_authorized(conn)) {
if (!is_authorized(inst, conn)) {
return BT_GATT_ERR(BT_ATT_ERR_AUTHORIZATION);
}
@ -1474,7 +1482,8 @@ static void in_call_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
BT_TBS_SERVICE_DEFINE(BT_UUID_TBS, &(_inst)) \
}
BT_GATT_SERVICE_DEFINE(gtbs_svc, BT_TBS_SERVICE_DEFINE(BT_UUID_GTBS, &gtbs_inst));
static struct bt_gatt_service gtbs_svc =
BT_GATT_SERVICE(((struct bt_gatt_attr[]){BT_TBS_SERVICE_DEFINE(BT_UUID_GTBS, &gtbs_inst)}));
BT_GATT_SERVICE_INSTANCE_DEFINE(tbs_service_list, svc_insts, CONFIG_BT_TBS_BEARER_COUNT,
BT_TBS_SERVICE_DEFINITION);
@ -1499,58 +1508,220 @@ static void signal_interval_timeout(struct k_work *work)
inst->pending_signal_strength_notification = false;
}
static void tbs_inst_init(struct tbs_inst *inst, const struct bt_gatt_attr *attrs,
size_t attr_count, const char *provider_name)
static int tbs_inst_init_and_register(struct tbs_inst *inst, struct bt_gatt_service *svc,
const struct bt_tbs_register_param *param)
{
LOG_DBG("inst %p index 0x%02x provider_name %s", inst, inst_index(inst), provider_name);
int err;
LOG_DBG("inst %p index 0x%02x", inst, inst_index(inst));
inst->ccid = bt_ccid_get_value();
(void)utf8_lcpy(inst->provider_name, provider_name, sizeof(inst->provider_name));
(void)utf8_lcpy(inst->uci, CONFIG_BT_TBS_UCI, sizeof(inst->uci));
inst->optional_opcodes = CONFIG_BT_TBS_SUPPORTED_FEATURES;
inst->technology = CONFIG_BT_TBS_TECHNOLOGY;
inst->signal_strength_interval = CONFIG_BT_TBS_SIGNAL_STRENGTH_INTERVAL;
inst->status_flags = CONFIG_BT_TBS_STATUS_FLAGS;
inst->attrs = attrs;
inst->attr_count = attr_count;
(void)utf8_lcpy(inst->provider_name, param->provider_name, sizeof(inst->provider_name));
(void)utf8_lcpy(inst->uci, param->uci, sizeof(inst->uci));
(void)utf8_lcpy(inst->uri_scheme_list, param->uri_schemes_supported,
sizeof(inst->uri_scheme_list));
inst->optional_opcodes = param->supported_features;
inst->technology = param->technology;
inst->attrs = svc->attrs;
inst->attr_count = svc->attr_count;
inst->authorization_required = param->authorization_required;
k_work_init_delayable(&inst->reporting_interval_work, signal_interval_timeout);
err = bt_gatt_service_register(svc);
if (err != 0) {
LOG_DBG("Could not register %sTBS: %d", param->gtbs ? "G" : "", err);
memset(inst, 0, sizeof(*inst));
return err;
}
return inst_index(inst);
}
static void gtbs_service_inst_init(struct tbs_inst *inst,
const struct bt_gatt_service_static *service)
static int gtbs_service_inst_register(const struct bt_tbs_register_param *param)
{
tbs_inst_init(inst, service->attrs, service->attr_count, "Generic TBS");
return tbs_inst_init_and_register(&gtbs_inst, &gtbs_svc, param);
}
static void tbs_service_inst_init(struct tbs_inst *inst, struct bt_gatt_service *service)
static int tbs_service_inst_register(const struct bt_tbs_register_param *param)
{
tbs_inst_init(inst, service->attrs, service->attr_count, CONFIG_BT_TBS_PROVIDER_NAME);
(void)utf8_lcpy(inst->uri_scheme_list, CONFIG_BT_TBS_URI_SCHEMES_LIST,
sizeof(inst->uri_scheme_list));
}
static int bt_tbs_init(void)
{
gtbs_service_inst_init(&gtbs_inst, &gtbs_svc);
for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) {
int err;
struct tbs_inst *inst = &svc_insts[i];
err = bt_gatt_service_register(&tbs_service_list[i]);
if (err != 0) {
LOG_ERR("Could not register TBS[%d]: %d", i, err);
if (!(inst_is_registered(inst))) {
return tbs_inst_init_and_register(inst, &tbs_service_list[i], param);
}
}
return -ENOMEM;
}
static bool valid_register_param(const struct bt_tbs_register_param *param)
{
size_t str_len;
if (param == NULL) {
LOG_DBG("param is NULL");
return false;
}
if (param->provider_name == NULL) {
LOG_DBG("provider_name is NULL");
return false;
}
str_len = strlen(param->provider_name);
if (str_len > CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH) {
LOG_DBG("Provider name length (%zu) larger than "
"CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH %d",
str_len, CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH);
return false;
}
if (param->uci == NULL) {
LOG_DBG("uci is NULL");
return false;
}
if (param->uri_schemes_supported == NULL) {
LOG_DBG("uri_schemes_supported is NULL");
return false;
}
if (!IN_RANGE(param->technology, BT_TBS_TECHNOLOGY_3G, BT_TBS_TECHNOLOGY_WCDMA)) {
LOG_DBG("Invalid technology: %u", param->technology);
return false;
}
if (param->supported_features > BT_TBS_FEATURE_ALL) {
LOG_DBG("Invalid supported_features: %u", param->supported_features);
return false;
}
if (CONFIG_BT_TBS_BEARER_COUNT == 0 && !param->gtbs) {
LOG_DBG("Cannot register TBS when CONFIG_BT_TBS_BEARER_COUNT=0");
return false;
}
return true;
}
int bt_tbs_register_bearer(const struct bt_tbs_register_param *param)
{
int ret;
CHECKIF(!valid_register_param(param)) {
LOG_DBG("Invalid parameters");
return -EINVAL;
}
if (param->gtbs && inst_is_registered(&gtbs_inst)) {
LOG_DBG("GTBS already registered");
return -EALREADY;
}
if (!param->gtbs && !inst_is_registered(&gtbs_inst)) {
LOG_DBG("GTBS not yet registered");
return -EAGAIN;
}
if (param->gtbs) {
ret = gtbs_service_inst_register(param);
if (ret < 0) {
LOG_DBG("Failed to register GTBS: %d", ret);
return -ENOEXEC;
}
} else if (CONFIG_BT_TBS_BEARER_COUNT > 0) {
ret = tbs_service_inst_register(param);
if (ret < 0) {
LOG_DBG("Failed to register GTBS: %d", ret);
if (ret == -ENOMEM) {
return -ENOMEM;
}
return -ENOEXEC;
}
}
/* ret will contain the index of the registered service */
return ret;
}
int bt_tbs_unregister_bearer(uint8_t bearer_index)
{
struct tbs_inst *inst = inst_lookup_index(bearer_index);
struct bt_gatt_service *svc;
struct k_work_sync sync;
bool restart_reporting_interval;
int err;
if (inst == NULL) {
LOG_DBG("Could not find inst by index %u", bearer_index);
return -EINVAL;
}
if (!inst_is_registered(inst)) {
LOG_DBG("Instance from index %u is not registered", bearer_index);
return -EALREADY;
}
if (inst_is_gtbs(inst)) {
for (size_t i = 0; i < ARRAY_SIZE(svc_insts); i++) {
struct tbs_inst *tbs = &svc_insts[i];
if (inst_is_registered(tbs)) {
LOG_DBG("TBS[%u] is registered, please unregister all TBS first",
bearer_index);
return -EAGAIN;
}
}
svc = &gtbs_svc;
} else {
svc = &tbs_service_list[bearer_index];
}
restart_reporting_interval =
k_work_cancel_delayable_sync(&inst->reporting_interval_work, &sync);
err = bt_gatt_service_unregister(svc);
if (err != 0) {
LOG_DBG("Failed to unregister service %p: %d", svc, err);
if (restart_reporting_interval && inst->signal_strength_interval != 0U) {
/* In this unlikely scenario we may report interval later than expected if
* the k_work was cancelled right before it was set to trigger. It is not a
* big deal and not worth trying to reschedule in a way that it would
* trigger at the same time again, as specific timing over GATT is a wishful
* dream anyways
*/
k_work_schedule(&inst->reporting_interval_work,
K_SECONDS(inst->signal_strength_interval));
}
tbs_service_inst_init(&svc_insts[i], &tbs_service_list[i]);
return -ENOEXEC;
}
memset(inst, 0, sizeof(*inst));
return 0;
}
SYS_INIT(bt_tbs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
/***************************** Profile API *****************************/
int bt_tbs_accept(uint8_t call_index)
{
struct tbs_inst *inst = lookup_inst_by_call_index(call_index);

View file

@ -15,6 +15,7 @@
#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/audio/lc3.h>
#include <zephyr/bluetooth/audio/tbs.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/byteorder.h>
#include <zephyr/bluetooth/gap.h>
@ -24,6 +25,7 @@
#include <zephyr/net_buf.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/toolchain.h>
#include "bap_common.h"
@ -194,6 +196,27 @@ static void init(void)
cap_stream_from_audio_test_stream(&broadcast_source_streams[i]);
bt_cap_stream_ops_register(broadcast_streams[i], &broadcast_stream_ops);
}
if (IS_ENABLED(CONFIG_BT_TBS)) {
const struct bt_tbs_register_param gtbs_param = {
.provider_name = "Generic TBS",
.uci = "un000",
.uri_schemes_supported = "tel,skype",
.gtbs = true,
.authorization_required = false,
.technology = BT_TBS_TECHNOLOGY_3G,
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
};
err = bt_tbs_register_bearer(&gtbs_param);
if (err < 0) {
FAIL("Failed to register GTBS (err %d)\n", err);
return;
}
printk("Registered GTBS\n");
}
}
static void setup_extended_adv(struct bt_le_ext_adv **adv)
@ -449,14 +472,15 @@ static void test_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast
static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source)
{
const uint16_t mock_ccid = 0xAB;
const uint8_t new_metadata[] = {
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING,
BT_AUDIO_PARENTAL_RATING_AGE_ANY),
};
const uint8_t invalid_metadata[] = {
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PARENTAL_RATING,
BT_AUDIO_PARENTAL_RATING_AGE_ANY),
};
int err;

View file

@ -8,6 +8,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <zephyr/autoconf.h>
#include <zephyr/bluetooth/audio/tbs.h>
@ -327,22 +328,85 @@ static void test_tbs_server_only(void)
test_set_status_flags();
}
static void test_main(void)
static void init(void)
{
const struct bt_tbs_register_param gtbs_param = {
.provider_name = "Generic TBS",
.uci = "un000",
.uri_schemes_supported = "tel,skype",
.gtbs = true,
.authorization_required = false,
.technology = BT_TBS_TECHNOLOGY_3G,
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
};
int err;
err = bt_enable(NULL);
if (err != 0) {
printk("Bluetooth init failed (err %d)\n", err);
FAIL("Bluetooth enable failed (err %d)\n", err);
return;
}
printk("Audio Client: Bluetooth initialized\n");
printk("Bluetooth initialized\n");
err = bt_conn_cb_register(&conn_callbacks);
if (err != 0) {
FAIL("Failed to register conn CBs (err %d)\n", err);
return;
}
err = bt_le_scan_cb_register(&common_scan_cb);
if (err != 0) {
FAIL("Failed to register scan CBs (err %d)\n", err);
return;
}
bt_conn_cb_register(&conn_callbacks);
bt_le_scan_cb_register(&common_scan_cb);
bt_tbs_register_cb(&tbs_cbs);
err = bt_tbs_register_bearer(&gtbs_param);
if (err < 0) {
FAIL("Failed to register GTBS (err %d)\n", err);
return;
}
printk("Registered GTBS\n");
for (int i = 0; i < CONFIG_BT_TBS_BEARER_COUNT; i++) {
char prov_name[22]; /* Enough to store "Telephone Bearer #255" */
const struct bt_tbs_register_param tbs_param = {
.provider_name = prov_name,
.uci = "un000",
.uri_schemes_supported = "tel,skype",
.gtbs = false,
.authorization_required = false,
/* Set different technologies per bearer */
.technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1,
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
};
snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i);
err = bt_tbs_register_bearer(&tbs_param);
if (err < 0) {
FAIL("Failed to register TBS[%d]: %d", i, err);
return;
}
printk("Registered TBS[%d] with index %u\n", i, (uint8_t)err);
}
}
static void test_main(void)
{
int err;
init();
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err != 0) {
FAIL("Scanning failed to start (err %d)\n", err);
@ -382,14 +446,7 @@ static void test_main(void)
static void tbs_test_server_only(void)
{
int err;
err = bt_enable(NULL);
if (err != 0) {
FAIL("Bluetooth init failed (err %d)\n", err);
return;
}
init();
test_tbs_server_only();