Page 1 of 1

Fluent HTTPS stream receive

Posted: Mon Apr 14, 2025 1:48 pm
by sdml12
I kinda listen radio via esp32s3.))
I receive stream like so(simplified for just speed measure):

Code: Select all

static void http_read_task(void* vParam)
{    
    //................
    timestamp1 = pdTICKS_TO_MS(xTaskGetTickCount());
    received = 0;
    while (1) {
        len = esp_http_client_read(client, http_buf, HTTP_BUF_SIZE);
        received += len;
        dt = pdTICKS_TO_MS(xTaskGetTickCount()) - timestamp1;
        if (dt) speed = received*1000/dt;
        ESP_LOGI(TAG, "Speed: %ld", speed);
    }
}
When stream is over plain HTTP - all fine, but when stream is over HTTPS there are options.
Some HTTPS stations are stuttering, in code above resulting speed is lower than bitrate.
In my understanding, this stations transmit stream at speed equal to audio bitrate and to have smooth sound we must constantly receive stream without gaps. As I think esp_http_client make gaps in receiving when TLS involved. It's not a network issue, on phone and same AP - all OK.
So, can somthing be done, without deep dive into low level programming of esp32?

Re: Fluent HTTPS stream receive

Posted: Tue Apr 15, 2025 12:09 am
by Sprite
If the bandwidth itself is sufficient, you may need to have a large-ish buffer between your http client and your MP3 player thing. E.g. run them in different tasks and have a large byte ringbuffer between the two.

Re: Fluent HTTPS stream receive

Posted: Tue Apr 15, 2025 4:07 am
by sdml12
Of course I tried large buffer, and not. On mobile phone, with the same envirinment, playing starts instantly and have no issues. On esp - tens of seconds preliminary buffering doesn't help. Only one task like above, running just for speed measurement, produces solid speeed about 25℅ lower than bitrare for most "bad" station.

Re: Fluent HTTPS stream receive

Posted: Tue Apr 15, 2025 5:06 am
by Sprite
How large is your http_buf? Might be that increasing that improves things.

Re: Fluent HTTPS stream receive

Posted: Tue Apr 15, 2025 9:53 am
by sdml12
Minimal working code for testing:

Code: Select all

#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "esp_http_client.h"

#define TAG "SPEEDTEST"
#define HTTP_BUF_SIZE 16384

static void http_read_task(void* vParam)
{
    uint32_t received = 0, timestamp1, dt;
    char* http_buf  = malloc(HTTP_BUF_SIZE);
    esp_http_client_config_t config = {
        .url = "https://vrx.piro.moe/stream-256",       // 256 kbit/s, "nastiest" station I know) 
        //.buffer_size = HTTP_BUF_SIZE,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_open(client, 0);
    esp_http_client_fetch_headers(client);
    
    timestamp1 = pdTICKS_TO_MS(xTaskGetTickCount());
    while (1) {
        received += esp_http_client_read(client, http_buf, HTTP_BUF_SIZE);
        dt = pdTICKS_TO_MS(xTaskGetTickCount()) - timestamp1;
        if (dt) ESP_LOGI(TAG, "Speed: %ld", (received/1024)*8000/dt);        // kbit/sec
    }
    //esp_http_client_cleanup(client);
}

static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) esp_wifi_connect();
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&(((ip_event_got_ip_t*)event_data)->ip_info.ip)));
        xTaskCreate(&http_read_task, "http_read_task", 6000, NULL, 5, NULL);
    }
}

void app_main()
{
    nvs_flash_init();
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&cfg);
    esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, &event_handler, NULL, NULL);
    esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL);
    wifi_config_t wifi_config = { .sta = {
        .ssid = "MY_SSID",
        .password = "MY_PASSWORD",
        .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        .sae_pwe_h2e = WPA3_SAE_PWE_HUNT_AND_PECK,
        .sae_h2e_identifier = ""
    }};
    esp_wifi_set_mode(WIFI_MODE_STA);
    esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    esp_wifi_start();
}

Re: Fluent HTTPS stream receive

Posted: Wed Apr 16, 2025 9:46 am
by Sprite
Interesting, thanks for posting the example code. I did some research, but it's not obvious where the bottleneck is. It's not the CPU power, both CPUs are like 95% idle. It's also not the hardware crypto accelerators; disabling them doesn't change the picture. Increasing the WiFi rx/tx buffers also does nothing. Think I need to pass this on to others, maybe they know.

Re: Fluent HTTPS stream receive

Posted: Wed Apr 16, 2025 7:58 pm
by chegewara
Hi, just an observation:
I dont think its esp32 issue. When i changed API to use perform instead of read then i see this with buffer size 8kB (i am testing on P4)

Code: Select all

I (12740) SPEEDTEST: HTTP_EVENT_ON_DATA, len=2800
I (13071) SPEEDTEST: HTTP_EVENT_ON_DATA, len=2800
I (13073) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (14095) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (15118) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (16144) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (16145) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (17167) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (18191) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (19233) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (19234) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (20246) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (21265) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (22290) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (23310) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (25358) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (25358) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4082
I (25359) SPEEDTEST: HTTP_EVENT_ON_DATA, len=14
I (25360) SPEEDTEST: HTTP_EVENT_ON_DATA, len=2960
I (25365) SPEEDTEST: HTTP_EVENT_ON_DATA, len=1099
I (26382) SPEEDTEST: HTTP_EVENT_ON_DATA, len=2997
I (26384) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (27406) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
I (28431) SPEEDTEST: HTTP_EVENT_ON_DATA, len=4096
Another thing is that http read stuck for about 1000ms (sometimes more) every 4096 bytes read, no matter what buffer size is (its good to test with size 64).

Re: Fluent HTTPS stream receive

Posted: Thu Apr 17, 2025 3:17 pm
by sdml12
I have news.))
Setting CONFIG_LWIP_TCP_WND_DEFAULT = 8192 (no more, no less) solves this.

Re: Fluent HTTPS stream receive

Posted: Fri Apr 18, 2025 7:03 am
by nilesh_kale
You can refer to the configuration settings used in the IDF/examples/wifi/iperf example, both from the default and target-specific sdkconfig, to optimize for maximum throughput.

I tried simulating a similar scenario on an ESP32-C3 using those configurations and observed a noticeable improvement in speed. I suggest you try it as well, and it would be helpful if you could share your observations.

Additionally, you might consider enabling the keep-alive options in the esp_http_client_config to further improve performance.