@@ -37,10 +37,24 @@ static uint32_t requested_bis_sync;
3737static struct bt_le_ext_adv * ext_adv ;
3838static const struct bt_bap_scan_delegator_recv_state * req_recv_state ;
3939
40+ #define SUPPORTED_CHAN_COUNTS BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2)
41+ #define SUPPORTED_MIN_OCTETS_PER_FRAME 30
42+ #define SUPPORTED_MAX_OCTETS_PER_FRAME 155
43+ #define SUPPORTED_MAX_FRAMES_PER_SDU 1
44+
45+ /* We support 1 or 2 channels, so the maximum SDU size we support will be 2 times the maximum frame
46+ * size per frame we support
47+ */
48+ #define SUPPORTED_MAX_SDU_SIZE (2 * SUPPORTED_MAX_FRAMES_PER_SDU * SUPPORTED_MAX_OCTETS_PER_FRAME)
49+
50+ BUILD_ASSERT (CONFIG_BT_ISO_RX_MTU >= SUPPORTED_MAX_SDU_SIZE );
51+
52+ #define SUPPORTED_CONTEXTS (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)
53+
4054static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3 (
41- BT_AUDIO_CODEC_CAP_FREQ_ANY , BT_AUDIO_CODEC_CAP_DURATION_ANY ,
42- BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT ( 1 , 2 ), 30 , 240 , 2 ,
43- ( BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA ) );
55+ BT_AUDIO_CODEC_CAP_FREQ_ANY , BT_AUDIO_CODEC_CAP_DURATION_ANY , SUPPORTED_CHAN_COUNTS ,
56+ SUPPORTED_MIN_OCTETS_PER_FRAME , SUPPORTED_MAX_OCTETS_PER_FRAME ,
57+ SUPPORTED_MAX_FRAMES_PER_SDU , SUPPORTED_CONTEXTS );
4458
4559static K_SEM_DEFINE (sem_started , 0U , ARRAY_SIZE (streams )) ;
4660static K_SEM_DEFINE (sem_stopped , 0U , ARRAY_SIZE (streams )) ;
@@ -52,6 +66,122 @@ static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
5266static const uint32_t bis_index_mask = BIT_MASK (ARRAY_SIZE (streams ) + 1U );
5367static uint32_t bis_index_bitfield ;
5468
69+ static uint8_t count_bits (enum bt_audio_location chan_allocation )
70+ {
71+ uint8_t cnt = 0U ;
72+
73+ while (chan_allocation != 0 ) {
74+ cnt += chan_allocation & 1U ;
75+ chan_allocation >>= 1 ;
76+ }
77+
78+ return cnt ;
79+ }
80+
81+ static bool valid_base_subgroup (const struct bt_bap_base_subgroup * subgroup )
82+ {
83+ struct bt_audio_codec_cfg codec_cfg = {0 };
84+ enum bt_audio_location chan_allocation ;
85+ uint8_t frames_blocks_per_sdu ;
86+ size_t min_sdu_size_required ;
87+ uint16_t octets_per_frame ;
88+ uint8_t chan_cnt ;
89+ int ret ;
90+
91+ ret = bt_bap_base_subgroup_codec_to_codec_cfg (subgroup , & codec_cfg );
92+ if (ret < 0 ) {
93+ printk ("Could not get subgroup codec_cfg: %d\n" , ret );
94+
95+ return false;
96+ }
97+
98+ ret = bt_audio_codec_cfg_get_freq (& codec_cfg );
99+ if (ret >= 0 ) {
100+ const int freq = bt_audio_codec_cfg_freq_to_freq_hz (ret );
101+
102+ if (freq < 0 ) {
103+ printk ("Invalid subgroup frequency value: %d (%d)\n" , ret , freq );
104+
105+ return false;
106+ }
107+ } else {
108+ printk ("Could not get subgroup frequency: %d\n" , ret );
109+
110+ return false;
111+ }
112+
113+ ret = bt_audio_codec_cfg_get_frame_dur (& codec_cfg );
114+ if (ret >= 0 ) {
115+ const int frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us (ret );
116+
117+ if (frame_duration_us < 0 ) {
118+ printk ("Invalid subgroup frame duration value: %d (%d)\n" , ret ,
119+ frame_duration_us );
120+
121+ return false;
122+ }
123+ } else {
124+ printk ("Could not get subgroup frame duration: %d\n" , ret );
125+
126+ return false;
127+ }
128+
129+ ret = bt_audio_codec_cfg_get_chan_allocation (& codec_cfg , & chan_allocation );
130+ if (ret == 0 ) {
131+ chan_cnt = count_bits (chan_allocation );
132+ } else {
133+ printk ("Could not get subgroup channel allocation: %d\n" , ret );
134+ /* Channel allocation is an optional field, and omitting it implicitly means mono */
135+ chan_cnt = 1U ;
136+ }
137+
138+ if (chan_cnt == 0 || (BIT (chan_cnt - 1 ) & SUPPORTED_CHAN_COUNTS ) == 0 ) {
139+ printk ("Unsupported channel count: %u\n" , chan_cnt );
140+
141+ return false;
142+ }
143+
144+ ret = bt_audio_codec_cfg_get_octets_per_frame (& codec_cfg );
145+ if (ret > 0 ) {
146+ octets_per_frame = (uint16_t )ret ;
147+ } else {
148+ printk ("Could not get subgroup octets per frame: %d\n" , ret );
149+
150+ return false;
151+ }
152+
153+ if (!IN_RANGE (octets_per_frame , SUPPORTED_MIN_OCTETS_PER_FRAME ,
154+ SUPPORTED_MAX_OCTETS_PER_FRAME )) {
155+ printk ("Unsupported octets per frame: %u\n" , octets_per_frame );
156+
157+ return false;
158+ }
159+
160+ ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu (& codec_cfg , false);
161+ if (ret > 0 ) {
162+ frames_blocks_per_sdu = (uint8_t )ret ;
163+ } else {
164+ printk ("Could not get subgroup octets per frame: %d\n" , ret );
165+ /* Frame blocks per SDU is optional and is implicitly 1 */
166+ frames_blocks_per_sdu = 1U ;
167+ }
168+
169+ /* An SDU can consist of X frame blocks, each with Y frames (one per channel) of size Z in
170+ * them. The minimum SDU size required for this is X * Y * Z.
171+ */
172+ min_sdu_size_required = chan_cnt * octets_per_frame * frames_blocks_per_sdu ;
173+ if (min_sdu_size_required > SUPPORTED_MAX_SDU_SIZE ) {
174+ printk ("With %zu channels and %u octets per frame and %u frames per block, SDUs "
175+ "shall be at minimum %zu, we only support %d\n" ,
176+ chan_cnt , octets_per_frame , frames_blocks_per_sdu , min_sdu_size_required ,
177+ SUPPORTED_MAX_SDU_SIZE );
178+
179+ return false;
180+ }
181+
182+ return true;
183+ }
184+
55185static bool base_subgroup_cb (const struct bt_bap_base_subgroup * subgroup , void * user_data )
56186{
57187 static uint8_t metadata [CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE ];
@@ -74,6 +204,11 @@ static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *
74204 metadata_size = (size_t )ret ;
75205 (void )memcpy (metadata , meta , metadata_size );
76206
207+ if (!valid_base_subgroup (subgroup )) {
208+ printk ("Invalid or unsupported subgroup\n" );
209+ return false;
210+ }
211+
77212 return true;
78213}
79214
@@ -258,10 +393,115 @@ static struct bt_bap_scan_delegator_cb scan_delegator_cbs = {
258393 .bis_sync_req = bis_sync_req_cb ,
259394};
260395
396+ static void validate_stream_codec_cfg (const struct bt_bap_stream * stream )
397+ {
398+ struct bt_audio_codec_cfg * codec_cfg = stream -> codec_cfg ;
399+ enum bt_audio_location chan_allocation ;
400+ uint8_t frames_blocks_per_sdu ;
401+ size_t min_sdu_size_required ;
402+ uint16_t octets_per_frame ;
403+ uint8_t chan_cnt ;
404+ int ret ;
405+
406+ ret = bt_audio_codec_cfg_get_freq (codec_cfg );
407+ if (ret >= 0 ) {
408+ const int freq = bt_audio_codec_cfg_freq_to_freq_hz (ret );
409+
410+ if (freq < 0 ) {
411+ FAIL ("Invalid frequency value: %d (%d)\n" , ret , freq );
412+
413+ return ;
414+ }
415+ } else {
416+ FAIL ("Could not get frequency: %d\n" , ret );
417+
418+ return ;
419+ }
420+
421+ ret = bt_audio_codec_cfg_get_frame_dur (codec_cfg );
422+ if (ret >= 0 ) {
423+ const int frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us (ret );
424+
425+ if (frame_duration_us < 0 ) {
426+ FAIL ("Invalid frame duration value: %d (%d)\n" , ret , frame_duration_us );
427+
428+ return ;
429+ }
430+ } else {
431+ FAIL ("Could not get frame duration: %d\n" , ret );
432+
433+ return ;
434+ }
435+
436+ /* The broadcast source sets the channel allocation in the BIS to
437+ * BT_AUDIO_LOCATION_FRONT_LEFT
438+ */
439+ ret = bt_audio_codec_cfg_get_chan_allocation (codec_cfg , & chan_allocation );
440+ if (ret == 0 ) {
441+ if (chan_allocation != BT_AUDIO_LOCATION_FRONT_LEFT ) {
442+ FAIL ("Unexpected channel allocation: 0x%08X" , chan_allocation );
443+
444+ return ;
445+ }
446+
447+ chan_cnt = count_bits (chan_allocation );
448+ } else {
449+ FAIL ("Could not get subgroup channel allocation: %d\n" , ret );
450+
451+ return ;
452+ }
453+
454+ if (chan_cnt == 0 || (BIT (chan_cnt - 1 ) & SUPPORTED_CHAN_COUNTS ) == 0 ) {
455+ FAIL ("Unsupported channel count: %u\n" , chan_cnt );
456+
457+ return ;
458+ }
459+
460+ ret = bt_audio_codec_cfg_get_octets_per_frame (codec_cfg );
461+ if (ret > 0 ) {
462+ octets_per_frame = (uint16_t )ret ;
463+ } else {
464+ FAIL ("Could not get subgroup octets per frame: %d\n" , ret );
465+
466+ return ;
467+ }
468+
469+ if (!IN_RANGE (octets_per_frame , SUPPORTED_MIN_OCTETS_PER_FRAME ,
470+ SUPPORTED_MAX_OCTETS_PER_FRAME )) {
471+ FAIL ("Unsupported octets per frame: %u\n" , octets_per_frame );
472+
473+ return ;
474+ }
475+
476+ ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu (codec_cfg , false);
477+ if (ret > 0 ) {
478+ frames_blocks_per_sdu = (uint8_t )ret ;
479+ } else {
480+ printk ("Could not get octets per frame: %d\n" , ret );
481+ /* Frame blocks per SDU is optional and is implicitly 1 */
482+ frames_blocks_per_sdu = 1U ;
483+ }
484+
485+ /* An SDU can consist of X frame blocks, each with Y frames (one per channel) of size Z in
486+ * them. The minimum SDU size required for this is X * Y * Z.
487+ */
488+ min_sdu_size_required = chan_cnt * octets_per_frame * frames_blocks_per_sdu ;
489+ if (min_sdu_size_required > stream -> qos -> sdu ) {
490+ FAIL ("With %zu channels and %u octets per frame and %u frames per block, SDUs "
491+ "shall be at minimum %zu, but the stream has been configured for %u\n" ,
492+ chan_cnt , octets_per_frame , frames_blocks_per_sdu , min_sdu_size_required ,
493+ stream -> qos -> sdu );
494+
495+ return ;
496+ }
497+ }
498+
261499static void started_cb (struct bt_bap_stream * stream )
262500{
263501 printk ("Stream %p started\n" , stream );
264502 k_sem_give (& sem_started );
503+
504+ validate_stream_codec_cfg (stream );
265505}
266506
267507static void stopped_cb (struct bt_bap_stream * stream , uint8_t reason )
0 commit comments