Skip to content

esp_webrtc: add public APIs to set video/audio bitrate via esp_capture (with pending apply before start) #108

@josefeliuf

Description

@josefeliuf

Checklist

  • Checked the issue tracker for similar issues to ensure this is not a duplicate.
  • Described the feature in detail and justified the reason for the request.
  • Provided specific use cases and examples.

Feature description

Summary

esp-webrtc-solution composes its media pipeline using esp_capture for capture/encode, but there’s currently no public API to adjust encoder bitrate at runtime from user code. I’m proposing two small wrapper APIs exposed by esp_webrtc that forward to esp_capture_sink_set_bitrate() for video and audio. This matches the layering described in the repo (core WebRTC + esp_capture + render + demos).

What I implemented (reference)

Public headers:

int esp_webrtc_set_video_bitrate(esp_webrtc_handle_t rtc_handle, uint32_t bps);
int esp_webrtc_set_audio_bitrate(esp_webrtc_handle_t rtc_handle, uint32_t bps);

Wrappers (core logic):

int esp_webrtc_set_video_bitrate(esp_webrtc_handle_t handle, uint32_t bps) {
    if (handle == NULL) return ESP_PEER_ERR_INVALID_ARG;
    webrtc_t *rtc = (webrtc_t *)handle;
    if (rtc->capture_path) {
        int ret = esp_capture_sink_set_bitrate(rtc->capture_path, ESP_CAPTURE_STREAM_TYPE_VIDEO, bps);
        return (ret == ESP_CAPTURE_ERR_OK) ? 0 : ret;
    }
    rtc->pending_video_bitrate_bps = bps;
    rtc->video_bitrate_pending = true;
    return 0;
}

int esp_webrtc_set_audio_bitrate(esp_webrtc_handle_t handle, uint32_t bps) {
    if (handle == NULL) return ESP_PEER_ERR_INVALID_ARG;
    webrtc_t *rtc = (webrtc_t *)handle;
    if (rtc->capture_path) {
        int ret = esp_capture_sink_set_bitrate(rtc->capture_path, ESP_CAPTURE_STREAM_TYPE_AUDIO, bps);
        return (ret == ESP_CAPTURE_ERR_OK) ? 0 : ret;
    }
    rtc->pending_audio_bitrate_bps = bps;
    rtc->audio_bitrate_pending = true;
    return 0;
}

In pc_start(), right after:

esp_capture_sink_setup(rtc->media_provider.capture, 0, &sink_cfg, &rtc->capture_path);
esp_capture_sink_enable(rtc->capture_path, ESP_CAPTURE_RUN_MODE_ALWAYS);

apply pending values:

// Apply pending bitrate settings now that sink exists
if (rtc->video_bitrate_pending && rtc->capture_path) {
    int bitrate_ret = esp_capture_sink_set_bitrate(rtc->capture_path, ESP_CAPTURE_STREAM_TYPE_VIDEO, 
                                                    rtc->pending_video_bitrate_bps);
    if (bitrate_ret == ESP_CAPTURE_ERR_OK) {
        ESP_LOGI(TAG, "Applied pending video bitrate: %lu bps", (unsigned long)rtc->pending_video_bitrate_bps);
    } else {
        ESP_LOGW(TAG, "Failed to apply pending video bitrate: %d", bitrate_ret);
    }
    rtc->video_bitrate_pending = false;
}

if (rtc->audio_bitrate_pending && rtc->capture_path) {
    int bitrate_ret = esp_capture_sink_set_bitrate(rtc->capture_path, ESP_CAPTURE_STREAM_TYPE_AUDIO, 
                                                    rtc->pending_audio_bitrate_bps);
    if (bitrate_ret == ESP_CAPTURE_ERR_OK) {
        ESP_LOGI(TAG, "Applied pending audio bitrate: %lu bps", (unsigned long)rtc->pending_audio_bitrate_bps);
    } else {
        ESP_LOGW(TAG, "Failed to apply pending audio bitrate: %d", bitrate_ret);
    }
    rtc->audio_bitrate_pending = false;
}

Why this belongs here

The solution packages esp_webrtc with its dependent components (including esp_capture) and ships demos that establish a full sender pipeline, so offering a first-class bitrate knob at this layer is ergonomic and expected by app developers.

Use cases

  • Network adaptation: Drop bitrate when RTT/loss rises or when the remote requests lower quality.

  • Thermal/power management: Reduce bitrate on thermals or battery constraints for portable devices.

  • Mode presets: Toggle between “HQ” (e.g., 1.2 Mbps) and “LQ” (e.g., 300 kbps) profiles in UI without restarting the stream.

  • Pre-start configuration: Set desired bitrate before calling esp_webrtc_start(); pending values are applied once the capture sink is created inside pc_start(). This aligns with esp_capture’s role as the capture/encode package for WebRTC in this repo.

Alternatives

  • Force renegotiation/restart: Heavier, risks glitches; unnecessary since encoders support runtime bitrate changes.

Additional context

I have a companion PR in espressif/esp-gmf (espressif/esp-gmf#30) that fixes esp_capture_sink_set_bitrate() routing so it reaches the video/audio path managers and underlying encoders (previously returned NOT_SUPPORTED). esp_capture is officially documented in the GMF repo and component registry as the capture/encode package used in WebRTC scenarios.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions