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.44k stars 438 forks source link

the application works in debug mode but crashes in non-debugging mode #997

Open TheBestWorldProgrammer opened 1 year ago

TheBestWorldProgrammer commented 1 year ago

Application: ssss.exe CoreCLR Version: 7.0.923.32018 .NET Version: 7.0.9 Description: The process was terminated due to an unhandled exception. Exception Info: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Stack: at SDL2.SDL.SDL_CloseAudioDevice(UInt32) at SDL2.SDL.SDL_CloseAudioDevice(UInt32) at SIPSorceryMedia.SDL2.SDL2Helper.CloseAudioDevice(UInt32) at SIPSorceryMedia.SDL2.SDL2Helper.CloseAudioPlaybackDevice(UInt32) at SIPSorceryMedia.SDL2.SDL2AudioEndPoint.CloseAudioSink() at SIPSorceryMedia.SDL2.SDL2AudioEndPoint.InitPlaybackDevice() at SIPSorceryMedia.SDL2.SDL2AudioEndPoint.SetAudioSinkFormat(SIPSorceryMedia.Abstractions.AudioFormat) at SIPSorcery.Media.VoIPMediaSession.AudioFormatsNegotiated(System.Collections.Generic.List1<SIPSorceryMedia.Abstractions.AudioFormat>) at SIPSorcery.Net.RTPSession.RaisedOnAudioFormatsNegotiated(Int32, System.Collections.Generic.List1) at SIPSorcery.net.RTP.AudioStream.CheckAudioFormatsNegotiation() at SIPSorcery.Net.RTPSession.SetRemoteDescription(SIPSorcery.SIP.App.SdpType, SIPSorcery.Net.SDP) at SIPSorcery.SIP.App.SIPUserAgent+d135.MoveNext() at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[SIPSorcery.SIP.App.SIPUserAgent+d135, SIPSorcery, Version=6.0.12.0, Culture=neutral, PublicKeyToken=null]](d135 ByRef) at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start[[SIPSorcery.SIP.App.SIPUserAgent+d135, SIPSorcery, Version=6.0.12.0, Culture=neutral, PublicKeyToken=null]](d135 ByRef) at SIPSorcery.SIP.App.SIPUserAgent.ClientCallAnsweredHandler(SIPSorcery.SIP.App.ISIPClientUserAgent, SIPSorcery.SIP.SIPResponse) at SIPSorcery.SIP.App.SIPClientUserAgent.ServerFinalResponseReceived(SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPTransaction, SIPSorcery.SIP.SIPResponse) at SIPSorcery.SIP.UACInviteTransaction+d__19.MoveNext() at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[SIPSorcery.SIP.UACInviteTransaction+d19, SIPSorcery, Version=6.0.12.0, Culture=neutral, PublicKeyToken=null]](d19 ByRef) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Net.Sockets.SocketError, System.Net.Primitives, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]].Start[[SIPSorcery.SIP.UACInviteTransaction+d__19, SIPSorcery, Version=6.0.12.0, Culture=neutral, PublicKeyToken=null]](d19 ByRef) at SIPSorcery.SIP.UACInviteTransaction.UACInviteTransaction_TransactionFinalResponseReceived(SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPTransaction, SIPSorcery.SIP.SIPResponse) at SIPSorcery.SIP.SIPTransaction.GotResponse(SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPResponse) at SIPSorcery.SIP.SIPTransport.SIPMessageReceived(SIPSorcery.SIP.SIPChannel, SIPSorcery.SIP.SIPEndPoint, SIPSorcery.SIP.SIPEndPoint, Byte[]) at SIPSorcery.SIP.SIPTransport.ProcessReceiveQueue() at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread)

nodminger commented 1 year ago

I sometimes get this error. But when I create a new project and use the same old code, the issue will be resolved. I don't know what causes this issue but you can use the method I told to temporarily work on your project till the problem is resolved. Before all this, try to run your program with .NET 6.

TheBestWorldProgrammer commented 1 year ago

I created new programs on different versions .NET , the result is the same

nodminger commented 1 year ago

For what scenario you are working on? Are you trying to capture audio device?

TheBestWorldProgrammer commented 1 year ago

For what scenario you are working on? Are you trying to capture audio device?

I'm writing a cross-platform softphone, I'm trying to capture audio devices using Sdl, create end points, then make a call. Everything works fine in the debug, but in the release version the application just crashes, and the Answer event using exactly the same media session works fine. I am writing on .net 7.0, AvaloniaUI

Code Answer public async Task Answer() { if (_pendingIncomingCall == null) { Console.WriteLine($"There was no pending call available to answer."); return false; } else { var sipRequest = _pendingIncomingCall.ClientTransaction.TransactionRequest;

            // Assume that if the INVITE request does not contain an SDP offer that it will be an 
            // audio only call.
            bool hasAudio = true;
            bool hasVideo = false;

            if (sipRequest.Body != null)
            {
                SDP offerSDP = SDP.ParseSDPDescription(sipRequest.Body);
                hasAudio = offerSDP.Media.Any(x =>
                    x.Media == SDPMediaTypesEnum.audio && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);
                hasVideo = offerSDP.Media.Any(x =>
                    x.Media == SDPMediaTypesEnum.video && x.MediaStreamStatus != MediaStreamStatusEnum.Inactive);
            }

            CreateMediaSessionRTP(AudioOutDeviceIndex, AudioInDeviceIndex);

            _sipUserAgent.RemotePutOnHold += OnRemotePutOnHold;
            _sipUserAgent.RemoteTookOffHold += OnRemoteTookOffHold;

            bool result = await _sipUserAgent.Answer(_pendingIncomingCall, _mediaSession);
            _pendingIncomingCall = null;

            return result;
        }
    }

code Call public async Task Call(string destination) { try { // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account. SIPURI? callURI = null; string? sipUsername = null; string? sipPassword = null; string? fromHeader = null; // This call will use the pre-configured SIP account. callURI = SIPURI.ParseSIPURIRelaxed(destination + "@" + _settings.Host); sipUsername = _settings.User; sipPassword = _settings.Password; fromHeader = (new SIPFromHeader(_settings.FromName, new SIPURI(_settings.User, _settings.Host, null), null)) .ToString();

            var dstEndpoint = SIPDns.ResolveAsync(callURI, false, _cts.Token);

            if (dstEndpoint == null)
            {
                _logger.Error($"Call failed, could not resolve {callURI}.");
                return false;
            }
            else
            {
                _logger.Info($"Call progressing, resolved {callURI} to {dstEndpoint}.");
                System.Diagnostics.Debug.WriteLine($"DNS lookup result for {callURI}: {dstEndpoint}.");
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword,
                    callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out,
                    SDP_MIME_CONTENTTYPE, null, null);

                _sipUserAgent.RemotePutOnHold += OnRemotePutOnHold;
                _sipUserAgent.RemoteTookOffHold += OnRemoteTookOffHold;

                await 
                    CreateMediaSessionRTP(AudioOutDeviceIndex, AudioInDeviceIndex);

                _sipUserAgent.Call(callDescriptor, _mediaSession,0);
                return true;
            }

            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            return false;
        }
    }

code mediaSession private Task CreateMediaSessionRTP(int audioOutDeviceIndex = 0, int audioInDeviceIndex = 0) { try { SDL2Helper.InitSDL(17u); var din = SDL2Helper.GetAudioPlaybackDevice(0);

            var micro = SDL2Helper.GetAudioRecordingDevice(0);
            var windowsAudioEndPoint =
                new SIPSorceryMedia.SDL2.SDL2AudioEndPoint(din, new AudioEncoder());
            //   windowsAudioEndPoint.SetAudioSinkFormat(new AudioFormat(SDPWellKnownMediaFormatsEnum.PCMU));
            var windowsAudioStartPoint =
                new SDL2AudioSource(micro, new AudioEncoder(), 160);

            //   windowsAudioStartPoint.SetAudioSourceFormat(new AudioFormat(SDPWellKnownMediaFormatsEnum.PCMU));
            var ses = new MediaEndPoints { AudioSink = windowsAudioEndPoint, AudioSource = windowsAudioStartPoint};
            var voipMediaSession = new VoIPMediaSession(ses,null,0,null);
            voipMediaSession.AcceptRtpFromAny = true;
            _mediaSession = voipMediaSession;
            return Task.CompletedTask;

        }
        catch (SocketException ex)
        {
              MessageBoxManager.GetMessageBoxStandard("", ex.Message).ShowAsync();
            return null;
        }
        catch (Exception ex)
        {
              MessageBoxManager.GetMessageBoxStandard("", ex.Message).ShowAsync();
            return null;
        }
    }

Also, it didn't work for me in the debug until I added this event, although it is in the il code

code ClientCallAnswered

private async void ClientCallAnswered(ISIPClientUserAgent ua, SIPResponse res) { try { var result = _mediaSession.SetRemoteDescription(SdpType.answer, SDP.ParseSDPDescription(res.Body)); if (result == SetDescriptionResultEnum.OK) { await _mediaSession.Start(); // test.Invoke(); } else { _sipUserAgent.Hangup(); } } catch (Exception e) { Console.WriteLine(e);

        }
    }
nodminger commented 1 year ago

The problem might be in the device you are capturing the audio from. I had the error System.AccessViolationException: Attempted to read or write protected memory when I tried to access my microphone(I worked in WebRTC examples). I gave wrong address for it initially. So I got that error. Please check how you are capturing and handling the audio device.

TheBestWorldProgrammer commented 1 year ago

The problem might be in the device you are capturing the audio from. I had the error System.AccessViolationException: Attempted to read or write protected memory when I tried to access my microphone(I worked in WebRTC examples). I gave wrong address for it initially. So I got that error. Please check how you are capturing and handling the audio device.

I have exactly the same error, can you please describe in more detail what kind of address it is, in what place it is located?

nodminger commented 1 year ago

If you use this command ffmpeg -list_devices true -f dshow -i dummy. It will show all the available video and audio devices. image You can either use the name directly or Alternative name(it will be a long string). These name should be mentioned correctly in the program to access the audio device correctly. I was working on Windows and WebRTC application. I don't know how it works in SIP. There might be some similar things in both SIP and WebRTC application. Please check them.

DavidMartynWood commented 1 year ago

Access volitions can be pretty hard to diagnose, and if it's only happening in release builds that's even trickier. Access violations happen when your application attempts to reach memory outside of its process space (the process violates its permission to access memory). It's likely that bad things happen in debug builds too, but because debug builds consume more memory it's not causing an access violation exception because the process is still accessing memory that it is allowed to access. This problem is almost certainly caused by a call into native code. If you add some logging to your application to help you work out which line of code is causing the exception it should help out. In my experience this is normally caused by an incorrect usage of a native API.

TheBestWorldProgrammer commented 1 year ago

Access volitions can be pretty hard to diagnose, and if it's only happening in release builds that's even trickier. Access violations happen when your application attempts to reach memory outside of its process space (the process violates its permission to access memory). It's likely that bad things happen in debug builds too, but because debug builds consume more memory it's not causing an access violation exception because the process is still accessing memory that it is allowed to access. This problem is almost certainly caused by a call into native code. If you add some logging to your application to help you work out which line of code is causing the exception it should help out. In my experience this is normally caused by an incorrect usage of a native API.

I checked with the help of logging, the names of audio devices are output normally. The string that causes exceptions is in the ClientCallAnswered event, and not in my case, but inside the sipsorcery.sdl library (my event is duplicated). The application almost always crashes when the subscriber picks up the phone. Sometimes there is a situation that after picking up the phone, the application does not crash, but the connection is one-way, and if you call again after such a case, it crashes. I've been working on this problem for about a month, I've tried a lot of things and I don't know what to do

TheBestWorldProgrammer commented 1 year ago

One more important note. It's OK to call on network phones (SIP) inside the network, but the mobile, application crashes var res = await _sipUserAgent.Call(callDescriptor, _mediaSession); Falls on this line