static int host_recv_pkt_cb(uint8_t *data, uint16_t len){ if (xPortInIsrContext()){ report_recv_called_from_isr(); return 0; } xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY); // check space uint16_t space = btstack_ring_buffer_bytes_free(&hci_ringbuffer); if (space < len){ xSemaphoreGive(ring_buffer_mutex); log_error("transport_recv_pkt_cb packet %u, space %u -> dropping packet", len, space); return 0; } // store size in ringbuffer uint8_t len_tag[2]; little_endian_store_16(len_tag, 0, len); btstack_ring_buffer_write(&hci_ringbuffer, len_tag, sizeof(len_tag)); // store in ringbuffer btstack_ring_buffer_write(&hci_ringbuffer, data, len); xSemaphoreGive(ring_buffer_mutex); // set flag and trigger delivery of packets on main thread transport_packets_to_deliver = 1; btstack_run_loop_freertos_trigger(); return 0; }
static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ UNUSED(sample_rate); UNUSED(context); #ifdef STORE_SBC_TO_WAV_FILE wav_writer_write_int16(num_samples*num_channels, data); frame_count++; #endif total_num_samples+=num_samples*num_channels; #ifdef HAVE_PORTAUDIO if (!pa_stream_started){ /* -- start stream -- */ PaError err = Pa_StartStream(stream); if (err != paNoError){ printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); return; } pa_stream_started = 1; pa_stream_paused = 1; } btstack_ring_buffer_write(&ring_buffer, (uint8_t *)data, num_samples*num_channels*2); #endif }
static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ UNUSED(context); UNUSED(sample_rate); UNUSED(data); UNUSED(num_samples); UNUSED(num_channels); #if (SCO_DEMO_MODE == SCO_DEMO_MODE_SINE) || (SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE) // printf("handle_pcm_data num samples %u, sample rate %d\n", num_samples, num_channels); #ifdef HAVE_PORTAUDIO // samples in callback in host endianess, ready for PortAudio playback btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)data, num_samples*num_channels*2); #endif /* HAVE_PORTAUDIO */ #ifdef SCO_WAV_FILENAME if (!num_samples_to_write) return; num_samples = btstack_min(num_samples, num_samples_to_write); num_samples_to_write -= num_samples; wav_writer_write_int16(num_samples, data); if (num_samples_to_write == 0){ wav_writer_close(); } #endif /* SCO_WAV_FILENAME */ #endif /* Demo mode sine or microphone */ }
static int portaudio_callback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { (void) timeInfo; /* Prevent unused variable warnings. */ (void) statusFlags; (void) inputBuffer; (void) userData; // output part // config based on codec int bytes_to_copy; uint32_t prebuffer_bytes; switch (negotiated_codec){ case HFP_CODEC_MSBC: bytes_to_copy = framesPerBuffer * MSBC_BYTES_PER_FRAME; prebuffer_bytes = MSBC_PA_PREBUFFER_BYTES; break; case HFP_CODEC_CVSD: bytes_to_copy = framesPerBuffer * CVSD_BYTES_PER_FRAME; prebuffer_bytes = CVSD_PA_PREBUFFER_BYTES; break; default: bytes_to_copy = framesPerBuffer * 2; // assume 1 channel / 16 bit audio samples prebuffer_bytes = 0xfffffff; break; } // fill with silence while paused if (pa_output_paused){ if (btstack_ring_buffer_bytes_available(&pa_output_ring_buffer) < prebuffer_bytes){ memset(outputBuffer, 0, bytes_to_copy); return 0; } else { // resume playback pa_output_paused = 0; } } // get data from ringbuffer uint32_t bytes_read = 0; btstack_ring_buffer_read(&pa_output_ring_buffer, outputBuffer, bytes_to_copy, &bytes_read); bytes_to_copy -= bytes_read; // fill with 0 if not enough if (bytes_to_copy){ memset(outputBuffer + bytes_read, 0, bytes_to_copy); pa_output_paused = 1; } // end of output part // input part -- just store in ring buffer #ifdef USE_PORTAUDIO_INPUT btstack_ring_buffer_write(&pa_input_ring_buffer, (uint8_t *)inputBuffer, framesPerBuffer * 2); pa_input_counter += framesPerBuffer * 2; #endif return 0; }
static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ UNUSED(sample_rate); UNUSED(context); #ifdef STORE_SBC_TO_WAV_FILE wav_writer_write_int16(num_samples*num_channels, data); frame_count++; #endif #ifdef HAVE_PORTAUDIO // store pcm samples in ring buffer btstack_ring_buffer_write(&ring_buffer, (uint8_t *)data, num_samples*num_channels*2); if (!audio_stream_started){ audio_stream_paused = 1; /* -- start stream -- */ PaError err = Pa_StartStream(stream); if (err != paNoError){ printf("Error starting the stream: \"%s\"\n", Pa_GetErrorText(err)); return; } audio_stream_started = 1; } #endif #ifdef HAVE_AUDIO_DMA // store in ring buffer uint8_t * write_data = start_of_buffer(write_buffer); uint16_t len = num_samples*num_channels*2; memcpy(write_data, data, len); audio_samples_len[write_buffer] = len; // add/drop audio frame to fix drift if (sbc_samples_fix > 0){ memcpy(write_data + len, write_data + len - 4, 4); audio_samples_len[write_buffer] += 4; } if (sbc_samples_fix < 0){ audio_samples_len[write_buffer] -= 4; } write_buffer = next_buffer(write_buffer); #endif }
static void fill_ring_buffer(void *userData){ paTestData *data = (paTestData*)userData; while (btstack_ring_buffer_bytes_free(&ring_buffer) > BYTES_PER_FRAME){ uint8_t write_data[BYTES_PER_FRAME]; *(int16_t*)&write_data[0] = data->sine[data->left_phase]; *(int16_t*)&write_data[2] = data->sine[data->right_phase]; btstack_ring_buffer_write(&ring_buffer, write_data, BYTES_PER_FRAME); write_wav_data((int16_t*)write_data, 1, NUM_CHANNELS, SAMPLE_RATE); data->left_phase += 1; if (data->left_phase >= TABLE_SIZE){ data->left_phase -= TABLE_SIZE; } data->right_phase += 2; /* higher pitch so we can distinguish left and right. */ if (data->right_phase >= TABLE_SIZE){ data->right_phase -= TABLE_SIZE; } } }
static void handle_l2cap_media_data_packet(uint8_t seid, uint8_t *packet, uint16_t size){ UNUSED(seid); int pos = 0; avdtp_media_packet_header_t media_header; if (!read_media_data_header(packet, size, &pos, &media_header)) return; avdtp_sbc_codec_header_t sbc_header; if (!read_sbc_header(packet, size, &pos, &sbc_header)) return; #ifdef HAVE_AUDIO_DMA // store sbc frame size for buffer management sbc_frame_size = (size-pos)/ sbc_header.num_frames; #endif #if defined(HAVE_PORTAUDIO) || defined(STORE_SBC_TO_WAV_FILE) btstack_sbc_decoder_process_data(&state, 0, packet+pos, size-pos); #endif #ifdef HAVE_AUDIO_DMA btstack_ring_buffer_write(&ring_buffer, packet+pos, size-pos); // decide on audio sync drift based on number of sbc frames in queue int sbc_frames_in_buffer = btstack_ring_buffer_bytes_available(&ring_buffer) / sbc_frame_size; if (sbc_frames_in_buffer < OPTIMAL_FRAMES_MIN){ sbc_samples_fix = 1; // duplicate last sample } else if (sbc_frames_in_buffer <= OPTIMAL_FRAMES_MAX){ sbc_samples_fix = 0; // nothing to do } else { sbc_samples_fix = -1; // drop last sample } // dump printf("%6u %03u %d\n", (int) btstack_run_loop_get_time_ms(), sbc_frames_in_buffer, sbc_samples_fix); #endif #ifdef STORE_SBC_TO_SBC_FILE fwrite(packet+pos, size-pos, 1, sbc_file); #endif }
static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ if (!num_samples_to_write) return; int16_t audio_frame_out[128]; // if (size > sizeof(audio_frame_out)){ printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); return; } #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) const int audio_bytes_read = size - 3; const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; // convert into host endian int16_t audio_frame_in[128]; int i; for (i=0;i<num_samples;i++){ audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); } btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); #endif #ifdef SCO_WAV_FILENAME // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) const int samples_to_write = btstack_min(num_samples, num_samples_to_write); wav_writer_write_le_int16(samples_to_write, audio_frame_out); num_samples_to_write -= samples_to_write; if (num_samples_to_write == 0){ wav_writer_close(); } #endif #ifdef USE_PORTAUDIO btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); #endif }