xref: /btstack/example/sco_demo_util.c (revision bd1920a3cca67680da0de3788427ca0f57ef31c5)
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
100f7c85330SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz
101f7c85330SMatthias Ringwald static const uint8_t sine[] = {
102f7c85330SMatthias Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
103f7c85330SMatthias Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
104f7c85330SMatthias Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
105f7c85330SMatthias Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
106f7c85330SMatthias Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
107f7c85330SMatthias Ringwald };
108f7c85330SMatthias Ringwald 
109f7c85330SMatthias Ringwald 
1108b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1118b29cfc6SMatthias Ringwald 
1128b29cfc6SMatthias Ringwald static int num_samples_to_write;
113fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state;
1148b29cfc6SMatthias Ringwald 
115fcb08cdbSMilanka Ringwald static sbc_decoder_state_t decoder_state;
1168b29cfc6SMatthias Ringwald 
1178b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){
1188b29cfc6SMatthias Ringwald     uint8_t buf[2];
1198b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1208b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 2, file);
1218b29cfc6SMatthias Ringwald }
1228b29cfc6SMatthias Ringwald 
1238b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){
1248b29cfc6SMatthias Ringwald     uint8_t buf[4];
1258b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1268b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 4, file);
1278b29cfc6SMatthias Ringwald }
1288b29cfc6SMatthias Ringwald 
1298b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){
130fcb08cdbSMilanka Ringwald     FILE * f = fopen(filename, "wb");
131fcb08cdbSMilanka Ringwald     printf("SCO Demo: creating wav file %s, %p\n", filename, f);
132fcb08cdbSMilanka Ringwald     return f;
1338b29cfc6SMatthias Ringwald }
1348b29cfc6SMatthias Ringwald 
1358b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
1368b29cfc6SMatthias Ringwald     /* write RIFF header */
1378b29cfc6SMatthias Ringwald     fwrite("RIFF", 1, 4, file);
1388b29cfc6SMatthias Ringwald     // num_samples = blocks * subbands
1398b29cfc6SMatthias Ringwald     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
1408b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes + 36);
1418b29cfc6SMatthias Ringwald     fwrite("WAVE", 1, 4, file);
1428b29cfc6SMatthias Ringwald 
1438b29cfc6SMatthias Ringwald     int byte_rate = sample_rate * num_channels * bytes_per_sample;
1448b29cfc6SMatthias Ringwald     int bits_per_sample = 8 * bytes_per_sample;
1458b29cfc6SMatthias Ringwald     int block_align = num_channels * bits_per_sample;
1468b29cfc6SMatthias Ringwald     int fmt_length = 16;
1478b29cfc6SMatthias Ringwald     int fmt_format_tag = 1; // PCM
1488b29cfc6SMatthias Ringwald 
1498b29cfc6SMatthias Ringwald     /* write fmt chunk */
1508b29cfc6SMatthias Ringwald     fwrite("fmt ", 1, 4, file);
1518b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, fmt_length);
1528b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, fmt_format_tag);
1538b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, num_channels);
1548b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, sample_rate);
1558b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, byte_rate);
1568b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, block_align);
1578b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, bits_per_sample);
1588b29cfc6SMatthias Ringwald 
1598b29cfc6SMatthias Ringwald     /* write data chunk */
1608b29cfc6SMatthias Ringwald     fwrite("data", 1, 4, file);
1618b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes);
1628b29cfc6SMatthias Ringwald }
1638b29cfc6SMatthias Ringwald 
1648b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
1658b29cfc6SMatthias Ringwald     fwrite(data, num_samples, 1, file);
1668b29cfc6SMatthias Ringwald }
1678b29cfc6SMatthias Ringwald 
168fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){
169fcb08cdbSMilanka Ringwald     fwrite(data, num_samples, 2, file);
170fcb08cdbSMilanka Ringwald }
171fcb08cdbSMilanka Ringwald 
172fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
173fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
174fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
175fcb08cdbSMilanka Ringwald 
176fcb08cdbSMilanka Ringwald     wav_writer_state_t * writer_state = (wav_writer_state_t*) context;
177fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
178fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
179fcb08cdbSMilanka Ringwald 
180fcb08cdbSMilanka Ringwald     write_wav_data_int16(writer_state->wav_file, num_samples, data);
181fcb08cdbSMilanka Ringwald     writer_state->total_num_samples+=num_samples;
182fcb08cdbSMilanka Ringwald     writer_state->frame_count++;
183fcb08cdbSMilanka Ringwald 
184fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
185fcb08cdbSMilanka Ringwald         sco_demo_close();
186fcb08cdbSMilanka Ringwald     }
187fcb08cdbSMilanka Ringwald }
188fcb08cdbSMilanka Ringwald 
189220eb563SMilanka Ringwald static void sco_demo_generate_sine(int16_t * pcm_samples){
190220eb563SMilanka Ringwald     int i;
191220eb563SMilanka Ringwald     for (i=0; i < hfp_msbc_num_audio_samples_per_frame(); i++){
192220eb563SMilanka Ringwald         uint8_t buf[2];
193220eb563SMilanka Ringwald         buf[0] = sine[phase++];
194220eb563SMilanka Ringwald         if (phase >= sizeof(sine)) phase = 0;
195220eb563SMilanka Ringwald         buf[1] = sine[phase++];
196220eb563SMilanka Ringwald         if (phase >= sizeof(sine)) phase = 0;
197220eb563SMilanka Ringwald         pcm_samples[i] = little_endian_read_16(buf, 0);
198220eb563SMilanka Ringwald     }
199220eb563SMilanka Ringwald }
200220eb563SMilanka Ringwald 
201220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){
202220eb563SMilanka Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
203220eb563SMilanka Ringwald     int16_t read_buffer[8*16*2];
204220eb563SMilanka Ringwald     sco_demo_generate_sine(read_buffer);
205220eb563SMilanka Ringwald     hfp_msbc_encode_audio_frame(read_buffer);
206220eb563SMilanka Ringwald     num_audio_frames++;
207220eb563SMilanka Ringwald }
208fcb08cdbSMilanka Ringwald 
209fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
210fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
211fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
212fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
213fcb08cdbSMilanka Ringwald 
214fcb08cdbSMilanka Ringwald     sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state);
215fcb08cdbSMilanka Ringwald 
216fcb08cdbSMilanka Ringwald     const int sample_rate = 16000;
217fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
218fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 2;
219fcb08cdbSMilanka Ringwald     const int num_channels = 1;
220fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
221fcb08cdbSMilanka Ringwald 
222fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
223220eb563SMilanka Ringwald 
224220eb563SMilanka Ringwald     wav_init(SCO_MSBC_FILENAME);
225220eb563SMilanka Ringwald     hfp_msbc_init();
226220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
227fcb08cdbSMilanka Ringwald }
228fcb08cdbSMilanka Ringwald 
229fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){
230fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
231fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
232fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
233fcb08cdbSMilanka Ringwald 
234fcb08cdbSMilanka Ringwald     const int sample_rate = 8000;
235fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
236fcb08cdbSMilanka Ringwald     const int num_channels = 1;
237fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 1;
238fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
239fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
240fcb08cdbSMilanka Ringwald }
241fcb08cdbSMilanka Ringwald 
242fcb08cdbSMilanka Ringwald 
243fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
244fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
245*bd1920a3SMatthias Ringwald         sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
246fcb08cdbSMilanka Ringwald         dump_data = 0;
247fcb08cdbSMilanka Ringwald     }
248fcb08cdbSMilanka Ringwald }
249fcb08cdbSMilanka Ringwald 
250fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
251fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
252fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
253fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
254fcb08cdbSMilanka Ringwald         // convert 8 bit signed to 8 bit unsigned
255fcb08cdbSMilanka Ringwald         int i;
256fcb08cdbSMilanka Ringwald         for (i=0;i<samples_to_write;i++){
257fcb08cdbSMilanka Ringwald             packet[3+i] += 128;
258fcb08cdbSMilanka Ringwald         }
259613518d1SMilanka Ringwald 
260613518d1SMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
261613518d1SMilanka Ringwald         write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]);
262fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
263fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
264fcb08cdbSMilanka Ringwald             sco_demo_close();
265fcb08cdbSMilanka Ringwald         }
266fcb08cdbSMilanka Ringwald         dump_data = 0;
267fcb08cdbSMilanka Ringwald     }
268fcb08cdbSMilanka Ringwald }
269fcb08cdbSMilanka Ringwald 
2708b29cfc6SMatthias Ringwald #endif
2714a96141eSMatthias Ringwald #endif
2728b29cfc6SMatthias Ringwald 
273fcb08cdbSMilanka Ringwald void sco_demo_close(void){
274fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
275fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
276fcb08cdbSMilanka Ringwald 
277613518d1SMilanka Ringwald #if 0
278fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
279220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
280fcb08cdbSMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
281fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
282fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
283fcb08cdbSMilanka 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);
284fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
285fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
286fcb08cdbSMilanka Ringwald     }
287613518d1SMilanka Ringwald #endif
288fcb08cdbSMilanka Ringwald #endif
289fcb08cdbSMilanka Ringwald #endif
290fcb08cdbSMilanka Ringwald }
291fcb08cdbSMilanka Ringwald 
292fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
293fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
294fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
295fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
29617cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
297220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
298fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
299fcb08cdbSMilanka Ringwald     } else {
300fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
301fcb08cdbSMilanka Ringwald     }
302fcb08cdbSMilanka Ringwald #endif
303fcb08cdbSMilanka Ringwald #endif
304fcb08cdbSMilanka Ringwald }
305fcb08cdbSMilanka Ringwald 
306f7c85330SMatthias Ringwald void sco_demo_init(void){
307f7c85330SMatthias Ringwald 
308f7c85330SMatthias Ringwald 	// status
309f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
310f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
311f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
312f7c85330SMatthias Ringwald #else
313f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
314f7c85330SMatthias Ringwald #endif
315f7c85330SMatthias Ringwald #endif
316f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
317f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
318f7c85330SMatthias Ringwald #endif
319f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
320f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
321f7c85330SMatthias Ringwald #endif
322f7c85330SMatthias Ringwald 
323f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
324f7c85330SMatthias Ringwald     int err;
325f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
326f7c85330SMatthias Ringwald 
327f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
328f7c85330SMatthias Ringwald     err = Pa_Initialize();
329f7c85330SMatthias Ringwald     if( err != paNoError ) return;
330f7c85330SMatthias Ringwald     /* -- setup input and output -- */
331f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
332f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
333f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
334f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
335f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
336f7c85330SMatthias Ringwald     /* -- setup stream -- */
337f7c85330SMatthias Ringwald     err = Pa_OpenStream(
338f7c85330SMatthias Ringwald            &stream,
339f7c85330SMatthias Ringwald            NULL, // &inputParameters,
340f7c85330SMatthias Ringwald            &outputParameters,
341f7c85330SMatthias Ringwald            SAMPLE_RATE,
342f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
343f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
344f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
345f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
346f7c85330SMatthias Ringwald     if( err != paNoError ) return;
347f7c85330SMatthias Ringwald     /* -- start stream -- */
348f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
349f7c85330SMatthias Ringwald     if( err != paNoError ) return;
350f7c85330SMatthias Ringwald #endif
351f7c85330SMatthias Ringwald 
352fcb08cdbSMilanka Ringwald //#if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
353f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
354fcb08cdbSMilanka Ringwald //#endif
355f7c85330SMatthias Ringwald 
356f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
357f7c85330SMatthias Ringwald     phase = 'a';
358f7c85330SMatthias Ringwald #endif
359f7c85330SMatthias Ringwald }
360f7c85330SMatthias Ringwald 
3614a96141eSMatthias Ringwald static void sco_report(void){
3624a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
3634a96141eSMatthias Ringwald }
364f7c85330SMatthias Ringwald 
365f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
366f7c85330SMatthias Ringwald 
367f7c85330SMatthias Ringwald     if (!sco_handle) return;
368f7c85330SMatthias Ringwald 
369f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
370f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
371f7c85330SMatthias Ringwald 
372f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
373f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
374f7c85330SMatthias Ringwald     // set handle + flags
375f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
376f7c85330SMatthias Ringwald     // set len
377f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
378220eb563SMilanka Ringwald     const int audio_samples_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
379f7c85330SMatthias Ringwald 
380f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
381220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
382220eb563SMilanka Ringwald 
383220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
384220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
385220eb563SMilanka Ringwald         }
386220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
387220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
388220eb563SMilanka Ringwald     } else {
389f7c85330SMatthias Ringwald         int i;
390220eb563SMilanka Ringwald         for (i=0;i<audio_samples_per_packet;i++){
391f7c85330SMatthias Ringwald             sco_packet[3+i] = sine[phase];
392f7c85330SMatthias Ringwald             phase++;
393f7c85330SMatthias Ringwald             if (phase >= sizeof(sine)) phase = 0;
394f7c85330SMatthias Ringwald         }
395220eb563SMilanka Ringwald     }
396f7c85330SMatthias Ringwald #else
397f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
398220eb563SMilanka Ringwald     memset(&sco_packet[3], phase++, audio_samples_per_packet);
399f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
400f7c85330SMatthias Ringwald #else
40138b2eaafSMatthias Ringwald     int j;
402220eb563SMilanka Ringwald     for (j=0;j<audio_samples_per_packet;j++){
40338b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
404f7c85330SMatthias Ringwald     }
405f7c85330SMatthias Ringwald #endif
406f7c85330SMatthias Ringwald #endif
407220eb563SMilanka Ringwald 
408f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
409f7c85330SMatthias Ringwald 
410f7c85330SMatthias Ringwald     // request another send event
411f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
412f7c85330SMatthias Ringwald 
4134a96141eSMatthias Ringwald     count_sent++;
4144a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
415f7c85330SMatthias Ringwald }
416f7c85330SMatthias Ringwald 
417fcb08cdbSMilanka Ringwald 
418f7c85330SMatthias Ringwald /**
419f7c85330SMatthias Ringwald  * @brief Process received data
420f7c85330SMatthias Ringwald  */
421f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
422f7c85330SMatthias Ringwald 
4238b29cfc6SMatthias Ringwald 
424fcb08cdbSMilanka Ringwald     dump_data = 1;
4258b29cfc6SMatthias Ringwald 
4264a96141eSMatthias Ringwald     count_received++;
4274a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
4284a96141eSMatthias Ringwald 
4294a96141eSMatthias Ringwald 
4304a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
4318b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
432220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
433fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
434fcb08cdbSMilanka Ringwald     } else {
435fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
4368b29cfc6SMatthias Ringwald     }
4378b29cfc6SMatthias Ringwald #endif
4384a96141eSMatthias Ringwald #endif
4398b29cfc6SMatthias Ringwald 
440f7c85330SMatthias Ringwald     if (packet[1] & 0xf0){
441f7c85330SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
442f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
443f7c85330SMatthias Ringwald         return;
444f7c85330SMatthias Ringwald     }
445f7c85330SMatthias Ringwald 
446f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
447f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
448f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
449f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
450f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
451f7c85330SMatthias Ringwald     if (end - start > 5){
452f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
453f7c85330SMatthias Ringwald     }
4548b29cfc6SMatthias Ringwald     dump_data = 0;
455f7c85330SMatthias Ringwald #endif
4568b29cfc6SMatthias Ringwald #endif
4578b29cfc6SMatthias Ringwald 
4588b29cfc6SMatthias Ringwald     if (dump_data){
459f7c85330SMatthias Ringwald         printf("data: ");
460f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
461f7c85330SMatthias Ringwald         int i;
462f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
463f7c85330SMatthias Ringwald             printf("%c", packet[i]);
464f7c85330SMatthias Ringwald         }
465f7c85330SMatthias Ringwald         printf("\n");
4668b29cfc6SMatthias Ringwald         dump_data = 0;
4678b29cfc6SMatthias Ringwald #else
468f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
469f7c85330SMatthias Ringwald #endif
4708b29cfc6SMatthias Ringwald     }
471f7c85330SMatthias Ringwald }
472