1*5c0702eaSMatthias Ringwald /* 2*5c0702eaSMatthias Ringwald * Copyright (C) 2022 BlueKitchen GmbH 3*5c0702eaSMatthias Ringwald * 4*5c0702eaSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*5c0702eaSMatthias Ringwald * modification, are permitted provided that the following conditions 6*5c0702eaSMatthias Ringwald * are met: 7*5c0702eaSMatthias Ringwald * 8*5c0702eaSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*5c0702eaSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*5c0702eaSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*5c0702eaSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*5c0702eaSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*5c0702eaSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*5c0702eaSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*5c0702eaSMatthias Ringwald * from this software without specific prior written permission. 16*5c0702eaSMatthias Ringwald * 17*5c0702eaSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 18*5c0702eaSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*5c0702eaSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20*5c0702eaSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 21*5c0702eaSMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22*5c0702eaSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23*5c0702eaSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24*5c0702eaSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25*5c0702eaSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26*5c0702eaSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27*5c0702eaSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*5c0702eaSMatthias Ringwald * SUCH DAMAGE. 29*5c0702eaSMatthias Ringwald * 30*5c0702eaSMatthias Ringwald */ 31*5c0702eaSMatthias Ringwald 32*5c0702eaSMatthias Ringwald #define BTSTACK_FILE__ "base_builder.c" 33*5c0702eaSMatthias Ringwald 34*5c0702eaSMatthias Ringwald /** 35*5c0702eaSMatthias Ringwald * @title Broadcast Audio Source Endpoint AD Builder 36*5c0702eaSMatthias Ringwald */ 37*5c0702eaSMatthias Ringwald 38*5c0702eaSMatthias Ringwald #include <string.h> 39*5c0702eaSMatthias Ringwald 40*5c0702eaSMatthias Ringwald #include "bluetooth.h" 41*5c0702eaSMatthias Ringwald #include "bluetooth_data_types.h" 42*5c0702eaSMatthias Ringwald #include "bluetooth_gatt.h" 43*5c0702eaSMatthias Ringwald #include "btstack_util.h" 44*5c0702eaSMatthias Ringwald #include "btstack_debug.h" 45*5c0702eaSMatthias Ringwald #include "le-audio/le_audio_base_builder.h" 46*5c0702eaSMatthias Ringwald 47*5c0702eaSMatthias Ringwald void le_audio_base_builder_init(base_builder_t * builder, uint8_t * buffer, uint16_t size, uint32_t presentation_delay_us){ 48*5c0702eaSMatthias Ringwald btstack_assert(size >= 8); 49*5c0702eaSMatthias Ringwald // default init 50*5c0702eaSMatthias Ringwald memset(builder, 0, sizeof(base_builder_t)); 51*5c0702eaSMatthias Ringwald builder->buffer = buffer; 52*5c0702eaSMatthias Ringwald builder->size = size; 53*5c0702eaSMatthias Ringwald builder->len = 0; 54*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = 7; 55*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID; 56*5c0702eaSMatthias Ringwald little_endian_store_16(builder->buffer, 2, ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE); 57*5c0702eaSMatthias Ringwald builder->len += 2; 58*5c0702eaSMatthias Ringwald little_endian_store_24(builder->buffer, 4, presentation_delay_us); 59*5c0702eaSMatthias Ringwald builder->len += 3; 60*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = 0; 61*5c0702eaSMatthias Ringwald builder->subgroup_offset = builder->len; 62*5c0702eaSMatthias Ringwald } 63*5c0702eaSMatthias Ringwald 64*5c0702eaSMatthias Ringwald void le_audio_base_builder_add_subgroup(base_builder_t * builder, 65*5c0702eaSMatthias Ringwald const uint8_t * codec_id, 66*5c0702eaSMatthias Ringwald uint8_t codec_specific_configuration_length, const uint8_t * codec_specific_configuration, 67*5c0702eaSMatthias Ringwald uint8_t metadata_length, const uint8_t * metadata){ 68*5c0702eaSMatthias Ringwald // check len 69*5c0702eaSMatthias Ringwald uint16_t additional_len = 1 + 5 + 1 + codec_specific_configuration_length + 1 + metadata_length; 70*5c0702eaSMatthias Ringwald btstack_assert((builder->len + additional_len) <= builder->size); 71*5c0702eaSMatthias Ringwald 72*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = 0; 73*5c0702eaSMatthias Ringwald memcpy(&builder->buffer[builder->len], codec_id, 5); 74*5c0702eaSMatthias Ringwald builder->len += 5; 75*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = codec_specific_configuration_length; 76*5c0702eaSMatthias Ringwald memcpy(&builder->buffer[builder->len], codec_specific_configuration, codec_specific_configuration_length); 77*5c0702eaSMatthias Ringwald builder->len += codec_specific_configuration_length; 78*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = metadata_length; 79*5c0702eaSMatthias Ringwald memcpy(&builder->buffer[builder->len], metadata, metadata_length); 80*5c0702eaSMatthias Ringwald builder->len += metadata_length; 81*5c0702eaSMatthias Ringwald builder->bis_offset = builder->len; 82*5c0702eaSMatthias Ringwald 83*5c0702eaSMatthias Ringwald // update num subgroups 84*5c0702eaSMatthias Ringwald builder->buffer[7]++; 85*5c0702eaSMatthias Ringwald 86*5c0702eaSMatthias Ringwald // update total len 87*5c0702eaSMatthias Ringwald builder->buffer[0] = builder->len - 1; 88*5c0702eaSMatthias Ringwald } 89*5c0702eaSMatthias Ringwald 90*5c0702eaSMatthias Ringwald /** 91*5c0702eaSMatthias Ringwald * Add BIS to current BASE 92*5c0702eaSMatthias Ringwald * @param builder 93*5c0702eaSMatthias Ringwald * @param bis_index 94*5c0702eaSMatthias Ringwald * @param codec_specific_configuration_length 95*5c0702eaSMatthias Ringwald * @param codec_specific_configuration 96*5c0702eaSMatthias Ringwald */ 97*5c0702eaSMatthias Ringwald void le_audio_base_builder_add_bis(base_builder_t * builder, 98*5c0702eaSMatthias Ringwald uint8_t bis_index, 99*5c0702eaSMatthias Ringwald uint8_t codec_specific_configuration_length, 100*5c0702eaSMatthias Ringwald const uint8_t * codec_specific_configuration){ 101*5c0702eaSMatthias Ringwald // check len 102*5c0702eaSMatthias Ringwald uint16_t additional_len = 1 + 1 + codec_specific_configuration_length; 103*5c0702eaSMatthias Ringwald btstack_assert((builder->len + additional_len) <= builder->size); 104*5c0702eaSMatthias Ringwald 105*5c0702eaSMatthias Ringwald // append data 106*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = bis_index; 107*5c0702eaSMatthias Ringwald builder->buffer[builder->len++] = codec_specific_configuration_length; 108*5c0702eaSMatthias Ringwald memcpy(&builder->buffer[builder->len], codec_specific_configuration, codec_specific_configuration_length); 109*5c0702eaSMatthias Ringwald builder->len += codec_specific_configuration_length; 110*5c0702eaSMatthias Ringwald 111*5c0702eaSMatthias Ringwald // update num bis 112*5c0702eaSMatthias Ringwald builder->buffer[builder->subgroup_offset]++; 113*5c0702eaSMatthias Ringwald 114*5c0702eaSMatthias Ringwald // update total len 115*5c0702eaSMatthias Ringwald builder->buffer[0] = builder->len - 1; 116*5c0702eaSMatthias Ringwald } 117*5c0702eaSMatthias Ringwald 118*5c0702eaSMatthias Ringwald uint16_t le_audio_base_builder_get_ad_data_size(const base_builder_t * builder){ 119*5c0702eaSMatthias Ringwald return builder->len; 120*5c0702eaSMatthias Ringwald } 121