Esempio n. 1
0
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; 
    }
}
Esempio n. 2
0
static void stdin_process(char cmd){
    uint8_t status = ERROR_CODE_SUCCESS;
    is_cmd_triggered_localy = 1;
    switch (cmd){
        case 'c':
            printf("Establish AVDTP Source connection to %s\n", device_addr_string);
            status = avdtp_source_connect(device_addr, &media_tracker.avdtp_cid);
            break;
        case 'C':
            printf("Disconnect AVDTP Source\n");
            status = avdtp_source_disconnect(media_tracker.avdtp_cid);
            break;
        case 'd':
            printf("Discover stream endpoints of %s\n", device_addr_string);
            status = avdtp_source_discover_stream_endpoints(media_tracker.avdtp_cid);
            break;
        case 'g':
            printf("Get capabilities of stream endpoint with seid %d\n", media_tracker.remote_seid);
            status = avdtp_source_get_capabilities(media_tracker.avdtp_cid, media_tracker.remote_seid);
            break;
        case 'a':
            printf("Get all capabilities of stream endpoint with seid %d\n", media_tracker.remote_seid);
            status = avdtp_source_get_all_capabilities(media_tracker.avdtp_cid, media_tracker.remote_seid);
            break;
        case 'f':
            printf("Get configuration of stream endpoint with seid %d\n", media_tracker.remote_seid);
            status = avdtp_source_get_configuration(media_tracker.avdtp_cid, media_tracker.remote_seid);
            break;
        case 's':
            printf("Set configuration of stream endpoint with seid %d\n", media_tracker.remote_seid);
            remote_configuration_bitmap = store_bit16(remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1);
            remote_configuration.media_codec.media_type = AVDTP_AUDIO;
            remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
            remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_configuration);
            remote_configuration.media_codec.media_codec_information = (uint8_t *)media_sbc_codec_configuration;

            initialize_streaming_context(media_sbc_codec_configuration);
            status = avdtp_source_set_configuration(media_tracker.avdtp_cid, media_tracker.local_seid, media_tracker.remote_seid, remote_configuration_bitmap, remote_configuration);
            break;
        case 'R':
            printf("Reconfigure stream endpoint with seid %d\n", media_tracker.remote_seid);
            remote_configuration_bitmap = store_bit16(remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1);
            remote_configuration.media_codec.media_type = AVDTP_AUDIO;
            remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
            remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_reconfiguration);
            remote_configuration.media_codec.media_codec_information = (uint8_t *)media_sbc_codec_reconfiguration;
            
            initialize_streaming_context(media_sbc_codec_reconfiguration);
            status = avdtp_source_reconfigure(media_tracker.avdtp_cid, media_tracker.local_seid, media_tracker.remote_seid, remote_configuration_bitmap, remote_configuration);
            break;
        case 'o':
            printf("Establish stream between local %d and remote %d seid\n", media_tracker.local_seid, media_tracker.remote_seid);
            initialize_sbc_encoder();
            status = avdtp_source_open_stream(media_tracker.avdtp_cid, media_tracker.local_seid, media_tracker.remote_seid);
            break;
        case 'm': 
            printf("Start stream between local %d and remote %d seid, \n", media_tracker.local_seid, media_tracker.remote_seid);
            status = avdtp_source_start_stream(media_tracker.avdtp_cid, media_tracker.local_seid);
            break;
        case 'A':
            printf("Abort stream between local %d and remote %d seid\n", media_tracker.local_seid, media_tracker.remote_seid);
            status = avdtp_source_abort_stream(media_tracker.avdtp_cid, media_tracker.local_seid);
            break;
        case 'S':
            printf("Release stream between local %d and remote %d seid\n", media_tracker.local_seid, media_tracker.remote_seid);
            status = avdtp_source_stop_stream(media_tracker.avdtp_cid, media_tracker.local_seid);
            break;
        case 'P':
            printf("Susspend stream between local %d and remote %d seid\n", media_tracker.local_seid, media_tracker.remote_seid);
            status = avdtp_source_suspend(media_tracker.avdtp_cid, media_tracker.local_seid);
            break;
        case 'X':
            printf("Stop streaming\n");
            status = avdtp_source_stop_stream(media_tracker.avdtp_cid, media_tracker.local_seid);
            break;
            
        case '\n':
        case '\r':
            break;
        default:
            show_usage();
            break;

    }
    if (status != ERROR_CODE_SUCCESS){
        printf("AVDTP Sink cmd \'%c\' failed, status 0x%02x\n", cmd, status);
    }
}