WebRTC not creating session description in C#

Godot Version

v4.2.2.stable.mono.official

Question

I am having trouble implementing the minimal setup for WebRTC as specified in the docs using C#.

The problem is that when I call CreateOffer(), SessionDescriptionCreated does not fire.

Here is my C# Code. I just attached this onto a Node on the scene.

using System.Threading.Tasks;
using Godot;

namespace WebRTCTest;

public partial class TestCSharp : Node
{
	private WebRtcPeerConnection conn1 = new();
	private WebRtcPeerConnection conn2 = new();
	WebRtcDataChannel ch1;
	WebRtcDataChannel ch2;

	public TestCSharp()
	{
		ch1 = conn1.CreateDataChannel("chat", new() { { "id", 1 }, { "negotiated", true } });
		ch2 = conn2.CreateDataChannel("chat", new() { { "id", 1 }, { "negotiated", true } });
	}

	public override async void _Ready()
	{
		conn1.SessionDescriptionCreated += (type, sdp) => conn1.SetLocalDescription(type, sdp);
		conn1.SessionDescriptionCreated += (type, sdp) => conn2.SetRemoteDescription(type, sdp);
		conn1.IceCandidateCreated += (media, index, name) => conn2.AddIceCandidate(media, (int)index, name);

		conn2.SessionDescriptionCreated += (type, sdp) => conn2.SetLocalDescription(type, sdp);
		conn2.SessionDescriptionCreated += (type, sdp) => conn1.SetRemoteDescription(type, sdp);
		conn2.IceCandidateCreated += (media, index, name) => conn1.AddIceCandidate(media, (int)index, name);

		conn1.SessionDescriptionCreated += (type, sdp) => GD.Print("c1 desc created");
		conn1.SessionDescriptionCreated += (type, sdp) => GD.Print("c1 ice candidate created");

		await Task.Delay(1000);

		conn1.CreateOffer();

		await Task.Delay(1000);

		ch1.PutPacket("hello".ToUtf8Buffer());
		GD.Print("finished running");
	}
}

and the errors in the console (raised by the ch1.PutPacket("hello".ToUtf8Buffer()) line):

NativeCalls.cs:4865 @ int Godot.NativeCalls.godot_icall_1_550(nint, nint, System.Byte[]): DataChannel is closed
NativeCalls.cs:4865 @ int Godot.NativeCalls.godot_icall_1_550(nint, nint, System.Byte[]): Method/function failed. Returning: FAILED

I tried printing out the connection state conn1 and it’s on “New” before I call CreateOffer() but gets stuck on “Connecting” after.

I’m not sure what happened but I remember my code working once and then just breaking after. I tried to implement the same coed in gdscript and the “session description created” signal fires properly.

here is the gdscript I used to test the webrtc:

extends Node

# Create the two peers
var p1 = WebRTCPeerConnection.new()
var p2 = WebRTCPeerConnection.new()
# And a negotiated channel for each each peer
var ch1 = p1.create_data_channel("chat", {"id": 1, "negotiated": true})
var ch2 = p2.create_data_channel("chat", {"id": 1, "negotiated": true})

func _ready():
	# Connect P1 session created to itself to set local description.
	p1.session_description_created.connect(p1.set_local_description)
	p1.session_description_created.connect(_test)
	# Connect P1 session and ICE created to p2 set remote description and candidates.
	p1.session_description_created.connect(p2.set_remote_description)
	p1.ice_candidate_created.connect(p2.add_ice_candidate)

	# Same for P2
	p2.session_description_created.connect(p2.set_local_description)
	p2.session_description_created.connect(p1.set_remote_description)
	p2.ice_candidate_created.connect(p1.add_ice_candidate)

	# Let P1 create the offer
	p1.create_offer()

	# Wait a second and send message from P1.
	await get_tree().create_timer(2).timeout
	ch1.put_packet("Hi from P1".to_utf8_buffer())

	# Wait a second and send message from P2.
	await get_tree().create_timer(2).timeout
	ch2.put_packet("Hi from P2".to_utf8_buffer())

func _test(_type, _sdp):
	print("offer created")

func _process(_delta):
	# Poll connections
	p1.poll()
	p2.poll()

	# Check for messages
	if ch1.get_ready_state() == ch1.STATE_OPEN and ch1.get_available_packet_count() > 0:
		print("P1 received: ", ch1.get_packet().get_string_from_utf8())
	if ch2.get_ready_state() == ch2.STATE_OPEN and ch2.get_available_packet_count() > 0:
		print("P2 received: ", ch2.get_packet().get_string_from_utf8())

and here is the console output:

offer created
P2 received: Hi from P1
P1 received: Hi from P2

I fixed it.

I just forgot to call conn1.Poll() and conn2.Poll() which is why the signals are not getting received…