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 17 years ago
parent a11ac5ae2f
commit dce6a54a4a

@ -7781,6 +7781,63 @@ static int find_sdp(struct sip_request *req)
return FALSE; 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 /*! \brief Process SIP SDP offer, select formats and activate RTP channels
If offer is rejected, we will not change any properties of the call If offer is rejected, we will not change any properties of the call
Return 0 on success, a negative value on errors. 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 { } else {
/* We already have a pending invite. Sorry. You are on hold. */ /* We already have a pending invite. Sorry. You are on hold. */
p->glareinvite = seqno; 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); 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); ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
/* Don't destroy dialog here */ /* 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); 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 */ /*! 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); 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 */ /*! Callback for changing DTMF mode */
int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode); int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode);
/*! Callback for retrieving statistics */ /*! 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); 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 * \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; struct sockaddr_in local_address;
/*! Address that we are sending RTP to */ /*! Address that we are sending RTP to */
struct sockaddr_in remote_address; 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 */ /*! Instance that we are bridged to if doing remote or local bridging */
struct ast_rtp_instance *bridged; struct ast_rtp_instance *bridged;
/*! Payload and packetization information */ /*! Payload and packetization information */
@ -373,6 +375,20 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc
return 0; 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) int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
{ {
if ((address->sin_family != AF_INET) || 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 */ 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 strict_rtp_address; /*!< Remote address information for strict RTP purposes */
struct sockaddr_in alt_rtp_address; /*!<Alternate remote address information */
struct rtp_red *red; 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 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 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_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_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 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); 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, .prop_set = ast_rtp_prop_set,
.fd = ast_rtp_fd, .fd = ast_rtp_fd,
.remote_address_set = ast_rtp_remote_address_set, .remote_address_set = ast_rtp_remote_address_set,
.alt_remote_address_set = ast_rtp_alt_remote_address_set,
.red_init = rtp_red_init, .red_init = rtp_red_init,
.red_buffer = rtp_red_buffer, .red_buffer = rtp_red_buffer,
.local_bridge = ast_rtp_local_bridge, .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; rtp->strict_rtp_state = STRICT_RTP_CLOSED;
} else if (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)) { 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)); /* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */
return &ast_null_frame; 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; 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 /*! \brief Write t140 redundacy frame
* \param data primary data to be buffered * \param data primary data to be buffered
*/ */

Loading…
Cancel
Save