nimble/services: add PACS

This commit adds Published Audio Capabilities Service/Prifile. In pair
ble_audio_codec module is added, that supports registering supported
codecs with their corresponding configurations.
This commit is contained in:
Krzysztof Kopyściński
2024-01-22 13:35:47 +01:00
committed by Krzysztof Kopyściński
parent 8debcf0c46
commit e55baf9843
21 changed files with 1643 additions and 10 deletions
+1
View File
@@ -54,6 +54,7 @@ syscfg.vals:
BLE_EATT_CHAN_NUM: 2
BLE_PHY_2M: 1
BLE_PHY_CODED: 1
BLE_AUDIO_MAX_CODEC_RECORDS: 2
# controller
BLE_LL_CFG_FEAT_LL_PRIVACY: 1
+246 -10
View File
@@ -208,19 +208,184 @@
*/
/** LE Audio Codec Config Type: Sampling Frequency. */
#define BLE_AUDIO_CODEC_SAMPLING_FREQ_TYPE 0x01
#define BLE_AUDIO_CODEC_CONF_SAMPLING_FREQ_TYPE 0x01
/** LE Audio Codec Config Type: Frame Duration. */
#define BLE_AUDIO_CODEC_FRAME_DURATION_TYPE 0x02
#define BLE_AUDIO_CODEC_CONF_FRAME_DURATION_TYPE 0x02
/** LE Audio Codec Config Type: Channel Allocation. */
#define BLE_AUDIO_CODEC_AUDIO_CHANNEL_ALLOCATION_TYPE 0x03
#define BLE_AUDIO_CODEC_CONF_AUDIO_CHANNEL_ALLOCATION_TYPE 0x03
/** LE Audio Codec Config Type: Octets Per Codec Frame. */
#define BLE_AUDIO_CODEC_OCTETS_PER_CODEC_FRAME_TYPE 0x04
#define BLE_AUDIO_CODEC_CONF_OCTETS_PER_CODEC_FRAME_TYPE 0x04
/** LE Audio Codec Config Type: Frame Blocks Per SDU. */
#define BLE_AUDIO_CODEC_FRAME_BLOCKS_PER_SDU_TYPE 0x05
#define BLE_AUDIO_CODEC_CONF_FRAME_BLOCKS_PER_SDU_TYPE 0x05
/** @} */
/**
* @defgroup ble_audio_codec_config Bluetooth Low Energy Audio Codec Specific Capabilities
* @{
*/
/** LE Audio Codec Specific Capability: Supported Sampling Frequencies. */
#define BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQ_TYPE 0x01
/** LE Audio Codec Specific Capability: Supported Frame Durations. */
#define BLE_AUDIO_CODEC_CAPS_FRAME_DURATION_TYPE 0x02
/** LE Audio Codec Specific Capability: Supported Audio Channel Counts. */
#define BLE_AUDIO_CODEC_CAPS_SUP_AUDIO_CHANNEL_COUNTS_TYPE 0x03
/** LE Audio Codec Specific Capability: Supported Octets Per Codec Frame. */
#define BLE_AUDIO_CODEC_CAPS_OCTETS_PER_CODEC_FRAME_TYPE 0x04
/** LE Audio Codec Specific Capability: Supported Codec Frames Per SDU. */
#define BLE_AUDIO_CODEC_CAPS_FRAMES_PER_SDU_TYPE 0x05
/** @} */
/**
* @defgroup ble_audio_contexts Bluetooth Low Energy Audio Context Types
* @{
*/
/** LE Audio Codec Context Type: Prohibited. */
#define BLE_AUDIO_CONTEXT_TYPE_PROHIBITED 0x0000
/** LE Audio Codec Context Type: Unspecified. */
#define BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED 0x0001
/** LE Audio Codec Context Type: Conversational. */
#define BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL 0x0002
/** LE Audio Codec Context Type: Media. */
#define BLE_AUDIO_CONTEXT_TYPE_MEDIA 0x0004
/** LE Audio Codec Context Type: Game. */
#define BLE_AUDIO_CONTEXT_TYPE_GAME 0x0008
/** LE Audio Codec Context Type: Instructional. */
#define BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL 0x0010
/** LE Audio Codec Context Type: Voice Assistants. */
#define BLE_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS 0x0020
/** LE Audio Codec Context Type: Live. */
#define BLE_AUDIO_CONTEXT_TYPE_LIVE 0x0040
/** LE Audio Codec Context Type: Sound Effects. */
#define BLE_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS 0x0080
/** LE Audio Codec Context Type: Notifications. */
#define BLE_AUDIO_CONTEXT_TYPE_NOTIFICATIONS 0x0100
/** LE Audio Codec Context Type: Ringtone. */
#define BLE_AUDIO_CONTEXT_TYPE_RINGTONE 0x0200
/** LE Audio Codec Context Type: Alerts. */
#define BLE_AUDIO_CONTEXT_TYPE_ALERTS 0x0400
/** LE Audio Codec Context Type: EmergencyAlarm. */
#define BLE_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM 0x0800
/** @} */
/**
* @defgroup ble_audio_contexts Bluetooth Low Energy Audio Supported Frame Durations
* @{
*/
/** LE Audio Codec Supported Frame Duration: 7.5 ms frame duration. */
#define BLE_AUDIO_CODEC_SUPPORTED_FRAME_DURATION_7_5_MS 0x0001
/** LE Audio Codec Supported Frame Duration: 10 ms frame duration. */
#define BLE_AUDIO_CODEC_SUPPORTED_FRAME_DURATION_10_MS 0x0002
/** LE Audio Codec Supported Frame Duration: 7.5 ms preferred. */
#define BLE_AUDIO_CODEC_PREFERED_FRAME_DURATION_7_5_MS 0x0010
/** LE Audio Codec Supported Frame Duration: 10 ms preferred. */
#define BLE_AUDIO_CODEC_PREFERED_FRAME_DURATION_10_MS 0x0020
/** @} */
/**
* @defgroup ble_audio_contexts Bluetooth Low Energy Audio Supported Sampling Frequencies
* @{
*/
/** LE Audio Codec Supported Sampling Frequency: 8000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_8000_HZ (1ULL << 0)
/** LE Audio Codec Supported Sampling Frequency: 11025 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_11025_HZ (1ULL << 1)
/** LE Audio Codec Supported Sampling Frequency: 16000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_16000_HZ (1ULL << 2)
/** LE Audio Codec Supported Sampling Frequency: 22050 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_22050_HZ (1ULL << 3)
/** LE Audio Codec Supported Sampling Frequency: 24000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_24000_HZ (1ULL << 4)
/** LE Audio Codec Supported Sampling Frequency: 32000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_32000_HZ (1ULL << 5)
/** LE Audio Codec Supported Sampling Frequency: 44100 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_44100_HZ (1ULL << 6)
/** LE Audio Codec Supported Sampling Frequency: 48000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_48000_HZ (1ULL << 7)
/** LE Audio Codec Supported Sampling Frequency: 88200 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_88200_HZ (1ULL << 8)
/** LE Audio Codec Supported Sampling Frequency: 96000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_96000_HZ (1ULL << 9)
/** LE Audio Codec Supported Sampling Frequency: 176400 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_176400_HZ (1ULL << 10)
/** LE Audio Codec Supported Sampling Frequency: 192000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_192000_HZ (1ULL << 11)
/** LE Audio Codec Supported Sampling Frequency: 384000 Hz. */
#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_384000_HZ (1ULL << 12)
/** @} */
/**
* @defgroup ble_audio_contexts Bluetooth Low Energy Audio Supported Channel Counts
* @{
*/
/** LE Audio Codec Supported Channel Count: 1. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_1 0x0001
/** LE Audio Codec Supported Channel Count: 2. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_2 0x0002
/** LE Audio Codec Supported Channel Count: 3. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_3 0x0004
/** LE Audio Codec Supported Channel Count: 4. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_4 0x0008
/** LE Audio Codec Supported Channel Count: 5. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_5 0x0010
/** LE Audio Codec Supported Channel Count: 6. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_6 0x0020
/** LE Audio Codec Supported Channel Count: 7. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_7 0x0040
/** LE Audio Codec Supported Channel Count: 8. */
#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_8 0x0080
/** @} */
@@ -244,16 +409,55 @@
_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_CONF_SAMPLING_FREQ_TYPE, _sampling_freq, \
2, BLE_AUDIO_CODEC_CONF_FRAME_DURATION_TYPE, _frame_duration, \
OPTIONAL_FIELD(5, BLE_AUDIO_CODEC_CONF_AUDIO_CHANNEL_ALLOCATION_TYPE, \
_audio_channel_alloc) \
3, BLE_AUDIO_CODEC_OCTETS_PER_CODEC_FRAME_TYPE, \
3, BLE_AUDIO_CODEC_CONF_OCTETS_PER_CODEC_FRAME_TYPE, \
(_octets_per_codec_frame), ((_octets_per_codec_frame) >> 8), \
OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_FRAME_BLOCKS_PER_SDU_TYPE, \
OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CONF_FRAME_BLOCKS_PER_SDU_TYPE, \
_codec_frame_blocks_per_sdu) \
}
/**
* @brief Helper macro used to build LTV array of Codec_Specific_Capabilities.
*
* @param _sampling_freq Supported_Sampling_Frequencies -
* two octet value
* @param _frame_duration Supported_Frame_Durations - single
* octet value
* @param _audio_channel_counts Supported_Audio_Channel_Counts -
* single octet value
* @param _min_octets_per_codec_frame minimum value of
* Supported_Octets_Per_Codec_Frame -
* two octet value
* @param _max_octets_per_codec_frame maximum value of
* Supported_Octets_Per_Codec_Frame -
* two octet value
* @param _codec_frames_per_sdu Supported_Max_Codec_Frames_Per_SDU -
* single octet value
*
* @return Pointer to a `ble_uuid16_t` structure.
*/
#define BLE_AUDIO_BUILD_CODEC_CAPS(_sampling_freq, \
_frame_duration, \
_audio_channel_counts, \
_min_octets_per_codec_frame, \
_max_octets_per_codec_frame, \
_codec_frames_per_sdu) \
{ \
3, BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQ_TYPE, \
(_sampling_freq), ((_sampling_freq) >> 8), \
2, BLE_AUDIO_CODEC_CAPS_FRAME_DURATION_TYPE, _frame_duration, \
OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CAPS_SUP_AUDIO_CHANNEL_COUNTS_TYPE, \
_audio_channel_counts) \
5, BLE_AUDIO_CODEC_CAPS_OCTETS_PER_CODEC_FRAME_TYPE, \
(_min_octets_per_codec_frame), ((_min_octets_per_codec_frame) >> 8), \
(_max_octets_per_codec_frame), ((_max_octets_per_codec_frame) >> 8), \
OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CAPS_FRAMES_PER_SDU_TYPE, \
_codec_frames_per_sdu) \
}
/** Codec Information */
struct ble_audio_codec_id {
/** Coding Format */
@@ -306,6 +510,12 @@ struct ble_audio_broadcast_name {
/** BLE Audio event: Broadcast Announcement */
#define BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT 0
/** BLE Audio event: Codec Registered */
#define BLE_AUDIO_EVENT_CODEC_REGISTERED 1
/** BLE Audio event: Codec Unregistered */
#define BLE_AUDIO_EVENT_CODEC_UNREGISTERED 2
/** @} */
/** @brief Broadcast Announcement */
@@ -329,6 +539,18 @@ struct ble_audio_event_broadcast_announcement {
struct ble_audio_broadcast_name *name;
};
/** @brief Codec Registered */
struct ble_audio_event_codec_registered {
/** Codec Record */
const struct ble_audio_codec_record *record;
};
/** @brief Codec Unregistered */
struct ble_audio_event_codec_unregistered {
/** Codec Record */
const struct ble_audio_codec_record *record;
};
/**
* Represents a BLE Audio related event. When such an event occurs, the host
* notifies the application by passing an instance of this structure to an
@@ -352,6 +574,20 @@ struct ble_audio_event {
* Represents a received Broadcast Announcement.
*/
struct ble_audio_event_broadcast_announcement broadcast_announcement;
/**
* @ref BLE_AUDIO_EVENT_CODEC_REGISTERED
*
* Represents a codec registration.
*/
struct ble_audio_event_codec_registered codec_registered;
/**
* @ref BLE_AUDIO_EVENT_CODEC_UNREGISTERED
*
* Represents a codec registration.
*/
struct ble_audio_event_codec_unregistered codec_unregistered;
};
};
@@ -0,0 +1,146 @@
/*
* 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_
/**
* @file ble_audio_codec.h
*
* @brief Bluetooth LE Audio Codec
*
* This header file provides the public API for managing LE Audio Codecs
*
* @defgroup ble_audio_codec Bluetooth LE Audio Codec
* @ingroup bt_host
* @{
*
* This API allows to create and manage list of LE Audio codecs with their capabilities and
* metadata. This list can be used by higher level services, like PACS. Memory management of
* codec entries is left to application and neither static nor dynamic allocation is enforced.
*
*/
#include "stdint.h"
#include "ble_audio.h"
/** Bit describing direction of codec configuration - source */
#define BLE_AUDIO_CODEC_DIR_SOURCE_BIT (1 << 0)
/** Bit describing direction of codec configuration - sink */
#define BLE_AUDIO_CODEC_DIR_SINK_BIT (1 << 1)
/** 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 */
const uint8_t *codec_spec_caps;
/* Metadata length */
uint8_t metadata_len;
/* Metadata */
const uint8_t *metadata;
/* Bitfield describing direction that codec is acting on. It is a logical OR of:
* - BLE_AUDIO_CODEC_DIR_SOURCE_BIT
* - BLE_AUDIO_CODEC_DIR_SINK_BIT
*/
uint8_t direction;
};
/** Type definition codec iteration callback function. */
typedef int ble_audio_codec_foreach_fn(const struct ble_audio_codec_record *record, void *arg);
struct ble_audio_codec_register_params {
/* Codec ID structure */
struct ble_audio_codec_id codec_id;
/* Codec Specific Capabilities length */
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;
/* Bitfield describing direction that codec is acting on. It is a logical OR of:
* - BLE_AUDIO_CODEC_DIR_SOURCE_BIT
* - BLE_AUDIO_CODEC_DIR_SINK_BIT
*/
uint8_t direction;
};
/**
* @brief Register codec entry
*
* @param[in] params Pointer to a `ble_audio_codec_register_params`
* structure that defines Codec Specific Capabilities
* @param[out] out_record Pointer to registered codec entry.
*
* @return 0 on success;
* A non-zero value on failure.
*/
int ble_audio_codec_register(const struct ble_audio_codec_register_params
*params,
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] direction Codec entry direction. It is any
* combination of following bits:
* - BLE_AUDIO_CODEC_DIR_SOURCE_BIT
* - BLE_AUDIO_CODEC_DIR_SINK_BIT
* This filters entries so the callback is called
* only on these have matching direction bit set.
* @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(uint8_t direction, ble_audio_codec_foreach_fn *cb, void *arg);
/**
* @}
*/
#endif /* H_BLE_AUDIO_CODEC_ */
@@ -0,0 +1,95 @@
/*
* 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_
/**
* @file ble_audio_svc_pacs.h
*
* @brief Bluetooth LE Audio PAC Service
*
* This header file provides the public API for interacting with the PACS package.
*
* @defgroup ble_audio_svc_pacs Bluetooth LE Audio PACS package
* @ingroup bt_host
* @{
*
* This package is used to setup PACS for codecs registered with @ref ble_audio_codec.
* To register a codec create it's definition as `ble_audio_codec_record` structure and register it
* using `ble_audio_codec_register()`. Up to BLE_AUDIO_MAX_CODEC_RECORDS entries may be registered.
* Registering and unregistering codecs, as well as setting PACS parameters will trigger sending
* notifications, if their support is enabled (see pacs/syscfg.yml).
*
*/
#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
struct ble_svc_audio_pacs_set_param {
/* Supported Audio Locations */
uint32_t audio_locations;
/* Supported Contexts */
uint16_t supported_contexts;
};
/**
* @brief Set PACS params.
*
* Set device capabilities reported in Published Audio Capabilities Service.
*
* @param[in] flags Flags that define if capabilities being set are for
* Sink or Source. Valid values are either
* `BLE_AUDIO_CODEC_FLAG_SOURCE` or `BLE_AUDIO_CODEC_FLAG_SINK`
* @param[in] param Pointer to a `ble_svc_audio_pacs_set_param`
* structure that defines capabilities supported by
* device.
*
* @return 0 on success;
* A non-zero value on failure.
*/
int ble_svc_audio_pacs_set(uint8_t flags, struct ble_svc_audio_pacs_set_param *param);
/**
* @brief Set available context types.
*
* @param[in] conn_handle Connection handle identifying connection for which contexts
* being set
* @param[in] sink_contexts Available Sink Contexts
* @param[in] source_contexts Available Source Contexts
*
* @return 0 on success;
* A non-zero value on failure.
*/
int ble_svc_audio_pacs_avail_contexts_set(uint16_t conn_handle,
uint16_t sink_contexts,
uint16_t source_contexts);
/**
* @}
*/
#endif /* H_BLE_AUDIO_SVC_PACS_ */
@@ -0,0 +1,63 @@
/*
* 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_LC3_
#define H_BLE_AUDIO_SVC_PACS_LC3_
/**
* @file ble_audio_svc_pacs_lc3.h
*
* @brief Bluetooth PAC Service for LC3 Codec
*
* This header file provides the public API for interacting with the PACS LC3 package, that
* registers PAC entry for LC3 codec with configurations contained in system configuration file
*
* @defgroup ble_audio_svc_pacs_lc3 Bluetooth LE Audio PACS LC3 package
* @ingroup ble_audio_svc_pacs
* @{
*
* This package is an example how to register codec entry that PACS can use to construct its entries
* for GATT database. This is high level package that can be used to construct basic PACS setup for
* LC3 codec. This package creates only single PAC entry per source and sink. If more PAC entries
* need to be created, with more advanced setup, @ref ble_audio_svc_pacs service shall be used in
* combination with @ref ble_audio_codec API.
*
*/
/**
* @brief Set available context types.
*
* @param[in] conn_handle Connection handle identifying connection for which contexts
* being set
* @param[in] sink_contexts Available Sink Contexts
* @param[in] source_contexts Available Source Contexts
*
* @return 0 on success;
* A non-zero value on failure.
*/
int ble_svc_audio_pacs_lc3_set_avail_contexts(uint16_t conn_handle,
uint16_t sink_contexts,
uint16_t source_contexts);
/**
* @}
*/
#endif /* H_BLE_AUDIO_SVC_PACS_LC3_ */
@@ -0,0 +1,34 @@
# 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.
pkg.name: nimble/host/audio/services/pacs/lc3
pkg.description: LC3 codec entry for Published Audio Capabilities Service
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "https://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
- pacs
- nimble
pkg.deps:
- nimble/host/audio/services/pacs
- nimble/host
pkg.init:
ble_svc_audio_pacs_lc3_init:
- $after:ble_svc_audio_pacs_init
@@ -0,0 +1,153 @@
/*
* 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 "audio/ble_audio_codec.h"
#include "services/pacs/ble_audio_svc_pacs.h"
#include "syscfg/syscfg.h"
#include "host/ble_hs.h"
/* Below is to unmangle comma separated Metadata octets from MYNEWT_VAL */
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define UNMANGLE_MYNEWT_VAL(X) STRIP_PARENS(_Args X)
#define BLE_SVC_AUDIO_PACS_LC3_CODEC_ID 0x06
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 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
);
#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA
static uint8_t ble_svc_audio_pacs_lc3_src_metadata[] =
{ UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA)) };
#endif
#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 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
};
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 int
codec_register(void)
{
int rc;
rc = ble_audio_codec_register(&src_codec_params, NULL);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = ble_audio_codec_register(&snk_codec_params, NULL);
SYSINIT_PANIC_ASSERT(rc == 0);
return 0;
}
int
ble_svc_audio_pacs_lc3_set_avail_contexts(uint16_t conn_handle,
uint16_t sink_contexts,
uint16_t source_contexts)
{
return ble_svc_audio_pacs_avail_contexts_set(conn_handle, sink_contexts,
source_contexts);
}
void
ble_svc_audio_pacs_lc3_init(void)
{
struct ble_svc_audio_pacs_set_param src_params = {
.audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS),
.supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS)
};
struct ble_svc_audio_pacs_set_param snk_params = {
.audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_AUDIO_LOCATIONS),
.supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS)
};
int rc;
rc = codec_register();
SYSINIT_PANIC_ASSERT(rc == 0);
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);
(void)rc;
}
@@ -0,0 +1,131 @@
# 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.
syscfg.defs:
BLE_SVC_AUDIO_PACS_LC3_SRC_SAMPLING_FREQUENCIES:
description: >
Sampling frequencies supported by LC3 codec, as source. This setting is mandatory.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.1.
Default value: 48000Hz
value: 0x80
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SRC_FRAME_DURATIONS:
description: >
Frame Durations supported by LC3 codec, as source. This setting is mandatory.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.2.
Default value: 7.5ms and 10ms supported, 10ms preferred.
value: 0x23
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS:
description: >
Audio Channel Counts supported by LC3 codec, as source. This setting is optional.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.3.
value:
BLE_SVC_AUDIO_PACS_LC3_SRC_MIN_OCTETS_PER_CODEC_FRAME:
description: >
Minimum number of Octets Per Codec Frame supported by LC3 codec, as source.
This setting is mandatory. Default value: 80
value: 80
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME:
description: >
Maximum number of Octets Per Codec Frame supported by LC3 codec, as source.
This setting is mandatory. Default value: 120
value: 120
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU:
description: >
Maximum number of Codec Frames Per SDU supported by LC3 codec, as source.
This setting is optional.
value:
BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA:
description: >
Optional Metadata to be attached to source codec capabilities. This value shall be in
form of bytes forming LTVs of Metadata. Example: '0x03, 0x01, 0x00, 0x08'
(lenght = 3, type = 0x01 (Preferred_Audio_Contexts), 0x00, 0x04 (Media))
value:
BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS:
description: >
Audio Locations supported by source codec. Value is an any combination of values defined
in Bluetooth Assigned Numbers 6.12.1. Default: Front Left and Front Right
value: 0x00000003
BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS:
description: >
Audio Locations supported by source codec. Value is an any combination of values defined
in Bluetooth Assigned Numbers 6.12.3. Default: Media
value: 0x0004
BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES:
description: >
Sampling frequencies supported by LC3 codec, as sink. This setting is mandatory.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.1.
Default value: 48000Hz
value: 0x80
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS:
description: >
Frame Durations supported by LC3 codec, as sink. This setting is mandatory.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.2.
Default value: 7.5ms and 10ms supported, 10ms preferred.
value: 0x23
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS:
description: >
Audio Channel Counts supported by LC3 codec, as sink. This setting is optional.
Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.3.
value:
BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME:
description: >
Minimum number of Octets Per Codec Frame supported by LC3 codec, as source.
This setting is mandatory. Default value: 80
value: 80
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_OCTETS_PER_CODEC_FRAME:
description: >
Maximum number of Octets Per Codec Frame supported by LC3 codec, as sink.
This setting is mandatory. Default value: 120
value: 120
restrictions:
- $notnull
BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU:
description: >
Maximum number of Codec Frames Per SDU supported by LC3 codec, as sink.
This setting is optional.
value:
BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA:
description: >
Optional Metadata to be attached to sink codec capabilities. This value shall be in
form of bytes forming LTVs of Metadata. Example: '0x03, 0x01, 0x00, 0x08'
(lenght = 3, type = 0x01 (Preferred_Audio_Contexts), 0x00, 0x04 (Media))
value:
BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_AUDIO_LOCATIONS:
description: >
Audio Locations supported by sink codec. Value is an any combination of values defined
in Bluetooth Assigned Numbers 6.12.1. Default: Front Left and Front Right
value: 0x00000003
BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS:
description: >
Audio Locations supported by sink codec. Value is an any combination of values defined
in Bluetooth Assigned Numbers 6.12.3. Default: Media
value: 0x0004
+33
View File
@@ -0,0 +1,33 @@
# 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.
pkg.name: nimble/host/audio/services/pacs
pkg.description: Published Audio Capabilities Service
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "https://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
- pacs
- nimble
pkg.deps:
- nimble/host
- nimble/host/services/gatt
pkg.init:
ble_svc_audio_pacs_init: 'MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SYSINIT_STAGE)'
@@ -0,0 +1,479 @@
/*
* 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 "audio/ble_audio.h"
#include "host/ble_hs.h"
#include "host/ble_gatt.h"
#include "audio/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)] = {
[0 ... MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1] = {
.conn_handle = BLE_HS_CONN_HANDLE_NONE,
.ble_svc_audio_pacs_avail_sink_contexts = 0,
.ble_svc_audio_pacs_avail_source_contexts = 0
}
};
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;
static struct ble_audio_event_listener ble_audio_listener;
struct pac_read_cb_arg {
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[]) {
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_PAC)
{
.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 | BLE_GATT_CHR_F_READ_ENC
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_PAC_NOTIFY)
| BLE_GATT_CHR_F_NOTIFY
#endif
},
#endif
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS)
{
.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 | BLE_GATT_CHR_F_READ_ENC
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS_NOTIFY)
| BLE_GATT_CHR_F_NOTIFY
#endif
},
#endif
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_PAC)
{
.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 | BLE_GATT_CHR_F_READ_ENC
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_PAC_NOTIFY)
| BLE_GATT_CHR_F_NOTIFY
#endif
},
#endif
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS)
{
.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 | BLE_GATT_CHR_F_READ_ENC
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS_NOTIFY)
| BLE_GATT_CHR_F_NOTIFY
#endif
},
#endif
{
.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 | 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 | BLE_GATT_CHR_F_READ_ENC
#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SUP_AUDIO_CTX_NOTIFY)
| BLE_GATT_CHR_F_NOTIFY
#endif
}, {
0, /* No more characteristics in this service */
}
}
},
{
0, /* No more services. */
},
};
static int
codec_record_to_pacs_entry(const struct ble_audio_codec_record *record, void *arg)
{
struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg;
uint8_t *buf;
int rc;
rc = os_mbuf_append(cb_arg->om, &record->codec_id.format, sizeof(uint8_t));
if (rc) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
buf = os_mbuf_extend(cb_arg->om, 4);
if (buf == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
put_le16(buf + 0, record->codec_id.company_id);
put_le16(buf + 2, record->codec_id.vendor_specific);
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 = {
.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(BLE_AUDIO_CODEC_DIR_SINK_BIT,
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 = {
.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(BLE_AUDIO_CODEC_DIR_SOURCE_BIT,
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)
{
uint8_t *buf;
buf = os_mbuf_extend(ctxt->om, 4);
if (buf == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
put_le32(buf + 0, ble_svc_audio_pacs_sink_audio_locations);
return 0;
}
static int
ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt *
ctxt)
{
uint8_t *buf;
buf = os_mbuf_extend(ctxt->om, 4);
if (buf == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
put_le32(buf + 0, ble_svc_audio_pacs_source_audio_locations);
return 0;
}
static struct available_ctx *
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 &ble_svc_audio_pacs_avail_contexts[i];
}
}
return NULL;
}
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;
uint8_t *buf;
avail_ctx = ble_svc_audio_pacs_find_avail_ctx(conn_handle);
buf = os_mbuf_extend(ctxt->om, 4);
if (buf == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
put_le16(buf + 0, avail_ctx->ble_svc_audio_pacs_avail_sink_contexts);
put_le16(buf + 2, avail_ctx->ble_svc_audio_pacs_avail_source_contexts);
return 0;
}
static int
ble_svc_audio_pacs_sup_audio_ctx_read_access(struct ble_gatt_access_ctxt
*ctxt)
{
uint8_t *buf;
buf = os_mbuf_extend(ctxt->om, 4);
if (buf == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
put_le16(buf + 0, ble_svc_audio_pacs_sup_sink_contexts);
put_le16(buf + 2, ble_svc_audio_pacs_sup_source_contexts);
return 0;
}
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);
rc = BLE_ATT_ERR_UNLIKELY;
}
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);
rc = BLE_ATT_ERR_UNLIKELY;
}
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);
rc = BLE_ATT_ERR_UNLIKELY;
}
return rc;
default:
assert(0);
return BLE_ATT_ERR_UNLIKELY;
}
}
static int
pac_notify(uint16_t chrc_uuid)
{
uint16_t chr_val_handle;
int rc;
if (!ble_hs_is_enabled()) {
/* Do not notify if host has not started yet */
return 0;
}
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(uint8_t flags, struct ble_svc_audio_pacs_set_param *param)
{
int rc;
if (flags & BLE_AUDIO_CODEC_DIR_SOURCE_BIT) {
ble_svc_audio_pacs_source_audio_locations = param->audio_locations;
ble_svc_audio_pacs_sup_source_contexts = param->supported_contexts;
rc = pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS);
if (rc != 0) {
return rc;
}
}
if (flags & BLE_AUDIO_CODEC_DIR_SINK_BIT) {
ble_svc_audio_pacs_sink_audio_locations = param->audio_locations;
ble_svc_audio_pacs_sup_sink_contexts = param->supported_contexts;
rc = pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS);
if (rc != 0) {
return rc;
}
}
return pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS);
}
int
ble_svc_audio_pacs_avail_contexts_set(uint16_t conn_handle,
uint16_t sink_contexts,
uint16_t source_contexts)
{
struct available_ctx *avail_ctx = ble_svc_audio_pacs_find_avail_ctx(conn_handle);
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(BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS);
}
static int
ble_pacs_audio_event(struct ble_audio_event *event, void *arg)
{
uint8_t codec_dir;
if (event->type == BLE_AUDIO_EVENT_CODEC_REGISTERED ||
event->type == BLE_AUDIO_EVENT_CODEC_UNREGISTERED) {
codec_dir = event->type == BLE_AUDIO_EVENT_CODEC_REGISTERED ?
event->codec_registered.record->direction :
event->codec_unregistered.record->direction;
if (codec_dir & BLE_AUDIO_CODEC_DIR_SOURCE_BIT) {
pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC);
}
if (codec_dir & BLE_AUDIO_CODEC_DIR_SINK_BIT) {
pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC);
}
}
return 0;
}
static int
ble_pacs_gap_event(struct ble_gap_event *event, void *arg)
{
struct available_ctx *avail_ctx;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
if (event->connect.status != 0) {
break;
}
avail_ctx = ble_svc_audio_pacs_find_avail_ctx(BLE_HS_CONN_HANDLE_NONE);
avail_ctx->conn_handle = event->connect.conn_handle;
break;
case BLE_GAP_EVENT_DISCONNECT:
avail_ctx = ble_svc_audio_pacs_find_avail_ctx(event->disconnect.conn.conn_handle);
if (avail_ctx >= 0) {
avail_ctx->conn_handle = BLE_HS_CONN_HANDLE_NONE;
}
break;
default:
break;
}
return 0;
}
void
ble_svc_audio_pacs_init(void)
{
int rc;
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
rc = ble_gatts_count_cfg(ble_svc_audio_pacs_defs);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = ble_gatts_add_svcs(ble_svc_audio_pacs_defs);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = ble_gap_event_listener_register(&ble_pacs_listener,
ble_pacs_gap_event, NULL);
SYSINIT_PANIC_ASSERT(rc == 0);
rc = ble_audio_event_listener_register(&ble_audio_listener, ble_pacs_audio_event, NULL);
SYSINIT_PANIC_ASSERT(rc == 0);
(void)rc;
}
@@ -0,0 +1,69 @@
# 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.
syscfg.defs:
BLE_SVC_AUDIO_PACS_SYSINIT_STAGE:
description: >
Sysinit stage for Published Audio Capabilities Service.
value: 303
BLE_SVC_AUDIO_PACS_SINK_PAC:
description: >
Enable Sink PAC characteristic.
If disabled, BLE_SVC_AUDIO_PACS_SOURCE_PAC must be enabled.
value: 1
BLE_SVC_AUDIO_PACS_SINK_PAC_NOTIFY:
description: >
Enable Sink PAC characteristic notifications.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SINK_PAC
BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS:
description: >
Enable SOURCE Sink Audio Locations characteristic.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SINK_PAC
BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS_NOTIFY:
description: >
Enable SOURCE Sink Audio Locations characteristic notifications.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS
BLE_SVC_AUDIO_PACS_SOURCE_PAC:
description: >
Enable Source PAC characteristic.
If disabled, BLE_SVC_AUDIO_PACS_SINK_PAC must be enabled.
value: 1
BLE_SVC_AUDIO_PACS_SOURCE_PAC_NOTIFY:
description: >
Enable Source PAC characteristic notifications.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SOURCE_PAC
BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS:
description: >
Enable Source Audio Locations characteristic.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SOURCE_PAC
BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS_NOTIFY:
description: >
Enable Source Audio Locations characteristic notifications.
value: 1
restrictions: BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS
BLE_SVC_AUDIO_PACS_SUP_AUDIO_CTX_NOTIFY:
description: >
Enable Supported Audio Contexts characteristic notifications.
value: 1
syscfg.restrictions:
- 'BLE_SVC_AUDIO_PACS_SINK_PAC == 1 || BLE_SVC_AUDIO_PACS_SOURCE_PAC == 1'
+138
View File
@@ -0,0 +1,138 @@
/*
* 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 "syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS)
#include "os/os.h"
#include "audio/ble_audio.h"
#include "audio/ble_audio_codec.h"
#include "ble_audio_priv.h"
#include "host/ble_hs.h"
#include "sysinit/sysinit.h"
static STAILQ_HEAD(, ble_audio_codec_record) ble_audio_codec_records;
static struct os_mempool ble_audio_codec_pool;
static os_membuf_t ble_audio_svc_pacs_pac_elem_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS),
sizeof (struct ble_audio_codec_record))
];
int
ble_audio_codec_register(const struct ble_audio_codec_register_params *params,
struct ble_audio_codec_record *out_record)
{
struct ble_audio_event codec_event = {
.type = BLE_AUDIO_EVENT_CODEC_REGISTERED
};
struct ble_audio_codec_record *record =
os_memblock_get(&ble_audio_codec_pool);
if (!record) {
return BLE_HS_ENOMEM;
}
record->codec_id = params->codec_id;
record->codec_spec_caps_len = params->codec_spec_caps_len;
record->codec_spec_caps = params->codec_spec_caps;
record->metadata_len = params->metadata_len;
record->metadata = params->metadata;
record->direction = params->direction;
if (STAILQ_EMPTY(&ble_audio_codec_records)) {
STAILQ_INSERT_HEAD(&ble_audio_codec_records, record, next);
} else {
STAILQ_INSERT_TAIL(&ble_audio_codec_records, record, next);
}
out_record = record;
codec_event.codec_registered.record = record;
(void)ble_audio_event_listener_call(&codec_event);
return 0;
}
int
ble_audio_codec_unregister(struct ble_audio_codec_record *codec_record)
{
struct ble_audio_event codec_event = {
.type = BLE_AUDIO_EVENT_CODEC_UNREGISTERED
};
STAILQ_REMOVE(&ble_audio_codec_records, codec_record,
ble_audio_codec_record, next);
codec_event.codec_unregistered.record = codec_record;
(void)ble_audio_event_listener_call(&codec_event);
return 0;
}
int
ble_audio_codec_foreach(uint8_t flags, ble_audio_codec_foreach_fn *cb, void *arg)
{
struct ble_audio_codec_record *record;
int rc;
STAILQ_FOREACH(record, &ble_audio_codec_records, next) {
if (record->direction & flags) {
rc = cb(record, arg);
if (rc != 0) {
return rc;
}
}
}
return 0;
}
struct ble_audio_codec_record *
ble_audio_codec_find(struct ble_audio_codec_id codec_id, uint8_t flag)
{
struct ble_audio_codec_record *record;
STAILQ_FOREACH(record, &ble_audio_codec_records, next) {
if (!memcmp(&record->codec_id, &codec_id,
sizeof(struct ble_audio_codec_id)) &&
(flag ? (record->direction & flag) : 1)) {
return record;
}
}
return NULL;
}
int
ble_audio_codec_init(void)
{
int rc;
STAILQ_INIT(&ble_audio_codec_records);
rc = os_mempool_init(&ble_audio_codec_pool,
MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS),
sizeof(struct ble_audio_codec_record),
ble_audio_svc_pacs_pac_elem_mem,
"ble_audio_codec_pool");
SYSINIT_PANIC_ASSERT(rc == 0);
return 0;
}
#endif
+4
View File
@@ -17,5 +17,9 @@
#
syscfg.defs:
BLE_AUDIO_MAX_CODEC_RECORDS:
description: >
Maximum number of registered audio codecs.
value: 0
syscfg.logs:
+25
View File
@@ -0,0 +1,25 @@
/*
* 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_PRIV_
#define H_BLE_AUDIO_CODEC_PRIV_
int ble_audio_codec_init(void);
#endif /* H_BLE_AUDIO_CODEC_PRIV_ */
+5
View File
@@ -765,6 +765,11 @@ ble_hs_init(void)
#endif
#endif
#if MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS)
rc = ble_audio_codec_init();
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
ble_hs_stop_init();
ble_mqueue_init(&ble_hs_rx_q, ble_hs_event_rx_data, NULL);
+1
View File
@@ -26,6 +26,7 @@
#include "ble_att_priv.h"
#include "ble_eatt_priv.h"
#include "ble_gap_priv.h"
#include "ble_audio_codec_priv.h"
#include "ble_gatt_priv.h"
#include "ble_hs_hci_priv.h"
#include "ble_hs_atomic_priv.h"
@@ -599,6 +599,10 @@
#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1)
#endif
#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS
#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0)
#endif
#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM
#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0)
#endif
@@ -600,6 +600,10 @@
#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1)
#endif
#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS
#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0)
#endif
#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM
#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0)
#endif
@@ -599,6 +599,10 @@
#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1)
#endif
#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS
#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0)
#endif
#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM
#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0)
#endif
+4
View File
@@ -598,6 +598,10 @@
#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1)
#endif
#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS
#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0)
#endif
#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM
#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0)
#endif
+4
View File
@@ -1515,6 +1515,10 @@
#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1)
#endif
#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS
#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0)
#endif
#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM
#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0)
#endif