Esempio n. 1
0
static int read_sbc_header(uint8_t * packet, int size, int * offset, avdtp_sbc_codec_header_t * sbc_header){
    int sbc_header_len = 12; // without crc
    int pos = *offset;
    
    if (size - pos < sbc_header_len){
        printf("Not enough data to read SBC header, expected %d, received %d\n", sbc_header_len, size-pos);
        return 0;
    }

    sbc_header->fragmentation = get_bit16(packet[pos], 7);
    sbc_header->starting_packet = get_bit16(packet[pos], 6);
    sbc_header->last_packet = get_bit16(packet[pos], 5);
    sbc_header->num_frames = packet[pos] & 0x0f;
    pos++;
    // printf("SBC HEADER: num_frames %u, fragmented %u, start %u, stop %u\n", sbc_header.num_frames, sbc_header.fragmentation, sbc_header.starting_packet, sbc_header.last_packet);
    *offset = pos;
    return 1;
}
Esempio n. 2
0
static int read_media_data_header(uint8_t *packet, int size, int *offset, avdtp_media_packet_header_t *media_header){
    int media_header_len = 12; // without crc
    int pos = *offset;
    
    if (size - pos < media_header_len){
        printf("Not enough data to read media packet header, expected %d, received %d\n", media_header_len, size-pos);
        return 0;
    }

    media_header->version = packet[pos] & 0x03;
    media_header->padding = get_bit16(packet[pos],2);
    media_header->extension = get_bit16(packet[pos],3);
    media_header->csrc_count = (packet[pos] >> 4) & 0x0F;
    pos++;

    media_header->marker = get_bit16(packet[pos],0);
    media_header->payload_type  = (packet[pos] >> 1) & 0x7F;
    pos++;

    media_header->sequence_number = big_endian_read_16(packet, pos);
    pos+=2;

    media_header->timestamp = big_endian_read_32(packet, pos);
    pos+=4;

    media_header->synchronization_source = big_endian_read_32(packet, pos);
    pos+=4;
    *offset = pos;
    // TODO: read csrc list
    
    // printf_hexdump( packet, pos );
    if (!is_media_header_reported_once){
        is_media_header_reported_once = 1;
        printf("MEDIA HEADER: %u timestamp, version %u, padding %u, extension %u, csrc_count %u\n", 
            media_header->timestamp, media_header->version, media_header->padding, media_header->extension, media_header->csrc_count);
        printf("MEDIA HEADER: marker %02x, payload_type %02x, sequence_number %u, synchronization_source %u\n", 
            media_header->marker, media_header->payload_type, media_header->sequence_number, media_header->synchronization_source);
    }
    return 1;
}
Esempio n. 3
0
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;
    media_header.version = packet[pos] & 0x03;
    media_header.padding = get_bit16(packet[pos],2);
    media_header.extension = get_bit16(packet[pos],3);
    media_header.csrc_count = (packet[pos] >> 4) & 0x0F;

    pos++;

    media_header.marker = get_bit16(packet[pos],0);
    media_header.payload_type  = (packet[pos] >> 1) & 0x7F;
    pos++;

    media_header.sequence_number = big_endian_read_16(packet, pos);
    pos+=2;

    media_header.timestamp = big_endian_read_32(packet, pos);
    pos+=4;

    media_header.synchronization_source = big_endian_read_32(packet, pos);
    pos+=4;

    UNUSED(media_header);

    // TODO: read csrc list
    
    // printf_hexdump( packet, pos );
    // printf("MEDIA HEADER: %u timestamp, version %u, padding %u, extension %u, csrc_count %u\n", 
    //     media_header.timestamp, media_header.version, media_header.padding, media_header.extension, media_header.csrc_count);
    // printf("MEDIA HEADER: marker %02x, payload_type %02x, sequence_number %u, synchronization_source %u\n", 
    //     media_header.marker, media_header.payload_type, media_header.sequence_number, media_header.synchronization_source);
    
    avdtp_sbc_codec_header_t sbc_header;
    sbc_header.fragmentation = get_bit16(packet[pos], 7);
    sbc_header.starting_packet = get_bit16(packet[pos], 6);
    sbc_header.last_packet = get_bit16(packet[pos], 5);
    sbc_header.num_frames = packet[pos] & 0x0f;
    pos++;

    UNUSED(sbc_header);
    // printf("SBC HEADER: num_frames %u, fragmented %u, start %u, stop %u\n", sbc_header.num_frames, sbc_header.fragmentation, sbc_header.starting_packet, sbc_header.last_packet);
    // printf_hexdump( packet+pos, size-pos );
    
#ifdef DECODE_SBC
    btstack_sbc_decoder_process_data(&state, 0, packet+pos, size-pos);
#endif

#ifdef STORE_SBC_TO_SBC_FILE
    fwrite(packet+pos, size-pos, 1, sbc_file);
#endif
#ifdef HAVE_PORTAUDIO
    log_info("PA: bytes avail after recv: %d", btstack_ring_buffer_bytes_available(&ring_buffer));
#endif
}
Esempio n. 4
0
void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_t *packet, uint16_t size, int offset, avdtp_context_t * context){
    // int status = 0;
    avdtp_stream_endpoint_t * stream_endpoint = NULL;
    
    uint8_t remote_sep_index;
    avdtp_sep_t sep;
    if (connection->initiator_connection_state == AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER) {
        connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE;
    } else {
        stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(connection->remote_seid, context);
        if (!stream_endpoint){
            stream_endpoint = avdtp_stream_endpoint_with_seid(connection->local_seid, context);
        }
        if (!stream_endpoint) return;
        sep.seid = connection->remote_seid;
        
        if (stream_endpoint->initiator_config_state != AVDTP_INITIATOR_W4_ANSWER) return;
        stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
    }
    
    switch (connection->signaling_packet.message_type){
        case AVDTP_RESPONSE_ACCEPT_MSG:
            switch (connection->signaling_packet.signal_identifier){
                case AVDTP_SI_DISCOVER:{
                    if (connection->signaling_packet.transaction_label != connection->initiator_transaction_label){
                        log_info("    unexpected transaction label, got %d, expected %d", connection->signaling_packet.transaction_label, connection->initiator_transaction_label);
                        // status = BAD_HEADER_FORMAT;
                        break;
                    }
                    
                    if (size == 3){
                        log_info("    ERROR code %02x", packet[offset]);
                        break;
                    }
                    
                int i;
                    for (i = offset; i < size; i += 2){
                        sep.seid = packet[i] >> 2;
                        offset++;
                        if (sep.seid < 0x01 || sep.seid > 0x3E){
                            log_info("    invalid sep id");
                            // status = BAD_ACP_SEID;
                            break;
                        }
                        sep.in_use = (packet[i] >> 1) & 0x01;
                        sep.media_type = (avdtp_media_type_t)(packet[i+1] >> 4);
                        sep.type = (avdtp_sep_type_t)((packet[i+1] >> 3) & 0x01);

                        if (avdtp_find_remote_sep(connection, sep.seid) == 0xFF){
                            connection->remote_seps[connection->remote_seps_num++] = sep;
                        }
                        avdtp_signaling_emit_sep(context->avdtp_callback, connection->avdtp_cid, sep);
                    }
                    break;
                }
                
                case AVDTP_SI_GET_CAPABILITIES:
                case AVDTP_SI_GET_ALL_CAPABILITIES:
                    sep.registered_service_categories = avdtp_unpack_service_capabilities(connection, &sep.capabilities, packet+offset, size-offset);
                    if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
                        switch (sep.capabilities.media_codec.media_codec_type){
                            case AVDTP_CODEC_SBC: 
                                avdtp_signaling_emit_media_codec_sbc_capability(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.capabilities.media_codec);
                                break;
                            default:
                                avdtp_signaling_emit_media_codec_other_capability(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.capabilities.media_codec);
                                break;
                        }
                    }
                    break;
                
                case AVDTP_SI_GET_CONFIGURATION:
                    sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, packet+offset, size-offset);
                    if (get_bit16(sep.configured_service_categories, AVDTP_MEDIA_CODEC)){
                        switch (sep.configuration.media_codec.media_codec_type){
                            case AVDTP_CODEC_SBC: 
                                avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.configuration.media_codec);
                                break;
                            default:
                                avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid,  connection->remote_seid, sep.configuration.media_codec);
                                break;
                        }
                    }
                    break;
                
                case AVDTP_SI_RECONFIGURE:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_RECONFIGURE: stream endpoint is null");
                        break;
                    }
                    sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+4, connection->signaling_packet.size-4);
                    // TODO check if configuration is supported
                    
                    remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
                    if (remote_sep_index != 0xFF){
                        stream_endpoint->remote_sep_index = remote_sep_index;
                        connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
                        stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
                        log_info("INT: update seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
                    } 
                    break;

                case AVDTP_SI_SET_CONFIGURATION:{
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_SET_CONFIGURATION: stream endpoint is null");
                        break;
                    }
                    sep.configured_service_categories = stream_endpoint->remote_capabilities_bitmap;
                    sep.configuration = stream_endpoint->remote_capabilities;
                    sep.in_use = 1;
                    // TODO check if configuration is supported
                    
                    // find or add sep
                    remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
                    if (remote_sep_index != 0xFF){
                        stream_endpoint->remote_sep_index = remote_sep_index;
                    } else {
                        stream_endpoint->remote_sep_index = connection->remote_seps_num;
                        connection->remote_seps_num++;
                    }
                    connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
                    log_info("INT: configured remote seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
                    break;
                }
                
                case AVDTP_SI_OPEN:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_OPEN: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM) {
                        log_error("AVDTP_SI_OPEN in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED;
                    connection->local_seid = stream_endpoint->sep.seid;
                    l2cap_create_channel(context->packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL);
                    return;
                case AVDTP_SI_START:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_START: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_OPENED) {
                        log_error("AVDTP_SI_START in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
                    break;
                case AVDTP_SI_SUSPEND:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_SUSPEND: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING) {
                        log_error("AVDTP_SI_SUSPEND in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
                    break;
                case AVDTP_SI_CLOSE:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_CLOSE: stream endpoint is null");
                        break;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CLOSING;
                    break;
                case AVDTP_SI_ABORT:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_ABORT: stream endpoint is null");
                        break;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
                    break;
                default:
                    log_info("    AVDTP_RESPONSE_ACCEPT_MSG, signal %d not implemented", connection->signaling_packet.signal_identifier);
                    break;
            }
            avdtp_signaling_emit_accept(context->avdtp_callback, connection->avdtp_cid, 0, connection->signaling_packet.signal_identifier);
            connection->initiator_transaction_label++;
            break;
        case AVDTP_RESPONSE_REJECT_MSG:
            log_info("    AVDTP_RESPONSE_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
            avdtp_signaling_emit_reject(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->signaling_packet.signal_identifier);
            return;
        case AVDTP_GENERAL_REJECT_MSG:
            log_info("    AVDTP_GENERAL_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
            avdtp_signaling_emit_general_reject(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->signaling_packet.signal_identifier);
            return;
        default:
            break;
    }
}