| /** @file |
| * @brief Bluetooth Call Control Profile (CCP) Call Controller role. |
| * |
| * Copyright (c) 2020 Nordic Semiconductor ASA |
| * Copyright (c) 2022 Codecoup |
| * Copyright 2023 NXP |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/sys/printk.h> |
| #include <zephyr/sys/util.h> |
| #include <string.h> |
| |
| #include <zephyr/bluetooth/conn.h> |
| #include <zephyr/bluetooth/audio/tbs.h> |
| |
| #define URI_SEPARATOR ":" |
| #define CALLER_ID "friend" |
| |
| static uint8_t new_call_index; |
| static char remote_uri[CONFIG_BT_TBS_MAX_URI_LENGTH]; |
| |
| static K_SEM_DEFINE(sem_discovery_done, 0, 1); |
| |
| static struct bt_conn *default_conn; |
| |
| static void discover_cb(struct bt_conn *conn, int err, uint8_t tbs_count, bool gtbs_found) |
| { |
| if (!gtbs_found) { |
| printk("CCP: Failed to discover GTBS\n"); |
| return; |
| } |
| |
| printk("CCP: Discovered GTBS\n"); |
| |
| if (err) { |
| printk("%s (err %d)\n", __func__, err); |
| return; |
| } |
| |
| /* Read Bearer URI Schemes Supported List Characteristic */ |
| bt_tbs_client_read_uri_list(conn, BT_TBS_GTBS_INDEX); |
| } |
| |
| static void originate_call_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint8_t call_index) |
| { |
| if (inst_index != BT_TBS_GTBS_INDEX) { |
| printk("Unexpected %s for instance %u\n", __func__, inst_index); |
| return; |
| } |
| |
| if (err) { |
| printk("%s (err %d)\n", __func__, err); |
| return; |
| } |
| printk("CCP: Call originate successful\n"); |
| new_call_index = call_index; |
| } |
| |
| static void terminate_call_cb(struct bt_conn *conn, int err, |
| uint8_t inst_index, uint8_t call_index) |
| { |
| if (inst_index != BT_TBS_GTBS_INDEX) { |
| printk("Unexpected %s for instance %u\n", __func__, inst_index); |
| return; |
| } |
| |
| if (err) { |
| printk("%s (err %d)\n", __func__, err); |
| return; |
| } |
| printk("CCP: Call with id %d terminated\n", call_index); |
| } |
| |
| static void read_uri_schemes_string_cb(struct bt_conn *conn, int err, |
| uint8_t inst_index, const char *value) |
| { |
| size_t i; |
| |
| if (inst_index != BT_TBS_GTBS_INDEX) { |
| printk("Unexpected %s for instance %u\n", __func__, inst_index); |
| return; |
| } |
| |
| if (err) { |
| printk("%s (err %d)\n", __func__, err); |
| return; |
| } |
| |
| /* Save first remote URI |
| * |
| * First search for the first comma (separator), and use that to determine the end of the |
| * first (or only) URI. Then use that length to copy the URI to `remote_uri` for later use. |
| */ |
| for (i = 0U; i < strlen(value); i++) { |
| if (value[i] == ',') { |
| break; |
| } |
| } |
| |
| if (i >= sizeof(remote_uri)) { |
| printk("Cannot store URI of length %zu: %s\n", i, value); |
| return; |
| } |
| |
| strncpy(remote_uri, value, i); |
| remote_uri[i] = '\0'; |
| |
| printk("CCP: Discovered remote URI: %s\n", remote_uri); |
| k_sem_give(&sem_discovery_done); |
| } |
| |
| struct bt_tbs_client_cb tbs_client_cb = { |
| .discover = discover_cb, |
| .uri_list = read_uri_schemes_string_cb, |
| .originate_call = originate_call_cb, |
| .terminate_call = terminate_call_cb, |
| }; |
| |
| int ccp_call_ctrl_init(struct bt_conn *conn) |
| { |
| int err; |
| |
| default_conn = bt_conn_ref(conn); |
| bt_tbs_client_register_cb(&tbs_client_cb); |
| err = bt_tbs_client_discover(conn); |
| if (err != 0) { |
| return err; |
| } |
| k_sem_take(&sem_discovery_done, K_FOREVER); |
| |
| return err; |
| } |
| |
| int ccp_originate_call(void) |
| { |
| int err; |
| char uri[CONFIG_BT_TBS_MAX_URI_LENGTH]; |
| |
| strcpy(uri, remote_uri); |
| strcat(uri, URI_SEPARATOR); |
| strcat(uri, CALLER_ID); |
| |
| err = bt_tbs_client_originate_call(default_conn, BT_TBS_GTBS_INDEX, uri); |
| if (err != BT_TBS_RESULT_CODE_SUCCESS) { |
| printk("TBS originate call failed: %d\n", err); |
| } |
| |
| return err; |
| } |
| |
| int ccp_terminate_call(void) |
| { |
| int err; |
| |
| err = bt_tbs_client_terminate_call(default_conn, BT_TBS_GTBS_INDEX, new_call_index); |
| if (err != BT_TBS_RESULT_CODE_SUCCESS) { |
| printk("TBS terminate call failed: %d\n", err); |
| } |
| |
| return err; |
| } |