MariuszSkamra commented on code in PR #1675: URL: https://github.com/apache/mynewt-nimble/pull/1675#discussion_r1465909058
########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; + + /* Codec entry flags. It is any combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + */ + uint8_t flags; + + /* Function used to parse Codec Specific Capabilities */ + ble_audio_codec_parser *parser; + + /* Optional argument for `ble_audio_codec_parser` */ + void *parser_arg; +}; + +/** Type definition codec iteration callback function. */ +typedef int ble_audio_codec_foreach_fn(struct ble_audio_codec_record * + record, void *arg); +/** + * @brief Register codec entry + * + * @param[in] codec_id Codec ID structure. + * @param[in] codec_spec_caps_len Codec Specific Capabilities length. + * @param[in] codec_spec_caps Codec Specific Capabilities data. + * @param[in] metadata_len Metadata length. + * @param[in] metadata Metadata. + * @param[in] flags Codec entry flags. It is any + * combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + * @param[in] cb Function used to parse Codec + * Specific Capabilities + * @param[in] cb_arg Optional callback argument. + * @param[out] out_record Pointer to registered codec entry. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_register(struct ble_audio_codec_id codec_id, + uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + uint8_t metadata_len, + uint8_t *metadata, + uint8_t flags, + ble_audio_codec_parser *cb, + void *cb_arg, + struct ble_audio_codec_record *out_record); +/** + * @brief Remove codec entry from register + * + * @param[in] codec_record Pointer to registered codec entry. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_unregister(struct ble_audio_codec_record *codec_record); + +/** + * @brief Iterate through all registered codecs and call function on every + * one of them. + * + * @param[in] cb Callback to be called on codec entries. + * @param[in] arg Optional callback argument. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_foreach(ble_audio_codec_foreach_fn *cb, void *arg); Review Comment: Having `flags` parameter here would be useful I think, so that function could filter out the direction for the user ########## nimble/host/include/host/ble_audio_common.h: ########## @@ -117,16 +150,54 @@ _octets_per_codec_frame, \ _codec_frame_blocks_per_sdu) \ { \ - 2, BLE_AUDIO_CODEC_SAMPLING_FREQ_TYPE, _sampling_freq, \ - 2, BLE_AUDIO_CODEC_FRAME_DURATION_TYPE, _frame_duration, \ - OPTIONAL_FIELD(5, BLE_AUDIO_CODEC_AUDIO_CHANNEL_ALLOCATION_TYPE, \ + 2, BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQS_TYPE, _sampling_freq, \ + 2, BLE_AUDIO_CODEC_CAPS_FRAME_DURATIONS_TYPE, _frame_duration, \ Review Comment: BLE_AUDIO_CODEC_CONF_FRAME_DURATION_TYPE ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sink_audio_locations, + sizeof ble_svc_audio_pacs_sink_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_source_audio_locations, Review Comment: ditto ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; Review Comment: const ########## nimble/host/include/host/ble_audio_common.h: ########## @@ -117,16 +150,54 @@ _octets_per_codec_frame, \ _codec_frame_blocks_per_sdu) \ { \ - 2, BLE_AUDIO_CODEC_SAMPLING_FREQ_TYPE, _sampling_freq, \ - 2, BLE_AUDIO_CODEC_FRAME_DURATION_TYPE, _frame_duration, \ - OPTIONAL_FIELD(5, BLE_AUDIO_CODEC_AUDIO_CHANNEL_ALLOCATION_TYPE, \ + 2, BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQS_TYPE, _sampling_freq, \ Review Comment: BLE_AUDIO_CODEC_CONF_SAMPLING_FREQ_TYPE ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; + + /* Codec entry flags. It is any combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + */ + uint8_t flags; + + /* Function used to parse Codec Specific Capabilities */ + ble_audio_codec_parser *parser; + + /* Optional argument for `ble_audio_codec_parser` */ + void *parser_arg; +}; + +/** Type definition codec iteration callback function. */ +typedef int ble_audio_codec_foreach_fn(struct ble_audio_codec_record * + record, void *arg); +/** + * @brief Register codec entry + * + * @param[in] codec_id Codec ID structure. + * @param[in] codec_spec_caps_len Codec Specific Capabilities length. + * @param[in] codec_spec_caps Codec Specific Capabilities data. + * @param[in] metadata_len Metadata length. + * @param[in] metadata Metadata. + * @param[in] flags Codec entry flags. It is any + * combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + * @param[in] cb Function used to parse Codec + * Specific Capabilities + * @param[in] cb_arg Optional callback argument. + * @param[out] out_record Pointer to registered codec entry. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_register(struct ble_audio_codec_id codec_id, + uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + uint8_t metadata_len, + uint8_t *metadata, + uint8_t flags, + ble_audio_codec_parser *cb, + void *cb_arg, Review Comment: Did you consider structure of parameters instead? I find a structure more to be easier to extend with additional parameters if needed. ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, Review Comment: ble_audio_codec_parser_fn ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; + + /* Codec entry flags. It is any combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + */ + uint8_t flags; + + /* Function used to parse Codec Specific Capabilities */ + ble_audio_codec_parser *parser; + + /* Optional argument for `ble_audio_codec_parser` */ + void *parser_arg; +}; + +/** Type definition codec iteration callback function. */ +typedef int ble_audio_codec_foreach_fn(struct ble_audio_codec_record * Review Comment: I think the `record` shall be const ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; + + /* Codec entry flags. It is any combination of following flags: + * - BLE_AUDIO_CODEC_FLAG_SOURCE + * - BLE_AUDIO_CODEC_FLAG_SINK + */ + uint8_t flags; + + /* Function used to parse Codec Specific Capabilities */ + ble_audio_codec_parser *parser; Review Comment: Who's gonna be user of this parser function? I wonder whether if it needs to be here. From PACS point of view, it needs a data pointer (flat buffer). ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, Review Comment: const ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { Review Comment: As you might wan to filter the so called type or direction of the CAP, please define and use mask `BLE_AUDIO_CODEC_FLAG_SOURCE | BLE_AUDIO_CODEC_FLAG_SINK` ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sink_audio_locations, + sizeof ble_svc_audio_pacs_sink_audio_locations); Review Comment: Remenber about the endianess conversion H->LE ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} Review Comment: Hmm, that does not look right to me, as I think you should send as many data as you could fit into the buffer, so that the remote could perform Long Value Read (incl. offset > 0). ########## nimble/host/include/host/ble_audio_codec.h: ########## @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +#include "stdint.h" +#include "ble_audio_common.h" + +#define BLE_AUDIO_CODEC_FLAG_SOURCE 0x01 +#define BLE_AUDIO_CODEC_FLAG_SINK 0x02 + +/** Type definition for Codec Specific Capabilities parser function. */ +typedef int ble_audio_codec_parser(uint8_t codec_spec_caps_len, + uint8_t *codec_spec_caps, + void *cb_arg); + + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; Review Comment: ditto ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } Review Comment: Codec CID and codec VID are uint16, thus need to be put in LE order ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; Review Comment: ditto ########## nimble/host/services/audio/pacs/include/services/pacs/ble_audio_svc_pacs.h: ########## @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef H_BLE_AUDIO_SVC_PACS_ +#define H_BLE_AUDIO_SVC_PACS_ + +#define BLE_SVC_AUDIO_PACS_UUID16 0x1850 +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC 0x2BC9 +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS 0x2BCA +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC 0x2BCB +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS 0x2BCC +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS 0x2BCD +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS 0x2BCE + +int ble_svc_audio_pacs_set_sink_audio_loc(uint32_t audio_locations); +int ble_svc_audio_pacs_set_source_audio_loc(uint32_t audio_locations); +int ble_svc_audio_pacs_set_sup_contexts(uint16_t sink_contexts, + uint16_t source_contexts); +int ble_svc_audio_pacs_set_avail_contexts(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts); Review Comment: I wonder whether is there a need to have those 4 functions instead of 1 e.g. ble_svc_audio_pacs_init. As those are basically used to initialize the characteristic values. What's your opinion on that? ``` struct ble_svc_audio_pacs_init_param { uint32_t audio_locations; uint16_t available_contexts; uint16_t supported_contexts; }; struct ble_svc_audio_pacs_init(uint8_t flags, struct ble_svc_audio_pacs_init_param *param); ``` where `flags ` are the ones from Codec API`. Hmm, this makes me feel that those should not be flags, but rather `type` with 2 possible values Sink and Source defined as enum probably so that we could reuse it in different services. ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sink_audio_locations, + sizeof ble_svc_audio_pacs_sink_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_source_audio_locations, + sizeof ble_svc_audio_pacs_source_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_find_avail_ctx(uint16_t conn_handle) +{ + int i; + + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { + if (ble_svc_audio_pacs_avail_contexts[i].conn_handle == conn_handle) { + return i; + } + } + return -BLE_HS_ENOENT; +} + +static int +ble_svc_audio_pacs_avail_audio_ctx_read_access(uint16_t conn_handle, + struct ble_gatt_access_ctxt * + ctxt) +{ + struct available_ctx *avail_ctx; + int ctx_idx; + int rc; + + ctx_idx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + if (ctxt < 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + avail_ctx = &ble_svc_audio_pacs_avail_contexts[ctx_idx]; + + rc = os_mbuf_append(ctxt->om, + &avail_ctx->ble_svc_audio_pacs_avail_sink_contexts, + sizeof(&avail_ctx->ble_svc_audio_pacs_avail_sink_contexts)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(ctxt->om, + &avail_ctx->ble_svc_audio_pacs_avail_source_contexts, + sizeof(&avail_ctx->ble_svc_audio_pacs_avail_source_contexts)); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sup_audio_ctx_read_access(struct ble_gatt_access_ctxt + *ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sup_sink_contexts, + sizeof ble_svc_audio_pacs_sup_sink_contexts); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sup_source_contexts, + sizeof ble_svc_audio_pacs_sup_source_contexts); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid); + int rc; + + switch (uuid16) { + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_pac_read_access(ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_pac_read_access(ctxt); + } else { + assert(0); + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_avail_audio_ctx_read_access(conn_handle, + ctxt); + } else { + assert(0); + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sup_audio_ctx_read_access(ctxt); + } else { + assert(0); + } + return rc; + default: + assert(0); + } +} + +int +ble_svc_audio_pacs_set_sink_audio_loc(uint32_t audio_locations) +{ + ble_svc_audio_pacs_sink_audio_locations = audio_locations; + + return 0; +} + +int +ble_svc_audio_pacs_set_source_audio_loc(uint32_t audio_locations) +{ + ble_svc_audio_pacs_source_audio_locations = audio_locations; + + return 0; +} Review Comment: As the notifications are unsupported, please disallow those functions to be called again. ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sink_audio_locations, + sizeof ble_svc_audio_pacs_sink_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_source_audio_locations, + sizeof ble_svc_audio_pacs_source_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_find_avail_ctx(uint16_t conn_handle) +{ + int i; + + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { + if (ble_svc_audio_pacs_avail_contexts[i].conn_handle == conn_handle) { + return i; + } + } + return -BLE_HS_ENOENT; +} + +static int +ble_svc_audio_pacs_avail_audio_ctx_read_access(uint16_t conn_handle, + struct ble_gatt_access_ctxt * + ctxt) +{ + struct available_ctx *avail_ctx; + int ctx_idx; + int rc; + + ctx_idx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + if (ctxt < 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + avail_ctx = &ble_svc_audio_pacs_avail_contexts[ctx_idx]; + + rc = os_mbuf_append(ctxt->om, + &avail_ctx->ble_svc_audio_pacs_avail_sink_contexts, + sizeof(&avail_ctx->ble_svc_audio_pacs_avail_sink_contexts)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(ctxt->om, + &avail_ctx->ble_svc_audio_pacs_avail_source_contexts, + sizeof(&avail_ctx->ble_svc_audio_pacs_avail_source_contexts)); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sup_audio_ctx_read_access(struct ble_gatt_access_ctxt + *ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sup_sink_contexts, + sizeof ble_svc_audio_pacs_sup_sink_contexts); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sup_source_contexts, + sizeof ble_svc_audio_pacs_sup_source_contexts); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid); + int rc; + + switch (uuid16) { + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_pac_read_access(ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_pac_read_access(ctxt); + } else { + assert(0); + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_avail_audio_ctx_read_access(conn_handle, + ctxt); + } else { + assert(0); + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sup_audio_ctx_read_access(ctxt); + } else { + assert(0); + } + return rc; + default: + assert(0); + } +} + +int +ble_svc_audio_pacs_set_sink_audio_loc(uint32_t audio_locations) +{ + ble_svc_audio_pacs_sink_audio_locations = audio_locations; + + return 0; +} + +int +ble_svc_audio_pacs_set_source_audio_loc(uint32_t audio_locations) +{ + ble_svc_audio_pacs_source_audio_locations = audio_locations; + + return 0; +} + +static int +pac_notify(uint16_t chrc_uuid) +{ + uint16_t chr_val_handle; + int rc; + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + BLE_UUID16_DECLARE(chrc_uuid), NULL, &chr_val_handle); + + if (!rc) { + ble_gatts_chr_updated(chr_val_handle); + } + + return rc; +} + +int +ble_svc_audio_pacs_set_avail_contexts(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts) +{ + struct available_ctx *avail_ctx; + uint16_t chr_uuid = BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS; + int ctx_idx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + + ctx_idx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + if (ctx_idx < 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + avail_ctx = &ble_svc_audio_pacs_avail_contexts[ctx_idx]; + + avail_ctx->ble_svc_audio_pacs_avail_sink_contexts = sink_contexts; + avail_ctx->ble_svc_audio_pacs_avail_source_contexts = source_contexts; + + return pac_notify(chr_uuid); +} + +int +ble_svc_audio_pacs_set_sup_contexts(uint16_t sink_contexts, + uint16_t source_contexts) +{ + ble_svc_audio_pacs_sup_sink_contexts = sink_contexts; + ble_svc_audio_pacs_sup_source_contexts = source_contexts; + + return 0; +} + Review Comment: redundant newline ########## nimble/host/services/audio/pacs/src/ble_audio_svc_pacs.c: ########## @@ -0,0 +1,428 @@ +/* + * 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. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; + +struct pac_read_cb_arg { + uint8_t flags; + struct os_mbuf *om; + uint8_t pac_count; +}; +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC + } , { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ_ENC, + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + int rc; + + if (!(record->flags & cb_arg->flags)) { + return 0; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_id, + sizeof(struct ble_audio_codec_id)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, + sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SINK, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .flags = BLE_AUDIO_CODEC_FLAG_SOURCE, + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_sink_audio_locations, + sizeof ble_svc_audio_pacs_sink_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + int rc; + + rc = os_mbuf_append(ctxt->om, &ble_svc_audio_pacs_source_audio_locations, + sizeof ble_svc_audio_pacs_source_audio_locations); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_find_avail_ctx(uint16_t conn_handle) Review Comment: Does this function performs the operation as it's name implies? For me it returns an array index. Consider returning `struct available_ctx *` from this function -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
