Example #1
0
static void hal_audio_dma_process(btstack_data_source_t * ds, btstack_data_source_callback_type_t callback_type){
    UNUSED(ds);
    UNUSED(callback_type);

    if (!media_initialized) return;

    int trigger_resume = 0;
    if (audio_stream_paused) {
        if (sbc_frame_size && btstack_ring_buffer_bytes_available(&ring_buffer) >= OPTIMAL_FRAMES_MIN * sbc_frame_size){
            trigger_resume = 1;
            // reset buffers
            playback_buffer = NUM_AUDIO_BUFFERS - 1;
            write_buffer = 0;
        } else {
            return;
        }
    }

    while (playback_buffer != write_buffer && btstack_ring_buffer_bytes_available(&ring_buffer) >= sbc_frame_size ){
        uint8_t frame[MAX_SBC_FRAME_SIZE];
        uint32_t bytes_read = 0;
        btstack_ring_buffer_read(&ring_buffer, frame, sbc_frame_size, &bytes_read);
        btstack_sbc_decoder_process_data(&state, 0, frame, sbc_frame_size);
    }

    if (trigger_resume){
        printf("%6u - resume\n", (int) btstack_run_loop_get_time_ms());
        audio_stream_paused = 0;
    }
}
Example #2
0
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;
}
Example #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
}
Example #4
0
static void transport_deliver_packets(void){
    xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY);
    while (btstack_ring_buffer_bytes_available(&hci_ringbuffer)){
        uint32_t number_read;
        uint8_t len_tag[2];
        btstack_ring_buffer_read(&hci_ringbuffer, len_tag, 2, &number_read);
        uint32_t len = little_endian_read_16(len_tag, 0);
        btstack_ring_buffer_read(&hci_ringbuffer, hci_receive_buffer, len, &number_read);
        xSemaphoreGive(ring_buffer_mutex);
        transport_packet_handler(hci_receive_buffer[0], &hci_receive_buffer[1], len-1);
        xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY);
    }
    xSemaphoreGive(ring_buffer_mutex);
}
Example #5
0
static int patestCallback( 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;

    uint32_t bytes_read = 0;
    int bytes_per_buffer = framesPerBuffer * BYTES_PER_FRAME;

    if (btstack_ring_buffer_bytes_available(&ring_buffer) >= bytes_per_buffer){
        btstack_ring_buffer_read(&ring_buffer, outputBuffer, bytes_per_buffer, &bytes_read);
    } else {
        printf("NOT ENOUGH DATA!\n");
        memset(outputBuffer, 0, bytes_per_buffer);
    }
    return paContinue;
}
Example #6
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;
    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
}
Example #7
0
static int patestCallback( const void *inputBuffer, void *outputBuffer,
                           unsigned long framesPerBuffer,
                           const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags,
                           void *userData ) {

    /** patestCallback is called from different thread, don't use hci_dump / log_info here without additional checks */

    (void) timeInfo; /* Prevent unused variable warnings. */
    (void) statusFlags;
    (void) inputBuffer;
    (void) userData;
    
    int bytes_to_copy = framesPerBuffer * BYTES_PER_FRAME;

    // fill with silence while paused
    if (pa_stream_paused){

        if (btstack_ring_buffer_bytes_available(&ring_buffer) < PREBUFFER_BYTES){
            // printf("PA: silence\n");
            memset(outputBuffer, 0, bytes_to_copy);
            return 0;
        } else {
            // resume playback
            pa_stream_paused = 0;
        }
    }

    // get data from ringbuffer
    uint32_t bytes_read = 0;
    btstack_ring_buffer_read(&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_stream_paused = 1;
    }
    return 0;
}
Example #8
0
void hal_audio_dma_done(void){
    if (audio_stream_paused){
        hal_audio_dma_play((const uint8_t *) silent_buffer, DMA_AUDIO_FRAMES*4);
        return;
    }
    // next buffer
    int next_playback_buffer = next_buffer(playback_buffer);
    uint8_t * playback_data;
    if (next_playback_buffer == write_buffer){

        // TODO: stop codec while playing silence when getting 'stream paused'

        // start playing silence
        audio_stream_paused = 1;
        hal_audio_dma_play((const uint8_t *) silent_buffer, DMA_AUDIO_FRAMES*4);
        printf("%6u - paused - bytes in buffer %u\n", (int) btstack_run_loop_get_time_ms(), btstack_ring_buffer_bytes_available(&ring_buffer));
        return;
    }
    playback_buffer = next_playback_buffer;
    playback_data = start_of_buffer(playback_buffer);
    hal_audio_dma_play(playback_data, audio_samples_len[playback_buffer]);
    // btstack_run_loop_embedded_trigger();
}
Example #9
0
void sco_demo_send(hci_con_handle_t sco_handle){

    if (!sco_handle) return;
    
    int sco_packet_length = hci_get_sco_packet_length();
    int sco_payload_length = sco_packet_length - 3;

    hci_reserve_packet_buffer();
    uint8_t * sco_packet = hci_get_outgoing_packet_buffer();
#if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE
#ifdef ENABLE_HFP_WIDE_BAND_SPEECH
    if (negotiated_codec == HFP_CODEC_MSBC){
        // overwrite
        sco_payload_length = 24;
        sco_packet_length = sco_payload_length + 3;

        if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
            log_error("mSBC stream is empty.");
        }
        hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
        if (msbc_file_out){
            // log outgoing mSBC data for testing
            fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
        }

        sco_demo_msbc_fill_sine_audio_frame();
    } else
#endif
    {
        const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME;  
        sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]);
    }
#endif

#if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE

#ifdef HAVE_PORTAUDIO
    if (negotiated_codec == HFP_CODEC_MSBC){
        // MSBC

        // overwrite
        sco_payload_length = 24;
        sco_packet_length = sco_payload_length + 3;

        if (pa_input_paused){
            if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){
                // resume sending
                pa_input_paused = 0;
            }
        }

        if (!pa_input_paused){
            int num_samples = hfp_msbc_num_audio_samples_per_frame();
            if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){
                int16_t sample_buffer[num_samples];
                uint32_t bytes_read;
                btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read);
                hfp_msbc_encode_audio_frame(sample_buffer);
                num_audio_frames++;
            }
        }

        if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){
            log_error("mSBC stream should not be empty.");
            memset(sco_packet + 3, 0, sco_payload_length);
            pa_input_paused = 1;
        } else {
            hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length);
            if (msbc_file_out){
                // log outgoing mSBC data for testing
                fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out);
            }
        }

    } else {
        // CVSD

        log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter);
        // fill with silence while paused
        int bytes_to_copy = sco_payload_length;
        if (pa_input_paused){
            if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){
                // resume sending
                pa_input_paused = 0;
            }
        }

        // get data from ringbuffer
        uint16_t pos = 0;
        uint8_t * sample_data = &sco_packet[3];
        if (!pa_input_paused){
            uint32_t bytes_read = 0;
            btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read);
            // flip 16 on big endian systems
            // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems
            if (btstack_is_big_endian()){
                int i;
                for (i=0;i<bytes_read;i+=2){
                    uint8_t tmp        = sample_data[i*2];
                    sample_data[i*2]   = sample_data[i*2+1];
                    sample_data[i*2+1] = tmp;
                }
            }
            bytes_to_copy -= bytes_read;
            pos           += bytes_read;
        }

        // fill with 0 if not enough
        if (bytes_to_copy){
            memset(sample_data + pos, 0, bytes_to_copy);
            pa_input_paused = 1;
        }
    }
#else
    // just send '0's
    if (negotiated_codec == HFP_CODEC_MSBC){
        sco_payload_length = 24;
        sco_packet_length = sco_payload_length + 3;
    }
    memset(sco_packet + 3, 0, sco_payload_length);
#endif
#endif

#if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII
    memset(&sco_packet[3], phase++, sco_payload_length);
    if (phase > 'z') phase = 'a';
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER
    int j;
    for (j=0;j<sco_payload_length;j++){
        sco_packet[3+j] = phase++;
    }
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_55
    int j;
    for (j=0;j<sco_payload_length;j++){
        // sco_packet[3+j] = j & 1 ? 0x35 : 0x53;
        sco_packet[3+j] = 0x55;
    }
#endif
#if SCO_DEMO_MODE == SCO_DEMO_MODE_00
    int j;
    for (j=0;j<sco_payload_length;j++){
        sco_packet[3+j] = 0x00;
    }
    // additional hack
    // big_endian_store_16(sco_packet, 5, phase++);
    (void) phase;
#endif

    // test silence
    // memset(sco_packet+3, 0, sco_payload_length);

    // set handle + flags
    little_endian_store_16(sco_packet, 0, sco_handle);
    // set len
    sco_packet[2] = sco_payload_length;
    // finally send packet 
    hci_send_sco_packet_buffer(sco_packet_length);

    // request another send event
    hci_request_sco_can_send_now_event();

    count_sent++;
#if SCO_DEMO_MODE != SCO_DEMO_MODE_55
    if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report();
#endif
}