static void initialize_sbc_encoder(void){ printf("streaming_context: block length %d, subbands %d, allocation_method %d, sampling_frequency %d, max_bitpool_value %d, channel_mode %d\n", sc.block_length, sc.subbands, sc.allocation_method, sc.sampling_frequency, sc.max_bitpool_value, sc.channel_mode); btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD, sc.block_length, sc.subbands, sc.allocation_method, sc.sampling_frequency, sc.max_bitpool_value, sc.channel_mode); }
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); uint8_t signal_identifier; uint8_t status; uint8_t local_seid; uint8_t remote_seid; uint16_t cid; bd_addr_t address; if (packet_type != HCI_EVENT_PACKET) return; if (hci_event_packet_get_type(packet) != HCI_EVENT_AVDTP_META) return; switch (packet[2]){ case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: avdtp_subevent_signaling_connection_established_get_bd_addr(packet, sc.remote_addr); cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet); status = avdtp_subevent_signaling_connection_established_get_status(packet); if (status != 0){ log_info("AVDTP_SUBEVENT_SIGNALING_CONNECTION failed status %d ---", status); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, status); break; } sc.active_remote_sep = NULL; next_remote_sep_index_to_query = 0; if (!sc.local_stream_endpoint) { app_state = A2DP_CONNECTED; uint8_t event[11]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED; little_endian_store_16(event, pos, cid); pos += 2; reverse_bd_addr(event+pos, sc.remote_addr); pos += 6; (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); return; } app_state = A2DP_W2_DISCOVER_SEPS; avdtp_source_discover_stream_endpoints(cid); break; case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND: break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{ if (!sc.local_stream_endpoint) { // printf("local seid %d \n", avdtp_subevent_signaling_media_codec_sbc_capability_get_local_seid(packet)); return; } uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet)); uint8_t channel_mode = avdtp_choose_sbc_channel_mode(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet)); uint8_t block_length = avdtp_choose_sbc_block_length(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet)); uint8_t subbands = avdtp_choose_sbc_subbands(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet)); uint8_t allocation_method = avdtp_choose_sbc_allocation_method(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet)); uint8_t max_bitpool_value = avdtp_choose_sbc_max_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet)); uint8_t min_bitpool_value = avdtp_choose_sbc_min_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet)); sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[0] = (sampling_frequency << 4) | channel_mode; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[1] = (block_length << 4) | (subbands << 2) | allocation_method; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[2] = min_bitpool_value; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[3] = max_bitpool_value; sc.local_stream_endpoint->remote_configuration_bitmap = store_bit16(sc.local_stream_endpoint->remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1); sc.local_stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC; app_state = A2DP_W2_SET_CONFIGURATION; break; } case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY: log_info("received non SBC codec. not implemented"); break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ // TODO check cid sc.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); sc.block_length = avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); sc.subbands = avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); sc.allocation_method = avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet) - 1; sc.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); sc.channel_mode = avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); // TODO: deal with reconfigure: avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); break; } case AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: cid = avdtp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(packet); a2dp_streaming_emit_can_send_media_packet_now(a2dp_source_context.a2dp_callback, cid, 0); break; case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED: avdtp_subevent_streaming_connection_established_get_bd_addr(packet, address); status = avdtp_subevent_streaming_connection_established_get_status(packet); cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet); remote_seid = avdtp_subevent_streaming_connection_established_get_remote_seid(packet); local_seid = avdtp_subevent_streaming_connection_established_get_local_seid(packet); if (status != 0){ log_info("AVDTP_SUBEVENT_STREAMING_CONNECTION could not be established, status %d ---", status); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, address, local_seid, remote_seid, status); break; } app_state = A2DP_STREAMING_OPENED; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, address, local_seid, remote_seid, 0); log_info("AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED --- avdtp_cid 0x%02x, local seid %d, remote seid %d", cid, local_seid, remote_seid); break; case AVDTP_SUBEVENT_SIGNALING_ACCEPT: // TODO check cid signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet); log_info("Accepted %d", signal_identifier); switch (app_state){ case A2DP_W2_DISCOVER_SEPS: app_state = A2DP_W2_GET_ALL_CAPABILITIES; sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++); if (!sc.active_remote_sep) { app_state = A2DP_IDLE; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); break; } // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); break; case A2DP_W2_GET_CAPABILITIES: case A2DP_W2_GET_ALL_CAPABILITIES: if (next_remote_sep_index_to_query < avdtp_source_remote_seps_num(cid)){ sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++); // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); } else { // printf("No more remote seps found\n"); app_state = A2DP_IDLE; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); } break; case A2DP_W2_SET_CONFIGURATION:{ if (!sc.local_stream_endpoint) return; app_state = A2DP_W2_GET_CONFIGURATION; avdtp_source_set_configuration(cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid, sc.local_stream_endpoint->remote_configuration_bitmap, sc.local_stream_endpoint->remote_configuration); break; } case A2DP_W2_GET_CONFIGURATION: app_state = A2DP_W2_OPEN_STREAM_WITH_SEID; avdtp_source_get_configuration(cid, sc.active_remote_sep->seid); break; case A2DP_W2_OPEN_STREAM_WITH_SEID:{ app_state = A2DP_W4_OPEN_STREAM_WITH_SEID; btstack_sbc_encoder_init(&sc.sbc_encoder_state, SBC_MODE_STANDARD, sc.block_length, sc.subbands, sc.allocation_method, sc.sampling_frequency, sc.max_bitpool_value, sc.channel_mode); avdtp_source_open_stream(cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid); break; } case A2DP_STREAMING_OPENED: if (!a2dp_source_context.a2dp_callback) return; switch (signal_identifier){ case AVDTP_SI_START:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_STARTED; little_endian_store_16(event, pos, cid); pos += 2; event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SI_SUSPEND:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_SUSPENDED; little_endian_store_16(event, pos, cid); pos += 2; event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SI_ABORT: case AVDTP_SI_CLOSE:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_STOPPED; little_endian_store_16(event, pos, cid); pos += 2; log_info("send A2DP_SUBEVENT_STREAM_RELEASED to app"); event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } default: break; } break; default: app_state = A2DP_IDLE; break; } break; case AVDTP_SUBEVENT_SIGNALING_REJECT: app_state = A2DP_IDLE; signal_identifier = avdtp_subevent_signaling_reject_get_signal_identifier(packet); log_info("Rejected %d", signal_identifier); break; case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT: app_state = A2DP_IDLE; signal_identifier = avdtp_subevent_signaling_general_reject_get_signal_identifier(packet); log_info("Rejected %d", signal_identifier); break; case AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:{ app_state = A2DP_IDLE; uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED; little_endian_store_16(event, pos, avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet)); pos += 2; event[pos++] = avdtp_subevent_streaming_connection_released_get_local_seid(packet); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED:{ app_state = A2DP_IDLE; uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_RELEASED; little_endian_store_16(event, pos, avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet)); pos += 2; event[pos++] = avdtp_subevent_streaming_connection_released_get_local_seid(packet); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } default: app_state = A2DP_IDLE; log_info("not implemented"); break; } }