AudioEffectRecord Buffer Only Returns 0's

Godot Version

4.6 beta (customization stemming from commit c1b067f83ce7433522b41d25e8f2d93bb25607bd)
This is on an M1 Mac, Tahoe 26.0.1.

Question

All traffic from my microphone seems to be returning a byte stream of 0’s instead of meaningful data. To debug this, I wrote a fairly simple script setup where the program accesses my microphone, records for 3 seconds, then plays it back. General outline:

  1. 3D Node scene with 3 children (two AudioStreamPlayer3D nodes called MicPlayer and ReplayPlayer, and a Timer called RecordTimer).
  2. Under the Audio menu along the bottom, I added a bus. I called it MicRecord added a Record effect.
  3. In the inspector for MicPlayer, I set Stream to a new AudioStreamMicrophone instance, enabled Autoplay, and set the bus to the newly-created MicRecord.
  4. I enabled Input in Project Settings (Project Settings → Audio → Driver → Enable Input).

I then have the following script. I’m including my debug print statements.

extends Node

@onready var mic_player = $MicPlayer
@onready var replay_player = $ReplayPlayer
@onready var record_timer = $RecordTimer

# Set this to the name of the Audio Bus you created with AudioEffectRecord
const RECORD_BUS_NAME = "MicRecord"
const RECORD_DURATION = 3.0

var recording_effect: AudioEffectRecord # A variable to hold the reference to the effect

func _ready():
	# 1. Get a reference to the AudioEffectRecord
	var bus_index = AudioServer.get_bus_index(RECORD_BUS_NAME)
	if bus_index == -1:
		print("Error: Audio Bus '" + RECORD_BUS_NAME + "' not found!")
		return

	# Assuming AudioEffectRecord is the first effect on the bus (index 0)
	recording_effect = AudioServer.get_bus_effect(bus_index, 0) as AudioEffectRecord
	if not recording_effect:
		print("Error: AudioEffectRecord not found on bus '" + RECORD_BUS_NAME + "'!")
		return

	# Connect the Timer's timeout signal to a function
	record_timer.timeout.connect(_on_record_timer_timeout)

	# 2. Start Recording
	print("--- Recording Started for " + str(RECORD_DURATION) + " seconds... ---")
	recording_effect.set_recording_active(true)
	record_timer.start(RECORD_DURATION)

func _on_record_timer_timeout():
	# 3. Stop Recording
	print("--- Recording Stopped! ---")
	recording_effect.set_recording_active(false)

	# 4. Get the recorded audio stream
	var recorded_stream = recording_effect.get_recording()
	
	if recorded_stream:
				# Save it to a WAV file
		var wav_path = "res://recorded_audio.wav"
		print(recorded_stream.data.slice(0, 10))
		var e = recorded_stream.save_to_wav(wav_path)
		print(e)
		
		# 5. Playback the recorded audio
		replay_player.stream = recorded_stream
		replay_player.play()
		print("--- Playing Back Recorded Audio... ---")
	else:
		print("No audio was recorded.")

These are the print statements I get:

--- Recording Started for 3.0 seconds... ---
--- Recording Stopped! ---
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0
--- Playing Back Recorded Audio... ---

Interestingly, I have a separate application that pings me when the camera or microphone are in use, and I do receive that notification when I run this from the editor. However, all I get is a stream of 0’s. Also, the saved file is basically just a blank audio file. It lasts for the expected duration, but no sound is made.

A user last year described a very similar situation (see here, esp. @tedson’s reply). However, there appeared to be a mismash of similar-but-different errors being addressed there, and thought it best to make a new issue on the topic.

I’m not sure if this is a Godot error, or if I’m doing something dumb - the latter is usually the case, so thought I’d go here first, see if anyone sees a problem.

Got it! So silly.

There is a distinction between AudioStreamPlayer nodes and AudioStreamPlayer3D nodes. With the former, you can just plop them into the scene as I have done and they will work just fine - if I replace my MicPlayer and ReplayPlayer nodes with their non-3D counterpart, the script works.

Going back to my original setup with AudioStreamPlayer3D nodes, they specifically need a listener in the 3D scene to register at all. In this case, if I add a Camera3D node, it will have a spatial source for both recording and playing back, and my original nodes will now work.

I played around with this to make sure I get it intuitively - if I move the ReplayPlayer far away from the Camera3D node, the replay occurs, but it is muffled - simulating the distance between AudioStreamPlayer3D and the Camera3D nodes. I assume that doing something similar with the MicPlayer will have a similar effect - it will act as though I am standing several meters away from my computer when recording anything.

The 2d and 3d variants of audiostreamers are simply positional audio emitters, e.g distance and azimuth of the listener should affect the volume falloff

Another note, while still playing around with this - I had noticed that there was an AudioListener3D node, and I wondered if it could take the place of a Camera3D node with respect to AudioStreamPlayer3D nodes (just as an experiment). Turns out it can specifically override an existing Camera3D as the current listening source (after enabling “Current” in the inspector), but will not work independently (ie, a Camera3D node still needs to be in the scene for AudioStreamPlayer3D to work at all).

1 Like