BLE Timing Variation While Streaming Live Microphone Data

Hi nordic,

I am streaming live microphone PCM data over BLE. The microphone data is continuously captured and stored in a buffer. Whenever 12 KB of audio data is available, I send that data over BLE to the connected device.

However, I am observing that sending the data over BLE takes a large and inconsistent amount of time.

For example, I measured the time taken by the send_data_chunk() function, which sends the data over BLE.
the api i am using is :

// Send data in 244-byte chunks
// ptr_buffer contains the live data 
// no_of_bytes is 12288 
// creating the chunk of 244 among 12288 , and sending over ble.
void send_data_chunk(struct bt_conn *conn, uint8_t *ptr_buffer, uint16_t no_of_bytes)
{
    static uint8_t first_time = 0;
    if (!conn)
    {
        printk("Error: No BLE connection.\n");
    }

    // Calculate chunk size based on negotiated MTU
    uint16_t chunk_size = 247 - 3; // MTU - ATT Header (3 bytes) //current_mtu
    if (chunk_size == 0)
    {
        printk("Error: Invalid chunk size (MTU too small).\n");
    }

    uint16_t data_sent = 0;
    int err = 0;
    uint32_t start_time = k_uptime_get_32();

    while (data_sent < no_of_bytes)
    {
        uint16_t bytes_to_send = MIN(chunk_size, no_of_bytes - data_sent);

        err = bt_gatt_notify(conn, &custom_service.attrs[DATA_NOTIFY_INDEX],
                             ptr_buffer + data_sent, bytes_to_send);

        if (err)
        {
            if (err == -ENOMEM || err == -EAGAIN)
            {
                printk("BLE notification queue full or busy (err %d). Retrying...\n", err);
                k_sleep(K_MSEC(1)); // Sleep briefly to allow BLE stack to process
                continue; // Try sending the same chunk again
            }
            else
            {
                printk("Notification failed (err %d) for chunk at offset %u.\n", err, data_sent);
                // return err; // Other error, stop sending this block
            }
        }
        data_sent += bytes_to_send;
    }

    uint32_t end_time = k_uptime_get_32();
    uint32_t diff_time = end_time - start_time;
    if (diff_time >= 10)
    {
        printk("Total send_data_chunk time for %u bytes: %u ms\n", no_of_bytes, end_time - start_time);
    }
    if (first_time == 0)
    {
        first_time = 1;
        printk("Total send_data_chunk time for %u bytes: %u ms\n", no_of_bytes, end_time - start_time);
    }
 
}

and the prj configurations i am using
CONFIG_BT=y                            
CONFIG_BT_PERIPHERAL=y                
CONFIG_BT_DEVICE_NAME="FYZKS_WDS"      
CONFIG_BT_GATT_CLIENT=y                
CONFIG_BT_ZEPHYR_NUS=y  

CONFIG_BT_USER_DATA_LEN_UPDATE=y        
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251      
CONFIG_BT_BUF_ACL_RX_SIZE=251          
CONFIG_BT_BUF_ACL_TX_SIZE=251          
CONFIG_BT_L2CAP_TX_MTU=247            
CONFIG_BT_USER_PHY_UPDATE=y            
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n


# Connection interval settings
CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6    
CONFIG_BT_PERIPHERAL_PREF_MAX_INT=8    
CONFIG_BT_PERIPHERAL_PREF_LATENCY=0  
CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=400  
CONFIG_BT_CTLR_TX_PWR_PLUS_4=y  

Below are the timing logs (internal debugging messages removed for clarity):
Total send_data_chunk time for 12288  bytes: 873 ms
Total send_data_chunk time for 12288 bytes: 887 ms
Total send_data_chunk time for 12288 bytes: 896 ms
Total send_data_chunk time for 12288 bytes: 888 ms
Total send_data_chunk time for 12288 bytes: 903 ms

From these logs, I observe:

  • Sending 12 KB of data takes around 880–900 ms

  • the timing is not constant. Sometimes the transmission completes in around 800 ms, while at other times it takes up to 1800 ms for similar amounts of data.(when flashed the same code again repeatedly whether we are achieving the same time or not )

Related