| /* |
| * 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; |
| |
| *rsp_len = tester_supported_commands(BTP_SERVICE_ID_PACS, rp->data); |
| *rsp_len += sizeof(*rp); |
| |
| 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)*/ |