xref: /btstack/example/sco_demo_util.c (revision fbc7c9f2bcce2ae889ba9f9b8e88863825d12925)
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"
48379d044eSMilanka Ringwald #include "btstack_cvsd_plc.h"
49220eb563SMilanka Ringwald #include "hfp_msbc.h"
50220eb563SMilanka Ringwald #include "hfp.h"
51fcb08cdbSMilanka Ringwald 
52*fbc7c9f2SMilanka Ringwald #include "wav_util.h"
53*fbc7c9f2SMilanka Ringwald 
54f7c85330SMatthias Ringwald // configure test mode
55f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_SINE		0
56f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_ASCII		1
57f7c85330SMatthias Ringwald #define SCO_DEMO_MODE_COUNTER	2
58f7c85330SMatthias Ringwald 
598b29cfc6SMatthias Ringwald 
60f7c85330SMatthias Ringwald // SCO demo configuration
61fcb08cdbSMilanka Ringwald #define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
62f7c85330SMatthias Ringwald #define SCO_REPORT_PERIOD 100
63f7c85330SMatthias Ringwald 
648b29cfc6SMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
658b29cfc6SMatthias Ringwald #define SCO_WAV_FILENAME      "sco_input.wav"
66d5e5f834SMatthias Ringwald #define SCO_MSBC_OUT_FILENAME "sco_output.msbc"
67d5e5f834SMatthias Ringwald #define SCO_MSBC_IN_FILENAME  "sco_input.mscb"
68220eb563SMilanka Ringwald 
69202da317SMilanka Ringwald #define SCO_WAV_DURATION_IN_SECONDS 15
708b29cfc6SMatthias Ringwald #endif
718b29cfc6SMatthias Ringwald 
72f7c85330SMatthias Ringwald 
73f7c85330SMatthias Ringwald #if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
74f7c85330SMatthias Ringwald #define USE_PORTAUDIO
75f7c85330SMatthias Ringwald #endif
76f7c85330SMatthias Ringwald 
77f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
78f7c85330SMatthias Ringwald #include <portaudio.h>
798b29cfc6SMatthias Ringwald // portaudio config
808b29cfc6SMatthias Ringwald #define NUM_CHANNELS 1
818b29cfc6SMatthias Ringwald #define SAMPLE_RATE 8000
828b29cfc6SMatthias Ringwald #define FRAMES_PER_BUFFER 24
838b29cfc6SMatthias Ringwald #define PA_SAMPLE_TYPE paInt8
84f7c85330SMatthias Ringwald // portaudio globals
85f7c85330SMatthias Ringwald static  PaStream * stream;
86f7c85330SMatthias Ringwald #endif
87f7c85330SMatthias Ringwald 
88fcb08cdbSMilanka Ringwald 
89fcb08cdbSMilanka Ringwald static int dump_data = 1;
90fcb08cdbSMilanka Ringwald 
91fcb08cdbSMilanka Ringwald static int count_sent = 0;
92fcb08cdbSMilanka Ringwald static int count_received = 0;
93d76591efSMatthias Ringwald static uint8_t negotiated_codec = 0;
94220eb563SMilanka Ringwald static int num_audio_frames = 0;
95fcb08cdbSMilanka Ringwald 
96d5e5f834SMatthias Ringwald FILE * msbc_file_in;
97d5e5f834SMatthias Ringwald FILE * msbc_file_out;
987294d009SMatthias Ringwald 
99f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
100d6a06398SMatthias Ringwald 
101f7c85330SMatthias Ringwald 
1028b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
1038b29cfc6SMatthias Ringwald 
1048b29cfc6SMatthias Ringwald static int num_samples_to_write;
1058b29cfc6SMatthias Ringwald 
1062afeea7fSMilanka Ringwald static btstack_sbc_decoder_state_t decoder_state;
10782e01da0SMilanka Ringwald static btstack_cvsd_plc_state_t cvsd_plc_state;
1088b29cfc6SMatthias Ringwald 
109fcb08cdbSMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){
110fcb08cdbSMilanka Ringwald     log_info("handle_pcm_data num samples %u / %u", num_samples, num_samples_to_write);
111fcb08cdbSMilanka Ringwald     if (!num_samples_to_write) return;
112fcb08cdbSMilanka Ringwald 
113fcb08cdbSMilanka Ringwald     num_samples = btstack_min(num_samples, num_samples_to_write);
114fcb08cdbSMilanka Ringwald     num_samples_to_write -= num_samples;
115fcb08cdbSMilanka Ringwald 
116*fbc7c9f2SMilanka Ringwald     wav_writer_write_int16(num_samples, data);
117fcb08cdbSMilanka Ringwald 
118fcb08cdbSMilanka Ringwald     if (num_samples_to_write == 0){
119fcb08cdbSMilanka Ringwald         sco_demo_close();
120fcb08cdbSMilanka Ringwald     }
121fcb08cdbSMilanka Ringwald }
122fcb08cdbSMilanka Ringwald 
123220eb563SMilanka Ringwald static void sco_demo_fill_audio_frame(void){
124220eb563SMilanka Ringwald     if (!hfp_msbc_can_encode_audio_frame_now()) return;
125*fbc7c9f2SMilanka Ringwald     int num_samples = hfp_msbc_num_audio_samples_per_frame();
126*fbc7c9f2SMilanka Ringwald     int16_t sample_buffer[num_samples];
127*fbc7c9f2SMilanka Ringwald     wav_synthesize_sine_wave_int16(num_samples, sample_buffer);
128d6a06398SMatthias Ringwald     hfp_msbc_encode_audio_frame(sample_buffer);
129220eb563SMilanka Ringwald     num_audio_frames++;
130220eb563SMilanka Ringwald }
131fcb08cdbSMilanka Ringwald 
132fcb08cdbSMilanka Ringwald static void sco_demo_init_mSBC(void){
133*fbc7c9f2SMilanka Ringwald     int sample_rate = 16000;
134*fbc7c9f2SMilanka Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate);
135*fbc7c9f2SMilanka Ringwald     btstack_sbc_decoder_init(&decoder_state, SBC_MODE_mSBC, &handle_pcm_data, NULL);
136fcb08cdbSMilanka Ringwald 
137*fbc7c9f2SMilanka Ringwald     num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
138220eb563SMilanka Ringwald 
139220eb563SMilanka Ringwald     hfp_msbc_init();
140220eb563SMilanka Ringwald     sco_demo_fill_audio_frame();
141973d7173SMatthias Ringwald 
142d5e5f834SMatthias Ringwald #ifdef SCO_MSBC_IN_FILENAME
143d5e5f834SMatthias Ringwald     msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
144d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
145d5e5f834SMatthias Ringwald #endif
1467294d009SMatthias Ringwald #ifdef SCO_MSBC_OUT_FILENAME
147d5e5f834SMatthias Ringwald     msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
148d5e5f834SMatthias Ringwald     printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
1497294d009SMatthias Ringwald #endif
150fcb08cdbSMilanka Ringwald }
151fcb08cdbSMilanka Ringwald 
152fcb08cdbSMilanka Ringwald static void sco_demo_receive_mSBC(uint8_t * packet, uint16_t size){
153fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
154d5e5f834SMatthias Ringwald         if (msbc_file_in){
155d5e5f834SMatthias Ringwald             // log incoming mSBC data for testing
156d5e5f834SMatthias Ringwald             fwrite(packet+3, size-3, 1, msbc_file_in);
157d5e5f834SMatthias Ringwald         }
1582afeea7fSMilanka Ringwald         btstack_sbc_decoder_process_data(&decoder_state, (packet[1] >> 4) & 3, packet+3, size-3);
159fcb08cdbSMilanka Ringwald         dump_data = 0;
160fcb08cdbSMilanka Ringwald     }
161fcb08cdbSMilanka Ringwald }
162fcb08cdbSMilanka Ringwald 
163*fbc7c9f2SMilanka Ringwald static void sco_demo_init_CVSD(void){
164*fbc7c9f2SMilanka Ringwald     int sample_rate = 8000;
165*fbc7c9f2SMilanka Ringwald     wav_writer_open(SCO_WAV_FILENAME, 1, sample_rate);
166*fbc7c9f2SMilanka Ringwald     btstack_cvsd_plc_init(&cvsd_plc_state);
167*fbc7c9f2SMilanka Ringwald     num_samples_to_write = sample_rate * SCO_WAV_DURATION_IN_SECONDS;
168*fbc7c9f2SMilanka Ringwald }
169*fbc7c9f2SMilanka Ringwald 
170fcb08cdbSMilanka Ringwald static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
171fcb08cdbSMilanka Ringwald     if (num_samples_to_write){
172fcb08cdbSMilanka Ringwald         const int num_samples = size - 3;
173fcb08cdbSMilanka Ringwald         const int samples_to_write = btstack_min(num_samples, num_samples_to_write);
17482e01da0SMilanka Ringwald         int8_t audio_frame_out[24];
175379d044eSMilanka Ringwald 
176*fbc7c9f2SMilanka Ringwald         // memcpy(audio_frame_out, (int8_t*)(packet+3), 24);
177*fbc7c9f2SMilanka Ringwald         btstack_cvsd_plc_process_data(&cvsd_plc_state, (int8_t *)(packet+3), num_samples, audio_frame_out);
178379d044eSMilanka Ringwald 
179*fbc7c9f2SMilanka Ringwald         wav_writer_write_int8(samples_to_write, audio_frame_out);
180fcb08cdbSMilanka Ringwald         num_samples_to_write -= samples_to_write;
181fcb08cdbSMilanka Ringwald         if (num_samples_to_write == 0){
182fcb08cdbSMilanka Ringwald             sco_demo_close();
183fcb08cdbSMilanka Ringwald         }
184fcb08cdbSMilanka Ringwald         dump_data = 0;
185fcb08cdbSMilanka Ringwald     }
186fcb08cdbSMilanka Ringwald }
187fcb08cdbSMilanka Ringwald 
1888b29cfc6SMatthias Ringwald #endif
1894a96141eSMatthias Ringwald #endif
1908b29cfc6SMatthias Ringwald 
191fcb08cdbSMilanka Ringwald void sco_demo_close(void){
192fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
19326463303SMilanka Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
194*fbc7c9f2SMilanka Ringwald     wav_writer_close();
19526463303SMilanka Ringwald     printf("SCO demo statistics: ");
19626463303SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
19726463303SMilanka Ringwald         printf("Used mSBC with PLC, number of processed frames: \n - %d good frames, \n - %d zero frames, \n - %d bad frames.", decoder_state.good_frames_nr, decoder_state.zero_frames_nr, decoder_state.bad_frames_nr);
19826463303SMilanka Ringwald     } else {
19926463303SMilanka Ringwald         printf("Used CVSD with PLC, number of proccesed frames: \n - %d good frames, \n - %d bad frames.", cvsd_plc_state.good_frames_nr, cvsd_plc_state.bad_frames_nr);
20026463303SMilanka Ringwald     }
20126463303SMilanka Ringwald #endif
20226463303SMilanka Ringwald #endif
20326463303SMilanka Ringwald 
20426463303SMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
205fcb08cdbSMilanka Ringwald #ifdef SCO_WAV_FILENAME
206fcb08cdbSMilanka Ringwald 
207613518d1SMilanka Ringwald #if 0
208fcb08cdbSMilanka Ringwald     printf("SCO Demo: closing wav file\n");
209220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
2106e046a36SMatthias Ringwald         wav_writer_state_t * writer_state = &wav_writer_state;
211fcb08cdbSMilanka Ringwald         if (!writer_state->wav_file) return;
212fcb08cdbSMilanka Ringwald         rewind(writer_state->wav_file);
2132afeea7fSMilanka 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);
214fcb08cdbSMilanka Ringwald         fclose(writer_state->wav_file);
215fcb08cdbSMilanka Ringwald         writer_state->wav_file = NULL;
216fcb08cdbSMilanka Ringwald     }
217613518d1SMilanka Ringwald #endif
218fcb08cdbSMilanka Ringwald #endif
219fcb08cdbSMilanka Ringwald #endif
220fcb08cdbSMilanka Ringwald }
221fcb08cdbSMilanka Ringwald 
222fcb08cdbSMilanka Ringwald void sco_demo_set_codec(uint8_t codec){
223fcb08cdbSMilanka Ringwald     if (negotiated_codec == codec) return;
224fcb08cdbSMilanka Ringwald     negotiated_codec = codec;
225fcb08cdbSMilanka Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
22617cd946eSMatthias Ringwald #if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
227220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
228fcb08cdbSMilanka Ringwald         sco_demo_init_mSBC();
229fcb08cdbSMilanka Ringwald     } else {
230fcb08cdbSMilanka Ringwald         sco_demo_init_CVSD();
231fcb08cdbSMilanka Ringwald     }
232fcb08cdbSMilanka Ringwald #endif
233fcb08cdbSMilanka Ringwald #endif
234fcb08cdbSMilanka Ringwald }
235fcb08cdbSMilanka Ringwald 
236f7c85330SMatthias Ringwald void sco_demo_init(void){
237f7c85330SMatthias Ringwald 
238f7c85330SMatthias Ringwald 	// status
239f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
240f7c85330SMatthias Ringwald #ifdef HAVE_PORTAUDIO
241f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
242f7c85330SMatthias Ringwald #else
243f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending sine wave, hexdump received data.\n");
244f7c85330SMatthias Ringwald #endif
245f7c85330SMatthias Ringwald #endif
246f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
247f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending ASCII blocks, print received data.\n");
248f7c85330SMatthias Ringwald #endif
249f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
250f7c85330SMatthias Ringwald 	printf("SCO Demo: Sending counter value, hexdump received data.\n");
251f7c85330SMatthias Ringwald #endif
252f7c85330SMatthias Ringwald 
253f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
254f7c85330SMatthias Ringwald     int err;
255f7c85330SMatthias Ringwald     PaStreamParameters outputParameters;
256f7c85330SMatthias Ringwald 
257f7c85330SMatthias Ringwald     /* -- initialize PortAudio -- */
258f7c85330SMatthias Ringwald     err = Pa_Initialize();
259f7c85330SMatthias Ringwald     if( err != paNoError ) return;
260f7c85330SMatthias Ringwald     /* -- setup input and output -- */
261f7c85330SMatthias Ringwald     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
262f7c85330SMatthias Ringwald     outputParameters.channelCount = NUM_CHANNELS;
263f7c85330SMatthias Ringwald     outputParameters.sampleFormat = PA_SAMPLE_TYPE;
264f7c85330SMatthias Ringwald     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
265f7c85330SMatthias Ringwald     outputParameters.hostApiSpecificStreamInfo = NULL;
266f7c85330SMatthias Ringwald     /* -- setup stream -- */
267f7c85330SMatthias Ringwald     err = Pa_OpenStream(
268f7c85330SMatthias Ringwald            &stream,
269f7c85330SMatthias Ringwald            NULL, // &inputParameters,
270f7c85330SMatthias Ringwald            &outputParameters,
271f7c85330SMatthias Ringwald            SAMPLE_RATE,
272f7c85330SMatthias Ringwald            FRAMES_PER_BUFFER,
273f7c85330SMatthias Ringwald            paClipOff, /* we won't output out of range samples so don't bother clipping them */
274f7c85330SMatthias Ringwald            NULL, 	  /* no callback, use blocking API */
275f7c85330SMatthias Ringwald            NULL ); 	  /* no callback, so no callback userData */
276f7c85330SMatthias Ringwald     if( err != paNoError ) return;
277f7c85330SMatthias Ringwald     /* -- start stream -- */
278f7c85330SMatthias Ringwald     err = Pa_StartStream( stream );
279f7c85330SMatthias Ringwald     if( err != paNoError ) return;
280f7c85330SMatthias Ringwald #endif
281f7c85330SMatthias Ringwald 
2827294d009SMatthias Ringwald #if SCO_DEMO_MODE != SCO_DEMO_MODE_SINE
283f7c85330SMatthias Ringwald     hci_set_sco_voice_setting(0x03);    // linear, unsigned, 8-bit, transparent
2847294d009SMatthias Ringwald #endif
285f7c85330SMatthias Ringwald 
286f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
287f7c85330SMatthias Ringwald     phase = 'a';
288f7c85330SMatthias Ringwald #endif
289f7c85330SMatthias Ringwald }
290f7c85330SMatthias Ringwald 
2914a96141eSMatthias Ringwald static void sco_report(void){
2924a96141eSMatthias Ringwald     printf("SCO: sent %u, received %u\n", count_sent, count_received);
2934a96141eSMatthias Ringwald }
294f7c85330SMatthias Ringwald 
295f7c85330SMatthias Ringwald void sco_demo_send(hci_con_handle_t sco_handle){
296f7c85330SMatthias Ringwald 
297f7c85330SMatthias Ringwald     if (!sco_handle) return;
298f7c85330SMatthias Ringwald 
299f7c85330SMatthias Ringwald     const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length();
300f7c85330SMatthias Ringwald     const int sco_payload_length = sco_packet_length - 3;
301f7c85330SMatthias Ringwald 
302f7c85330SMatthias Ringwald     hci_reserve_packet_buffer();
303f7c85330SMatthias Ringwald     uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
304f7c85330SMatthias Ringwald     // set handle + flags
305f7c85330SMatthias Ringwald     little_endian_store_16(sco_packet, 0, sco_handle);
306f7c85330SMatthias Ringwald     // set len
307f7c85330SMatthias Ringwald     sco_packet[2] = sco_payload_length;
308220eb563SMilanka Ringwald     const int audio_samples_per_packet = sco_payload_length;    // for 8-bit data. for 16-bit data it's /2
309f7c85330SMatthias Ringwald 
310f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
311220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
312220eb563SMilanka Ringwald 
313220eb563SMilanka Ringwald         if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
314220eb563SMilanka Ringwald             log_error("mSBC stream is empty.");
315220eb563SMilanka Ringwald         }
316220eb563SMilanka Ringwald         hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
317d5e5f834SMatthias Ringwald         if (msbc_file_out){
318d76591efSMatthias Ringwald             // log outgoing mSBC data for testing
319d5e5f834SMatthias Ringwald             fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
320d76591efSMatthias Ringwald         }
3217294d009SMatthias Ringwald 
322220eb563SMilanka Ringwald         sco_demo_fill_audio_frame();
323220eb563SMilanka Ringwald     } else {
324*fbc7c9f2SMilanka Ringwald         wav_synthesize_sine_wave_int8(audio_samples_per_packet, (int8_t *) (sco_packet+3));
325220eb563SMilanka Ringwald     }
326f7c85330SMatthias Ringwald #else
327f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
328220eb563SMilanka Ringwald     memset(&sco_packet[3], phase++, audio_samples_per_packet);
329f7c85330SMatthias Ringwald     if (phase > 'z') phase = 'a';
330f7c85330SMatthias Ringwald #else
33138b2eaafSMatthias Ringwald     int j;
332220eb563SMilanka Ringwald     for (j=0;j<audio_samples_per_packet;j++){
33338b2eaafSMatthias Ringwald         sco_packet[3+j] = phase++;
334f7c85330SMatthias Ringwald     }
335f7c85330SMatthias Ringwald #endif
336f7c85330SMatthias Ringwald #endif
337220eb563SMilanka Ringwald 
338f7c85330SMatthias Ringwald     hci_send_sco_packet_buffer(sco_packet_length);
339f7c85330SMatthias Ringwald 
340f7c85330SMatthias Ringwald     // request another send event
341f7c85330SMatthias Ringwald     hci_request_sco_can_send_now_event();
342f7c85330SMatthias Ringwald 
3434a96141eSMatthias Ringwald     count_sent++;
3444a96141eSMatthias Ringwald     if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
345f7c85330SMatthias Ringwald }
346f7c85330SMatthias Ringwald 
347f7c85330SMatthias Ringwald /**
348f7c85330SMatthias Ringwald  * @brief Process received data
349f7c85330SMatthias Ringwald  */
350f7c85330SMatthias Ringwald void sco_demo_receive(uint8_t * packet, uint16_t size){
351f7c85330SMatthias Ringwald 
352fcb08cdbSMilanka Ringwald     dump_data = 1;
3538b29cfc6SMatthias Ringwald 
3544a96141eSMatthias Ringwald     count_received++;
3554a96141eSMatthias Ringwald     // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report();
3564a96141eSMatthias Ringwald 
3574a96141eSMatthias Ringwald 
3584a96141eSMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
3598b29cfc6SMatthias Ringwald #ifdef SCO_WAV_FILENAME
360220eb563SMilanka Ringwald     if (negotiated_codec == HFP_CODEC_MSBC){
361fcb08cdbSMilanka Ringwald         sco_demo_receive_mSBC(packet, size);
362fcb08cdbSMilanka Ringwald     } else {
363fcb08cdbSMilanka Ringwald         sco_demo_receive_CVSD(packet, size);
3648b29cfc6SMatthias Ringwald     }
3658b29cfc6SMatthias Ringwald #endif
3664a96141eSMatthias Ringwald #endif
3678b29cfc6SMatthias Ringwald 
368b3f76298SMilanka Ringwald     if (packet[1] & 0x30){
369b3f76298SMilanka Ringwald         printf("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
370b3f76298SMilanka Ringwald         log_info("SCO CRC Error: %x - data: ", (packet[1] & 0x30) >> 4);
371f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
372b3f76298SMilanka Ringwald 
373f7c85330SMatthias Ringwald         return;
374f7c85330SMatthias Ringwald     }
375f7c85330SMatthias Ringwald 
376f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
377f7c85330SMatthias Ringwald #ifdef USE_PORTAUDIO
378f7c85330SMatthias Ringwald     uint32_t start = btstack_run_loop_get_time_ms();
379f7c85330SMatthias Ringwald     Pa_WriteStream( stream, &packet[3], size -3);
380f7c85330SMatthias Ringwald     uint32_t end   = btstack_run_loop_get_time_ms();
381f7c85330SMatthias Ringwald     if (end - start > 5){
382f7c85330SMatthias Ringwald         printf("Portaudio: write stream took %u ms\n", end - start);
383f7c85330SMatthias Ringwald     }
3848b29cfc6SMatthias Ringwald     dump_data = 0;
385f7c85330SMatthias Ringwald #endif
3868b29cfc6SMatthias Ringwald #endif
3878b29cfc6SMatthias Ringwald 
3888b29cfc6SMatthias Ringwald     if (dump_data){
389f7c85330SMatthias Ringwald         printf("data: ");
390f7c85330SMatthias Ringwald #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
391f7c85330SMatthias Ringwald         int i;
392f7c85330SMatthias Ringwald         for (i=3;i<size;i++){
393f7c85330SMatthias Ringwald             printf("%c", packet[i]);
394f7c85330SMatthias Ringwald         }
395f7c85330SMatthias Ringwald         printf("\n");
3968b29cfc6SMatthias Ringwald         dump_data = 0;
3978b29cfc6SMatthias Ringwald #else
398f7c85330SMatthias Ringwald         printf_hexdump(&packet[3], size-3);
399f7c85330SMatthias Ringwald #endif
4008b29cfc6SMatthias Ringwald     }
401f7c85330SMatthias Ringwald }
402