xref: /btstack/example/sco_demo_util.c (revision 2ec72fbbcd8bed6a2a9637e1001e9a24b5c7c58e)
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 
42*2ec72fbbSMilanka Ringwald 
43*2ec72fbbSMilanka Ringwald #include <stdio.h>
44*2ec72fbbSMilanka Ringwald 
45f7c85330SMatthias Ringwald #include "sco_demo_util.h"
46fcb08cdbSMilanka Ringwald #include "btstack_debug.h"
47fcb08cdbSMilanka Ringwald #include "sbc_decoder.h"
48fcb08cdbSMilanka Ringwald 
49f7c85330SMatthias Ringwald // configure test mode
50f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		0
51f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		1
52f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	2
53f7c85330SMatthias Ringwald 
548b29cfc6SMatthias Ringwald 
55f7c85330SMatthias Ringwald // SCO demo configuration
56fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
57f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100
58f7c85330SMatthias Ringwald 
598b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
608b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME "sco_input.wav"
618b29cfc6SMatthias Ringwald #define SCO_WAV_DURATION_IN_SECONDS 30
628b29cfc6SMatthias Ringwald #endif
638b29cfc6SMatthias Ringwald 
64f7c85330SMatthias Ringwald 
65f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
66f7c85330SMatthias Ringwald #define USE_PORTAUDIO
67f7c85330SMatthias Ringwald #endif
68f7c85330SMatthias Ringwald 
69f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
70f7c85330SMatthias Ringwald #include <portaudio.h>
718b29cfc6SMatthias Ringwald // portaudio config
728b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1
738b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000
748b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24
758b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8
76f7c85330SMatthias Ringwald // portaudio globals
77f7c85330SMatthias Ringwald static  PaStream * stream;
78f7c85330SMatthias Ringwald #endif
79f7c85330SMatthias Ringwald 
80fcb08cdbSMilanka Ringwald typedef struct wav_writer_state {
81fcb08cdbSMilanka Ringwald     FILE * wav_file;
82fcb08cdbSMilanka Ringwald     int total_num_samples;
83fcb08cdbSMilanka Ringwald     int frame_count;
84fcb08cdbSMilanka Ringwald } wav_writer_state_t;
85fcb08cdbSMilanka Ringwald 
86fcb08cdbSMilanka Ringwald static int dump_data = 1;
87fcb08cdbSMilanka Ringwald 
88fcb08cdbSMilanka Ringwald static int phase;
89fcb08cdbSMilanka Ringwald static int count_sent = 0;
90fcb08cdbSMilanka Ringwald static int count_received = 0;
91fcb08cdbSMilanka Ringwald static uint8_t negotiated_codec = 0; // CVSD
92fcb08cdbSMilanka Ringwald 
93f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
94f7c85330SMatthias Ringwald // input signal: pre-computed sine wave, 160 Hz
95f7c85330SMatthias Ringwald static const uint8_t sine[] = {
96f7c85330SMatthias Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
97f7c85330SMatthias Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
98f7c85330SMatthias Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
99f7c85330SMatthias Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
100f7c85330SMatthias Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
101f7c85330SMatthias Ringwald };
102f7c85330SMatthias Ringwald 
103f7c85330SMatthias Ringwald 
1048b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1058b29cfc6SMatthias Ringwald 
1068b29cfc6SMatthias Ringwald static int num_samples_to_write;
107fcb08cdbSMilanka Ringwald static wav_writer_state_t wav_writer_state;
1088b29cfc6SMatthias Ringwald 
109fcb08cdbSMilanka Ringwald static sbc_decoder_state_t decoder_state;
1108b29cfc6SMatthias Ringwald 
1118b29cfc6SMatthias Ringwald static void little_endian_fstore_16(FILE * file, uint16_t value){
1128b29cfc6SMatthias Ringwald     uint8_t buf[2];
1138b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1148b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 2, file);
1158b29cfc6SMatthias Ringwald }
1168b29cfc6SMatthias Ringwald 
1178b29cfc6SMatthias Ringwald static void little_endian_fstore_32(FILE * file, uint32_t value){
1188b29cfc6SMatthias Ringwald     uint8_t buf[4];
1198b29cfc6SMatthias Ringwald     little_endian_store_32(buf, 0, value);
1208b29cfc6SMatthias Ringwald     fwrite(&buf, 1, 4, file);
1218b29cfc6SMatthias Ringwald }
1228b29cfc6SMatthias Ringwald 
1238b29cfc6SMatthias Ringwald static FILE * wav_init(const char * filename){
124fcb08cdbSMilanka Ringwald     FILE * f = fopen(filename, "wb");
125fcb08cdbSMilanka Ringwald     printf("SCO Demo: creating wav file %s, %p\n", filename, f);
126fcb08cdbSMilanka Ringwald     return f;
1278b29cfc6SMatthias Ringwald }
1288b29cfc6SMatthias Ringwald 
1298b29cfc6SMatthias Ringwald static void write_wav_header(FILE * file, int sample_rate, int num_channels, int num_samples, int bytes_per_sample){
1308b29cfc6SMatthias Ringwald     /* write RIFF header */
1318b29cfc6SMatthias Ringwald     fwrite("RIFF", 1, 4, file);
1328b29cfc6SMatthias Ringwald     // num_samples = blocks * subbands
1338b29cfc6SMatthias Ringwald     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * num_channels);
1348b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes + 36);
1358b29cfc6SMatthias Ringwald     fwrite("WAVE", 1, 4, file);
1368b29cfc6SMatthias Ringwald 
1378b29cfc6SMatthias Ringwald     int byte_rate = sample_rate * num_channels * bytes_per_sample;
1388b29cfc6SMatthias Ringwald     int bits_per_sample = 8 * bytes_per_sample;
1398b29cfc6SMatthias Ringwald     int block_align = num_channels * bits_per_sample;
1408b29cfc6SMatthias Ringwald     int fmt_length = 16;
1418b29cfc6SMatthias Ringwald     int fmt_format_tag = 1; // PCM
1428b29cfc6SMatthias Ringwald 
1438b29cfc6SMatthias Ringwald     /* write fmt chunk */
1448b29cfc6SMatthias Ringwald     fwrite("fmt ", 1, 4, file);
1458b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, fmt_length);
1468b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, fmt_format_tag);
1478b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, num_channels);
1488b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, sample_rate);
1498b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, byte_rate);
1508b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, block_align);
1518b29cfc6SMatthias Ringwald     little_endian_fstore_16(file, bits_per_sample);
1528b29cfc6SMatthias Ringwald 
1538b29cfc6SMatthias Ringwald     /* write data chunk */
1548b29cfc6SMatthias Ringwald     fwrite("data", 1, 4, file);
1558b29cfc6SMatthias Ringwald     little_endian_fstore_32(file, data_bytes);
1568b29cfc6SMatthias Ringwald }
1578b29cfc6SMatthias Ringwald 
1588b29cfc6SMatthias Ringwald static void write_wav_data_uint8(FILE * file, unsigned long num_samples, uint8_t * data){
1598b29cfc6SMatthias Ringwald     fwrite(data, num_samples, 1, file);
1608b29cfc6SMatthias Ringwald }
1618b29cfc6SMatthias Ringwald 
162fcb08cdbSMilanka Ringwald static void write_wav_data_int16(FILE * file, int num_samples, int16_t * data){
163fcb08cdbSMilanka Ringwald     fwrite(data, num_samples, 2, file);
164fcb08cdbSMilanka Ringwald }
165fcb08cdbSMilanka Ringwald 
166fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
167fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
168fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
169fcb08cdbSMilanka Ringwald 
170fcb08cdbSMilanka Ringwald     wav_writer_state_t * writer_state = (wav_writer_state_t*) context;
171fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
172fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
173fcb08cdbSMilanka Ringwald 
174fcb08cdbSMilanka Ringwald     write_wav_data_int16(writer_state->wav_file, num_samples, data);
175fcb08cdbSMilanka Ringwald     writer_state->total_num_samples+=num_samples;
176fcb08cdbSMilanka Ringwald     writer_state->frame_count++;
177fcb08cdbSMilanka Ringwald 
178fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
179fcb08cdbSMilanka Ringwald         sco_demo_close();
180fcb08cdbSMilanka Ringwald     }
181fcb08cdbSMilanka Ringwald }
182fcb08cdbSMilanka Ringwald 
183fcb08cdbSMilanka Ringwald 
184fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
185fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
186fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
187fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
188fcb08cdbSMilanka Ringwald 
189fcb08cdbSMilanka Ringwald     sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, (void*)&wav_writer_state);
190fcb08cdbSMilanka Ringwald 
191fcb08cdbSMilanka Ringwald     const int sample_rate = 16000;
192fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
193fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 2;
194fcb08cdbSMilanka Ringwald     const int num_channels = 1;
195fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
196fcb08cdbSMilanka Ringwald 
197fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
198fcb08cdbSMilanka Ringwald }
199fcb08cdbSMilanka Ringwald 
200fcb08cdbSMilanka Ringwald static void sco_demo_init_CVSD(void){
201fcb08cdbSMilanka Ringwald     wav_writer_state.wav_file = wav_init(SCO_WAV_FILENAME);
202fcb08cdbSMilanka Ringwald     wav_writer_state.frame_count = 0;
203fcb08cdbSMilanka Ringwald     wav_writer_state.total_num_samples = 0;
204fcb08cdbSMilanka Ringwald 
205fcb08cdbSMilanka Ringwald     const int sample_rate = 8000;
206fcb08cdbSMilanka Ringwald     const int num_samples = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
207fcb08cdbSMilanka Ringwald     const int num_channels = 1;
208fcb08cdbSMilanka Ringwald     const int bytes_per_sample = 1;
209fcb08cdbSMilanka Ringwald     num_samples_to_write = num_samples;
210fcb08cdbSMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, sample_rate, num_channels, num_samples, bytes_per_sample);
211fcb08cdbSMilanka Ringwald }
212fcb08cdbSMilanka Ringwald 
213fcb08cdbSMilanka Ringwald 
214fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
215fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
216fcb08cdbSMilanka Ringwald         sbc_decoder_process_data(&decoder_state, packet+3, size-3);
217fcb08cdbSMilanka Ringwald         dump_data = 0;
218fcb08cdbSMilanka Ringwald     }
219fcb08cdbSMilanka Ringwald }
220fcb08cdbSMilanka Ringwald 
221fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
222fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
223fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
224fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
225fcb08cdbSMilanka Ringwald         // convert 8 bit signed to 8 bit unsigned
226fcb08cdbSMilanka Ringwald         int i;
227fcb08cdbSMilanka Ringwald         for (i=0;i<samples_to_write;i++){
228fcb08cdbSMilanka Ringwald             packet[3+i] += 128;
229fcb08cdbSMilanka Ringwald         }
230613518d1SMilanka Ringwald 
231613518d1SMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
232613518d1SMilanka Ringwald         write_wav_data_uint8(writer_state->wav_file, samples_to_write, &packet[3]);
233fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
234fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
235fcb08cdbSMilanka Ringwald             sco_demo_close();
236fcb08cdbSMilanka Ringwald         }
237fcb08cdbSMilanka Ringwald         dump_data = 0;
238fcb08cdbSMilanka Ringwald     }
239fcb08cdbSMilanka Ringwald }
240fcb08cdbSMilanka Ringwald 
2418b29cfc6SMatthias Ringwald #endif
2424a96141eSMatthias Ringwald #endif
2438b29cfc6SMatthias Ringwald 
244fcb08cdbSMilanka Ringwald void sco_demo_close(void){
245fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
246fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
247fcb08cdbSMilanka Ringwald 
248613518d1SMilanka Ringwald #if 0
249fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
250fcb08cdbSMilanka Ringwald     if (negotiated_codec == 0x02){
251fcb08cdbSMilanka Ringwald         wav_writer_state_t * writer_state = (wav_writer_state_t*) decoder_state.context;
252fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
253fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
254fcb08cdbSMilanka 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);
255fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
256fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
257fcb08cdbSMilanka Ringwald     }
258613518d1SMilanka Ringwald #endif
259fcb08cdbSMilanka Ringwald #endif
260fcb08cdbSMilanka Ringwald #endif
261fcb08cdbSMilanka Ringwald }
262fcb08cdbSMilanka Ringwald 
263fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
264fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
265fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
266fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
267fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
268fcb08cdbSMilanka Ringwald     if (negotiated_codec == 0x02){
269fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
270fcb08cdbSMilanka Ringwald     } else {
271fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
272fcb08cdbSMilanka Ringwald     }
273fcb08cdbSMilanka Ringwald #endif
274fcb08cdbSMilanka Ringwald #endif
275fcb08cdbSMilanka Ringwald }
276fcb08cdbSMilanka Ringwald 
277f7c85330SMatthias Ringwald void sco_demo_init(void){
278f7c85330SMatthias Ringwald 
279f7c85330SMatthias Ringwald 	// status
280f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
281f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
282f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
283f7c85330SMatthias Ringwald #else
284f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
285f7c85330SMatthias Ringwald #endif
286f7c85330SMatthias Ringwald #endif
287f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
288f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
289f7c85330SMatthias Ringwald #endif
290f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
291f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
292f7c85330SMatthias Ringwald #endif
293f7c85330SMatthias Ringwald 
294f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
295f7c85330SMatthias Ringwald     int err;
296f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
297f7c85330SMatthias Ringwald 
298f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
299f7c85330SMatthias Ringwald     err = Pa_Initialize();
300f7c85330SMatthias Ringwald     if( err != paNoError ) return;
301f7c85330SMatthias Ringwald     /* -- setup input and output -- */
302f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
303f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
304f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
305f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
306f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
307f7c85330SMatthias Ringwald     /* -- setup stream -- */
308f7c85330SMatthias Ringwald     err = Pa_OpenStream(
309f7c85330SMatthias Ringwald            &stream,
310f7c85330SMatthias Ringwald            NULL, // &inputParameters,
311f7c85330SMatthias Ringwald            &outputParameters,
312f7c85330SMatthias Ringwald            SAMPLE_RATE,
313f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
314f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
315f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
316f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
317f7c85330SMatthias Ringwald     if( err != paNoError ) return;
318f7c85330SMatthias Ringwald     /* -- start stream -- */
319f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
320f7c85330SMatthias Ringwald     if( err != paNoError ) return;
321f7c85330SMatthias Ringwald #endif
322f7c85330SMatthias Ringwald 
323fcb08cdbSMilanka Ringwald //#if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
324f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
325fcb08cdbSMilanka Ringwald //#endif
326f7c85330SMatthias Ringwald 
327f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
328f7c85330SMatthias Ringwald     phase = 'a';
329f7c85330SMatthias Ringwald #endif
330f7c85330SMatthias Ringwald }
331f7c85330SMatthias Ringwald 
3324a96141eSMatthias Ringwald static void sco_report(void){
3334a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
3344a96141eSMatthias Ringwald }
335f7c85330SMatthias Ringwald 
336f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
337f7c85330SMatthias Ringwald 
338f7c85330SMatthias Ringwald     if (!sco_handle) return;
339f7c85330SMatthias Ringwald 
340f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
341f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
342f7c85330SMatthias Ringwald 
343f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
344f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
345f7c85330SMatthias Ringwald     // set handle + flags
346f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
347f7c85330SMatthias Ringwald     // set len
348f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
349f7c85330SMatthias Ringwald     const int frames_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
350f7c85330SMatthias Ringwald 
351f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
352f7c85330SMatthias Ringwald     int i;
353f7c85330SMatthias Ringwald     for (i=0;i<frames_per_packet;i++){
354f7c85330SMatthias Ringwald         sco_packet[3+i] = sine[phase];
355f7c85330SMatthias Ringwald         phase++;
356f7c85330SMatthias Ringwald         if (phase >= sizeof(sine)) phase = 0;
357f7c85330SMatthias Ringwald     }
358f7c85330SMatthias Ringwald #else
359f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
360f7c85330SMatthias Ringwald     memset(&sco_packet[3], phase++, frames_per_packet);
361f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
362f7c85330SMatthias Ringwald #else
36338b2eaafSMatthias Ringwald     int j;
36438b2eaafSMatthias Ringwald     for (j=0;j<frames_per_packet;j++){
36538b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
366f7c85330SMatthias Ringwald     }
367f7c85330SMatthias Ringwald #endif
368f7c85330SMatthias Ringwald #endif
369f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
370f7c85330SMatthias Ringwald 
371f7c85330SMatthias Ringwald     // request another send event
372f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
373f7c85330SMatthias Ringwald 
3744a96141eSMatthias Ringwald     count_sent++;
3754a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
376f7c85330SMatthias Ringwald }
377f7c85330SMatthias Ringwald 
378fcb08cdbSMilanka Ringwald 
379f7c85330SMatthias Ringwald /**
380f7c85330SMatthias Ringwald  * @brief Process received data
381f7c85330SMatthias Ringwald  */
382f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
383f7c85330SMatthias Ringwald 
3848b29cfc6SMatthias Ringwald 
385fcb08cdbSMilanka Ringwald     dump_data = 1;
3868b29cfc6SMatthias Ringwald 
3874a96141eSMatthias Ringwald     count_received++;
3884a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
3894a96141eSMatthias Ringwald 
3904a96141eSMatthias Ringwald 
3914a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
3928b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
393fcb08cdbSMilanka Ringwald     if (negotiated_codec == 0x02){
394fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
395fcb08cdbSMilanka Ringwald     } else {
396fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
3978b29cfc6SMatthias Ringwald     }
3988b29cfc6SMatthias Ringwald #endif
3994a96141eSMatthias Ringwald #endif
4008b29cfc6SMatthias Ringwald 
401f7c85330SMatthias Ringwald     if (packet[1] & 0xf0){
402f7c85330SMatthias Ringwald         printf("SCO CRC Error: %x - data: ", packet[1] >> 4);
403f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
404f7c85330SMatthias Ringwald         return;
405f7c85330SMatthias Ringwald     }
406f7c85330SMatthias Ringwald 
407f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
408f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
409f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
410f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
411f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
412f7c85330SMatthias Ringwald     if (end - start > 5){
413f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
414f7c85330SMatthias Ringwald     }
4158b29cfc6SMatthias Ringwald     dump_data = 0;
416f7c85330SMatthias Ringwald #endif
4178b29cfc6SMatthias Ringwald #endif
4188b29cfc6SMatthias Ringwald 
4198b29cfc6SMatthias Ringwald     if (dump_data){
420f7c85330SMatthias Ringwald         printf("data: ");
421f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
422f7c85330SMatthias Ringwald         int i;
423f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
424f7c85330SMatthias Ringwald             printf("%c", packet[i]);
425f7c85330SMatthias Ringwald         }
426f7c85330SMatthias Ringwald         printf("\n");
4278b29cfc6SMatthias Ringwald         dump_data = 0;
4288b29cfc6SMatthias Ringwald #else
429f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
430f7c85330SMatthias Ringwald #endif
4318b29cfc6SMatthias Ringwald     }
432f7c85330SMatthias Ringwald }
433