1a602f23dSMatthias Ringwald /* 2a602f23dSMatthias Ringwald * Copyright (C) 2023 BlueKitchen GmbH 3a602f23dSMatthias Ringwald * 4a602f23dSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5a602f23dSMatthias Ringwald * modification, are permitted provided that the following conditions 6a602f23dSMatthias Ringwald * are met: 7a602f23dSMatthias Ringwald * 8a602f23dSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9a602f23dSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10a602f23dSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11a602f23dSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12a602f23dSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13a602f23dSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14a602f23dSMatthias Ringwald * contributors may be used to endorse or promote products derived 15a602f23dSMatthias Ringwald * from this software without specific prior written permission. 16a602f23dSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17a602f23dSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18a602f23dSMatthias Ringwald * monetary gain. 19a602f23dSMatthias Ringwald * 20a602f23dSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21a602f23dSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22a602f23dSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23a602f23dSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24a602f23dSMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25a602f23dSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26a602f23dSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27a602f23dSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28a602f23dSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29a602f23dSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30a602f23dSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31a602f23dSMatthias Ringwald * SUCH DAMAGE. 32a602f23dSMatthias Ringwald * 33a602f23dSMatthias Ringwald * Please inquire about commercial licensing options at 34a602f23dSMatthias Ringwald * [email protected] 35a602f23dSMatthias Ringwald * 36a602f23dSMatthias Ringwald */ 37a602f23dSMatthias Ringwald 38a602f23dSMatthias Ringwald #define BTSTACK_FILE__ "hfp_codec.c" 39a602f23dSMatthias Ringwald 40a602f23dSMatthias Ringwald // ***************************************************************************** 41a602f23dSMatthias Ringwald // 42a602f23dSMatthias Ringwald // HFP Codec 43a602f23dSMatthias Ringwald // 44a602f23dSMatthias Ringwald // ***************************************************************************** 45a602f23dSMatthias Ringwald 46a602f23dSMatthias Ringwald #include "btstack_config.h" 47a602f23dSMatthias Ringwald 48a602f23dSMatthias Ringwald #include <string.h> 49a602f23dSMatthias Ringwald 50a602f23dSMatthias Ringwald #include "hfp_codec.h" 51a602f23dSMatthias Ringwald #include "btstack_debug.h" 52a602f23dSMatthias Ringwald 53*eaf8fe31SMatthias Ringwald // enable to send test data 54*eaf8fe31SMatthias Ringwald // #define HFP_CODEC_TEST 55*eaf8fe31SMatthias Ringwald 56a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 57a602f23dSMatthias Ringwald #include "btstack_sbc.h" 58a602f23dSMatthias Ringwald #define FRAME_SIZE_MSBC 57 59a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples); 60a602f23dSMatthias Ringwald #endif 61a602f23dSMatthias Ringwald 6216527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 6316527ed5SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME 58 6416527ed5SMatthias Ringwald static void hfp_codec_encode_lc3swb(hfp_codec_t * hfp_codec, int16_t * pcm_samples); 6516527ed5SMatthias Ringwald #endif 6616527ed5SMatthias Ringwald 67a602f23dSMatthias Ringwald 68a602f23dSMatthias Ringwald void hfp_codec_init(hfp_codec_t * hfp_codec, uint8_t codec_id){ 69a602f23dSMatthias Ringwald memset(hfp_codec, 0, sizeof(hfp_codec_t)); 70a602f23dSMatthias Ringwald hfp_h2_framing_init(&hfp_codec->h2_framing); 71a602f23dSMatthias Ringwald switch (codec_id){ 72a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 73a602f23dSMatthias Ringwald case HFP_CODEC_MSBC: 74a602f23dSMatthias Ringwald hfp_codec->samples_per_frame = 120; 75a602f23dSMatthias Ringwald hfp_codec->encode = &hfp_codec_encode_msbc; 76a602f23dSMatthias Ringwald btstack_sbc_encoder_init(&hfp_codec->msbc_state, SBC_MODE_mSBC, 16, 8, SBC_ALLOCATION_METHOD_LOUDNESS, 16000, 26, SBC_CHANNEL_MODE_MONO); 77a602f23dSMatthias Ringwald break; 78a602f23dSMatthias Ringwald #endif 7916527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 8016527ed5SMatthias Ringwald case HFP_CODEC_LC3_SWB: 8116527ed5SMatthias Ringwald hfp_codec->samples_per_frame = 240; 8216527ed5SMatthias Ringwald hfp_codec->encode = &hfp_codec_encode_lc3swb; 8316527ed5SMatthias Ringwald // init lc3 encoder 8416527ed5SMatthias Ringwald hfp_codec->lc3_encoder = btstack_lc3_encoder_google_init_instance(&hfp_codec->lc3_encoder_context); 8516527ed5SMatthias Ringwald hfp_codec->lc3_encoder->configure(&hfp_codec->lc3_encoder_context, 32000, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME); 8616527ed5SMatthias Ringwald break; 8716527ed5SMatthias Ringwald #endif 88a602f23dSMatthias Ringwald default: 89a602f23dSMatthias Ringwald btstack_assert(false); 90a602f23dSMatthias Ringwald break; 91a602f23dSMatthias Ringwald } 92a602f23dSMatthias Ringwald } 93a602f23dSMatthias Ringwald 94a602f23dSMatthias Ringwald bool hfp_codec_can_encode_audio_frame_now(const hfp_codec_t * hfp_codec){ 95f789a318SMatthias Ringwald return hfp_codec->write_pos <= SCO_FRAME_SIZE; 96a602f23dSMatthias Ringwald } 97a602f23dSMatthias Ringwald 98a602f23dSMatthias Ringwald uint16_t hfp_codec_num_audio_samples_per_frame(const hfp_codec_t * hfp_codec){ 99a602f23dSMatthias Ringwald return hfp_codec->samples_per_frame; 100a602f23dSMatthias Ringwald } 101a602f23dSMatthias Ringwald 102a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 103a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 104a602f23dSMatthias Ringwald // Encode SBC Frame 105a602f23dSMatthias Ringwald btstack_sbc_encoder_process_data(pcm_samples); 106f789a318SMatthias Ringwald (void)memcpy(&hfp_codec->sco_packet[hfp_codec->write_pos], btstack_sbc_encoder_sbc_buffer(), FRAME_SIZE_MSBC); 107a602f23dSMatthias Ringwald hfp_codec->write_pos += FRAME_SIZE_MSBC; 108f789a318SMatthias Ringwald // Final padding to use SCO_FRAME_SIZE bytes 109a602f23dSMatthias Ringwald hfp_codec->sco_packet[hfp_codec->write_pos++] = 0; 110a602f23dSMatthias Ringwald } 111a602f23dSMatthias Ringwald #endif 112a602f23dSMatthias Ringwald 11316527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 11416527ed5SMatthias Ringwald static void hfp_codec_encode_lc3swb(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 11516527ed5SMatthias Ringwald // Encode LC3 Frame 11616527ed5SMatthias Ringwald hfp_codec->lc3_encoder->encode_signed_16(&hfp_codec->lc3_encoder_context, pcm_samples, 1, &hfp_codec->sco_packet[hfp_codec->write_pos]); 11716527ed5SMatthias Ringwald hfp_codec->write_pos += LC3_SWB_OCTETS_PER_FRAME; 11816527ed5SMatthias Ringwald } 11916527ed5SMatthias Ringwald #endif 12016527ed5SMatthias Ringwald 121a602f23dSMatthias Ringwald void hfp_codec_encode_audio_frame(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 122a602f23dSMatthias Ringwald btstack_assert(hfp_codec_can_encode_audio_frame_now(hfp_codec)); 123f789a318SMatthias Ringwald // Synchronization Header H2 124f789a318SMatthias Ringwald hfp_h2_framing_add_header(&hfp_codec->h2_framing, &hfp_codec->sco_packet[hfp_codec->write_pos]); 125f789a318SMatthias Ringwald hfp_codec->write_pos += 2; 126a602f23dSMatthias Ringwald // encode 127*eaf8fe31SMatthias Ringwald #ifdef HFP_CODEC_TEST 128*eaf8fe31SMatthias Ringwald // packet counter 129*eaf8fe31SMatthias Ringwald static uint8_t counter = 0; 130*eaf8fe31SMatthias Ringwald hfp_codec->sco_packet[hfp_codec->write_pos++] = counter++; 131*eaf8fe31SMatthias Ringwald // test data 132*eaf8fe31SMatthias Ringwald uint8_t i; 133*eaf8fe31SMatthias Ringwald for (i=3;i<SCO_FRAME_SIZE;i++){ 134*eaf8fe31SMatthias Ringwald hfp_codec->sco_packet[hfp_codec->write_pos++] = i; 135*eaf8fe31SMatthias Ringwald } 136*eaf8fe31SMatthias Ringwald #else 137a602f23dSMatthias Ringwald hfp_codec->encode(hfp_codec, pcm_samples); 138*eaf8fe31SMatthias Ringwald #endif 139f789a318SMatthias Ringwald log_info("Encode frame, read %u, write %u", hfp_codec->read_pos, hfp_codec->write_pos); 140a602f23dSMatthias Ringwald } 141a602f23dSMatthias Ringwald 142a602f23dSMatthias Ringwald uint16_t hfp_codec_num_bytes_available(const hfp_codec_t * hfp_codec){ 143a602f23dSMatthias Ringwald return hfp_codec->write_pos - hfp_codec->read_pos; 144a602f23dSMatthias Ringwald } 145f789a318SMatthias Ringwald 146ffdcc4c7SMatthias Ringwald void hfp_codec_read_from_stream(hfp_codec_t * hfp_codec, uint8_t * buf, uint16_t size){ 147a602f23dSMatthias Ringwald uint16_t num_bytes_available = hfp_codec_num_bytes_available(hfp_codec); 148a602f23dSMatthias Ringwald btstack_assert(num_bytes_available >= size); 149a602f23dSMatthias Ringwald 150a602f23dSMatthias Ringwald uint16_t num_bytes_to_copy = btstack_min(num_bytes_available, size); 151a602f23dSMatthias Ringwald 152a602f23dSMatthias Ringwald memcpy(buf, &hfp_codec->sco_packet[hfp_codec->read_pos], num_bytes_to_copy); 153a602f23dSMatthias Ringwald hfp_codec->read_pos += num_bytes_to_copy; 154f789a318SMatthias Ringwald 155f789a318SMatthias Ringwald // reset buffer 156f789a318SMatthias Ringwald if (hfp_codec->read_pos == hfp_codec->write_pos){ 157f789a318SMatthias Ringwald hfp_codec->read_pos = 0; 158f789a318SMatthias Ringwald hfp_codec->write_pos = 0; 159f789a318SMatthias Ringwald } 160f789a318SMatthias Ringwald 161f789a318SMatthias Ringwald log_info("Read %u from stream, read %u, write %u", size, hfp_codec->read_pos, hfp_codec->write_pos); 162a602f23dSMatthias Ringwald } 163a602f23dSMatthias Ringwald 164a602f23dSMatthias Ringwald void hfp_codec_deinit(hfp_codec_t * hfp_codec){ 165a602f23dSMatthias Ringwald UNUSED(hfp_codec); 166a602f23dSMatthias Ringwald } 167