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 53a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 54a602f23dSMatthias Ringwald #include "btstack_sbc.h" 55a602f23dSMatthias Ringwald #define FRAME_SIZE_MSBC 57 56a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples); 57a602f23dSMatthias Ringwald #endif 58a602f23dSMatthias Ringwald 5916527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 6016527ed5SMatthias Ringwald #define LC3_SWB_OCTETS_PER_FRAME 58 6116527ed5SMatthias Ringwald static void hfp_codec_encode_lc3swb(hfp_codec_t * hfp_codec, int16_t * pcm_samples); 6216527ed5SMatthias Ringwald #endif 6316527ed5SMatthias Ringwald 64a602f23dSMatthias Ringwald #include "hfp_codec.h" 65a602f23dSMatthias Ringwald 66a602f23dSMatthias Ringwald void hfp_codec_init(hfp_codec_t * hfp_codec, uint8_t codec_id){ 67a602f23dSMatthias Ringwald memset(hfp_codec, 0, sizeof(hfp_codec_t)); 68a602f23dSMatthias Ringwald hfp_h2_framing_init(&hfp_codec->h2_framing); 69a602f23dSMatthias Ringwald switch (codec_id){ 70a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 71a602f23dSMatthias Ringwald case HFP_CODEC_MSBC: 72a602f23dSMatthias Ringwald hfp_codec->samples_per_frame = 120; 73a602f23dSMatthias Ringwald hfp_codec->encode = &hfp_codec_encode_msbc; 74a602f23dSMatthias Ringwald btstack_sbc_encoder_init(&hfp_codec->msbc_state, SBC_MODE_mSBC, 16, 8, SBC_ALLOCATION_METHOD_LOUDNESS, 16000, 26, SBC_CHANNEL_MODE_MONO); 75a602f23dSMatthias Ringwald break; 76a602f23dSMatthias Ringwald #endif 7716527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 7816527ed5SMatthias Ringwald case HFP_CODEC_LC3_SWB: 7916527ed5SMatthias Ringwald hfp_codec->samples_per_frame = 240; 8016527ed5SMatthias Ringwald hfp_codec->encode = &hfp_codec_encode_lc3swb; 8116527ed5SMatthias Ringwald // init lc3 encoder 8216527ed5SMatthias Ringwald hfp_codec->lc3_encoder = btstack_lc3_encoder_google_init_instance(&hfp_codec->lc3_encoder_context); 8316527ed5SMatthias Ringwald hfp_codec->lc3_encoder->configure(&hfp_codec->lc3_encoder_context, 32000, BTSTACK_LC3_FRAME_DURATION_7500US, LC3_SWB_OCTETS_PER_FRAME); 8416527ed5SMatthias Ringwald break; 8516527ed5SMatthias Ringwald #endif 86a602f23dSMatthias Ringwald default: 87a602f23dSMatthias Ringwald btstack_assert(false); 88a602f23dSMatthias Ringwald break; 89a602f23dSMatthias Ringwald } 90a602f23dSMatthias Ringwald } 91a602f23dSMatthias Ringwald 92a602f23dSMatthias Ringwald bool hfp_codec_can_encode_audio_frame_now(const hfp_codec_t * hfp_codec){ 93*f789a318SMatthias Ringwald return hfp_codec->write_pos <= SCO_FRAME_SIZE; 94a602f23dSMatthias Ringwald } 95a602f23dSMatthias Ringwald 96a602f23dSMatthias Ringwald uint16_t hfp_codec_num_audio_samples_per_frame(const hfp_codec_t * hfp_codec){ 97a602f23dSMatthias Ringwald return hfp_codec->samples_per_frame; 98a602f23dSMatthias Ringwald } 99a602f23dSMatthias Ringwald 100a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH 101a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 102a602f23dSMatthias Ringwald // Encode SBC Frame 103a602f23dSMatthias Ringwald btstack_sbc_encoder_process_data(pcm_samples); 104*f789a318SMatthias Ringwald (void)memcpy(&hfp_codec->sco_packet[hfp_codec->write_pos], btstack_sbc_encoder_sbc_buffer(), FRAME_SIZE_MSBC); 105a602f23dSMatthias Ringwald hfp_codec->write_pos += FRAME_SIZE_MSBC; 106*f789a318SMatthias Ringwald // Final padding to use SCO_FRAME_SIZE bytes 107a602f23dSMatthias Ringwald hfp_codec->sco_packet[hfp_codec->write_pos++] = 0; 108a602f23dSMatthias Ringwald } 109a602f23dSMatthias Ringwald #endif 110a602f23dSMatthias Ringwald 11116527ed5SMatthias Ringwald #ifdef ENABLE_HFP_SUPER_WIDE_BAND_SPEECH 11216527ed5SMatthias Ringwald static void hfp_codec_encode_lc3swb(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 11316527ed5SMatthias Ringwald // Encode LC3 Frame 11416527ed5SMatthias Ringwald hfp_codec->lc3_encoder->encode_signed_16(&hfp_codec->lc3_encoder_context, pcm_samples, 1, &hfp_codec->sco_packet[hfp_codec->write_pos]); 11516527ed5SMatthias Ringwald hfp_codec->write_pos += LC3_SWB_OCTETS_PER_FRAME; 11616527ed5SMatthias Ringwald } 11716527ed5SMatthias Ringwald #endif 11816527ed5SMatthias Ringwald 119a602f23dSMatthias Ringwald void hfp_codec_encode_audio_frame(hfp_codec_t * hfp_codec, int16_t * pcm_samples){ 120a602f23dSMatthias Ringwald btstack_assert(hfp_codec_can_encode_audio_frame_now(hfp_codec)); 121*f789a318SMatthias Ringwald uint16_t offset = hfp_codec->write_pos; 122*f789a318SMatthias Ringwald // Synchronization Header H2 123*f789a318SMatthias Ringwald hfp_h2_framing_add_header(&hfp_codec->h2_framing, &hfp_codec->sco_packet[hfp_codec->write_pos]); 124*f789a318SMatthias Ringwald hfp_codec->write_pos += 2; 125a602f23dSMatthias Ringwald // encode 126a602f23dSMatthias Ringwald hfp_codec->encode(hfp_codec, pcm_samples); 127*f789a318SMatthias Ringwald log_info("Encode frame, read %u, write %u", hfp_codec->read_pos, hfp_codec->write_pos); 128a602f23dSMatthias Ringwald } 129a602f23dSMatthias Ringwald 130a602f23dSMatthias Ringwald uint16_t hfp_codec_num_bytes_available(const hfp_codec_t * hfp_codec){ 131a602f23dSMatthias Ringwald return hfp_codec->write_pos - hfp_codec->read_pos; 132a602f23dSMatthias Ringwald } 133*f789a318SMatthias Ringwald 134ffdcc4c7SMatthias Ringwald void hfp_codec_read_from_stream(hfp_codec_t * hfp_codec, uint8_t * buf, uint16_t size){ 135a602f23dSMatthias Ringwald uint16_t num_bytes_available = hfp_codec_num_bytes_available(hfp_codec); 136a602f23dSMatthias Ringwald btstack_assert(num_bytes_available >= size); 137a602f23dSMatthias Ringwald 138a602f23dSMatthias Ringwald uint16_t num_bytes_to_copy = btstack_min(num_bytes_available, size); 139a602f23dSMatthias Ringwald 140a602f23dSMatthias Ringwald memcpy(buf, &hfp_codec->sco_packet[hfp_codec->read_pos], num_bytes_to_copy); 141a602f23dSMatthias Ringwald hfp_codec->read_pos += num_bytes_to_copy; 142*f789a318SMatthias Ringwald 143*f789a318SMatthias Ringwald // reset buffer 144*f789a318SMatthias Ringwald if (hfp_codec->read_pos == hfp_codec->write_pos){ 145*f789a318SMatthias Ringwald hfp_codec->read_pos = 0; 146*f789a318SMatthias Ringwald hfp_codec->write_pos = 0; 147*f789a318SMatthias Ringwald } 148*f789a318SMatthias Ringwald 149*f789a318SMatthias Ringwald log_info("Read %u from stream, read %u, write %u", size, hfp_codec->read_pos, hfp_codec->write_pos); 150a602f23dSMatthias Ringwald } 151a602f23dSMatthias Ringwald 152a602f23dSMatthias Ringwald void hfp_codec_deinit(hfp_codec_t * hfp_codec){ 153a602f23dSMatthias Ringwald UNUSED(hfp_codec); 154a602f23dSMatthias Ringwald } 155