Skip to content

Audio Capture ​

Godot CEF supports two modes for handling browser audio:

  1. Direct Playback (Default): Audio plays directly through the system's default audio output. This is simpler and has lower latency.
  2. Audio Capture: Audio is captured and routed through Godot's audio system, allowing you to process, mix, or spatialize browser audio.

Enabling Audio Capture ​

Audio capture is configured via Project Settings and applies to all CefTexture instances.

  1. Go to Project → Project Settings
  2. Navigate to godot_cef → audio
  3. Enable enable_audio_capture

WARNING

Audio capture mode must be configured before any browsers are created. Changing this setting requires restarting your Godot application.

How It Works ​

When audio capture is enabled:

  1. CEF sends audio data to Godot instead of playing it directly
  2. Audio is buffered as PCM samples in an internal queue
  3. You create an AudioStreamGenerator and connect it to an AudioStreamPlayer
  4. Each frame, you push the buffered audio to the playback
[CEF Browser] → [Audio Handler] → [Buffer Queue] → [AudioStreamGenerator] → [AudioStreamPlayer]

Basic Usage ​

gdscript
extends Control

@onready var cef_texture: CefTexture = $CefTexture
@onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer

func _ready():
    # Check if audio capture is enabled in project settings
    if cef_texture.is_audio_capture_enabled():
        # Create and assign the audio stream
        var audio_stream = cef_texture.create_audio_stream()
        audio_player.stream = audio_stream
        audio_player.play()

func _process(_delta):
    # Push audio data every frame
    if cef_texture.is_audio_capture_enabled():
        var playback = audio_player.get_stream_playback()
        if playback:
            cef_texture.push_audio_to_playback(playback)

API Reference ​

Methods ​

is_audio_capture_enabled() -> bool ​

Returns true if audio capture mode is enabled in project settings.

gdscript
if cef_texture.is_audio_capture_enabled():
    print("Audio capture is enabled")

create_audio_stream() -> AudioStreamGenerator ​

Creates and returns an AudioStreamGenerator configured with the correct sample rate (matching Godot's audio output).

TIP

The sample rate is automatically read from Godot's AudioServer.get_mix_rate(), ensuring compatibility with your project's audio settings.

gdscript
var audio_stream = cef_texture.create_audio_stream()
audio_player.stream = audio_stream

push_audio_to_playback(playback: AudioStreamGeneratorPlayback) -> int ​

Pushes buffered audio data from CEF to the given playback. Returns the number of frames pushed.

Call this method every frame in _process() to continuously feed audio data.

gdscript
func _process(_delta):
    var playback = audio_player.get_stream_playback()
    if playback:
        var frames_pushed = cef_texture.push_audio_to_playback(playback)

has_audio_data() -> bool ​

Returns true if there is audio data available in the buffer.

gdscript
if cef_texture.has_audio_data():
    print("Audio data available")

get_audio_buffer_size() -> int ​

Returns the number of audio packets currently buffered.

gdscript
var buffer_size = cef_texture.get_audio_buffer_size()
print("Buffered packets: ", buffer_size)

Advanced Usage ​

3D Spatial Audio ​

You can use AudioStreamPlayer3D to spatialize browser audio in 3D space:

gdscript
extends Node3D

@onready var cef_texture: CefTexture = $Screen/CefTexture
@onready var audio_player: AudioStreamPlayer3D = $AudioStreamPlayer3D

func _ready():
    if cef_texture.is_audio_capture_enabled():
        var audio_stream = cef_texture.create_audio_stream()
        audio_player.stream = audio_stream
        audio_player.play()

func _process(_delta):
    if cef_texture.is_audio_capture_enabled():
        var playback = audio_player.get_stream_playback()
        if playback:
            cef_texture.push_audio_to_playback(playback)

Multiple Browsers ​

Each CefTexture has its own audio buffer. You can route different browsers to different audio players:

gdscript
@onready var browser1: CefTexture = $Browser1
@onready var browser2: CefTexture = $Browser2
@onready var player1: AudioStreamPlayer = $AudioPlayer1
@onready var player2: AudioStreamPlayer = $AudioPlayer2

func _ready():
    if browser1.is_audio_capture_enabled():
        player1.stream = browser1.create_audio_stream()
        player1.play()
        
        player2.stream = browser2.create_audio_stream()
        player2.play()

func _process(_delta):
    if browser1.is_audio_capture_enabled():
        var pb1 = player1.get_stream_playback()
        var pb2 = player2.get_stream_playback()
        if pb1:
            browser1.push_audio_to_playback(pb1)
        if pb2:
            browser2.push_audio_to_playback(pb2)

Audio Processing with AudioEffects ​

Since browser audio goes through Godot's audio system, you can apply AudioEffects:

  1. Create an AudioBus in the Audio tab
  2. Add effects (reverb, EQ, compression, etc.)
  3. Set your AudioStreamPlayer to use that bus
gdscript
audio_player.bus = "BrowserAudio"  # Custom bus with effects

Comparison: Direct Playback vs Audio Capture ​

FeatureDirect PlaybackAudio Capture
Setup ComplexityNoneRequires code
LatencyLowerSlightly higher
CPU UsageLowerSlightly higher
3D Spatialization❌✅
Audio Effects❌✅
Volume ControlSystem onlyFull Godot control
Multiple outputs❌✅
Audio mixing❌✅

Troubleshooting ​

No Audio ​

  1. Verify enable_audio_capture is enabled in Project Settings
  2. Ensure you're calling push_audio_to_playback() every frame
  3. Check that audio_player.play() has been called
  4. Verify the AudioStreamPlayer volume is not zero

Audio Stuttering ​

  • Ensure push_audio_to_playback() is called in _process(), not _physics_process()
  • Check that your game maintains a stable framerate
  • The internal buffer can hold ~100 packets; if you're processing too slowly, audio may be dropped

Audio Delay ​

Audio capture inherently adds a small amount of latency due to buffering. If low latency is critical and you don't need audio processing, consider using direct playback mode instead.