Help with Proximity Chat

Godot Version

4.5.1

Question

Im new to Godot and want to implement a proximity voice chat and followed a tutorial on Youtube. That didnt work and now I tried to use some AI to help me fix my problem, which is loud static, cracking noise and beeps, but that also didnt work. Does anyone know whats wrong in my code?

extends CharacterBody3D

@onready var player_name_label: Label = %PlayerNameLabel
@onready var camera: Camera3D = %Camera
@onready var kamerapivot: Marker3D = %Kamerapivot
@onready var multiplayer_synchronizer: MultiplayerSynchronizer = %MultiplayerSynchronizer
@onready var prox_network: AudioStreamPlayer3D = $ProxNetwork
@onready var prox_local: AudioStreamPlayer3D = $ProxLocal

var max_frames_per_process := 256
var current_sample_rate: int = 24000
var has_loopback: bool = false
var local_playback: AudioStreamGeneratorPlayback = null
var local_voice_buffer: PackedByteArray = PackedByteArray()
var network_playback: AudioStreamGeneratorPlayback = null
var network_voice_buffer: PackedByteArray = PackedByteArray()
var packet_read_limit: int = 5

@export var player_name:String = "Gubi Fortnite"
@export var steam_id:int = 0
@export var mouse_sensitivity = 0.002

var last_position: Vector3 = Vector3.ZERO

const SPEED = 8.0
const JUMP_VELOCITY = 7.5

func _enter_tree() -> void:
	set_multiplayer_authority(name.to_int())

func _ready() -> void:
	current_sample_rate = Steam.getVoiceOptimalSampleRate()
	if current_sample_rate <= 0:
		current_sample_rate = 24000
	print(current_sample_rate)
	prox_local.stream.mix_rate = current_sample_rate
	prox_local.play()
	await get_tree().process_frame
	local_playback = prox_local.get_stream_playback()
	print(prox_local.stream)
	print(local_playback)
	
	prox_network.stream.mix_rate = current_sample_rate
	prox_network.play()
	network_playback = prox_network.get_stream_playback()
	
	add_to_group("players")
	
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	if is_multiplayer_authority():
		camera.set_current(true)
		sync_player_data.rpc(SteamManager.STEAM_ID)
	else:
		request_data.rpc_id(get_multiplayer_authority())
		
	

@rpc("any_peer", "reliable")
func request_data():
	var requester_id = multiplayer.get_remote_sender_id()
	sync_player_data.rpc_id(requester_id, SteamManager.STEAM_ID)

@rpc("any_peer", "call_local", "reliable")
func sync_player_data(new_id: int):
	player_name = Steam.getFriendPersonaName(new_id)
	steam_id = new_id
	if player_name_label:
		player_name_label.text = player_name



func _unhandled_input(event):
	if mouse_sensitivity == null:
		return
	if event is InputEventMouseMotion:
		# Körper horizontal drehen (Y-Achse)
		rotate_y(-event.relative.x * mouse_sensitivity)
		
		# Kamera vertikal drehen (X-Achse)
		kamerapivot.rotate_x(-event.relative.y * mouse_sensitivity)
		
		# Limitieren, damit man keinen Überschlag macht
		kamerapivot.rotation.x = clamp(kamerapivot.rotation.x, deg_to_rad(-80), deg_to_rad(80))

func _physics_process(delta: float) -> void:
	if !is_multiplayer_authority():
		return
	
	if not is_on_floor():
		velocity += get_gravity() * delta

	
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	
	var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_backwards")
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)
		
	if velocity.length() > 500 or global_position.distance_to(last_position) > 5.0:
		print("reset")
		velocity = Vector3.ZERO
		position = Vector3.ZERO
	
	last_position = global_position
	
	move_and_slide()
	
	for i in get_slide_collision_count():
		var collision = get_slide_collision(i)
		var collider = collision.get_collider()
		
		if collider is RigidBody3D:
			var push_dir = -collision.get_normal()
			var push_force = 150.0 * delta
			var total_impulse = push_dir * push_force
			
			collider.apply_push.rpc(total_impulse)

func _input(event: InputEvent) -> void:
	if !is_multiplayer_authority():
		return
		
	if Input.is_action_just_pressed("voice_record"):
		record_voice(true)
	elif Input.is_action_just_released("voice_record"):
		record_voice(false)

func _process(delta: float) -> void:
	if is_multiplayer_authority():
		check_for_voice()

func process_voice_data(voice_data:Dictionary, voice_source:String) -> void:
	var decompressed_voice: Dictionary
	if voice_source == "local":
		decompressed_voice = Steam.decompressVoice(voice_data['buffer'], current_sample_rate)
	elif voice_source == "network":
		decompressed_voice = Steam.decompressVoice(voice_data['voice_data'], current_sample_rate)
	if decompressed_voice['result'] == Steam.VOICE_RESULT_OK and decompressed_voice['uncompressed'].size() > 0:
		
		if voice_source == "local":
			local_voice_buffer.append_array(decompressed_voice['uncompressed'])

			var i := 0

			while i + 1 < local_voice_buffer.size():

				var raw_value := local_voice_buffer.decode_s16(i)

				var sample := clampf(raw_value / 32768.0, -1.0, 1.0)

				local_playback.push_frame(Vector2(sample, sample))

				i += 2
				
			local_voice_buffer = local_voice_buffer.slice(i)
			
		elif voice_source == "network":
			
			network_voice_buffer.append_array(decompressed_voice['uncompressed'])
			if network_voice_buffer.size() < 4096:
					return
			var frames_available = network_playback.get_frames_available()

			var n = 0
			for i in range(0, min(frames_available * 2, network_voice_buffer.size() - 1), 2):
				var raw_value := network_voice_buffer.decode_s16(i)
				var sample := clampf(raw_value / 32768.0, -1.0, 1.0)
				
				network_playback.push_frame(Vector2(sample, sample))

				n = i + 2

			network_voice_buffer = network_voice_buffer.slice(n)
	
func record_voice(is_recording: bool) -> void:
	Steam.setInGameVoiceSpeaking(SteamManager.STEAM_ID, is_recording)

	if is_recording:
		Steam.startVoiceRecording()
	else:
		Steam.stopVoiceRecording()
		local_voice_buffer = PackedByteArray()
		network_voice_buffer = PackedByteArray()
		if local_playback:
			var frames := local_playback.get_frames_available()
			for _i in range(frames):
				local_playback.push_frame(Vector2.ZERO)

func check_for_voice() -> void:
	var available_voice: Dictionary = Steam.getVoice()
	if available_voice['result'] == Steam.VOICE_RESULT_OK and available_voice['buffer'].size() > 0:
		if available_voice['result'] == Steam.VOICE_RESULT_OK:
			SteamManager.send_voice_data(available_voice['buffer'])
			
			if has_loopback:
				process_voice_data(available_voice, "local")

func get_sample_rate(is_toggled: bool = true) -> void:
	if is_toggled:
		current_sample_rate = Steam.getVoiceOptimalSampleRate()
	else:
		current_sample_rate = 24000

	prox_network.stream.mix_rate = current_sample_rate
	prox_local.stream.mix_rate = current_sample_rate


extends Node

const PACKET_READ_LIMIT: int = 32

var STEAM_APP_ID:int = 480
var STEAM_USERNAME:String = ""
var STEAM_ID:int = 0

var is_lobby_host:bool = false
var lobby_id:int = 0
var lobby_members:Array

#var peer:SteamMultiplayerPeer = SteamMultiplayerPeer.new()

func _ready() -> void:
	print("Steam initialized: ", Steam.steamInit(STEAM_APP_ID, true))
	Steam.initRelayNetworkAccess()
	
	STEAM_ID = Steam.getSteamID()
	print(STEAM_ID)
	
	STEAM_USERNAME = Steam.getPersonaName()
	print(STEAM_USERNAME)
	
	Steam.lobby_joined.connect(_on_lobby_joined)
	Steam.p2p_session_request.connect(_on_p2p_session_request)


func _process(_delta: float) -> void:
	if lobby_id > 0:
		read_all_p2p_msg_packets()
		read_all_p2p_voice_packets()
	Steam.run_callbacks()

func _on_lobby_joined(this_lobby_id:int, _permissions:int, _locked:bool, response:int):
	if response == Steam.CHAT_ROOM_ENTER_RESPONSE_SUCCESS:
		lobby_id = this_lobby_id
		get_lobby_members()
		make_p2p_handshake()
		

func _on_p2p_session_request(remote_id:int):
	Steam.acceptP2PSessionWithUser(remote_id)

func make_p2p_handshake():
	send_p2p_packet(0, {"message" : "handshake", "steam_id" : STEAM_ID, "username" : STEAM_USERNAME}, Steam.P2P_SEND_UNRELIABLE)

func send_voice_data(voice_data: PackedByteArray):
	send_p2p_packet(1, {"voice_data" : voice_data, "steam_id" : STEAM_ID, "username" : STEAM_USERNAME}, Steam.P2P_SEND_UNRELIABLE)
	

func send_p2p_packet(this_target: int, packet_data: Dictionary, send_type: int = 0):
	var channel:int = 0
	var this_data: PackedByteArray
	this_data.append_array(var_to_bytes(packet_data))
	
	if this_target == 0:
		if lobby_members.size() > 1:
			for member in lobby_members:
				if member["steam_id"] != STEAM_ID:
					Steam.sendP2PPacket(member["steam_id"], this_data, send_type, channel)			
	elif this_target == 1:
		if lobby_members.size() > 1:
			for member in lobby_members:
				if member["steam_id"] != STEAM_ID:
					Steam.sendP2PPacket(member["steam_id"], this_data, send_type, 1)	
	else:
		Steam.sendP2PPacket(this_target, this_data, send_type, channel)

func get_lobby_members():
	lobby_members.clear()
	
	var num_of_lobby_members: int = Steam.getNumLobbyMembers(lobby_id)
	
	for member in range(0,num_of_lobby_members):
		var member_steam_id: int = Steam.getLobbyMemberByIndex(lobby_id, member)
		var member_steam_name: String = Steam.getFriendPersonaName(member_steam_id)
		
		lobby_members.append({
			"steam_id": member_steam_id,
			"steam_name": member_steam_name,
		})

func read_all_p2p_msg_packets(read_count : int = 0):
	if read_count >= PACKET_READ_LIMIT:
		return
	
	if Steam.getAvailableP2PPacketSize() > 0:
		read_p2p_msg_packet()
		read_all_p2p_msg_packets(read_count + 1)
		
func read_all_p2p_voice_packets(read_count : int = 0):
	if read_count >= PACKET_READ_LIMIT:
		return
	
	if Steam.getAvailableP2PPacketSize(1) > 0:
		read_p2p_voice_packet()
		read_all_p2p_voice_packets(read_count + 1)
		
func read_p2p_msg_packet():
	var packet_size: int = Steam.getAvailableP2PPacketSize(0)
	if packet_size > 0:
		var this_packet: Dictionary = Steam.readP2PPacket(packet_size, 0)
		var packet_sender: int = this_packet["remote_steam_id"]
		var packet_code: PackedByteArray = this_packet["data"]
		var readable_data: Dictionary = bytes_to_var(packet_code)
		
		if readable_data.has("message"):
			match readable_data["message"]:
				"handshake":
					print("PLAYER: ", readable_data["username"], " has joined!")
					get_lobby_members()

func read_p2p_voice_packet():
	var packet_size: int = Steam.getAvailableP2PPacketSize(1)
	if packet_size > 0:
		var this_packet: Dictionary = Steam.readP2PPacket(packet_size, 1)
		var packet_sender: int = this_packet["remote_steam_id"]
		var packet_code: PackedByteArray = this_packet["data"]
		var readable_data: Dictionary = bytes_to_var(packet_code)
		
		if readable_data.has("voice_data"):
			print("reading ", readable_data["username"], "'s voice data.")
			var players_in_scene: Array = get_tree().get_nodes_in_group("players")
			print("packet_sender:", packet_sender)
			print("players_in_scene size:", players_in_scene.size())
			print("players_in_scene:", players_in_scene)
			for player in players_in_scene:
				print("checking player:", player.name, "steam:", player.steam_id)
				if player.steam_id == packet_sender:
					player.process_voice_data(readable_data, "network")
				else:
					pass