xref: /btstack/example/sco_demo_util.c (revision b3f76298ca1ccca314e568b77c5d0fcf231f5b47)
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"
48220eb563SMilanka Ringwald #include "hfp_msbc.h"
49220eb563SMilanka Ringwald #include "hfp.h"
50fcb08cdbSMilanka Ringwald 
51f7c85330SMatthias Ringwald // configure test mode
52f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		0
53f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		1
54f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	2
55f7c85330SMatthias Ringwald 
568b29cfc6SMatthias Ringwald 
57f7c85330SMatthias Ringwald // SCO demo configuration
58fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
59f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100
60f7c85330SMatthias Ringwald 
618b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
628b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME      "sco_input.wav"
63d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc"
64d5e5f834SMatthias Ringwald #define SCO_MSBC_IN_FILENAME  "sco_input.mscb"
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;
96d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0;
97220eb563SMilanka Ringwald static int num_audio_frames = 0;
98fcb08cdbSMilanka Ringwald 
99d5e5f834SMatthias Ringwald FILE * msbc_file_in;
100d5e5f834SMatthias Ringwald FILE * msbc_file_out;
1017294d009SMatthias Ringwald 
102f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
103d6a06398SMatthias Ringwald 
104d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 8 kHz
105f7c85330SMatthias Ringwald static const uint8_t sine[] = {
106f7c85330SMatthias Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
107f7c85330SMatthias Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
108f7c85330SMatthias Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
109f7c85330SMatthias Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
110f7c85330SMatthias Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
111f7c85330SMatthias Ringwald };
112f7c85330SMatthias Ringwald 
113d6a06398SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
114d6a06398SMatthias Ringwald static const int16_t sine_int16[] = {
115d6a06398SMatthias Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
116d6a06398SMatthias Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
117d6a06398SMatthias Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
118d6a06398SMatthias Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
119d6a06398SMatthias Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
120d6a06398SMatthias Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
121d6a06398SMatthias Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
122d6a06398SMatthias Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
123d6a06398SMatthias Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
124d6a06398SMatthias Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
125d6a06398SMatthias Ringwald };
126f7c85330SMatthias Ringwald 
1278b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1288b29cfc6SMatthias Ringwald 
1298b29cfc6SMatthias Ringwald static int num_samples_to_write;
130fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state;
1318b29cfc6SMatthias Ringwald 
1322afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state;
1338b29cfc6SMatthias Ringwald 
1348b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){
1358b29cfc6SMatthias Ringwald     uint8_t buf[2];
1368b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1378b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 2, file);
1388b29cfc6SMatthias Ringwald }
1398b29cfc6SMatthias Ringwald 
1408b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){
1418b29cfc6SMatthias Ringwald     uint8_t buf[4];
1428b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1438b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 4, file);
1448b29cfc6SMatthias Ringwald }
1458b29cfc6SMatthias Ringwald 
1468b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){
147fcb08cdbSMilanka Ringwald     FILE * f = fopen(filename, "wb");
148fcb08cdbSMilanka Ringwald     printf("SCO Demo: creating wav file %s, %p\n", filename, f);
149fcb08cdbSMilanka Ringwald     return f;
1508b29cfc6SMatthias Ringwald }
1518b29cfc6SMatthias Ringwald 
1528b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
1538b29cfc6SMatthias Ringwald     /* write RIFF header */
1548b29cfc6SMatthias Ringwald     fwrite("RIFF", 1, 4, file);
1558b29cfc6SMatthias Ringwald     // num_samples = blocks * subbands
1568b29cfc6SMatthias Ringwald     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
1578b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes + 36);
1588b29cfc6SMatthias Ringwald     fwrite("WAVE", 1, 4, file);
1598b29cfc6SMatthias Ringwald 
1608b29cfc6SMatthias Ringwald     int byte_rate = sample_rate * num_channels * bytes_per_sample;
1618b29cfc6SMatthias Ringwald     int bits_per_sample = 8 * bytes_per_sample;
1628b29cfc6SMatthias Ringwald     int block_align = num_channels * bits_per_sample;
1638b29cfc6SMatthias Ringwald     int fmt_length = 16;
1648b29cfc6SMatthias Ringwald     int fmt_format_tag = 1; // PCM
1658b29cfc6SMatthias Ringwald 
1668b29cfc6SMatthias Ringwald     /* write fmt chunk */
1678b29cfc6SMatthias Ringwald     fwrite("fmt ", 1, 4, file);
1688b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, fmt_length);
1698b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, fmt_format_tag);
1708b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, num_channels);
1718b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, sample_rate);
1728b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, byte_rate);
1738b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, block_align);
1748b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, bits_per_sample);
1758b29cfc6SMatthias Ringwald 
1768b29cfc6SMatthias Ringwald     /* write data chunk */
1778b29cfc6SMatthias Ringwald     fwrite("data", 1, 4, file);
1788b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes);
1798b29cfc6SMatthias Ringwald }
1808b29cfc6SMatthias Ringwald 
1818b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
1828b29cfc6SMatthias Ringwald     fwrite(data, num_samples, 1, file);
1838b29cfc6SMatthias Ringwald }
1848b29cfc6SMatthias Ringwald 
185fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){
186fcb08cdbSMilanka Ringwald     fwrite(data, num_samples, 2, file);
187fcb08cdbSMilanka Ringwald }
188fcb08cdbSMilanka Ringwald 
189fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
190fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
191fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
192fcb08cdbSMilanka Ringwald 
193fcb08cdbSMilanka Ringwald     wav_writer_state_t * writer_state = (wav_writer_state_t*) context;
194fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
195fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
196fcb08cdbSMilanka Ringwald 
197fcb08cdbSMilanka Ringwald     write_wav_data_int16(writer_state->wav_file, num_samples, data);
198fcb08cdbSMilanka Ringwald     writer_state->total_num_samples+=num_samples;
199fcb08cdbSMilanka Ringwald     writer_state->frame_count++;
200fcb08cdbSMilanka Ringwald 
201fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
202fcb08cdbSMilanka Ringwald         sco_demo_close();
203fcb08cdbSMilanka Ringwald     }
204fcb08cdbSMilanka Ringwald }
205fcb08cdbSMilanka Ringwald 
206220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){
207220eb563SMilanka Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
208d6a06398SMatthias Ringwald     int i;
209d6a06398SMatthias Ringwald     int16_t sample_buffer[8*16*2];
210d6a06398SMatthias Ringwald     for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){
211d6a06398SMatthias Ringwald         sample_buffer[i] = sine_int16[phase++];
212d6a06398SMatthias Ringwald         if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){
213d6a06398SMatthias Ringwald             phase = 0;
214d6a06398SMatthias Ringwald         }
215d6a06398SMatthias Ringwald     }
216d6a06398SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
217220eb563SMilanka Ringwald     num_audio_frames++;
218220eb563SMilanka Ringwald }
219fcb08cdbSMilanka Ringwald 
220fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
221fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
222fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
223fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
224fcb08cdbSMilanka Ringwald 
2252afeea7fSMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state);
226fcb08cdbSMilanka Ringwald 
227fcb08cdbSMilanka Ringwald     const int sample_rate = 16000;
228fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
229fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 2;
230fcb08cdbSMilanka Ringwald     const int num_channels = 1;
231fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
232fcb08cdbSMilanka Ringwald 
233fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
234220eb563SMilanka Ringwald 
235220eb563SMilanka Ringwald     hfp_msbc_init();
236220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
237973d7173SMatthias Ringwald 
238d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
239d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
240d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
241d5e5f834SMatthias Ringwald #endif
2427294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
243d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
244d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
2457294d009SMatthias Ringwald #endif
246fcb08cdbSMilanka Ringwald }
247fcb08cdbSMilanka Ringwald 
248fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){
249fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
250fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
251fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
252fcb08cdbSMilanka Ringwald 
253fcb08cdbSMilanka Ringwald     const int sample_rate = 8000;
254fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
255fcb08cdbSMilanka Ringwald     const int num_channels = 1;
256fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 1;
257fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
258fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
259fcb08cdbSMilanka Ringwald }
260fcb08cdbSMilanka Ringwald 
261fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
262fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
263d5e5f834SMatthias Ringwald         if (msbc_file_in){
264d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
265d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
266d5e5f834SMatthias Ringwald         }
2672afeea7fSMilanka Ringwald         btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
268fcb08cdbSMilanka Ringwald         dump_data = 0;
269fcb08cdbSMilanka Ringwald     }
270fcb08cdbSMilanka Ringwald }
271fcb08cdbSMilanka Ringwald 
272fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
273fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
274fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
275fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
276fcb08cdbSMilanka Ringwald         // convert 8 bit signed to 8 bit unsigned
277fcb08cdbSMilanka Ringwald         int i;
278fcb08cdbSMilanka Ringwald         for (i=0;i<samples_to_write;i++){
279fcb08cdbSMilanka Ringwald             packet[3+i] += 128;
280fcb08cdbSMilanka Ringwald         }
281613518d1SMilanka Ringwald 
2826e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
283613518d1SMilanka Ringwald         write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]);
284fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
285fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
286fcb08cdbSMilanka Ringwald             sco_demo_close();
287fcb08cdbSMilanka Ringwald         }
288fcb08cdbSMilanka Ringwald         dump_data = 0;
289*b3f76298SMilanka Ringwald 
290*b3f76298SMilanka Ringwald         // convert back
291*b3f76298SMilanka Ringwald         int i;
292*b3f76298SMilanka Ringwald         for (i=0;i<samples_to_write;i++){
293*b3f76298SMilanka Ringwald             packet[3+i] += 128;
294*b3f76298SMilanka Ringwald         }
295fcb08cdbSMilanka Ringwald     }
296fcb08cdbSMilanka Ringwald }
297fcb08cdbSMilanka Ringwald 
2988b29cfc6SMatthias Ringwald #endif
2994a96141eSMatthias Ringwald #endif
3008b29cfc6SMatthias Ringwald 
301fcb08cdbSMilanka Ringwald void sco_demo_close(void){
302fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
303fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
304fcb08cdbSMilanka Ringwald 
305613518d1SMilanka Ringwald #if 0
306fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
307220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
3086e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
309fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
310fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
3112afeea7fSMilanka 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);
312fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
313fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
314fcb08cdbSMilanka Ringwald     }
315613518d1SMilanka Ringwald #endif
316fcb08cdbSMilanka Ringwald #endif
317fcb08cdbSMilanka Ringwald #endif
318fcb08cdbSMilanka Ringwald }
319fcb08cdbSMilanka Ringwald 
320fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
321fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
322fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
323fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
32417cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
325220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
326fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
327fcb08cdbSMilanka Ringwald     } else {
328fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
329fcb08cdbSMilanka Ringwald     }
330fcb08cdbSMilanka Ringwald #endif
331fcb08cdbSMilanka Ringwald #endif
332fcb08cdbSMilanka Ringwald }
333fcb08cdbSMilanka Ringwald 
334f7c85330SMatthias Ringwald void sco_demo_init(void){
335f7c85330SMatthias Ringwald 
336f7c85330SMatthias Ringwald 	// status
337f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
338f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
339f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
340f7c85330SMatthias Ringwald #else
341f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
342f7c85330SMatthias Ringwald #endif
343f7c85330SMatthias Ringwald #endif
344f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
345f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
346f7c85330SMatthias Ringwald #endif
347f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
348f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
349f7c85330SMatthias Ringwald #endif
350f7c85330SMatthias Ringwald 
351f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
352f7c85330SMatthias Ringwald     int err;
353f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
354f7c85330SMatthias Ringwald 
355f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
356f7c85330SMatthias Ringwald     err = Pa_Initialize();
357f7c85330SMatthias Ringwald     if( err != paNoError ) return;
358f7c85330SMatthias Ringwald     /* -- setup input and output -- */
359f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
360f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
361f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
362f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
363f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
364f7c85330SMatthias Ringwald     /* -- setup stream -- */
365f7c85330SMatthias Ringwald     err = Pa_OpenStream(
366f7c85330SMatthias Ringwald            &stream,
367f7c85330SMatthias Ringwald            NULL, // &inputParameters,
368f7c85330SMatthias Ringwald            &outputParameters,
369f7c85330SMatthias Ringwald            SAMPLE_RATE,
370f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
371f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
372f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
373f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
374f7c85330SMatthias Ringwald     if( err != paNoError ) return;
375f7c85330SMatthias Ringwald     /* -- start stream -- */
376f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
377f7c85330SMatthias Ringwald     if( err != paNoError ) return;
378f7c85330SMatthias Ringwald #endif
379f7c85330SMatthias Ringwald 
3807294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
381f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
3827294d009SMatthias Ringwald #endif
383f7c85330SMatthias Ringwald 
384f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
385f7c85330SMatthias Ringwald     phase = 'a';
386f7c85330SMatthias Ringwald #endif
387f7c85330SMatthias Ringwald }
388f7c85330SMatthias Ringwald 
3894a96141eSMatthias Ringwald static void sco_report(void){
3904a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
3914a96141eSMatthias Ringwald }
392f7c85330SMatthias Ringwald 
393f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
394f7c85330SMatthias Ringwald 
395f7c85330SMatthias Ringwald     if (!sco_handle) return;
396f7c85330SMatthias Ringwald 
397f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
398f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
399f7c85330SMatthias Ringwald 
400f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
401f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
402f7c85330SMatthias Ringwald     // set handle + flags
403f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
404f7c85330SMatthias Ringwald     // set len
405f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
406220eb563SMilanka Ringwald     const int audio_samples_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
407f7c85330SMatthias Ringwald 
408f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
409220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
410220eb563SMilanka Ringwald 
411220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
412220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
413220eb563SMilanka Ringwald         }
414220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
415d5e5f834SMatthias Ringwald         if (msbc_file_out){
416d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
417d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
418d76591efSMatthias Ringwald         }
4197294d009SMatthias Ringwald 
420220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
421220eb563SMilanka Ringwald     } else {
422f7c85330SMatthias Ringwald         int i;
423220eb563SMilanka Ringwald         for (i=0;i<audio_samples_per_packet;i++){
424f7c85330SMatthias Ringwald             sco_packet[3+i] = sine[phase];
425f7c85330SMatthias Ringwald             phase++;
426f7c85330SMatthias Ringwald             if (phase >= sizeof(sine)) phase = 0;
427f7c85330SMatthias Ringwald         }
428220eb563SMilanka Ringwald     }
429f7c85330SMatthias Ringwald #else
430f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
431220eb563SMilanka Ringwald     memset(&sco_packet[3], phase++, audio_samples_per_packet);
432f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
433f7c85330SMatthias Ringwald #else
43438b2eaafSMatthias Ringwald     int j;
435220eb563SMilanka Ringwald     for (j=0;j<audio_samples_per_packet;j++){
43638b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
437f7c85330SMatthias Ringwald     }
438f7c85330SMatthias Ringwald #endif
439f7c85330SMatthias Ringwald #endif
440220eb563SMilanka Ringwald 
441f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
442f7c85330SMatthias Ringwald 
443f7c85330SMatthias Ringwald     // request another send event
444f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
445f7c85330SMatthias Ringwald 
4464a96141eSMatthias Ringwald     count_sent++;
4474a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
448f7c85330SMatthias Ringwald }
449f7c85330SMatthias Ringwald 
450f7c85330SMatthias Ringwald /**
451f7c85330SMatthias Ringwald  * @brief Process received data
452f7c85330SMatthias Ringwald  */
453f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
454f7c85330SMatthias Ringwald 
455fcb08cdbSMilanka Ringwald     dump_data = 1;
4568b29cfc6SMatthias Ringwald 
4574a96141eSMatthias Ringwald     count_received++;
4584a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
4594a96141eSMatthias Ringwald 
4604a96141eSMatthias Ringwald 
4614a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4628b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
463220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
464fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
465fcb08cdbSMilanka Ringwald     } else {
466fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
4678b29cfc6SMatthias Ringwald     }
4688b29cfc6SMatthias Ringwald #endif
4694a96141eSMatthias Ringwald #endif
4708b29cfc6SMatthias Ringwald 
471*b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
472*b3f76298SMilanka Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
473*b3f76298SMilanka Ringwald         log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
474f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
475*b3f76298SMilanka Ringwald 
476f7c85330SMatthias Ringwald         return;
477f7c85330SMatthias Ringwald     }
478f7c85330SMatthias Ringwald 
479f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
480f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
481f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
482f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
483f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
484f7c85330SMatthias Ringwald     if (end - start > 5){
485f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
486f7c85330SMatthias Ringwald     }
4878b29cfc6SMatthias Ringwald     dump_data = 0;
488f7c85330SMatthias Ringwald #endif
4898b29cfc6SMatthias Ringwald #endif
4908b29cfc6SMatthias Ringwald 
4918b29cfc6SMatthias Ringwald     if (dump_data){
492f7c85330SMatthias Ringwald         printf("data: ");
493f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
494f7c85330SMatthias Ringwald         int i;
495f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
496f7c85330SMatthias Ringwald             printf("%c", packet[i]);
497f7c85330SMatthias Ringwald         }
498f7c85330SMatthias Ringwald         printf("\n");
4998b29cfc6SMatthias Ringwald         dump_data = 0;
5008b29cfc6SMatthias Ringwald #else
501f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
502f7c85330SMatthias Ringwald #endif
5038b29cfc6SMatthias Ringwald     }
504f7c85330SMatthias Ringwald }
505