Review Board 1.7.16


Add ability to set an alternate source for RTP media. Helps in SIP glare situations.

Review Request #252 - Created May 19, 2009 and submitted

Mark Michelson
branches/1.4/
Reviewers
asterisk-dev
Asterisk
For a description of the problem, see this: http://lists.digium.com/pipermail/asterisk-dev/2009-May/038348.html

This patch implements a way to let the RTP stack know that there may be a potential alternate source for media. The alterations to RTP are:

* new function ast_rtp_set_altpeer to set what the alternate media source may be.
* new sockaddr_in structures inside the ast_rtp and ast_rtcp structures to hold these alternate sources.
* ast_rtp_read and ast_rtcp_read have been updated to expect media from these alternate sources.

The alterations to chan_sip are:

* new function get_ip_and_port_from_sdp to get the remote IP address and port for audio/video streams from the SDP
* When we are going to respond to a REINVITE with a 491, we call get_ip_and_port_from_sdp, followed by ast_rtp_set_altpeer so that the
  RTP stack will not react incorrectly when it receives media from this alternate source.

Please see the "Testing Done" section for some code review details.
I tested by setting up phones and Asterisk boxes as shown in the first diagram in the link I printed in the "Description."

I found that in REINVITE glare situations, I always successfully had two-way audio. There was a slight catch, though. Usually there would be about a 0.5-1 second gap between when the callee answered the phone and when the caller was able to hear the callee's audio. I have not yet been able to track this odd behavior down. So, in addition to making sure that what I have presented here looks reasonable, if any reviewers might be able to point out what potentially is causing the short delay upon answering the calls, please speak up.

Changes between revision 1 and 2

1 2
1 2

  1. /branches/1.4/channels/chan_sip.c: Loading...
/branches/1.4/channels/chan_sip.c
Diff Revision 1 Diff Revision 2
[20] 5112 lines
[+20] [+] static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, int holdstate, int sendonly)
5113
enum media_type {
5113
enum media_type {
5114
	SDP_AUDIO,
5114
	SDP_AUDIO,
5115
	SDP_VIDEO,
5115
	SDP_VIDEO,
5116
};
5116
};
5117

    
   
5117

   
5118
static struct sockaddr_in get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media)
5118
static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin)
5119
{
5119
{
5120
	const char *m;
5120
	const char *m;
5121
	const char *c;
5121
	const char *c;
5122
	int miterator = req->sdp_start;
5122
	int miterator = req->sdp_start;
5123
	int citerator = req->sdp_start;
5123
	int citerator = req->sdp_start;
5124
	int x = 0;
5124
	int x = 0;
5125
	struct sockaddr_in sin = {0,}; /* We need to zero this so that we can detect an error in the caller */

   
5126
	int numberofports;
5125
	int numberofports;
5127
	int len;
5126
	int len;
5128
	char host[258] = ""; /*Initialize to empty so we will know if we have any input */
5127
	char host[258] = ""; /*Initialize to empty so we will know if we have any input */
5129
	struct ast_hostent audiohp;
5128
	struct ast_hostent audiohp;
5130
	struct hostent *hp;
5129
	struct hostent *hp;
[+20] [20] 21 lines
[+20] static struct sockaddr_in get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media) static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin)
5152
		}
5151
		}
5153
	}
5152
	}
5154

    
   
5153

   
5155
	if (ast_strlen_zero(host) || x == 0) {
5154
	if (ast_strlen_zero(host) || x == 0) {
5156
		ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
5155
		ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
5157
		return sin;
5156
		return -1;
5158
	}
5157
	}
5159

    
   
5158

   
5160
	hp = ast_gethostbyname(host, &audiohp);
5159
	hp = ast_gethostbyname(host, &audiohp);
5161
	if (!hp) {
5160
	if (!hp) {
5162
		ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
5161
		ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
5163
		return sin;
5162
		return -1;
5164
	}
5163
	}
5165

    
   
5164

   
5166
	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
5165
	memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
5167
	sin.sin_port = htons(x);
5166
	sin->sin_port = htons(x);
5168
	return sin;
5167
	return -0;
5169
}
5168
}
5170

    
   
5169

   
5171
/*! \brief Process SIP SDP offer, select formats and activate RTP channels
5170
/*! \brief Process SIP SDP offer, select formats and activate RTP channels
5172
	If offer is rejected, we will not change any properties of the call
5171
	If offer is rejected, we will not change any properties of the call
5173
 	Return 0 on success, a negative value on errors.
5172
 	Return 0 on success, a negative value on errors.
[+20] [20] 9336 lines
[+20] [+] static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock)
14510
			__sip_ack(p, p->lastinvite, FLAG_RESPONSE, 0);
14509
			__sip_ack(p, p->lastinvite, FLAG_RESPONSE, 0);
14511
		} else {
14510
		} else {
14512
			/* We already have a pending invite. Sorry. You are on hold. */
14511
			/* We already have a pending invite. Sorry. You are on hold. */
14513
			p->glareinvite = seqno;
14512
			p->glareinvite = seqno;
14514
			if (p->rtp && find_sdp(req)) {
14513
			if (p->rtp && find_sdp(req)) {
14515
				struct sockaddr_in sin = get_ip_and_port_from_sdp(req, SDP_AUDIO);
14514
				struct sockaddr_in sin;
14516
				if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
14515
				if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &sin)) {
14517
					ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
14516
					ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
14518
				} else {
14517
				} else {
14519
					ast_rtp_set_alt_peer(p->rtp, &sin);
14518
					ast_rtp_set_alt_peer(p->rtp, &sin);
14520
				}
14519
				}
14521
				if (p->vrtp) {
14520
				if (p->vrtp) {
14522
					sin = get_ip_and_port_from_sdp(req, SDP_VIDEO);
14521
					if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &sin)) {
14523
					if (sin.sin_addr.s_addr == 0 || sin.sin_port == 0) {

   
14524
						ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
14522
						ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
14525
					} else {
14523
					} else {
14526
						ast_rtp_set_alt_peer(p->vrtp, &sin);
14524
						ast_rtp_set_alt_peer(p->vrtp, &sin);
14527
					}
14525
					}
14528
				}
14526
				}
[+20] [20] 4668 lines
  1. /branches/1.4/channels/chan_sip.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.