sipsorcery-org / sipsorcery

A WebRTC, SIP and VoIP library for C# and .NET. Designed for real-time communications apps.
https://sipsorcery-org.github.io/sipsorcery
Other
1.39k stars 424 forks source link

How to set requireEvenPort to false in RTPSession #1101

Open diontools opened 3 months ago

diontools commented 3 months ago

Hello. I am implementing a program that streams pre-recorded audio when a call comes in. After updating SIPSorcery from v6.0.12 to v6.2.1, I encountered the following error message and the program stopped working:

System.ArgumentException: Cannot specify both require even port and a specific non-even port to bind on. Set port to 0.

In my environment, I need to specify an odd port number, so I cannot get the new version to work. Is there a way to set requireEvenPort to false?

Here is a simplified implementation:

userAgent.OnIncomingCall += async (userAgent, request) =>
{
    var sdp = SDP.ParseSDPDescription(request.Body);
    var audioMedia = sdp.Media.Find(media => media.Media == SDPMediaTypesEnum.audio);
    using var audioSession = new AudioSession(audioMedia.Port + 1);
    var uas = userAgent.AcceptCall(request);
    var isAnswerOk = await userAgent.Answer(uas, audioSession);

    // audio playback code here ...
};

class AudioSession : RTPSession, IMediaSession
{
    public AudioExtrasSource AudioExtrasSource { get; private set; }

    public AudioSession(int bindPort)
        : base(isMediaMultiplexed: false, isRtcpMultiplexed: true, isSecure: false, bindPort: bindPort)
    {
        this.AudioExtrasSource = new AudioExtrasSource(
            new AudioEncoder(),
            new AudioSourceOptions
            {
                AudioSource = AudioSourcesEnum.Music,
            }
        );

        this.AudioExtrasSource.RestrictFormats(format => format.Codec == AudioCodecsEnum.PCMU);

        this.AudioExtrasSource.OnAudioSourceEncodedSample += base.SendAudio;
        base.OnAudioFormatsNegotiated += this.AudioFormatsNegotiated;

        var track = new MediaStreamTrack(this.AudioExtrasSource.GetAudioSourceFormats())
        {
            NoDtmfSupport = true,
        };
        base.addTrack(track);
    }

    private void AudioFormatsNegotiated(List<AudioFormat> audoFormats)
    {
        AudioFormat audioSourceFormat = audoFormats.First();
        this.AudioExtrasSource.SetAudioSourceFormat(audioSourceFormat);
    }

    public override async Task Start()
    {
        if (!base.IsStarted)
        {
            await base.Start().ConfigureAwait(continueOnCapturedContext: false);
            await this.AudioExtrasSource.StartAudio().ConfigureAwait(continueOnCapturedContext: false);
        }
    }

    public override async void Close(string reason)
    {
        if (!base.IsClosed)
        {
            base.Close(reason);
            this.AudioExtrasSource.OnAudioSourceEncodedSample -= base.SendAudio;
            await this.AudioExtrasSource.CloseAudio().ConfigureAwait(continueOnCapturedContext: false);
        }
    }
}