mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-24 21:39:55 +00:00
Merge branch 'develop' of https://github.com/bluekitchen/btstack into develop
This commit is contained in:
commit
2faa06e0e6
@ -59,11 +59,12 @@
|
|||||||
|
|
||||||
|
|
||||||
// test modes
|
// test modes
|
||||||
#define SCO_DEMO_MODE_SINE 0
|
#define SCO_DEMO_MODE_SINE 0
|
||||||
#define SCO_DEMO_MODE_ASCII 1
|
#define SCO_DEMO_MODE_ASCII 1
|
||||||
#define SCO_DEMO_MODE_COUNTER 2
|
#define SCO_DEMO_MODE_COUNTER 2
|
||||||
#define SCO_DEMO_MODE_55 3
|
#define SCO_DEMO_MODE_55 3
|
||||||
#define SCO_DEMO_MODE_00 4
|
#define SCO_DEMO_MODE_00 4
|
||||||
|
#define SCO_DEMO_MODE_MICROPHONE 5
|
||||||
|
|
||||||
// SCO demo configuration
|
// SCO demo configuration
|
||||||
#define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
|
#define SCO_DEMO_MODE SCO_DEMO_MODE_SINE
|
||||||
@ -90,34 +91,50 @@
|
|||||||
#define MSBC_SAMPLE_RATE 16000
|
#define MSBC_SAMPLE_RATE 16000
|
||||||
#define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS)
|
#define MSBC_BYTES_PER_FRAME (2*NUM_CHANNELS)
|
||||||
|
|
||||||
#if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE)
|
#if defined(HAVE_PORTAUDIO) && (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE || SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
|
||||||
#define USE_PORTAUDIO
|
#define USE_PORTAUDIO
|
||||||
#define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME)
|
#define CVSD_PA_PREBUFFER_BYTES (SCO_CVSD_PA_PREBUFFER_MS * CVSD_SAMPLE_RATE/1000 * CVSD_BYTES_PER_FRAME)
|
||||||
#define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME)
|
#define MSBC_PA_PREBUFFER_BYTES (SCO_MSBC_PA_PREBUFFER_MS * MSBC_SAMPLE_RATE/1000 * MSBC_BYTES_PER_FRAME)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_PORTAUDIO
|
#ifdef USE_PORTAUDIO
|
||||||
static PaStream * stream;
|
|
||||||
static int pa_stream_started = 0;
|
// bidirectional audio stream
|
||||||
static int pa_stream_paused = 0;
|
static PaStream * pa_stream;
|
||||||
static uint8_t ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
|
|
||||||
static btstack_ring_buffer_t ring_buffer;
|
// output
|
||||||
|
static int pa_output_started = 0;
|
||||||
|
static int pa_output_paused = 0;
|
||||||
|
static uint8_t pa_output_ring_buffer_storage[2*MSBC_PA_PREBUFFER_BYTES];
|
||||||
|
static btstack_ring_buffer_t pa_output_ring_buffer;
|
||||||
|
|
||||||
|
// input
|
||||||
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
|
||||||
|
#define USE_PORTAUDIO_INPUT
|
||||||
|
static int pa_input_started = 0;
|
||||||
|
static int pa_input_paused = 0;
|
||||||
|
static uint8_t pa_input_ring_buffer_storage[2*8000]; // full second input buffer
|
||||||
|
static btstack_ring_buffer_t pa_input_ring_buffer;
|
||||||
|
static int pa_input_counter;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int dump_data = 1;
|
static int dump_data = 1;
|
||||||
static int count_sent = 0;
|
static int count_sent = 0;
|
||||||
static int count_received = 0;
|
static int count_received = 0;
|
||||||
static int negotiated_codec = -1;
|
static int negotiated_codec = -1;
|
||||||
static int phase = 0;
|
|
||||||
static int num_audio_frames = 0;
|
|
||||||
|
|
||||||
static btstack_sbc_decoder_state_t decoder_state;
|
btstack_sbc_decoder_state_t decoder_state;
|
||||||
static btstack_cvsd_plc_state_t cvsd_plc_state;
|
btstack_cvsd_plc_state_t cvsd_plc_state;
|
||||||
static int num_samples_to_write;
|
|
||||||
|
|
||||||
FILE * msbc_file_in;
|
FILE * msbc_file_in;
|
||||||
FILE * msbc_file_out;
|
FILE * msbc_file_out;
|
||||||
|
|
||||||
|
int num_samples_to_write;
|
||||||
|
int num_audio_frames;
|
||||||
|
int phase;
|
||||||
|
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||||
|
|
||||||
// input signal: pre-computed sine wave, 160 Hz at 16000 kHz
|
// input signal: pre-computed sine wave, 160 Hz at 16000 kHz
|
||||||
@ -146,7 +163,7 @@ static void sco_demo_sine_wave_int16_at_8000_hz(int num_samples, int16_t * data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sco_demo_fill_audio_frame(void){
|
static void sco_demo_msbc_fill_sine_audio_frame(void){
|
||||||
if (!hfp_msbc_can_encode_audio_frame_now()) return;
|
if (!hfp_msbc_can_encode_audio_frame_now()) return;
|
||||||
int num_samples = hfp_msbc_num_audio_samples_per_frame();
|
int num_samples = hfp_msbc_num_audio_samples_per_frame();
|
||||||
int16_t sample_buffer[num_samples];
|
int16_t sample_buffer[num_samples];
|
||||||
@ -154,8 +171,8 @@ static void sco_demo_fill_audio_frame(void){
|
|||||||
hfp_msbc_encode_audio_frame(sample_buffer);
|
hfp_msbc_encode_audio_frame(sample_buffer);
|
||||||
num_audio_frames++;
|
num_audio_frames++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SCO_WAV_FILENAME
|
|
||||||
#ifdef USE_PORTAUDIO
|
#ifdef USE_PORTAUDIO
|
||||||
static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
|
static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
|
||||||
unsigned long framesPerBuffer,
|
unsigned long framesPerBuffer,
|
||||||
@ -167,6 +184,8 @@ static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
|
|||||||
(void) inputBuffer;
|
(void) inputBuffer;
|
||||||
(void) userData;
|
(void) userData;
|
||||||
|
|
||||||
|
// output part
|
||||||
|
|
||||||
// config based on codec
|
// config based on codec
|
||||||
int bytes_to_copy;
|
int bytes_to_copy;
|
||||||
int prebuffer_bytes;
|
int prebuffer_bytes;
|
||||||
@ -186,62 +205,74 @@ static int portaudio_callback( const void *inputBuffer, void *outputBuffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fill with silence while paused
|
// fill with silence while paused
|
||||||
if (pa_stream_paused){
|
if (pa_output_paused){
|
||||||
if (btstack_ring_buffer_bytes_available(&ring_buffer) < prebuffer_bytes){
|
if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){
|
||||||
memset(outputBuffer, 0, bytes_to_copy);
|
memset(outputBuffer, 0, bytes_to_copy);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// resume playback
|
// resume playback
|
||||||
pa_stream_paused = 0;
|
pa_output_paused = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get data from ringbuffer
|
// get data from ringbuffer
|
||||||
uint32_t bytes_read = 0;
|
uint32_t bytes_read = 0;
|
||||||
btstack_ring_buffer_read(&ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
|
btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read);
|
||||||
bytes_to_copy -= bytes_read;
|
bytes_to_copy -= bytes_read;
|
||||||
|
|
||||||
// fill with 0 if not enough
|
// fill with 0 if not enough
|
||||||
if (bytes_to_copy){
|
if (bytes_to_copy){
|
||||||
memset(outputBuffer + bytes_read, 0, bytes_to_copy);
|
memset(outputBuffer + bytes_read, 0, bytes_to_copy);
|
||||||
pa_stream_paused = 1;
|
pa_output_paused = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
// end of output part
|
||||||
}
|
|
||||||
|
|
||||||
static void portaudio_start(void){
|
// input part -- just store in ring buffer
|
||||||
if (!pa_stream_started){
|
#ifdef USE_PORTAUDIO_INPUT
|
||||||
/* -- start stream -- */
|
btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2);
|
||||||
PaError err = Pa_StartStream(stream);
|
pa_input_counter += framesPerBuffer * 2;
|
||||||
if (err != paNoError){
|
#endif
|
||||||
printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err));
|
|
||||||
return;
|
return 0;
|
||||||
}
|
|
||||||
pa_stream_started = 1;
|
|
||||||
pa_stream_paused = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return 1 if ok
|
// return 1 if ok
|
||||||
static int portaudio_initialize(int sample_rate){
|
static int portaudio_initialize(int sample_rate){
|
||||||
PaError err;
|
PaError err;
|
||||||
PaStreamParameters outputParameters;
|
|
||||||
|
|
||||||
/* -- initialize PortAudio -- */
|
/* -- initialize PortAudio -- */
|
||||||
printf("PortAudio: Initialize\n");
|
printf("PortAudio: Initialize\n");
|
||||||
err = Pa_Initialize();
|
err = Pa_Initialize();
|
||||||
if( err != paNoError ) return 0;
|
if( err != paNoError ) return 0;
|
||||||
|
|
||||||
/* -- setup input and output -- */
|
/* -- setup input and output -- */
|
||||||
|
const PaDeviceInfo *deviceInfo;
|
||||||
|
PaStreamParameters * inputParameters = NULL;
|
||||||
|
PaStreamParameters outputParameters;
|
||||||
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
|
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
|
||||||
outputParameters.channelCount = NUM_CHANNELS;
|
outputParameters.channelCount = NUM_CHANNELS;
|
||||||
outputParameters.sampleFormat = paInt16;
|
outputParameters.sampleFormat = paInt16;
|
||||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
|
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
|
||||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
/* -- setup stream -- */
|
deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
|
||||||
|
log_info("PortAudio: Output device: %s", deviceInfo->name);
|
||||||
|
#ifdef USE_PORTAUDIO_INPUT
|
||||||
|
PaStreamParameters theInputParameters;
|
||||||
|
theInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
|
||||||
|
theInputParameters.channelCount = NUM_CHANNELS;
|
||||||
|
theInputParameters.sampleFormat = paInt16;
|
||||||
|
theInputParameters.suggestedLatency = Pa_GetDeviceInfo( theInputParameters.device )->defaultHighOutputLatency;
|
||||||
|
theInputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
inputParameters = &theInputParameters;
|
||||||
|
deviceInfo = Pa_GetDeviceInfo( inputParameters->device );
|
||||||
|
log_info("PortAudio: Input device: %s", deviceInfo->name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -- setup output stream -- */
|
||||||
printf("PortAudio: Open stream\n");
|
printf("PortAudio: Open stream\n");
|
||||||
err = Pa_OpenStream(
|
err = Pa_OpenStream(
|
||||||
&stream,
|
&pa_stream,
|
||||||
NULL, // &inputParameters,
|
inputParameters,
|
||||||
&outputParameters,
|
&outputParameters,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
0,
|
0,
|
||||||
@ -252,11 +283,54 @@ static int portaudio_initialize(int sample_rate){
|
|||||||
printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err));
|
printf("Error opening portaudio stream: \"%s\"\n", Pa_GetErrorText(err));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset(ring_buffer_storage, 0, sizeof(ring_buffer_storage));
|
memset(pa_output_ring_buffer_storage, 0, sizeof(pa_output_ring_buffer_storage));
|
||||||
btstack_ring_buffer_init(&ring_buffer, ring_buffer_storage, sizeof(ring_buffer_storage));
|
btstack_ring_buffer_init(&pa_output_ring_buffer, pa_output_ring_buffer_storage, sizeof(pa_output_ring_buffer_storage));
|
||||||
pa_stream_started = 0;
|
#ifdef USE_PORTAUDIO_INPUT
|
||||||
|
memset(pa_input_ring_buffer_storage, 0, sizeof(pa_input_ring_buffer_storage));
|
||||||
|
btstack_ring_buffer_init(&pa_input_ring_buffer, pa_input_ring_buffer_storage, sizeof(pa_input_ring_buffer_storage));
|
||||||
|
printf("PortAudio: Input buffer size %u\n", btstack_ring_buffer_bytes_free(&pa_input_ring_buffer));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -- start stream -- */
|
||||||
|
err = Pa_StartStream(pa_stream);
|
||||||
|
if (err != paNoError){
|
||||||
|
printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pa_output_started = 1;
|
||||||
|
pa_output_paused = 1;
|
||||||
|
#ifdef USE_PORTAUDIO_INPUT
|
||||||
|
pa_input_started = 1;
|
||||||
|
pa_input_paused = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void portaudio_terminate(void){
|
||||||
|
if (!pa_stream) return;
|
||||||
|
|
||||||
|
PaError err;
|
||||||
|
printf("PortAudio: Stop Stream\n");
|
||||||
|
err = Pa_StopStream(pa_stream);
|
||||||
|
if (err != paNoError){
|
||||||
|
printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("PortAudio: Close Stream\n");
|
||||||
|
err = Pa_CloseStream(pa_stream);
|
||||||
|
if (err != paNoError){
|
||||||
|
printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pa_stream = NULL;
|
||||||
|
printf("PortAudio: Terminate\n");
|
||||||
|
err = Pa_Terminate();
|
||||||
|
if (err != paNoError){
|
||||||
|
printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -266,8 +340,7 @@ static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, i
|
|||||||
|
|
||||||
// printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
|
// printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels);
|
||||||
#ifdef HAVE_PORTAUDIO
|
#ifdef HAVE_PORTAUDIO
|
||||||
portaudio_start();
|
btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
|
||||||
btstack_ring_buffer_write(&ring_buffer, (uint8_t *)data, num_samples*num_channels*2);
|
|
||||||
#else
|
#else
|
||||||
UNUSED(num_channels);
|
UNUSED(num_channels);
|
||||||
#endif
|
#endif
|
||||||
@ -293,12 +366,15 @@ static void sco_demo_init_mSBC(void){
|
|||||||
num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
|
num_samples_to_write = MSBC_SAMPLE_RATE * SCO_WAV_DURATION_IN_SECONDS;
|
||||||
|
|
||||||
hfp_msbc_init();
|
hfp_msbc_init();
|
||||||
sco_demo_fill_audio_frame();
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||||
|
sco_demo_msbc_fill_sine_audio_frame();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SCO_MSBC_IN_FILENAME
|
#ifdef SCO_MSBC_IN_FILENAME
|
||||||
msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
|
msbc_file_in = fopen(SCO_MSBC_IN_FILENAME, "wb");
|
||||||
printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
|
printf("SCO Demo: creating mSBC in file %s, %p\n", SCO_MSBC_IN_FILENAME, msbc_file_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SCO_MSBC_OUT_FILENAME
|
#ifdef SCO_MSBC_OUT_FILENAME
|
||||||
msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
|
msbc_file_out = fopen(SCO_MSBC_OUT_FILENAME, "wb");
|
||||||
printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
|
printf("SCO Demo: creating mSBC out file %s, %p\n", SCO_MSBC_OUT_FILENAME, msbc_file_out);
|
||||||
@ -356,50 +432,26 @@ static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){
|
|||||||
sco_demo_close();
|
sco_demo_close();
|
||||||
}
|
}
|
||||||
#ifdef USE_PORTAUDIO
|
#ifdef USE_PORTAUDIO
|
||||||
portaudio_start();
|
btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
|
||||||
btstack_ring_buffer_write(&ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sco_demo_close(void){
|
void sco_demo_close(void){
|
||||||
printf("SCO demo close\n");
|
printf("SCO demo close\n");
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
|
||||||
|
|
||||||
#if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
|
#if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
|
||||||
wav_writer_close();
|
wav_writer_close();
|
||||||
|
#endif
|
||||||
printf("SCO demo statistics: ");
|
printf("SCO demo statistics: ");
|
||||||
if (negotiated_codec == HFP_CODEC_MSBC){
|
if (negotiated_codec == HFP_CODEC_MSBC){
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_PORTAUDIO
|
#ifdef HAVE_PORTAUDIO
|
||||||
if (pa_stream_started){
|
portaudio_terminate();
|
||||||
printf("PortAudio: Stop Stream\n");
|
|
||||||
PaError err = Pa_StopStream(stream);
|
|
||||||
if (err != paNoError){
|
|
||||||
printf("Error stopping the stream: \"%s\"\n", Pa_GetErrorText(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pa_stream_started = 0;
|
|
||||||
printf("PortAudio: Close Stream\n");
|
|
||||||
err = Pa_CloseStream(stream);
|
|
||||||
if (err != paNoError){
|
|
||||||
printf("Error closing the stream: \"%s\"\n", Pa_GetErrorText(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("PortAudio: Terminate\n");
|
|
||||||
err = Pa_Terminate();
|
|
||||||
if (err != paNoError){
|
|
||||||
printf("Error terminating portaudio: \"%s\"\n", Pa_GetErrorText(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SCO_WAV_FILENAME
|
#ifdef SCO_WAV_FILENAME
|
||||||
@ -424,7 +476,7 @@ void sco_demo_close(void){
|
|||||||
void sco_demo_set_codec(uint8_t codec){
|
void sco_demo_set_codec(uint8_t codec){
|
||||||
if (negotiated_codec == codec) return;
|
if (negotiated_codec == codec) return;
|
||||||
negotiated_codec = codec;
|
negotiated_codec = codec;
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
|
||||||
#if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
|
#if defined(SCO_WAV_FILENAME) || defined(SCO_SBC_FILENAME)
|
||||||
if (negotiated_codec == HFP_CODEC_MSBC){
|
if (negotiated_codec == HFP_CODEC_MSBC){
|
||||||
sco_demo_init_mSBC();
|
sco_demo_init_mSBC();
|
||||||
@ -436,8 +488,10 @@ void sco_demo_set_codec(uint8_t codec){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sco_demo_init(void){
|
void sco_demo_init(void){
|
||||||
|
|
||||||
// status
|
// status
|
||||||
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
|
||||||
|
printf("SCO Demo: Sending and receiving audio via portaudio.\n");
|
||||||
|
#endif
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||||
#ifdef HAVE_PORTAUDIO
|
#ifdef HAVE_PORTAUDIO
|
||||||
printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
|
printf("SCO Demo: Sending sine wave, audio output via portaudio.\n");
|
||||||
@ -452,7 +506,7 @@ void sco_demo_init(void){
|
|||||||
printf("SCO Demo: Sending counter value, hexdump received data.\n");
|
printf("SCO Demo: Sending counter value, hexdump received data.\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
|
||||||
hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD
|
hci_set_sco_voice_setting(0x60); // linear, unsigned, 16-bit, CVSD
|
||||||
#else
|
#else
|
||||||
hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent
|
hci_set_sco_voice_setting(0x03); // linear, unsigned, 8-bit, transparent
|
||||||
@ -479,7 +533,6 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
|||||||
uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
|
uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
||||||
if (negotiated_codec == HFP_CODEC_MSBC){
|
if (negotiated_codec == HFP_CODEC_MSBC){
|
||||||
|
|
||||||
// overwrite
|
// overwrite
|
||||||
sco_payload_length = 24;
|
sco_payload_length = 24;
|
||||||
sco_packet_length = sco_payload_length + 3;
|
sco_packet_length = sco_payload_length + 3;
|
||||||
@ -493,12 +546,91 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
|||||||
fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
|
fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
sco_demo_fill_audio_frame();
|
sco_demo_msbc_fill_sine_audio_frame();
|
||||||
} else {
|
} else {
|
||||||
const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
|
const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;
|
||||||
sco_demo_sine_wave_int16_at_8000_hz(audio_samples_per_packet, (int16_t *) (sco_packet+3));
|
sco_demo_sine_wave_int16_at_8000_hz(audio_samples_per_packet, (int16_t *) (sco_packet+3));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE
|
||||||
|
|
||||||
|
#ifdef HAVE_PORTAUDIO
|
||||||
|
if (negotiated_codec == HFP_CODEC_MSBC){
|
||||||
|
// MSBC
|
||||||
|
|
||||||
|
// overwrite
|
||||||
|
sco_payload_length = 24;
|
||||||
|
sco_packet_length = sco_payload_length + 3;
|
||||||
|
|
||||||
|
if (pa_input_paused){
|
||||||
|
if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
|
||||||
|
// resume sending
|
||||||
|
pa_input_paused = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_input_paused){
|
||||||
|
int num_samples = hfp_msbc_num_audio_samples_per_frame();
|
||||||
|
if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){
|
||||||
|
int16_t sample_buffer[num_samples];
|
||||||
|
uint32_t bytes_read;
|
||||||
|
btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read);
|
||||||
|
hfp_msbc_encode_audio_frame(sample_buffer);
|
||||||
|
num_audio_frames++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
|
||||||
|
log_error("mSBC stream should not be empty.");
|
||||||
|
memset(sco_packet + 3, 0, sco_payload_length);
|
||||||
|
pa_input_paused = 1;
|
||||||
|
} else {
|
||||||
|
hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
|
||||||
|
if (msbc_file_out){
|
||||||
|
// log outgoing mSBC data for testing
|
||||||
|
fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// CVSD
|
||||||
|
|
||||||
|
log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter);
|
||||||
|
// fill with silence while paused
|
||||||
|
int bytes_to_copy = sco_payload_length;
|
||||||
|
if (pa_input_paused){
|
||||||
|
if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
|
||||||
|
// resume sending
|
||||||
|
pa_input_paused = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get data from ringbuffer
|
||||||
|
uint16_t pos = 0;
|
||||||
|
if (!pa_input_paused){
|
||||||
|
uint32_t bytes_read = 0;
|
||||||
|
btstack_ring_buffer_read(&pa_input_ring_buffer, sco_packet + 3, bytes_to_copy, &bytes_read);
|
||||||
|
bytes_to_copy -= bytes_read;
|
||||||
|
pos += bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill with 0 if not enough
|
||||||
|
if (bytes_to_copy){
|
||||||
|
memset(sco_packet + 3 + pos, 0, bytes_to_copy);
|
||||||
|
pa_input_paused = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// just send '0's
|
||||||
|
if (negotiated_codec == HFP_CODEC_MSBC){
|
||||||
|
sco_payload_length = 24;
|
||||||
|
sco_packet_length = sco_payload_length + 3;
|
||||||
|
}
|
||||||
|
memset(sco_packet + 3, 0, sco_payload_length);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
|
#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
|
||||||
memset(&sco_packet[3], phase++, sco_payload_length);
|
memset(&sco_packet[3], phase++, sco_payload_length);
|
||||||
if (phase > 'z') phase = 'a';
|
if (phase > 'z') phase = 'a';
|
||||||
@ -526,6 +658,9 @@ void sco_demo_send(hci_con_handle_t sco_handle){
|
|||||||
(void) phase;
|
(void) phase;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// test silence
|
||||||
|
// memset(sco_packet+3, 0, sco_payload_length);
|
||||||
|
|
||||||
// set handle + flags
|
// set handle + flags
|
||||||
little_endian_store_16(sco_packet, 0, sco_handle);
|
little_endian_store_16(sco_packet, 0, sco_handle);
|
||||||
// set len
|
// set len
|
||||||
@ -573,20 +708,18 @@ void sco_demo_receive(uint8_t * packet, uint16_t size){
|
|||||||
packets = 0;
|
packets = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
|
#if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE)
|
||||||
#ifdef SCO_WAV_FILENAME
|
|
||||||
switch (negotiated_codec){
|
switch (negotiated_codec){
|
||||||
case HFP_CODEC_MSBC:
|
case HFP_CODEC_MSBC:
|
||||||
sco_demo_receive_mSBC(packet, size);
|
sco_demo_receive_mSBC(packet, size);
|
||||||
break;
|
break;
|
||||||
case HFP_CODEC_CVSD:
|
case HFP_CODEC_CVSD:
|
||||||
sco_demo_receive_CVSD(packet, size);
|
sco_demo_receive_CVSD(packet, size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dump_data = 0;
|
dump_data = 0;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (packet[1] & 0x30){
|
if (packet[1] & 0x30){
|
||||||
|
@ -42,8 +42,10 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "btstack_ring_buffer.h"
|
#include "btstack_ring_buffer.h"
|
||||||
|
#include "btstack_util.h"
|
||||||
|
|
||||||
#define ERROR_CODE_MEMORY_CAPACITY_EXCEEDED 0x07
|
#define ERROR_CODE_MEMORY_CAPACITY_EXCEEDED 0x07
|
||||||
|
|
||||||
@ -79,15 +81,27 @@ int btstack_ring_buffer_write(btstack_ring_buffer_t * ring_buffer, uint8_t * dat
|
|||||||
if (btstack_ring_buffer_bytes_free(ring_buffer) < data_length){
|
if (btstack_ring_buffer_bytes_free(ring_buffer) < data_length){
|
||||||
return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
|
return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
|
||||||
}
|
}
|
||||||
int count = 0;
|
|
||||||
while (count < data_length){
|
// copy first chunk
|
||||||
if (ring_buffer->last_written_index < ring_buffer->size - 1){
|
unsigned int bytes_until_end = ring_buffer->size - ring_buffer->last_written_index;
|
||||||
ring_buffer->last_written_index++;
|
unsigned int bytes_to_copy = btstack_min(bytes_until_end, data_length);
|
||||||
} else {
|
memcpy(&ring_buffer->storage[ring_buffer->last_written_index], data, bytes_to_copy);
|
||||||
ring_buffer->last_written_index = 0;
|
data_length -= bytes_to_copy;
|
||||||
}
|
data += bytes_to_copy;
|
||||||
ring_buffer->storage[ring_buffer->last_written_index] = data[count++];
|
|
||||||
|
// update last written index
|
||||||
|
ring_buffer->last_written_index += bytes_to_copy;
|
||||||
|
if (ring_buffer->last_written_index == ring_buffer->size){
|
||||||
|
ring_buffer->last_written_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy second chunk
|
||||||
|
if (data_length) {
|
||||||
|
memcpy(&ring_buffer->storage[0], data, data_length);
|
||||||
|
ring_buffer->last_written_index += data_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark buffer as full
|
||||||
if (ring_buffer->last_written_index == ring_buffer->last_read_index){
|
if (ring_buffer->last_written_index == ring_buffer->last_read_index){
|
||||||
ring_buffer->full = 1;
|
ring_buffer->full = 1;
|
||||||
}
|
}
|
||||||
@ -96,20 +110,30 @@ int btstack_ring_buffer_write(btstack_ring_buffer_t * ring_buffer, uint8_t * dat
|
|||||||
|
|
||||||
// fetch data_length bytes from ring buffer
|
// fetch data_length bytes from ring buffer
|
||||||
void btstack_ring_buffer_read(btstack_ring_buffer_t * ring_buffer, uint8_t * data, uint32_t data_length, uint32_t * number_of_bytes_read){
|
void btstack_ring_buffer_read(btstack_ring_buffer_t * ring_buffer, uint8_t * data, uint32_t data_length, uint32_t * number_of_bytes_read){
|
||||||
uint32_t count = 0;
|
// limit data to get and report
|
||||||
while (count < data_length && btstack_ring_buffer_bytes_available(ring_buffer)){
|
data_length = btstack_min(data_length, btstack_ring_buffer_bytes_available(ring_buffer));
|
||||||
if (ring_buffer->last_read_index < ring_buffer->last_written_index ) {
|
*number_of_bytes_read = data_length;
|
||||||
ring_buffer->last_read_index++;
|
|
||||||
} else {
|
// copy first chunk
|
||||||
if (ring_buffer->last_read_index < ring_buffer->size - 1){
|
unsigned int bytes_until_end = ring_buffer->size - ring_buffer->last_read_index;
|
||||||
ring_buffer->last_read_index++;
|
unsigned int bytes_to_copy = btstack_min(bytes_until_end, data_length);
|
||||||
} else {
|
memcpy(data, &ring_buffer->storage[ring_buffer->last_read_index], bytes_to_copy);
|
||||||
ring_buffer->last_read_index = 0;
|
data_length -= bytes_to_copy;
|
||||||
}
|
data += bytes_to_copy;
|
||||||
}
|
|
||||||
ring_buffer->full = 0;
|
// update last read index
|
||||||
data[count++] = ring_buffer->storage[ring_buffer->last_read_index];
|
ring_buffer->last_read_index += bytes_to_copy;
|
||||||
|
if (ring_buffer->last_read_index == ring_buffer->size){
|
||||||
|
ring_buffer->last_read_index = 0;
|
||||||
}
|
}
|
||||||
*number_of_bytes_read = count;
|
|
||||||
|
// copy second chunk
|
||||||
|
if (data_length) {
|
||||||
|
memcpy(data, &ring_buffer->storage[0], data_length);
|
||||||
|
ring_buffer->last_read_index += data_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear full flag
|
||||||
|
ring_buffer->full = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,7 +650,7 @@ static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
|
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
|
||||||
log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command);
|
// log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command);
|
||||||
if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
switch(hfp_connection->command){
|
switch(hfp_connection->command){
|
||||||
@ -1641,7 +1641,7 @@ static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_
|
|||||||
|
|
||||||
static void hfp_run_for_context(hfp_connection_t *hfp_connection){
|
static void hfp_run_for_context(hfp_connection_t *hfp_connection){
|
||||||
|
|
||||||
log_info("hfp_run_for_context %p", hfp_connection);
|
// log_info("hfp_run_for_context %p", hfp_connection);
|
||||||
|
|
||||||
if (!hfp_connection) return;
|
if (!hfp_connection) return;
|
||||||
|
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
#include "CppUTest/TestHarness.h"
|
#include "CppUTest/TestHarness.h"
|
||||||
#include "CppUTest/CommandLineTestRunner.h"
|
#include "CppUTest/CommandLineTestRunner.h"
|
||||||
#include "btstack_ring_buffer.h"
|
#include "btstack_ring_buffer.h"
|
||||||
|
#include "btstack_util.h"
|
||||||
|
|
||||||
static uint8_t storage[10];
|
static uint8_t storage[10];
|
||||||
|
|
||||||
|
uint32_t btstack_min(uint32_t a, uint32_t b){
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_GROUP(RingBuffer){
|
TEST_GROUP(RingBuffer){
|
||||||
btstack_ring_buffer_t ring_buffer;
|
btstack_ring_buffer_t ring_buffer;
|
||||||
int storage_size;
|
int storage_size;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user