diff options
Diffstat (limited to 'src/sample/ble_audio_ba/ble_audio_ba_role.c')
-rw-r--r-- | src/sample/ble_audio_ba/ble_audio_ba_role.c | 610 |
1 files changed, 610 insertions, 0 deletions
diff --git a/src/sample/ble_audio_ba/ble_audio_ba_role.c b/src/sample/ble_audio_ba/ble_audio_ba_role.c new file mode 100644 index 0000000..e8a003c --- /dev/null +++ b/src/sample/ble_audio_ba/ble_audio_ba_role.c @@ -0,0 +1,610 @@ +#include <string.h> +#include "trace.h" +#include "user_cmd.h" +#include "user_cmd_parse.h" +#include "link_mgr.h" +#include "ble_audio_ba_role.h" +#include "bap.h" +#include "app_task.h" +#include "profile_server.h" +#include "ble_audio_ba_role.h" +#if LE_AUDIO_LIB_SUPPORT +#include "ble_audio.h" +#endif +#if BT_GATT_CLIENT_SUPPORT +#include "bt_gatt_client.h" +#endif +#include "bass_def.h" +#include "base_data_parse.h" +#include "ble_audio_sync.h" +#include "bass_client.h" + +#if LE_AUDIO_BROADCAST_ASSISTANT_ROLE +typedef struct +{ + bool pa_print; + bool need_release; + T_BLE_AUDIO_SYNC_HANDLE sync_handle; + T_GAP_PA_SYNC_STATE source_pa_state; +} T_APP_BA_CB; + +T_APP_BA_CB app_ba_cb; + +bool ble_audio_adv_filter_service_data(uint8_t report_data_len, uint8_t *p_report_data, + uint16_t uuid, uint8_t **pp_service_data, uint16_t *p_data_len) +{ + uint8_t *p_buffer = NULL; + uint8_t pos = 0; + + while (pos < report_data_len) + { + /* Length of the AD structure. */ + uint16_t length = p_report_data[pos++]; + uint8_t type; + + if (length < 1) + { + return false; + } + + if ((length > 0x01) && ((pos + length) <= report_data_len)) + { + /* Copy the AD Data to buffer. */ + p_buffer = p_report_data + pos + 1; + /* AD Type, one octet. */ + type = p_report_data[pos]; + + switch (type) + { + case GAP_ADTYPE_SERVICE_DATA: + case GAP_ADTYPE_16BIT_MORE: //just for pts + { + uint16_t srv_uuid; + LE_STREAM_TO_UINT16(srv_uuid, p_buffer); + if (srv_uuid == uuid) + { + if (pp_service_data != NULL) + { + *pp_service_data = p_buffer; + } + if (p_data_len != NULL) + { + *p_data_len = length - 3; + } + return true; + } + } + break; + + default: + break; + } + } + + pos += length; + } + return false; +} + +void app_ble_audio_handle_adv_report(T_LE_EXT_ADV_REPORT_INFO *p_report) +{ + T_DEV_INFO *p_dev_info = NULL; + uint8_t *p_service_data; + uint16_t service_data_len; + + if (ble_audio_adv_filter_service_data(p_report->data_len, + p_report->p_data, + BROADCAST_AUDIO_ANNOUNCEMENT_SRV_UUID, &p_service_data, &service_data_len)) + { + if (service_data_len == BROADCAST_ID_LEN) + { + link_mgr_add_device(p_report->bd_addr, + p_report->addr_type, &p_dev_info); + if (p_dev_info) + { + p_dev_info->uuid16 = BROADCAST_AUDIO_ANNOUNCEMENT_SRV_UUID; + memcpy(p_dev_info->broadcast_id, p_service_data, BROADCAST_ID_LEN); + p_dev_info->adv_sid = p_report->adv_sid; + data_uart_print("Found dev[%d] = [%02x:%02x:%02x:%02x:%02x:%02x], broadcast audio announcement\r\n", + p_dev_info->idx, + p_dev_info->bd_addr[5], p_dev_info->bd_addr[4], + p_dev_info->bd_addr[3], p_dev_info->bd_addr[2], + p_dev_info->bd_addr[1], p_dev_info->bd_addr[0]); + } + } + + } + if (ble_audio_adv_filter_service_data(p_report->data_len, + p_report->p_data, + GATT_UUID_BASS, &p_service_data, &service_data_len)) + { + link_mgr_add_device(p_report->bd_addr, + p_report->addr_type, &p_dev_info); + if (p_dev_info) + { + p_dev_info->uuid16 = GATT_UUID_BASS; + data_uart_print("Found dev[%d] = [%02x:%02x:%02x:%02x:%02x:%02x], BASS\r\n", + p_dev_info->idx, + p_dev_info->bd_addr[5], p_dev_info->bd_addr[4], + p_dev_info->bd_addr[3], p_dev_info->bd_addr[2], + p_dev_info->bd_addr[1], p_dev_info->bd_addr[0]); + } + } +} + +void app_ba_print_lv2(uint16_t length, uint8_t *p_data) +{ + uint16_t idx = 0; + uint16_t len; + uint8_t type; + + for (; idx < length;) + { + len = p_data[idx]; + idx++; + type = p_data[idx]; + data_uart_print(" Length: [%d (0x%02x)]\r\n", len, len); + data_uart_print(" Type and Value:\r\n"); + data_uart_print(" Type: [%d (0x%02x)]\r\n", type, type); + data_uart_print(" Value: [0x"); + for (uint8_t i = 1; i < len; i++) + { + data_uart_print("%02x", p_data[idx + i]); + } + data_uart_print("]\r\n"); + idx += len; + } +} +void app_ba_print_lv3(uint16_t length, uint8_t *p_data) +{ + uint16_t idx = 0; + uint16_t len; + uint8_t type; + + for (; idx < length;) + { + len = p_data[idx]; + idx++; + type = p_data[idx]; + data_uart_print(" Length: [%d (0x%02x)]\r\n", len, len); + data_uart_print(" Type and Value:\r\n"); + data_uart_print(" Type: [%d (0x%02x)]\r\n", type, type); + data_uart_print(" Value: [0x"); + for (uint8_t i = 1; i < len; i++) + { + data_uart_print("%02x", p_data[idx + i]); + } + data_uart_print("]\r\n"); + idx += len; + } +} + + +void app_ba_print_base_info(uint16_t length, uint8_t *p_pa_data) +{ + uint8_t codec_id_level2[CODEC_ID_LEN];// + uint8_t codec_cfg_len; + uint16_t uuid; + uint8_t i = 0; + uint8_t j = 0; + uint8_t num_subgroups; + uint32_t presentation_delay; + + data_uart_print("- Set Basic Audio Announcements data:Basic Audio Announcements: \r\n"); + data_uart_print(" Length: [%d (0x%02x)]\r\n", p_pa_data[0], p_pa_data[0]); + data_uart_print(" AD Type: [%d (0x%02x)]\r\n", p_pa_data[1], p_pa_data[1]); + STREAM_SKIP_LEN(p_pa_data, 2); + LE_STREAM_TO_UINT16(uuid, p_pa_data); + if (uuid != BASIC_AUDIO_ANNOUNCEMENT_SRV_UUID) + { + return; + } + data_uart_print(" Basic Audio Announcement Service UUID: [%d (0x%04x)] Service UUID\r\n", uuid, + uuid); + LE_STREAM_TO_UINT24(presentation_delay, p_pa_data); + LE_STREAM_TO_UINT8(num_subgroups, p_pa_data); + data_uart_print(" Presentation Delay: [%d (0x%06x)]\r\n", presentation_delay, presentation_delay); + data_uart_print(" Num Subgroups: [%d (0x%02x)]\r\n", num_subgroups, num_subgroups); + data_uart_print(" Codec And Metadata Subgroups: {\r\n"); + + for (i = 0; i < num_subgroups; i++) + { + uint8_t num_bis;// + uint8_t metadata_len; + LE_STREAM_TO_UINT8(num_bis, p_pa_data); + data_uart_print(" Num BIS: [%d (0x%02x)]\r\n", num_bis, num_bis); + data_uart_print(" Codec And Metadata Lv2:\r\n"); + memcpy(codec_id_level2, p_pa_data, CODEC_ID_LEN); + STREAM_SKIP_LEN(p_pa_data, CODEC_ID_LEN); + data_uart_print(" Codec Configuration:\r\n"); + data_uart_print(" Codec ID: [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x]\r\n", + codec_id_level2[0], codec_id_level2[1], codec_id_level2[2], + codec_id_level2[3], codec_id_level2[4]); + + + LE_STREAM_TO_UINT8(codec_cfg_len, p_pa_data); + data_uart_print(" Codec Specific Configuration Length: [%d (0x%02x)]\r\n", codec_cfg_len, + codec_cfg_len); + data_uart_print(" LTV Wrapper: {\r\n"); + if (codec_cfg_len != 0) + { + app_ba_print_lv2(codec_cfg_len, p_pa_data); + } + STREAM_SKIP_LEN(p_pa_data, codec_cfg_len); + + LE_STREAM_TO_UINT8(metadata_len, p_pa_data); + data_uart_print(" Metadata Length: [%d (0x%02x)]\r\n", metadata_len, metadata_len); + data_uart_print(" Metadata:\r\n"); + data_uart_print(" LTV Wrapper: {\r\n"); + if (metadata_len != 0) + { + app_ba_print_lv2(metadata_len, p_pa_data); + } + STREAM_SKIP_LEN(p_pa_data, metadata_len); + + for (j = 0; j < num_bis; j++) + { + uint8_t bis_index; + data_uart_print(" BIS Codec Subgroup Lv3: {\r\n"); + LE_STREAM_TO_UINT8(bis_index, p_pa_data); + data_uart_print(" BIS index: [%d (0x%02x)]\r\n", bis_index, bis_index); + LE_STREAM_TO_UINT8(codec_cfg_len, p_pa_data); + data_uart_print(" Codec Specific Configuration Length: [%d (0x%02x)]\r\n", codec_cfg_len, + codec_cfg_len); + data_uart_print(" Codec Specific Configuration LTV: \r\n"); + if (codec_cfg_len != 0) + { + app_ba_print_lv3(codec_cfg_len, p_pa_data); + } + STREAM_SKIP_LEN(p_pa_data, codec_cfg_len); + } + } +} + +static void app_ble_audio_pa_sync_cb(T_BLE_AUDIO_SYNC_HANDLE handle, uint8_t cb_type, + void *p_cb_data) +{ + T_BLE_AUDIO_SYNC_CB_DATA *p_sync_cb = (T_BLE_AUDIO_SYNC_CB_DATA *)p_cb_data; + switch (cb_type) + { + case MSG_BLE_AUDIO_PA_SYNC_STATE: + { + APP_PRINT_TRACE3("MSG_BLE_AUDIO_PA_SYNC_STATE: sync_state %d, action %d, cause 0x%x\r\n", + p_sync_cb->p_pa_sync_state->sync_state, + p_sync_cb->p_pa_sync_state->action, + p_sync_cb->p_pa_sync_state->cause); + app_ba_cb.source_pa_state = p_sync_cb->p_pa_sync_state->sync_state; + if (p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_SYNCHRONIZED) + { + data_uart_print("PA SYNCHRONIZED\r\n"); + } + else if (p_sync_cb->p_pa_sync_state->sync_state == GAP_PA_SYNC_STATE_TERMINATED) + { + data_uart_print("PA TERMINATED\r\n"); + if (app_ba_cb.need_release) + { + if (ble_audio_sync_realese(app_ba_cb.sync_handle)) + { + memset(&app_ba_cb, 0, sizeof(app_ba_cb)); + } + } + } + } + break; + + case MSG_BLE_AUDIO_PA_REPORT_INFO: + { +#if 1 + if (app_ba_cb.pa_print == false) + { + app_ba_print_base_info(p_sync_cb->p_le_periodic_adv_report_info->data_len, + p_sync_cb->p_le_periodic_adv_report_info->p_data); + app_ba_cb.pa_print = true; + } +#endif + } + break; + + case MSG_BLE_AUDIO_BASE_DATA_MODIFY_INFO: + { + APP_PRINT_TRACE1("MSG_BLE_AUDIO_BASE_DATA_MODIFY_INFO: p_base_mapping %p\r\n", + p_sync_cb->p_base_data_modify_info->p_base_mapping); + if (p_sync_cb->p_base_data_modify_info->p_base_mapping) + { + base_data_print(p_sync_cb->p_base_data_modify_info->p_base_mapping); + } + } + break; + + case MSG_BLE_AUDIO_PA_BIGINFO: + { + } + break; + default: + break; + } + return; +} + +bool app_ble_audio_pa_sync(T_DEV_INFO *p_dev_info) +{ + uint8_t options = 0; + uint8_t sync_cte_type = 0; + uint16_t sync_timeout = 1000; + uint16_t skip = 0; + + if (app_ba_cb.sync_handle == NULL) + { + app_ba_cb.sync_handle = ble_audio_sync_create(app_ble_audio_pa_sync_cb, + p_dev_info->bd_type, + p_dev_info->bd_addr, p_dev_info->adv_sid, + p_dev_info->broadcast_id); + } + if (app_ba_cb.sync_handle == NULL) + { + goto failed; + } + + if (ble_audio_pa_sync_establish(app_ba_cb.sync_handle, + options, sync_cte_type, skip, sync_timeout) == false) + { + goto failed; + } + return true; +failed: + data_uart_print("bap_ba_ts_pa_sync: failed\r\n"); + return false; +} + +bool app_ble_audio_stop_pa_sync(bool need_release) +{ + if (app_ba_cb.sync_handle != NULL) + { + app_ba_cb.need_release = need_release; + return ble_audio_pa_terminate(app_ba_cb.sync_handle); + } + return false; +} + +T_APP_RESULT app_handle_bass_client_msg(T_LE_AUDIO_MSG msg, void *buf) +{ + T_APP_RESULT app_result = APP_RESULT_SUCCESS; + T_BLE_LINK *p_link = NULL; + uint8_t err_idx = 0; + switch (msg) + { + case LE_AUDIO_MSG_BASS_CLIENT_DIS_DONE: + { + T_BASS_CLIENT_DIS_DONE *p_data = (T_BASS_CLIENT_DIS_DONE *)buf; + APP_PRINT_INFO3("LE_AUDIO_MSG_BASS_CLIENT_DIS_DONE: conn_handle 0x%x, is_found %d, brs_char_num %d", + p_data->conn_handle, + p_data->is_found, + p_data->brs_char_num); + p_link = ble_link_find_by_conn_handle(p_data->conn_handle); + if (p_link == NULL) + { + err_idx = 0x10; + goto failed; + } + if (p_data->is_found) + { + if (p_data->load_form_ftl == false) + { + bass_enable_cccd(p_data->conn_handle); + } + for (uint8_t i = 0; i < p_data->brs_char_num; i++) + { + bass_read_brs_value(p_data->conn_handle, i); + } + p_link->brs_char_num = p_data->brs_char_num; + } + } + break; + + case LE_AUDIO_MSG_BASS_CLIENT_CCCD: + { + T_BASS_CLIENT_CCCD *p_data = (T_BASS_CLIENT_CCCD *)buf; + APP_PRINT_INFO2("LE_AUDIO_MSG_BASS_CLIENT_CCCD: conn_handle 0x%x, cause 0x%x", + p_data->conn_handle, + p_data->cause); + } + break; + case LE_AUDIO_MSG_BASS_CLIENT_CP_RESULT: + { + T_BASS_CLIENT_CP_RESULT *p_data = (T_BASS_CLIENT_CP_RESULT *)buf; + APP_PRINT_INFO2("LE_AUDIO_MSG_BASS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x", + p_data->conn_handle, + p_data->cause); + } + break; + + case LE_AUDIO_MSG_BASS_CLIENT_SYNC_INFO_REQ: + { + T_BASS_CLIENT_SYNC_INFO_REQ *p_data = (T_BASS_CLIENT_SYNC_INFO_REQ *)buf; + APP_PRINT_INFO2("LE_AUDIO_MSG_BASS_CLIENT_SYNC_INFO_REQ: conn_handle 0x%x, instance_id %d", + p_data->conn_handle, + p_data->instance_id); + p_link = ble_link_find_by_conn_handle(p_data->conn_handle); + if (p_link == NULL) + { + err_idx = 0x10; + goto failed; + } + if (ble_audio_check_remote_features(p_data->conn_handle, LE_SUPPORT_FEATURES_MASK_ARRAY_INDEX3, + LE_SUPPORT_FEATURES_PAST_RECIPIENT_MASK_BIT)) + { + T_BASS_PAST_SRV_DATA srv_data; + srv_data.adv_a_match_ext_adv = 0; + srv_data.adv_a_match_src = 0; + srv_data.source_id = p_link->source_id; + if (bass_transfer_syncinfo_of_remote_src(app_ba_cb.sync_handle, p_data->conn_handle, + srv_data) == false) + { + err_idx = 1; + goto failed; + } + } + } + break; + + case LE_AUDIO_MSG_BASS_CLIENT_BRS_DATA: + { + T_BASS_CLIENT_BRS_DATA *p_data = (T_BASS_CLIENT_BRS_DATA *)buf; + APP_PRINT_INFO4("LE_AUDIO_MSG_BASS_CLIENT_BRS_DATA: conn_handle 0x%x, notify %d, read_cause 0x%x, instance_id %d", + p_data->conn_handle, p_data->notify, p_data->read_cause, p_data->instance_id); + p_link = ble_link_find_by_conn_handle(p_data->conn_handle); + if (p_link == NULL) + { + err_idx = 0x10; + goto failed; + } + if (p_data->p_brs_data && p_data->p_brs_data->brs_is_used) + { + APP_PRINT_INFO7("LE_AUDIO_MSG_BASS_CLIENT_BRS_DATA: source_id %d, source_address_type 0x%x, source_address %s, source_adv_sid %d, pa_sync_state %d, bis_sync_state 0x%x, big_encryption %d", + p_data->p_brs_data->source_id, + p_data->p_brs_data->source_address_type, + TRACE_BDADDR(p_data->p_brs_data->source_address), + p_data->p_brs_data->source_adv_sid, + p_data->p_brs_data->pa_sync_state, + p_data->p_brs_data->bis_sync_state, + p_data->p_brs_data->big_encryption); + if (p_data->p_brs_data->num_subgroups) + { + APP_PRINT_INFO4("LE_AUDIO_MSG_BASS_CLIENT_BRS_DATA: num_subgroups %d, bis_info_size %d, bis_sync 0x%x, metadata_len %d", + p_data->p_brs_data->num_subgroups, + p_data->p_brs_data->bis_info_size, + p_data->p_brs_data->p_cp_bis_info[0].bis_sync, + p_data->p_brs_data->p_cp_bis_info[0].metadata_len); + } + + p_link->source_id = p_data->p_brs_data->source_id; + p_link->pa_sync_state = p_data->p_brs_data->pa_sync_state; + p_link->bis_sync_state = p_data->p_brs_data->bis_sync_state; + } + else + { + p_link->source_id = 0; + p_link->pa_sync_state = PA_SYNC_STATE_NOT_SYNC; + p_link->bis_sync_state = 0; + } + } + break; + default: + break; + } + return app_result; +failed: + APP_PRINT_TRACE1("app_handle_bass_client_msg:failed, err_idx %d", err_idx); + return app_result; +} + +T_APP_RESULT app_ble_audio_msg_cb(T_LE_AUDIO_MSG msg, void *buf) +{ + T_APP_RESULT app_result = APP_RESULT_SUCCESS; + uint16_t msg_group; + + APP_PRINT_TRACE1("app_ble_audio_msg_cb: msg 0x%04x", msg); + + msg_group = msg & 0xff00; + + switch (msg_group) + { + case LE_AUDIO_MSG_GROUP_BASS_CLIENT: + app_result = app_handle_bass_client_msg(msg, buf); + break; + + case LE_AUDIO_MSG_GROUP_BAP: + break; + + default: + break; + } + + return app_result; +} + +T_APP_RESULT app_profile_callback(T_SERVER_ID service_id, void *p_data) +{ + T_APP_RESULT app_result = APP_RESULT_SUCCESS; + if (service_id == SERVICE_PROFILE_GENERAL_ID) + { + T_SERVER_APP_CB_DATA *p_param = (T_SERVER_APP_CB_DATA *)p_data; + switch (p_param->eventId) + { + case PROFILE_EVT_SRV_REG_COMPLETE:// srv register result event. + APP_PRINT_INFO1("PROFILE_EVT_SRV_REG_COMPLETE: result %d", + p_param->event_data.service_reg_result); + break; + + case PROFILE_EVT_SEND_DATA_COMPLETE: + break; + + default: + break; + } + } + + return app_result; +} + +bool app_ble_audio_add_source(T_BLE_LINK *p_link, T_BASS_PA_SYNC pa_sync, uint32_t bis_array) +{ + if (app_ba_cb.sync_handle != NULL) + { + if (bass_cp_add_source_by_sync_info(app_ba_cb.sync_handle, p_link->conn_handle, pa_sync, + bis_array, + false)) + { + return true; + } + } + return false; +} + +bool app_ble_audio_modify_source(T_BLE_LINK *p_link, T_BASS_PA_SYNC pa_sync, uint32_t bis_array) +{ + if (app_ba_cb.sync_handle != NULL) + { + if (bass_cp_modify_source_by_sync_info(app_ba_cb.sync_handle, p_link->conn_handle, + p_link->source_id, pa_sync, bis_array, false)) + { + return true; + } + } + return false; +} + +bool app_ble_audio_profile_init(void) +{ + server_register_app_cb(app_profile_callback); + client_init(2); + T_BAP_ROLE_INFO role_info; + T_BLE_AUDIO_PARAMS ble_audio_param; + ble_audio_param.p_fun_cb = app_ble_audio_msg_cb; + ble_audio_param.evt_queue_handle = evt_queue_handle; + ble_audio_param.io_queue_handle = io_queue_handle; + if (ble_audio_init(&ble_audio_param) == false) + { + goto failed; + } + role_info.role_mask = BAP_BROADCAST_ASSISTANT_ROLE; + role_info.isoc_cig_max_num = 0; + role_info.isoc_cis_max_num = 0; + role_info.pa_adv_num = 0; + role_info.isoc_big_broadcaster_num = 0; + role_info.isoc_bis_broadcaster_num = 0; + role_info.pa_sync_num = 2; + role_info.isoc_big_receiver_num = 0; + role_info.isoc_bis_receiver_num = 0; + role_info.brs_num = 0; + role_info.init_gap = true; + if (bap_role_init(&role_info) == false) + { + goto failed; + } + return true; +failed: + APP_PRINT_ERROR0("app_ble_audio_profile_init: failed"); + return false; +} +#endif |