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