xref: /btstack/example/sco_demo_util.c (revision 26463303c90044fdee6c9ce5f6ae3e922655d93c)
1f7c85330SMatthias Ringwald /*
2f7c85330SMatthias Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3f7c85330SMatthias Ringwald  *
4f7c85330SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5f7c85330SMatthias Ringwald  * modification, are permitted provided that the following conditions
6f7c85330SMatthias Ringwald  * are met:
7f7c85330SMatthias Ringwald  *
8f7c85330SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10f7c85330SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11f7c85330SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12f7c85330SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13f7c85330SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14f7c85330SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15f7c85330SMatthias Ringwald  *    from this software without specific prior written permission.
16f7c85330SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17f7c85330SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18f7c85330SMatthias Ringwald  *    monetary gain.
19f7c85330SMatthias Ringwald  *
20f7c85330SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21f7c85330SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22f7c85330SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23f7c85330SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24f7c85330SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25f7c85330SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26f7c85330SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27f7c85330SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28f7c85330SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29f7c85330SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30f7c85330SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31f7c85330SMatthias Ringwald  * SUCH DAMAGE.
32f7c85330SMatthias Ringwald  *
33f7c85330SMatthias Ringwald  * Please inquire about commercial licensing options at
34f7c85330SMatthias Ringwald  * [email protected]
35f7c85330SMatthias Ringwald  *
36f7c85330SMatthias Ringwald  */
37f7c85330SMatthias Ringwald 
38f7c85330SMatthias Ringwald /*
39f7c85330SMatthias Ringwald  * sco_demo_util.c - send/receive test data via SCO, used by hfp_*_demo and hsp_*_demo
40f7c85330SMatthias Ringwald  */
41f7c85330SMatthias Ringwald 
422ec72fbbSMilanka Ringwald 
432ec72fbbSMilanka Ringwald #include <stdio.h>
442ec72fbbSMilanka Ringwald 
45f7c85330SMatthias Ringwald #include "sco_demo_util.h"
46fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
470c87db9eSMilanka Ringwald #include "btstack_sbc.h"
48379d044eSMilanka Ringwald #include "btstack_cvsd_plc.h"
49220eb563SMilanka Ringwald #include "hfp_msbc.h"
50220eb563SMilanka Ringwald #include "hfp.h"
51fcb08cdbSMilanka Ringwald 
52f7c85330SMatthias Ringwald // configure test mode
53f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		0
54f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		1
55f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	2
56f7c85330SMatthias Ringwald 
578b29cfc6SMatthias Ringwald 
58f7c85330SMatthias Ringwald // SCO demo configuration
59fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
60f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100
61f7c85330SMatthias Ringwald 
628b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
638b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME      "sco_input.wav"
64d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc"
65d5e5f834SMatthias Ringwald #define SCO_MSBC_IN_FILENAME  "sco_input.mscb"
66220eb563SMilanka Ringwald 
678b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30
688b29cfc6SMatthias Ringwald #endif
698b29cfc6SMatthias Ringwald 
70f7c85330SMatthias Ringwald 
71f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
72f7c85330SMatthias Ringwald #define USE_PORTAUDIO
73f7c85330SMatthias Ringwald #endif
74f7c85330SMatthias Ringwald 
75f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
76f7c85330SMatthias Ringwald #include <portaudio.h>
778b29cfc6SMatthias Ringwald // portaudio config
788b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1
798b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000
808b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24
818b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8
82f7c85330SMatthias Ringwald // portaudio globals
83f7c85330SMatthias Ringwald static  PaStream * stream;
84f7c85330SMatthias Ringwald #endif
85f7c85330SMatthias Ringwald 
86fcb08cdbSMilanka Ringwald typedef struct wav_writer_state {
87fcb08cdbSMilanka Ringwald     FILE * wav_file;
88fcb08cdbSMilanka Ringwald     int total_num_samples;
89fcb08cdbSMilanka Ringwald     int frame_count;
90fcb08cdbSMilanka Ringwald } wav_writer_state_t;
91fcb08cdbSMilanka Ringwald 
92fcb08cdbSMilanka Ringwald static int dump_data = 1;
93fcb08cdbSMilanka Ringwald 
94220eb563SMilanka Ringwald static int phase = 0;
95fcb08cdbSMilanka Ringwald static int count_sent = 0;
96fcb08cdbSMilanka Ringwald static int count_received = 0;
97d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0;
98220eb563SMilanka Ringwald static int num_audio_frames = 0;
99fcb08cdbSMilanka Ringwald 
100d5e5f834SMatthias Ringwald FILE * msbc_file_in;
101d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1027294d009SMatthias Ringwald 
103f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
104d6a06398SMatthias Ringwald 
105d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 8 kHz
106f7c85330SMatthias Ringwald static const uint8_t sine[] = {
107f7c85330SMatthias Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
108f7c85330SMatthias Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
109f7c85330SMatthias Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
110f7c85330SMatthias Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
111f7c85330SMatthias Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
112f7c85330SMatthias Ringwald };
113f7c85330SMatthias Ringwald 
114d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
115d6a06398SMatthias Ringwald static const int16_t sine_int16[] = {
116d6a06398SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
117d6a06398SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
118d6a06398SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
119d6a06398SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
120d6a06398SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
121d6a06398SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
122d6a06398SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
123d6a06398SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
124d6a06398SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
125d6a06398SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
126d6a06398SMatthias Ringwald };
127f7c85330SMatthias Ringwald 
1288b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1298b29cfc6SMatthias Ringwald 
1308b29cfc6SMatthias Ringwald static int num_samples_to_write;
131fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state;
1328b29cfc6SMatthias Ringwald 
1332afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state;
13482e01da0SMilanka Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
1358b29cfc6SMatthias Ringwald 
1368b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){
1378b29cfc6SMatthias Ringwald     uint8_t buf[2];
1388b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1398b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 2, file);
1408b29cfc6SMatthias Ringwald }
1418b29cfc6SMatthias Ringwald 
1428b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){
1438b29cfc6SMatthias Ringwald     uint8_t buf[4];
1448b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1458b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 4, file);
1468b29cfc6SMatthias Ringwald }
1478b29cfc6SMatthias Ringwald 
1488b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){
149fcb08cdbSMilanka Ringwald     FILE * f = fopen(filename, "wb");
150fcb08cdbSMilanka Ringwald     printf("SCO Demo: creating wav file %s, %p\n", filename, f);
151fcb08cdbSMilanka Ringwald     return f;
1528b29cfc6SMatthias Ringwald }
1538b29cfc6SMatthias Ringwald 
1548b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
1558b29cfc6SMatthias Ringwald     /* write RIFF header */
1568b29cfc6SMatthias Ringwald     fwrite("RIFF", 1, 4, file);
1578b29cfc6SMatthias Ringwald     // num_samples = blocks * subbands
1588b29cfc6SMatthias Ringwald     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
1598b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes + 36);
1608b29cfc6SMatthias Ringwald     fwrite("WAVE", 1, 4, file);
1618b29cfc6SMatthias Ringwald 
1628b29cfc6SMatthias Ringwald     int byte_rate = sample_rate * num_channels * bytes_per_sample;
1638b29cfc6SMatthias Ringwald     int bits_per_sample = 8 * bytes_per_sample;
1648b29cfc6SMatthias Ringwald     int block_align = num_channels * bits_per_sample;
1658b29cfc6SMatthias Ringwald     int fmt_length = 16;
1668b29cfc6SMatthias Ringwald     int fmt_format_tag = 1; // PCM
1678b29cfc6SMatthias Ringwald 
1688b29cfc6SMatthias Ringwald     /* write fmt chunk */
1698b29cfc6SMatthias Ringwald     fwrite("fmt ", 1, 4, file);
1708b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, fmt_length);
1718b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, fmt_format_tag);
1728b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, num_channels);
1738b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, sample_rate);
1748b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, byte_rate);
1758b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, block_align);
1768b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, bits_per_sample);
1778b29cfc6SMatthias Ringwald 
1788b29cfc6SMatthias Ringwald     /* write data chunk */
1798b29cfc6SMatthias Ringwald     fwrite("data", 1, 4, file);
1808b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes);
1818b29cfc6SMatthias Ringwald }
1828b29cfc6SMatthias Ringwald 
1838b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
1848b29cfc6SMatthias Ringwald     fwrite(data, num_samples, 1, file);
1858b29cfc6SMatthias Ringwald }
1868b29cfc6SMatthias Ringwald 
187fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){
188fcb08cdbSMilanka Ringwald     fwrite(data, num_samples, 2, file);
189fcb08cdbSMilanka Ringwald }
190fcb08cdbSMilanka Ringwald 
191fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
192fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
193fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
194fcb08cdbSMilanka Ringwald 
195fcb08cdbSMilanka Ringwald     wav_writer_state_t * writer_state = (wav_writer_state_t*) context;
196fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
197fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
198fcb08cdbSMilanka Ringwald 
199fcb08cdbSMilanka Ringwald     write_wav_data_int16(writer_state->wav_file, num_samples, data);
200fcb08cdbSMilanka Ringwald     writer_state->total_num_samples+=num_samples;
201fcb08cdbSMilanka Ringwald     writer_state->frame_count++;
202fcb08cdbSMilanka Ringwald 
203fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
204fcb08cdbSMilanka Ringwald         sco_demo_close();
205fcb08cdbSMilanka Ringwald     }
206fcb08cdbSMilanka Ringwald }
207fcb08cdbSMilanka Ringwald 
208220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){
209220eb563SMilanka Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
210d6a06398SMatthias Ringwald     int i;
211d6a06398SMatthias Ringwald     int16_t sample_buffer[8*16*2];
212d6a06398SMatthias Ringwald     for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){
213d6a06398SMatthias Ringwald         sample_buffer[i] = sine_int16[phase++];
214d6a06398SMatthias Ringwald         if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){
215d6a06398SMatthias Ringwald             phase = 0;
216d6a06398SMatthias Ringwald         }
217d6a06398SMatthias Ringwald     }
218d6a06398SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
219220eb563SMilanka Ringwald     num_audio_frames++;
220220eb563SMilanka Ringwald }
221fcb08cdbSMilanka Ringwald 
222fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
223fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
224fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
225fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
226fcb08cdbSMilanka Ringwald 
2272afeea7fSMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state);
228fcb08cdbSMilanka Ringwald 
229fcb08cdbSMilanka Ringwald     const int sample_rate = 16000;
230fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
231fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 2;
232fcb08cdbSMilanka Ringwald     const int num_channels = 1;
233fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
234fcb08cdbSMilanka Ringwald 
235fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
236220eb563SMilanka Ringwald 
237220eb563SMilanka Ringwald     hfp_msbc_init();
238220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
239973d7173SMatthias Ringwald 
240d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
241d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
242d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
243d5e5f834SMatthias Ringwald #endif
2447294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
245d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
246d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
2477294d009SMatthias Ringwald #endif
248fcb08cdbSMilanka Ringwald }
249fcb08cdbSMilanka Ringwald 
250fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){
251379d044eSMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
252fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
253fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
254fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
255fcb08cdbSMilanka Ringwald 
256fcb08cdbSMilanka Ringwald     const int sample_rate = 8000;
257fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
258fcb08cdbSMilanka Ringwald     const int num_channels = 1;
259fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 1;
260fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
261fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
262fcb08cdbSMilanka Ringwald }
263fcb08cdbSMilanka Ringwald 
264fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
265fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
266d5e5f834SMatthias Ringwald         if (msbc_file_in){
267d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
268d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
269d5e5f834SMatthias Ringwald         }
2702afeea7fSMilanka Ringwald         btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
271fcb08cdbSMilanka Ringwald         dump_data = 0;
272fcb08cdbSMilanka Ringwald     }
273fcb08cdbSMilanka Ringwald }
274fcb08cdbSMilanka Ringwald 
275fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
276fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
277fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
278fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
27982e01da0SMilanka Ringwald         int8_t audio_frame_out[24];
280379d044eSMilanka Ringwald 
28182e01da0SMilanka Ringwald         btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3),num_samples,audio_frame_out);
282379d044eSMilanka Ringwald 
283fcb08cdbSMilanka Ringwald         // convert 8 bit signed to 8 bit unsigned
284fcb08cdbSMilanka Ringwald         int i;
285fcb08cdbSMilanka Ringwald         for (i=0;i<samples_to_write;i++){
286379d044eSMilanka Ringwald             audio_frame_out[i] += 128;
287fcb08cdbSMilanka Ringwald         }
288613518d1SMilanka Ringwald 
2896e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
29082e01da0SMilanka Ringwald         write_wav_data_uint8(writer_state->wav_file, samples_to_write, (uint8_t*)audio_frame_out);
291fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
292fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
293fcb08cdbSMilanka Ringwald             sco_demo_close();
294fcb08cdbSMilanka Ringwald         }
295fcb08cdbSMilanka Ringwald         dump_data = 0;
296b3f76298SMilanka Ringwald 
297b3f76298SMilanka Ringwald         // convert back
298b3f76298SMilanka Ringwald         for (i=0;i<samples_to_write;i++){
299379d044eSMilanka Ringwald             audio_frame_out[i] += 128;
300b3f76298SMilanka Ringwald         }
301fcb08cdbSMilanka Ringwald     }
302fcb08cdbSMilanka Ringwald }
303fcb08cdbSMilanka Ringwald 
3048b29cfc6SMatthias Ringwald #endif
3054a96141eSMatthias Ringwald #endif
3068b29cfc6SMatthias Ringwald 
307fcb08cdbSMilanka Ringwald void sco_demo_close(void){
308fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
309*26463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
310*26463303SMilanka Ringwald     printf("SCO demo statistics: ");
311*26463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
312*26463303SMilanka Ringwald         printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr);
313*26463303SMilanka Ringwald     } else {
314*26463303SMilanka Ringwald         printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr);
315*26463303SMilanka Ringwald     }
316*26463303SMilanka Ringwald #endif
317*26463303SMilanka Ringwald #endif
318*26463303SMilanka Ringwald 
319*26463303SMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
320fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
321fcb08cdbSMilanka Ringwald 
322613518d1SMilanka Ringwald #if 0
323fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
324220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
3256e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
326fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
327fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
3282afeea7fSMilanka Ringwald         write_wav_header(writer_state->wav_file, writer_state->total_num_samples, btstack_sbc_decoder_num_channels(&decoder_state), btstack_sbc_decoder_sample_rate(&decoder_state),2);
329fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
330fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
331fcb08cdbSMilanka Ringwald     }
332613518d1SMilanka Ringwald #endif
333fcb08cdbSMilanka Ringwald #endif
334fcb08cdbSMilanka Ringwald #endif
335fcb08cdbSMilanka Ringwald }
336fcb08cdbSMilanka Ringwald 
337fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
338fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
339fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
340fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
34117cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
342220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
343fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
344fcb08cdbSMilanka Ringwald     } else {
345fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
346fcb08cdbSMilanka Ringwald     }
347fcb08cdbSMilanka Ringwald #endif
348fcb08cdbSMilanka Ringwald #endif
349fcb08cdbSMilanka Ringwald }
350fcb08cdbSMilanka Ringwald 
351f7c85330SMatthias Ringwald void sco_demo_init(void){
352f7c85330SMatthias Ringwald 
353f7c85330SMatthias Ringwald 	// status
354f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
355f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
356f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
357f7c85330SMatthias Ringwald #else
358f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
359f7c85330SMatthias Ringwald #endif
360f7c85330SMatthias Ringwald #endif
361f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
362f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
363f7c85330SMatthias Ringwald #endif
364f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
365f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
366f7c85330SMatthias Ringwald #endif
367f7c85330SMatthias Ringwald 
368f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
369f7c85330SMatthias Ringwald     int err;
370f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
371f7c85330SMatthias Ringwald 
372f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
373f7c85330SMatthias Ringwald     err = Pa_Initialize();
374f7c85330SMatthias Ringwald     if( err != paNoError ) return;
375f7c85330SMatthias Ringwald     /* -- setup input and output -- */
376f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
377f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
378f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
379f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
380f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
381f7c85330SMatthias Ringwald     /* -- setup stream -- */
382f7c85330SMatthias Ringwald     err = Pa_OpenStream(
383f7c85330SMatthias Ringwald            &stream,
384f7c85330SMatthias Ringwald            NULL, // &inputParameters,
385f7c85330SMatthias Ringwald            &outputParameters,
386f7c85330SMatthias Ringwald            SAMPLE_RATE,
387f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
388f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
389f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
390f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
391f7c85330SMatthias Ringwald     if( err != paNoError ) return;
392f7c85330SMatthias Ringwald     /* -- start stream -- */
393f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
394f7c85330SMatthias Ringwald     if( err != paNoError ) return;
395f7c85330SMatthias Ringwald #endif
396f7c85330SMatthias Ringwald 
3977294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
398f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
3997294d009SMatthias Ringwald #endif
400f7c85330SMatthias Ringwald 
401f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
402f7c85330SMatthias Ringwald     phase = 'a';
403f7c85330SMatthias Ringwald #endif
404f7c85330SMatthias Ringwald }
405f7c85330SMatthias Ringwald 
4064a96141eSMatthias Ringwald static void sco_report(void){
4074a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
4084a96141eSMatthias Ringwald }
409f7c85330SMatthias Ringwald 
410f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
411f7c85330SMatthias Ringwald 
412f7c85330SMatthias Ringwald     if (!sco_handle) return;
413f7c85330SMatthias Ringwald 
414f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
415f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
416f7c85330SMatthias Ringwald 
417f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
418f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
419f7c85330SMatthias Ringwald     // set handle + flags
420f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
421f7c85330SMatthias Ringwald     // set len
422f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
423220eb563SMilanka Ringwald     const int audio_samples_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
424f7c85330SMatthias Ringwald 
425f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
426220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
427220eb563SMilanka Ringwald 
428220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
429220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
430220eb563SMilanka Ringwald         }
431220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
432d5e5f834SMatthias Ringwald         if (msbc_file_out){
433d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
434d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
435d76591efSMatthias Ringwald         }
4367294d009SMatthias Ringwald 
437220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
438220eb563SMilanka Ringwald     } else {
439f7c85330SMatthias Ringwald         int i;
440220eb563SMilanka Ringwald         for (i=0;i<audio_samples_per_packet;i++){
441f7c85330SMatthias Ringwald             sco_packet[3+i] = sine[phase];
442f7c85330SMatthias Ringwald             phase++;
443f7c85330SMatthias Ringwald             if (phase >= sizeof(sine)) phase = 0;
444f7c85330SMatthias Ringwald         }
445220eb563SMilanka Ringwald     }
446f7c85330SMatthias Ringwald #else
447f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
448220eb563SMilanka Ringwald     memset(&sco_packet[3], phase++, audio_samples_per_packet);
449f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
450f7c85330SMatthias Ringwald #else
45138b2eaafSMatthias Ringwald     int j;
452220eb563SMilanka Ringwald     for (j=0;j<audio_samples_per_packet;j++){
45338b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
454f7c85330SMatthias Ringwald     }
455f7c85330SMatthias Ringwald #endif
456f7c85330SMatthias Ringwald #endif
457220eb563SMilanka Ringwald 
458f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
459f7c85330SMatthias Ringwald 
460f7c85330SMatthias Ringwald     // request another send event
461f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
462f7c85330SMatthias Ringwald 
4634a96141eSMatthias Ringwald     count_sent++;
4644a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
465f7c85330SMatthias Ringwald }
466f7c85330SMatthias Ringwald 
467f7c85330SMatthias Ringwald /**
468f7c85330SMatthias Ringwald  * @brief Process received data
469f7c85330SMatthias Ringwald  */
470f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
471f7c85330SMatthias Ringwald 
472fcb08cdbSMilanka Ringwald     dump_data = 1;
4738b29cfc6SMatthias Ringwald 
4744a96141eSMatthias Ringwald     count_received++;
4754a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
4764a96141eSMatthias Ringwald 
4774a96141eSMatthias Ringwald 
4784a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4798b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
480220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
481fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
482fcb08cdbSMilanka Ringwald     } else {
483fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
4848b29cfc6SMatthias Ringwald     }
4858b29cfc6SMatthias Ringwald #endif
4864a96141eSMatthias Ringwald #endif
4878b29cfc6SMatthias Ringwald 
488b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
489b3f76298SMilanka Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
490b3f76298SMilanka Ringwald         log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
491f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
492b3f76298SMilanka Ringwald 
493f7c85330SMatthias Ringwald         return;
494f7c85330SMatthias Ringwald     }
495f7c85330SMatthias Ringwald 
496f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
497f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
498f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
499f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
500f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
501f7c85330SMatthias Ringwald     if (end - start > 5){
502f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
503f7c85330SMatthias Ringwald     }
5048b29cfc6SMatthias Ringwald     dump_data = 0;
505f7c85330SMatthias Ringwald #endif
5068b29cfc6SMatthias Ringwald #endif
5078b29cfc6SMatthias Ringwald 
5088b29cfc6SMatthias Ringwald     if (dump_data){
509f7c85330SMatthias Ringwald         printf("data: ");
510f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
511f7c85330SMatthias Ringwald         int i;
512f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
513f7c85330SMatthias Ringwald             printf("%c", packet[i]);
514f7c85330SMatthias Ringwald         }
515f7c85330SMatthias Ringwald         printf("\n");
5168b29cfc6SMatthias Ringwald         dump_data = 0;
5178b29cfc6SMatthias Ringwald #else
518f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
519f7c85330SMatthias Ringwald #endif
5208b29cfc6SMatthias Ringwald     }
521f7c85330SMatthias Ringwald }
522