xref: /btstack/example/sco_demo_util.c (revision d6a0639857c8a02b83a990b64d7d0a49c11c5109)
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"
474e074f72SMilanka Ringwald #include "btstack_sbc_decoder.h"
48220eb563SMilanka Ringwald #include "btstack_sbc_encoder.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"
64220eb563SMilanka Ringwald #define SCO_MSBC_FILENAME "sco_output.msbc"
65220eb563SMilanka Ringwald 
668b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30
678b29cfc6SMatthias Ringwald #endif
688b29cfc6SMatthias Ringwald 
69f7c85330SMatthias Ringwald 
70f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
71f7c85330SMatthias Ringwald #define USE_PORTAUDIO
72f7c85330SMatthias Ringwald #endif
73f7c85330SMatthias Ringwald 
74f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
75f7c85330SMatthias Ringwald #include <portaudio.h>
768b29cfc6SMatthias Ringwald // portaudio config
778b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1
788b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000
798b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24
808b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8
81f7c85330SMatthias Ringwald // portaudio globals
82f7c85330SMatthias Ringwald static  PaStream * stream;
83f7c85330SMatthias Ringwald #endif
84f7c85330SMatthias Ringwald 
85fcb08cdbSMilanka Ringwald typedef struct wav_writer_state {
86fcb08cdbSMilanka Ringwald     FILE * wav_file;
87fcb08cdbSMilanka Ringwald     int total_num_samples;
88fcb08cdbSMilanka Ringwald     int frame_count;
89fcb08cdbSMilanka Ringwald } wav_writer_state_t;
90fcb08cdbSMilanka Ringwald 
91fcb08cdbSMilanka Ringwald static int dump_data = 1;
92fcb08cdbSMilanka Ringwald 
93220eb563SMilanka Ringwald static int phase = 0;
94fcb08cdbSMilanka Ringwald static int count_sent = 0;
95fcb08cdbSMilanka Ringwald static int count_received = 0;
96220eb563SMilanka Ringwald static uint8_t negotiated_codec = HFP_CODEC_CVSD;
97220eb563SMilanka Ringwald static int num_audio_frames = 0;
98fcb08cdbSMilanka Ringwald 
99f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
100*d6a06398SMatthias Ringwald 
101*d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 8 kHz
102f7c85330SMatthias Ringwald static const uint8_t sine[] = {
103f7c85330SMatthias Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
104f7c85330SMatthias Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
105f7c85330SMatthias Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
106f7c85330SMatthias Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
107f7c85330SMatthias Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
108f7c85330SMatthias Ringwald };
109f7c85330SMatthias Ringwald 
110*d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
111*d6a06398SMatthias Ringwald static const int16_t sine_int16[] = {
112*d6a06398SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
113*d6a06398SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
114*d6a06398SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
115*d6a06398SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
116*d6a06398SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
117*d6a06398SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
118*d6a06398SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
119*d6a06398SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
120*d6a06398SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
121*d6a06398SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
122*d6a06398SMatthias Ringwald };
123f7c85330SMatthias Ringwald 
1248b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1258b29cfc6SMatthias Ringwald 
1268b29cfc6SMatthias Ringwald static int num_samples_to_write;
127fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state;
1288b29cfc6SMatthias Ringwald 
129fcb08cdbSMilanka Ringwald static sbc_decoder_state_t decoder_state;
1308b29cfc6SMatthias Ringwald 
1318b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){
1328b29cfc6SMatthias Ringwald     uint8_t buf[2];
1338b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1348b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 2, file);
1358b29cfc6SMatthias Ringwald }
1368b29cfc6SMatthias Ringwald 
1378b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){
1388b29cfc6SMatthias Ringwald     uint8_t buf[4];
1398b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1408b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 4, file);
1418b29cfc6SMatthias Ringwald }
1428b29cfc6SMatthias Ringwald 
1438b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){
144fcb08cdbSMilanka Ringwald     FILE * f = fopen(filename, "wb");
145fcb08cdbSMilanka Ringwald     printf("SCO Demo: creating wav file %s, %p\n", filename, f);
146fcb08cdbSMilanka Ringwald     return f;
1478b29cfc6SMatthias Ringwald }
1488b29cfc6SMatthias Ringwald 
1498b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
1508b29cfc6SMatthias Ringwald     /* write RIFF header */
1518b29cfc6SMatthias Ringwald     fwrite("RIFF", 1, 4, file);
1528b29cfc6SMatthias Ringwald     // num_samples = blocks * subbands
1538b29cfc6SMatthias Ringwald     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
1548b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes + 36);
1558b29cfc6SMatthias Ringwald     fwrite("WAVE", 1, 4, file);
1568b29cfc6SMatthias Ringwald 
1578b29cfc6SMatthias Ringwald     int byte_rate = sample_rate * num_channels * bytes_per_sample;
1588b29cfc6SMatthias Ringwald     int bits_per_sample = 8 * bytes_per_sample;
1598b29cfc6SMatthias Ringwald     int block_align = num_channels * bits_per_sample;
1608b29cfc6SMatthias Ringwald     int fmt_length = 16;
1618b29cfc6SMatthias Ringwald     int fmt_format_tag = 1; // PCM
1628b29cfc6SMatthias Ringwald 
1638b29cfc6SMatthias Ringwald     /* write fmt chunk */
1648b29cfc6SMatthias Ringwald     fwrite("fmt ", 1, 4, file);
1658b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, fmt_length);
1668b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, fmt_format_tag);
1678b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, num_channels);
1688b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, sample_rate);
1698b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, byte_rate);
1708b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, block_align);
1718b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, bits_per_sample);
1728b29cfc6SMatthias Ringwald 
1738b29cfc6SMatthias Ringwald     /* write data chunk */
1748b29cfc6SMatthias Ringwald     fwrite("data", 1, 4, file);
1758b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes);
1768b29cfc6SMatthias Ringwald }
1778b29cfc6SMatthias Ringwald 
1788b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
1798b29cfc6SMatthias Ringwald     fwrite(data, num_samples, 1, file);
1808b29cfc6SMatthias Ringwald }
1818b29cfc6SMatthias Ringwald 
182fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){
183fcb08cdbSMilanka Ringwald     fwrite(data, num_samples, 2, file);
184fcb08cdbSMilanka Ringwald }
185fcb08cdbSMilanka Ringwald 
186fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
187fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
188fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
189fcb08cdbSMilanka Ringwald 
190fcb08cdbSMilanka Ringwald     wav_writer_state_t * writer_state = (wav_writer_state_t*) context;
191fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
192fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
193fcb08cdbSMilanka Ringwald 
194fcb08cdbSMilanka Ringwald     write_wav_data_int16(writer_state->wav_file, num_samples, data);
195fcb08cdbSMilanka Ringwald     writer_state->total_num_samples+=num_samples;
196fcb08cdbSMilanka Ringwald     writer_state->frame_count++;
197fcb08cdbSMilanka Ringwald 
198fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
199fcb08cdbSMilanka Ringwald         sco_demo_close();
200fcb08cdbSMilanka Ringwald     }
201fcb08cdbSMilanka Ringwald }
202fcb08cdbSMilanka Ringwald 
203220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){
204220eb563SMilanka Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
205*d6a06398SMatthias Ringwald     int i;
206*d6a06398SMatthias Ringwald     int16_t sample_buffer[8*16*2];
207*d6a06398SMatthias Ringwald     for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){
208*d6a06398SMatthias Ringwald         sample_buffer[i] = sine_int16[phase++];
209*d6a06398SMatthias Ringwald         if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){
210*d6a06398SMatthias Ringwald             phase = 0;
211*d6a06398SMatthias Ringwald         }
212*d6a06398SMatthias Ringwald     }
213*d6a06398SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
214220eb563SMilanka Ringwald     num_audio_frames++;
215220eb563SMilanka Ringwald }
216fcb08cdbSMilanka Ringwald 
217fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
218fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
219fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
220fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
221fcb08cdbSMilanka Ringwald 
222fcb08cdbSMilanka Ringwald     sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state);
223fcb08cdbSMilanka Ringwald 
224fcb08cdbSMilanka Ringwald     const int sample_rate = 16000;
225fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
226fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 2;
227fcb08cdbSMilanka Ringwald     const int num_channels = 1;
228fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
229fcb08cdbSMilanka Ringwald 
230fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
231220eb563SMilanka Ringwald 
232220eb563SMilanka Ringwald     hfp_msbc_init();
233220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
234973d7173SMatthias Ringwald 
235973d7173SMatthias Ringwald     // HACK: should be handled by HFP or HSP layer on (e)SCO connection request, not here
236973d7173SMatthias Ringwald     // transparent data
237973d7173SMatthias Ringwald     hci_set_sco_voice_setting(0x0003);
238fcb08cdbSMilanka Ringwald }
239fcb08cdbSMilanka Ringwald 
240fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){
241fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
242fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
243fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
244fcb08cdbSMilanka Ringwald 
245fcb08cdbSMilanka Ringwald     const int sample_rate = 8000;
246fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
247fcb08cdbSMilanka Ringwald     const int num_channels = 1;
248fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 1;
249fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
250fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
251973d7173SMatthias Ringwald 
252973d7173SMatthias Ringwald     // HACK: should be handled by HFP or HSP layer on (e)SCO connection request, not here
253973d7173SMatthias Ringwald     // signed 8 bit pcm data with CVSD over the air
254973d7173SMatthias Ringwald     hci_set_sco_voice_setting(0x0040);
255fcb08cdbSMilanka Ringwald }
256fcb08cdbSMilanka Ringwald 
257fcb08cdbSMilanka Ringwald 
258fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
259fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
260bd1920a3SMatthias Ringwald         sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
261fcb08cdbSMilanka Ringwald         dump_data = 0;
262fcb08cdbSMilanka Ringwald     }
263fcb08cdbSMilanka Ringwald }
264fcb08cdbSMilanka Ringwald 
265fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
266fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
267fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
268fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
269fcb08cdbSMilanka Ringwald         // convert 8 bit signed to 8 bit unsigned
270fcb08cdbSMilanka Ringwald         int i;
271fcb08cdbSMilanka Ringwald         for (i=0;i<samples_to_write;i++){
272fcb08cdbSMilanka Ringwald             packet[3+i] += 128;
273fcb08cdbSMilanka Ringwald         }
274613518d1SMilanka Ringwald 
275613518d1SMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
276613518d1SMilanka Ringwald         write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]);
277fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
278fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
279fcb08cdbSMilanka Ringwald             sco_demo_close();
280fcb08cdbSMilanka Ringwald         }
281fcb08cdbSMilanka Ringwald         dump_data = 0;
282fcb08cdbSMilanka Ringwald     }
283fcb08cdbSMilanka Ringwald }
284fcb08cdbSMilanka Ringwald 
2858b29cfc6SMatthias Ringwald #endif
2864a96141eSMatthias Ringwald #endif
2878b29cfc6SMatthias Ringwald 
288fcb08cdbSMilanka Ringwald void sco_demo_close(void){
289fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
290fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
291fcb08cdbSMilanka Ringwald 
292613518d1SMilanka Ringwald #if 0
293fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
294220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
295fcb08cdbSMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
296fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
297fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
298fcb08cdbSMilanka Ringwald         write_wav_header(writer_state->wav_file, writer_state->total_num_samples, sbc_decoder_num_channels(&decoder_state), sbc_decoder_sample_rate(&decoder_state),2);
299fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
300fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
301fcb08cdbSMilanka Ringwald     }
302613518d1SMilanka Ringwald #endif
303fcb08cdbSMilanka Ringwald #endif
304fcb08cdbSMilanka Ringwald #endif
305fcb08cdbSMilanka Ringwald }
306fcb08cdbSMilanka Ringwald 
307fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
308fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
309fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
310fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
31117cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
312220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
313fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
314fcb08cdbSMilanka Ringwald     } else {
315fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
316fcb08cdbSMilanka Ringwald     }
317fcb08cdbSMilanka Ringwald #endif
318fcb08cdbSMilanka Ringwald #endif
319fcb08cdbSMilanka Ringwald }
320fcb08cdbSMilanka Ringwald 
321f7c85330SMatthias Ringwald void sco_demo_init(void){
322f7c85330SMatthias Ringwald 
323f7c85330SMatthias Ringwald 	// status
324f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
325f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
326f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
327f7c85330SMatthias Ringwald #else
328f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
329f7c85330SMatthias Ringwald #endif
330f7c85330SMatthias Ringwald #endif
331f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
332f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
333f7c85330SMatthias Ringwald #endif
334f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
335f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
336f7c85330SMatthias Ringwald #endif
337f7c85330SMatthias Ringwald 
338f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
339f7c85330SMatthias Ringwald     int err;
340f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
341f7c85330SMatthias Ringwald 
342f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
343f7c85330SMatthias Ringwald     err = Pa_Initialize();
344f7c85330SMatthias Ringwald     if( err != paNoError ) return;
345f7c85330SMatthias Ringwald     /* -- setup input and output -- */
346f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
347f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
348f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
349f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
350f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
351f7c85330SMatthias Ringwald     /* -- setup stream -- */
352f7c85330SMatthias Ringwald     err = Pa_OpenStream(
353f7c85330SMatthias Ringwald            &stream,
354f7c85330SMatthias Ringwald            NULL, // &inputParameters,
355f7c85330SMatthias Ringwald            &outputParameters,
356f7c85330SMatthias Ringwald            SAMPLE_RATE,
357f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
358f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
359f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
360f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
361f7c85330SMatthias Ringwald     if( err != paNoError ) return;
362f7c85330SMatthias Ringwald     /* -- start stream -- */
363f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
364f7c85330SMatthias Ringwald     if( err != paNoError ) return;
365f7c85330SMatthias Ringwald #endif
366f7c85330SMatthias Ringwald 
367fcb08cdbSMilanka Ringwald //#if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
368f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
369fcb08cdbSMilanka Ringwald //#endif
370f7c85330SMatthias Ringwald 
371f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
372f7c85330SMatthias Ringwald     phase = 'a';
373f7c85330SMatthias Ringwald #endif
374f7c85330SMatthias Ringwald }
375f7c85330SMatthias Ringwald 
3764a96141eSMatthias Ringwald static void sco_report(void){
3774a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
3784a96141eSMatthias Ringwald }
379f7c85330SMatthias Ringwald 
380f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
381f7c85330SMatthias Ringwald 
382f7c85330SMatthias Ringwald     if (!sco_handle) return;
383f7c85330SMatthias Ringwald 
384f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
385f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
386f7c85330SMatthias Ringwald 
387f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
388f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
389f7c85330SMatthias Ringwald     // set handle + flags
390f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
391f7c85330SMatthias Ringwald     // set len
392f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
393220eb563SMilanka Ringwald     const int audio_samples_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
394f7c85330SMatthias Ringwald 
395f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
396220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
397220eb563SMilanka Ringwald 
398220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
399220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
400220eb563SMilanka Ringwald         }
401220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
402220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
403220eb563SMilanka Ringwald     } else {
404f7c85330SMatthias Ringwald         int i;
405220eb563SMilanka Ringwald         for (i=0;i<audio_samples_per_packet;i++){
406f7c85330SMatthias Ringwald             sco_packet[3+i] = sine[phase];
407f7c85330SMatthias Ringwald             phase++;
408f7c85330SMatthias Ringwald             if (phase >= sizeof(sine)) phase = 0;
409f7c85330SMatthias Ringwald         }
410220eb563SMilanka Ringwald     }
411f7c85330SMatthias Ringwald #else
412f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
413220eb563SMilanka Ringwald     memset(&sco_packet[3], phase++, audio_samples_per_packet);
414f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
415f7c85330SMatthias Ringwald #else
41638b2eaafSMatthias Ringwald     int j;
417220eb563SMilanka Ringwald     for (j=0;j<audio_samples_per_packet;j++){
41838b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
419f7c85330SMatthias Ringwald     }
420f7c85330SMatthias Ringwald #endif
421f7c85330SMatthias Ringwald #endif
422220eb563SMilanka Ringwald 
423f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
424f7c85330SMatthias Ringwald 
425f7c85330SMatthias Ringwald     // request another send event
426f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
427f7c85330SMatthias Ringwald 
4284a96141eSMatthias Ringwald     count_sent++;
4294a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
430f7c85330SMatthias Ringwald }
431f7c85330SMatthias Ringwald 
432fcb08cdbSMilanka Ringwald 
433f7c85330SMatthias Ringwald /**
434f7c85330SMatthias Ringwald  * @brief Process received data
435f7c85330SMatthias Ringwald  */
436f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
437f7c85330SMatthias Ringwald 
4388b29cfc6SMatthias Ringwald 
439fcb08cdbSMilanka Ringwald     dump_data = 1;
4408b29cfc6SMatthias Ringwald 
4414a96141eSMatthias Ringwald     count_received++;
4424a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
4434a96141eSMatthias Ringwald 
4444a96141eSMatthias Ringwald 
4454a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4468b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
447220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
448fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
449fcb08cdbSMilanka Ringwald     } else {
450fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
4518b29cfc6SMatthias Ringwald     }
4528b29cfc6SMatthias Ringwald #endif
4534a96141eSMatthias Ringwald #endif
4548b29cfc6SMatthias Ringwald 
455f7c85330SMatthias Ringwald     if (packet[1] & 0xf0){
456f7c85330SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
457f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
458f7c85330SMatthias Ringwald         return;
459f7c85330SMatthias Ringwald     }
460f7c85330SMatthias Ringwald 
461f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
462f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
463f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
464f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
465f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
466f7c85330SMatthias Ringwald     if (end - start > 5){
467f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
468f7c85330SMatthias Ringwald     }
4698b29cfc6SMatthias Ringwald     dump_data = 0;
470f7c85330SMatthias Ringwald #endif
4718b29cfc6SMatthias Ringwald #endif
4728b29cfc6SMatthias Ringwald 
4738b29cfc6SMatthias Ringwald     if (dump_data){
474f7c85330SMatthias Ringwald         printf("data: ");
475f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
476f7c85330SMatthias Ringwald         int i;
477f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
478f7c85330SMatthias Ringwald             printf("%c", packet[i]);
479f7c85330SMatthias Ringwald         }
480f7c85330SMatthias Ringwald         printf("\n");
4818b29cfc6SMatthias Ringwald         dump_data = 0;
4828b29cfc6SMatthias Ringwald #else
483f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
484f7c85330SMatthias Ringwald #endif
4858b29cfc6SMatthias Ringwald     }
486f7c85330SMatthias Ringwald }
487