/// <summary> /// Handler for when an in dialog request is received on an established call. /// Typical types of request will be re-INVITES for things like putting a call on or /// off hold and REFER requests for transfers. Some in dialog request types, such /// as re-INVITES have specific events so they can be bubbled up to the /// application to deal with. /// </summary> /// <param name="sipRequest">The in dialog request received.</param> private async Task DialogRequestReceivedAsync(SIPRequest sipRequest) { if (sipRequest.Method == SIPMethodsEnum.BYE) { logger.LogInformation($"Remote call party hungup {sipRequest.StatusLine}."); Dialogue.DialogueState = SIPDialogueStateEnum.Terminated; SIPNonInviteTransaction byeTx = new SIPNonInviteTransaction(m_transport, sipRequest, null); byeTx.SendResponse(SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null)); CallEnded(); } else if (sipRequest.Method == SIPMethodsEnum.INVITE) { logger.LogDebug($"Re-INVITE request received {sipRequest.StatusLine}."); UASInviteTransaction reInviteTransaction = new UASInviteTransaction(m_transport, sipRequest, m_outboundProxy); try { SDP offer = SDP.ParseSDPDescription(sipRequest.Body); var setRemoteResult = MediaSession.SetRemoteDescription(offer); if (setRemoteResult != SetDescriptionResultEnum.OK) { logger.LogWarning($"Unable to set remote description from reINVITE request {setRemoteResult}"); var notAcceptableResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptable, setRemoteResult.ToString()); reInviteTransaction.SendFinalResponse(notAcceptableResponse); } else { var answerSdp = MediaSession.CreateAnswer(null); CheckRemotePartyHoldCondition(MediaSession.RemoteDescription); Dialogue.RemoteSDP = sipRequest.Body; Dialogue.SDP = answerSdp.ToString(); Dialogue.RemoteCSeq = sipRequest.Header.CSeq; var okResponse = reInviteTransaction.GetOkResponse(SDP.SDP_MIME_CONTENTTYPE, Dialogue.SDP); reInviteTransaction.SendFinalResponse(okResponse); } } catch (Exception ex) { logger.LogError(ex, "MediaSession can't process the re-INVITE request."); if (OnReinviteRequest == null) { // The application isn't prepared to accept re-INVITE requests and we can't work out what it was for. // We'll reject as gently as we can to try and not lose the call. SIPResponse notAcceptableResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptable, null); reInviteTransaction.SendFinalResponse(notAcceptableResponse); } else { // The application is going to handle the re-INVITE request. We'll send a Trying response as a precursor. SIPResponse tryingResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Trying, null); await reInviteTransaction.SendProvisionalResponse(tryingResponse).ConfigureAwait(false); OnReinviteRequest.Invoke(reInviteTransaction); } } } else if (sipRequest.Method == SIPMethodsEnum.OPTIONS) { //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "OPTIONS request for established dialogue " + dialogue.DialogueName + ".", dialogue.Owner)); SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); okResponse.Body = Dialogue.RemoteSDP; okResponse.Header.ContentLength = okResponse.Body.Length; okResponse.Header.ContentType = m_sdpContentType; await SendResponseAsync(okResponse).ConfigureAwait(false); } else if (sipRequest.Method == SIPMethodsEnum.MESSAGE) { //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "MESSAGE for call " + sipRequest.URI.ToString() + ": " + sipRequest.Body + ".", dialogue.Owner)); SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await m_transport.SendResponseAsync(okResponse).ConfigureAwait(false); } else if (sipRequest.Method == SIPMethodsEnum.REFER) { if (sipRequest.Header.ReferTo.IsNullOrBlank()) { // A REFER request must have a Refer-To header. //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Bad REFER request, no Refer-To header.", dialogue.Owner)); SIPResponse invalidResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing mandatory Refer-To header"); await SendResponseAsync(invalidResponse).ConfigureAwait(false); } else { //TODO: Add handling logic for in transfer requests from the remote call party. } } else if (sipRequest.Method == SIPMethodsEnum.NOTIFY) { SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await SendResponseAsync(okResponse).ConfigureAwait(false); if (sipRequest.Body?.Length > 0 && sipRequest.Header.ContentType?.Contains(m_sipReferContentType) == true) { OnTransferNotify?.Invoke(sipRequest.Body); } } }