Trunk implementation of setting an alternate RTP source.

This contains the interface by which we can let an rtp instance know
that it might start receiving audio from a new source. This is similar
in nature to revision 197588 of Asterisk 1.4.

Review: https://reviewboard.asterisk.org/r/276



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@201583 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/1.8.6
Mark Michelson 16 years ago
parent a11ac5ae2f
commit dce6a54a4a

@ -7781,6 +7781,63 @@ static int find_sdp(struct sip_request *req)
return FALSE;
}
enum media_type {
SDP_AUDIO,
SDP_VIDEO,
};
static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin)
{
const char *m;
const char *c;
int miterator = req->sdp_start;
int citerator = req->sdp_start;
int x = 0;
int numberofports;
int len;
char host[258] = ""; /*Initialize to empty so we will know if we have any input */
struct ast_hostent audiohp;
struct hostent *hp;
c = get_sdp_iterate(&citerator, req, "c");
if (sscanf(c, "IN IP4 %256s", host) != 1) {
ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
/* Continue since there may be a valid host in a c= line specific to the audio stream */
}
/* We only want the m and c lines for audio */
while ((m = get_sdp_iterate(&miterator, req, "m"))) {
if ((media == SDP_AUDIO && ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
(sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1 && len > 0))) ||
(media == SDP_VIDEO && ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
(sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1 && len > 0)))) {
/* See if there's a c= line for this media stream.
* XXX There is no guarantee that we'll be grabbing the c= line for this
* particular media stream here. However, this is the same logic used in process_sdp.
*/
c = get_sdp_iterate(&citerator, req, "c");
if (!ast_strlen_zero(c)) {
sscanf(c, "IN IP4 %256s", host);
}
break;
}
}
if (ast_strlen_zero(host) || x == 0) {
ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
return -1;
}
hp = ast_gethostbyname(host, &audiohp);
if (!hp) {
ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
return -1;
}
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
sin->sin_port = htons(x);
return 0;
}
/*! \brief Process SIP SDP offer, select formats and activate RTP channels
If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors.
@ -19907,6 +19964,21 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
} else {
/* We already have a pending invite. Sorry. You are on hold. */
p->glareinvite = seqno;
if (p->rtp && find_sdp(req)) {
struct sockaddr_in sin;
if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &sin)) {
ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
} else {
ast_rtp_instance_set_alt_remote_address(p->rtp, &sin);
}
if (p->vrtp) {
if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &sin)) {
ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
} else {
ast_rtp_instance_set_alt_remote_address(p->vrtp, &sin);
}
}
}
transmit_response_reliable(p, "491 Request Pending", req);
ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
/* Don't destroy dialog here */

@ -323,6 +323,8 @@ struct ast_rtp_engine {
void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref);
/*! Callback for setting the remote address that RTP is to be sent to */
void (*remote_address_set)(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
/*! Callback for setting an alternate remote address */
void (*alt_remote_address_set)(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
/*! Callback for changing DTMF mode */
int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode);
/*! Callback for retrieving statistics */
@ -638,6 +640,28 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r
*/
int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
/*!
* \brief Set the address of an an alternate RTP address to receive from
*
* \param instance The RTP instance to change the address on
* \param address Address to set it to
*
* \retval 0 success
* \retval -1 failure
*
* Example usage:
*
* \code
* ast_rtp_instance_set_alt_remote_address(instance, &sin);
* \endcode
*
* This changes the alternate remote address that RTP will be sent to on instance to the address given in the sin
* structure.
*
* \since 1.6.3
*/
int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
/*!
* \brief Set the address that we are expecting to receive RTP on
*

@ -50,6 +50,8 @@ struct ast_rtp_instance {
struct sockaddr_in local_address;
/*! Address that we are sending RTP to */
struct sockaddr_in remote_address;
/*! Alternate address that we are receiving RTP from */
struct sockaddr_in alt_remote_address;
/*! Instance that we are bridged to if doing remote or local bridging */
struct ast_rtp_instance *bridged;
/*! Payload and packetization information */
@ -373,6 +375,20 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc
return 0;
}
int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
{
instance->alt_remote_address.sin_addr = address->sin_addr;
instance->alt_remote_address.sin_port = address->sin_port;
/* oink */
if (instance->engine->alt_remote_address_set) {
instance->engine->alt_remote_address_set(instance, &instance->alt_remote_address);
}
return 0;
}
int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
{
if ((address->sin_family != AF_INET) ||

@ -166,6 +166,7 @@ struct ast_rtp {
enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */
struct sockaddr_in alt_rtp_address; /*!<Alternate remote address information */
struct rtp_red *red;
};
@ -257,6 +258,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp);
static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1);
@ -278,6 +280,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
.prop_set = ast_rtp_prop_set,
.fd = ast_rtp_fd,
.remote_address_set = ast_rtp_remote_address_set,
.alt_remote_address_set = ast_rtp_alt_remote_address_set,
.red_init = rtp_red_init,
.red_buffer = rtp_red_buffer,
.local_bridge = ast_rtp_local_bridge,
@ -1878,8 +1881,14 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
rtp->strict_rtp_state = STRICT_RTP_CLOSED;
} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
if ((rtp->strict_rtp_address.sin_addr.s_addr != sin.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sin.sin_port)) {
ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
return &ast_null_frame;
/* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */
if ((rtp->alt_rtp_address.sin_addr.s_addr == sin.sin_addr.s_addr) && (rtp->alt_rtp_address.sin_port == sin.sin_port)) {
/* ooh, we did! You're now the new expected address, son! */
rtp->strict_rtp_address = sin;
} else {
ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
return &ast_null_frame;
}
}
}
@ -2200,6 +2209,18 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
return;
}
static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
/* No need to futz with rtp->rtcp here because ast_rtcp_read is already able to adjust if receiving
* RTCP from an "unexpected" source
*/
rtp->alt_rtp_address = *sin;
return;
}
/*! \brief Write t140 redundacy frame
* \param data primary data to be buffered
*/

Loading…
Cancel
Save