sipsorcery icon indicating copy to clipboard operation
sipsorcery copied to clipboard

createAnswer generates invalid SDP setup attribute (actpass instead of active/passive)

Open neko0461 opened this issue 2 months ago • 3 comments

When generating an SDP answer with createAnswer(), the resulting SDP incorrectly contains:

a=setup:actpass

According to RFC 4145 and RFC 5763, the setup attribute in an SDP answer must be either active or passive. actpass is only valid for the offer.

This causes interoperability issues with WebRTC implementations (e.g. Android WebRTC), which reject the answer with an error like:

"Answerer must use either active or passive value for setup attribute"

Example generated answer SDP:

v=0 o=- 65090 0 IN IP4 127.0.0.1 s=sipsorcery t=0 0 m=audio 9 UDP/TLS/RTP/SAVP 110 c=IN IP4 0.0.0.0 a=ice-ufrag:ILIO a=ice-pwd:BWBFSNYIXHNBPEOOJOULFFMN a=fingerprint:sha-256 55:AD:4B:5E:02:0F:B5:FD:3C:51:93:2B:69:76:4D:E8:FE:C4:31:29:08:5B:26:FC:7C:E9:21:6E:8B:7E:3D:74 a=setup:actpass <-- invalid in answer a=mid:0 a=rtcp-mux a=sendrecv

Expected behavior:

  • createAnswer() should set a=setup:active or a=setup:passive based on the DTLS role (or IceRole), instead of leaving actpass.

There are commented-out lines in the code that suggest this was intended:

// audioAnnouncement.IceRole = IceRole;
// videoAnnouncement.IceRole = IceRole;

neko0461 avatar Oct 03 '25 06:10 neko0461

Thanks for the bug report. I'll take a look soon'ish.

sipsorcery avatar Oct 06 '25 18:10 sipsorcery

@neko0461 what interoperability issues is this causing?

ispysoftware avatar Nov 11 '25 11:11 ispysoftware

I think you just need to replace

//if (answerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio))
//{
//    var audioAnnouncement = answerSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).Single();
//    audioAnnouncement.IceRole = IceRole;
//}

//if (answerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.video))
//{
//    var videoAnnouncement = answerSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).Single();
//    videoAnnouncement.IceRole = IceRole;
//}

with

var answerRole = (IceRole == IceRolesEnum.active)
    ? IceRolesEnum.active
    : IceRolesEnum.passive;

foreach (var ann in answerSdp.Media)
{
    ann.IceRole = answerRole;
}

ispysoftware avatar Nov 11 '25 22:11 ispysoftware