xref: /btstack/src/classic/hfp_codec.c (revision a602f23dae681bacd6cd3f686fb26b1e738bca46)
1*a602f23dSMatthias Ringwald /*
2*a602f23dSMatthias Ringwald  * Copyright (C) 2023 BlueKitchen GmbH
3*a602f23dSMatthias Ringwald  *
4*a602f23dSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*a602f23dSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*a602f23dSMatthias Ringwald  * are met:
7*a602f23dSMatthias Ringwald  *
8*a602f23dSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*a602f23dSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*a602f23dSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*a602f23dSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*a602f23dSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*a602f23dSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*a602f23dSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*a602f23dSMatthias Ringwald  *    from this software without specific prior written permission.
16*a602f23dSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*a602f23dSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*a602f23dSMatthias Ringwald  *    monetary gain.
19*a602f23dSMatthias Ringwald  *
20*a602f23dSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*a602f23dSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*a602f23dSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*a602f23dSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*a602f23dSMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*a602f23dSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*a602f23dSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*a602f23dSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*a602f23dSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*a602f23dSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*a602f23dSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*a602f23dSMatthias Ringwald  * SUCH DAMAGE.
32*a602f23dSMatthias Ringwald  *
33*a602f23dSMatthias Ringwald  * Please inquire about commercial licensing options at
34*a602f23dSMatthias Ringwald  * [email protected]
35*a602f23dSMatthias Ringwald  *
36*a602f23dSMatthias Ringwald  */
37*a602f23dSMatthias Ringwald 
38*a602f23dSMatthias Ringwald #define BTSTACK_FILE__ "hfp_codec.c"
39*a602f23dSMatthias Ringwald 
40*a602f23dSMatthias Ringwald // *****************************************************************************
41*a602f23dSMatthias Ringwald //
42*a602f23dSMatthias Ringwald // HFP Codec
43*a602f23dSMatthias Ringwald //
44*a602f23dSMatthias Ringwald // *****************************************************************************
45*a602f23dSMatthias Ringwald 
46*a602f23dSMatthias Ringwald #include "btstack_config.h"
47*a602f23dSMatthias Ringwald 
48*a602f23dSMatthias Ringwald #include <string.h>
49*a602f23dSMatthias Ringwald 
50*a602f23dSMatthias Ringwald #include "hfp_codec.h"
51*a602f23dSMatthias Ringwald #include "btstack_debug.h"
52*a602f23dSMatthias Ringwald 
53*a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
54*a602f23dSMatthias Ringwald #include "btstack_sbc.h"
55*a602f23dSMatthias Ringwald #define FRAME_SIZE_MSBC 57
56*a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples);
57*a602f23dSMatthias Ringwald #endif
58*a602f23dSMatthias Ringwald 
59*a602f23dSMatthias Ringwald #include "hfp_codec.h"
60*a602f23dSMatthias Ringwald 
61*a602f23dSMatthias Ringwald void hfp_codec_init(hfp_codec_t * hfp_codec, uint8_t codec_id){
62*a602f23dSMatthias Ringwald     memset(hfp_codec, 0, sizeof(hfp_codec_t));
63*a602f23dSMatthias Ringwald     hfp_h2_framing_init(&hfp_codec->h2_framing);
64*a602f23dSMatthias Ringwald     switch (codec_id){
65*a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
66*a602f23dSMatthias Ringwald         case HFP_CODEC_MSBC:
67*a602f23dSMatthias Ringwald             hfp_codec->samples_per_frame = 120;
68*a602f23dSMatthias Ringwald             hfp_codec->encode = &hfp_codec_encode_msbc;
69*a602f23dSMatthias Ringwald             btstack_sbc_encoder_init(&hfp_codec->msbc_state, SBC_MODE_mSBC, 16, 8, SBC_ALLOCATION_METHOD_LOUDNESS, 16000, 26, SBC_CHANNEL_MODE_MONO);
70*a602f23dSMatthias Ringwald             break;
71*a602f23dSMatthias Ringwald #endif
72*a602f23dSMatthias Ringwald         default:
73*a602f23dSMatthias Ringwald             btstack_assert(false);
74*a602f23dSMatthias Ringwald             break;
75*a602f23dSMatthias Ringwald     }
76*a602f23dSMatthias Ringwald }
77*a602f23dSMatthias Ringwald 
78*a602f23dSMatthias Ringwald bool hfp_codec_can_encode_audio_frame_now(const hfp_codec_t * hfp_codec){
79*a602f23dSMatthias Ringwald     return hfp_codec->read_pos == hfp_codec->write_pos;
80*a602f23dSMatthias Ringwald }
81*a602f23dSMatthias Ringwald 
82*a602f23dSMatthias Ringwald uint16_t hfp_codec_num_audio_samples_per_frame(const hfp_codec_t * hfp_codec){
83*a602f23dSMatthias Ringwald     return hfp_codec->samples_per_frame;
84*a602f23dSMatthias Ringwald }
85*a602f23dSMatthias Ringwald 
86*a602f23dSMatthias Ringwald #ifdef ENABLE_HFP_WIDE_BAND_SPEECH
87*a602f23dSMatthias Ringwald static void hfp_codec_encode_msbc(hfp_codec_t * hfp_codec, int16_t * pcm_samples){
88*a602f23dSMatthias Ringwald     // Synchronization Header H2
89*a602f23dSMatthias Ringwald     hfp_h2_framing_add_header(&hfp_codec->h2_framing, hfp_codec->sco_packet);
90*a602f23dSMatthias Ringwald     hfp_codec->write_pos += 2;
91*a602f23dSMatthias Ringwald 
92*a602f23dSMatthias Ringwald     // Encode SBC Frame
93*a602f23dSMatthias Ringwald     btstack_sbc_encoder_process_data(pcm_samples);
94*a602f23dSMatthias Ringwald     (void)memcpy(&hfp_codec->sco_packet[hfp_codec->write_pos],
95*a602f23dSMatthias Ringwald                  btstack_sbc_encoder_sbc_buffer(), FRAME_SIZE_MSBC);
96*a602f23dSMatthias Ringwald     hfp_codec->write_pos += FRAME_SIZE_MSBC;
97*a602f23dSMatthias Ringwald 
98*a602f23dSMatthias Ringwald     // Final padding to use 60 bytes
99*a602f23dSMatthias Ringwald     hfp_codec->sco_packet[hfp_codec->write_pos++] = 0;
100*a602f23dSMatthias Ringwald }
101*a602f23dSMatthias Ringwald #endif
102*a602f23dSMatthias Ringwald 
103*a602f23dSMatthias Ringwald void hfp_codec_encode_audio_frame(hfp_codec_t * hfp_codec, int16_t * pcm_samples){
104*a602f23dSMatthias Ringwald     btstack_assert(hfp_codec_can_encode_audio_frame_now(hfp_codec));
105*a602f23dSMatthias Ringwald 
106*a602f23dSMatthias Ringwald     // reset packet buffer
107*a602f23dSMatthias Ringwald     hfp_codec->read_pos = 0;
108*a602f23dSMatthias Ringwald     hfp_codec->write_pos = 0;
109*a602f23dSMatthias Ringwald 
110*a602f23dSMatthias Ringwald     // encode
111*a602f23dSMatthias Ringwald     hfp_codec->encode(hfp_codec, pcm_samples);
112*a602f23dSMatthias Ringwald }
113*a602f23dSMatthias Ringwald 
114*a602f23dSMatthias Ringwald uint16_t hfp_codec_num_bytes_available(const hfp_codec_t * hfp_codec){
115*a602f23dSMatthias Ringwald     return hfp_codec->write_pos - hfp_codec->read_pos;
116*a602f23dSMatthias Ringwald }
117*a602f23dSMatthias Ringwald 
118*a602f23dSMatthias Ringwald void hfp_msbc_read_from_stream(hfp_codec_t * hfp_codec, uint8_t * buf, int size){
119*a602f23dSMatthias Ringwald     uint16_t num_bytes_available = hfp_codec_num_bytes_available(hfp_codec);
120*a602f23dSMatthias Ringwald     btstack_assert(num_bytes_available >= size);
121*a602f23dSMatthias Ringwald 
122*a602f23dSMatthias Ringwald     uint16_t num_bytes_to_copy = btstack_min(num_bytes_available, size);
123*a602f23dSMatthias Ringwald 
124*a602f23dSMatthias Ringwald     memcpy(buf, &hfp_codec->sco_packet[hfp_codec->read_pos], num_bytes_to_copy);
125*a602f23dSMatthias Ringwald     hfp_codec->read_pos += num_bytes_to_copy;
126*a602f23dSMatthias Ringwald }
127*a602f23dSMatthias Ringwald 
128*a602f23dSMatthias Ringwald void hfp_codec_deinit(hfp_codec_t * hfp_codec){
129*a602f23dSMatthias Ringwald     UNUSED(hfp_codec);
130*a602f23dSMatthias Ringwald }
131