/** * @brief Process received data */ void sco_demo_receive(uint8_t * packet, uint16_t size){ int dump_data = 1; count_received++; // if ((count_received % SCO_REPORT_PERIOD) == 0) sco_report(); #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE #ifdef SCO_WAV_FILENAME if (num_samples_to_write){ const int num_samples = size - 3; const int samples_to_write = btstack_min(num_samples, num_samples_to_write); // convert 8 bit signed to 8 bit unsigned int i; for (i=0;i<samples_to_write;i++){ packet[3+i] += 128; } write_wav_data_uint8(wav_file, samples_to_write, &packet[3]); num_samples_to_write -= samples_to_write; if (num_samples_to_write == 0){ printf("SCO Demo: closing wav file\n"); fclose(wav_file); } dump_data = 0; } #endif #endif if (packet[1] & 0xf0){ printf("SCO CRC Error: %x - data: ", packet[1] >> 4); printf_hexdump(&packet[3], size-3); return; }
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 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 }
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); UNUSED(channel); UNUSED(size); uint16_t mtu; switch(state){ case TC_W4_SERVICE_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: // store service (we expect only one) gatt_event_service_query_result_get_service(packet, &le_streamer_service); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // service query complete, look for characteristic state = TC_W4_CHARACTERISTIC_RX_RESULT; printf("Search for LE Streamer RX characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_streamer_service, le_streamer_characteristic_rx_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_RX_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &le_streamer_characteristic_rx); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // rx characteristiic found, look for tx characteristic state = TC_W4_CHARACTERISTIC_TX_RESULT; printf("Search for LE Streamer TX characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_streamer_service, le_streamer_characteristic_tx_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_TX_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &le_streamer_characteristic_tx); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // register handler for notifications listener_registered = 1; gatt_client_listen_for_characteristic_value_updates(¬ification_listener, handle_gatt_client_event, connection_handle, &le_streamer_characteristic_tx); // setup tracking le_streamer_connection.name = 'A'; le_streamer_connection.test_data_len = ATT_DEFAULT_MTU - 3; test_reset(&le_streamer_connection); gatt_client_get_mtu(connection_handle, &mtu); le_streamer_connection.test_data_len = btstack_min(mtu - 3, sizeof(le_streamer_connection.test_data)); printf("%c: ATT MTU = %u => use test data of len %u\n", le_streamer_connection.name, mtu, le_streamer_connection.test_data_len); // enable notifications #if (TEST_MODE & TEST_MODE_ENABLE_NOTIFICATIONS) printf("Start streaming - enable notify on test characteristic.\n"); state = TC_W4_ENABLE_NOTIFICATIONS_COMPLETE; gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &le_streamer_characteristic_tx, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; #endif state = TC_W4_TEST_DATA; #if (TEST_MODE & TEST_MODE_WRITE_WITHOUT_RESPONSE) printf("Start streaming - request can send now.\n"); gatt_client_request_can_write_without_response_event(handle_gatt_client_event, connection_handle); #endif break; default: break; } break; case TC_W4_ENABLE_NOTIFICATIONS_COMPLETE: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_QUERY_COMPLETE: printf("Notifications enabled, status %02x\n", gatt_event_query_complete_get_status(packet)); state = TC_W4_TEST_DATA; #if (TEST_MODE & TEST_MODE_WRITE_WITHOUT_RESPONSE) printf("Start streaming - request can send now.\n"); gatt_client_request_can_write_without_response_event(handle_gatt_client_event, connection_handle); #endif break; default: break; } break; case TC_W4_TEST_DATA: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_NOTIFICATION: test_track_data(&le_streamer_connection, gatt_event_notification_get_value_length(packet)); break; case GATT_EVENT_QUERY_COMPLETE: break; case GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE: streamer(&le_streamer_connection); break; default: printf("Unknown packet type %x\n", hci_event_packet_get_type(packet)); break; } break; default: printf("error\n"); break; } }