apps/bttester/src/btp_pacs.c (267 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* btp_pacs.c - Bluetooth Published Audio Capacity Service Tester */ #include "syscfg/syscfg.h" #if MYNEWT_VAL(BLE_AUDIO) #include "audio/ble_audio.h" #include "audio/ble_audio_codec.h" #include "btp/bttester.h" #include "host/ble_gap.h" #include "os/util.h" #include <stdint.h> #include "btp/btp.h" #include "btp/btp_pacs.h" #include "services/pacs/ble_audio_svc_pacs.h" #include "services/pacs/ble_audio_svc_pacs_lc3.h" #define BLE_SVC_AUDIO_PACS_LC3_CODEC_ID 0x06 #define BTTESTER_SUPPORTED_CTXTS 0x07 struct set_avail_cb_data { uint16_t src_ctxts; uint16_t snk_ctxts; }; #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA static uint8_t ble_svc_audio_pacs_lc3_snk_metadata[] = { UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA)) }; #endif static uint8_t ble_svc_audio_pacs_lc3_snk_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES), MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS), #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS), #else , #endif MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME), MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU), #endif ); static uint8_t ble_svc_audio_pacs_lc3_src_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SAMPLING_FREQUENCIES), MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_FRAME_DURATIONS), #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS), #else , #endif MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MIN_OCTETS_PER_CODEC_FRAME), MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU), #endif ); static struct ble_audio_codec_register_params snk_codec_params = { .codec_id = { .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, .company_id = 0x00, .vendor_specific = 0x00 }, .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_snk_codec_spec_caps), .codec_spec_caps = ble_svc_audio_pacs_lc3_snk_codec_spec_caps, #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA .metadata_len = sizeof(ble_svc_audio_pacs_lc3_snk_metadata), .metadata = ble_svc_audio_pacs_lc3_snk_metadata, #else .metadata_len = 0, #endif .direction = BLE_AUDIO_CODEC_DIR_SINK_BIT }; static struct ble_audio_codec_register_params src_codec_params = { .codec_id = { .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, .company_id = 0x00, .vendor_specific = 0x00 }, .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_src_codec_spec_caps), .codec_spec_caps = ble_svc_audio_pacs_lc3_src_codec_spec_caps, #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA .metadata_len = sizeof(ble_svc_audio_pacs_lc3_src_metadata), .metadata = ble_svc_audio_pacs_lc3_src_metadata, #else .metadata_len = 0, #endif .direction = BLE_AUDIO_CODEC_DIR_SOURCE_BIT }; int set_available(uint16_t conn_handle, void *arg) { int rc; struct set_avail_cb_data *avail_data = arg; rc = ble_svc_audio_pacs_avail_contexts_set(conn_handle, avail_data->snk_ctxts, avail_data->src_ctxts); if (rc) { return BTP_STATUS_FAILED; } return BTP_STATUS_SUCCESS; } static uint8_t pacs_set_available_contexts(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_pacs_set_available_contexts_cmd *cp = cmd; uint16_t source_contexts = le16toh(cp->source_contexts); uint16_t sink_conexts = le16toh(cp->sink_contexts); struct set_avail_cb_data cb_data; /* If this originated from pacs_update_characteristic - we update with unspecified */ if (sink_conexts == BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS) { cb_data.snk_ctxts = BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED; cb_data.src_ctxts = BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED; } else { cb_data.snk_ctxts = sink_conexts; cb_data.src_ctxts = source_contexts; } ble_gap_conn_foreach_handle(set_available, &cb_data); return BTP_STATUS_SUCCESS; } static uint8_t pacs_set_snk_location(void) { int rc; struct ble_svc_audio_pacs_set_param snk_params = { .audio_locations = 0, .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS) }; rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); if (rc) { return BTP_STATUS_FAILED; } return BTP_STATUS_SUCCESS; } static uint8_t pacs_set_src_location(void) { int rc; struct ble_svc_audio_pacs_set_param src_params = { .audio_locations = 0, .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS) }; rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); if (rc) { return BTP_STATUS_FAILED; } return BTP_STATUS_SUCCESS; } static uint8_t pacs_update_characteristic(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { int rc; const struct btp_pacs_update_characteristic_cmd *cp = cmd; switch (cp->char_id) { case BTP_PACS_CHARACTERISTIC_SINK_PAC: rc = ble_audio_codec_register(&snk_codec_params, NULL); if (rc) { return BTP_STATUS_FAILED; } break; case BTP_PACS_CHARACTERISTIC_SOURCE_PAC: rc = ble_audio_codec_register(&src_codec_params, NULL); if (rc) { return BTP_STATUS_FAILED; } break; case BTP_PACS_CHARACTERISTIC_SINK_AUDIO_LOCATIONS: rc = pacs_set_snk_location(); if (rc) { return BTP_STATUS_FAILED; } break; case BTP_PACS_CHARACTERISTIC_SOURCE_AUDIO_LOCATIONS: rc = pacs_set_src_location(); if (rc) { return BTP_STATUS_FAILED; } break; case BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS: rc = pacs_set_available_contexts(cmd, cmd_len, rsp, rsp_len); if (rc) { return BTP_STATUS_FAILED; } break; default: return BTP_STATUS_FAILED; } return BTP_STATUS_SUCCESS; } static uint8_t pacs_set_supported_contexts(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { int rc; const struct btp_pacs_set_supported_contexts_cmd *sup_ctxts = cmd; struct ble_svc_audio_pacs_set_param src_params = { .audio_locations = 0, .supported_contexts = sup_ctxts->source_contexts, }; struct ble_svc_audio_pacs_set_param snk_params = { .audio_locations = 0, .supported_contexts = sup_ctxts->sink_contexts, }; rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); if (rc) { return BTP_STATUS_FAILED; } rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); if (rc) { return BTP_STATUS_FAILED; } return BTP_STATUS_SUCCESS; } static uint8_t supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { struct btp_pacs_read_supported_commands_rp *rp = rsp; /* octet 0 */ tester_set_bit(rp->data, BTP_PACS_READ_SUPPORTED_COMMANDS); tester_set_bit(rp->data, BTP_PACS_UPDATE_CHARACTERISTIC); tester_set_bit(rp->data, BTP_PACS_SET_AVAILABLE_CONTEXTS); tester_set_bit(rp->data, BTP_PACS_SET_SUPPORTED_CONTEXTS); *rsp_len = sizeof(*rp) + 1; return BTP_STATUS_SUCCESS; } static const struct btp_handler handlers[] = { { .opcode = BTP_PACS_READ_SUPPORTED_COMMANDS, .expect_len = 0, .func = supported_commands, }, { .opcode = BTP_PACS_UPDATE_CHARACTERISTIC, .expect_len = sizeof(struct btp_pacs_update_characteristic_cmd), .func = pacs_update_characteristic, }, { .opcode = BTP_PACS_SET_AVAILABLE_CONTEXTS, .expect_len = sizeof(struct btp_pacs_set_available_contexts_cmd), .func = pacs_set_available_contexts, }, { .opcode = BTP_PACS_SET_SUPPORTED_CONTEXTS, .expect_len = sizeof(struct btp_pacs_set_supported_contexts_cmd), .func = pacs_set_supported_contexts, }, }; uint8_t tester_init_pacs(void) { int rc; struct ble_svc_audio_pacs_set_param src_params = { .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS), .supported_contexts = BTTESTER_SUPPORTED_CTXTS }; struct ble_svc_audio_pacs_set_param snk_params = { .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS), .supported_contexts = BTTESTER_SUPPORTED_CTXTS }; rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); SYSINIT_PANIC_ASSERT(rc == 0); rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); SYSINIT_PANIC_ASSERT(rc == 0); tester_register_command_handlers(BTP_SERVICE_ID_PACS, handlers, ARRAY_SIZE(handlers)); return BTP_STATUS_SUCCESS; } uint8_t tester_unregister_pacs(void) { return BTP_STATUS_SUCCESS; } #endif /* MYNEWT_VAL(BLE_AUDIO)*/