'yes' and g.726 audio is negotiated, forces the codec to be treated as if it
is AAL2 packed on the channel.
+* A new 'rtp_keepalive' endpoint option has been added. This option specifies
+ an interval, in seconds, at which we will send RTP comfort noise packets to
+ the endpoint. This functions identically to chan_sip's "rtpkeepalive" option.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.3.0 to Asterisk 13.4.0 ------------
------------------------------------------------------------------------------
--- /dev/null
+"""Add RTP keepalive
+
+Revision ID: 498357a710ae
+Revises: 28b8e71e541f
+Create Date: 2015-07-10 16:42:12.244421
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '498357a710ae'
+down_revision = '28b8e71e541f'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('rtp_keepalive', sa.Integer))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'rtp_keepalive')
enum ast_sip_session_media_encryption encryption;
/*! Do we want to optimistically support encryption if possible? */
unsigned int encryption_optimistic;
+ /*! Number of seconds between RTP keepalive packets */
+ unsigned int keepalive;
};
/*!
enum ast_sip_session_media_encryption encryption;
/*! \brief The media transport in use for this stream */
pj_str_t transport;
+ /*! \brief Scheduler ID for RTP keepalive */
+ int keepalive_sched_id;
/*! \brief Stream is on hold */
unsigned int held:1;
/*! \brief Stream type this session media handles */
struct ast_rtp_rtcp_report *report,
struct ast_json *blob);
+/*!
+ * \brief Get the last RTP transmission time
+ *
+ * \param rtp The instance from which to get the last transmission time
+ * \return The last RTP transmission time
+ */
+time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp);
+
+/*!
+ * \brief Set the last RTP transmission time
+ *
+ * \param rtp The instance on which to set the last transmission time
+ * \param time The last transmission time
+ */
+void ast_rtp_instance_set_last_tx(struct ast_rtp_instance *rtp, time_t time);
+
/*! \addtogroup StasisTopicsAndMessages
* @{
*/
struct ast_srtp *srtp;
/*! Channel unique ID */
char channel_uniqueid[AST_MAX_UNIQUEID];
+ /*! Time of last packet sent */
+ time_t last_tx;
};
/*! List of RTP engines that are currently registered */
return 0;
}
+
+
+time_t ast_rtp_instance_get_last_tx(const struct ast_rtp_instance *rtp)
+{
+ return rtp->last_tx;
+}
+
+void ast_rtp_instance_set_last_tx(struct ast_rtp_instance *rtp, time_t time)
+{
+ rtp->last_tx = time;
+}
have this accountcode set on it.
</para></description>
</configOption>
+ <configOption name="rtp_keepalive">
+ <synopsis>Number of seconds between RTP comfort noise keepalive packets.</synopsis>
+ <description><para>
+ At the specified interval, Asterisk will send an RTP comfort noise frame. This may
+ be useful for situations where Asterisk is behind a NAT or firewall and must keep a
+ hole open in order to allow for media to arrive at Asterisk.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_keepalive", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.keepalive));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
}
}
+static int send_keepalive(const void *data)
+{
+ struct ast_sip_session_media *session_media = (struct ast_sip_session_media *) data;
+ struct ast_rtp_instance *rtp = session_media->rtp;
+ int keepalive;
+ time_t interval;
+ int send_keepalive;
+
+ if (!rtp) {
+ return 0;
+ }
+
+ keepalive = ast_rtp_instance_get_keepalive(rtp);
+
+ if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) {
+ ast_debug(3, "Not sending RTP keepalive on RTP instance %p since direct media is in use\n", rtp);
+ return keepalive * 1000;
+ }
+
+ interval = time(NULL) - ast_rtp_instance_get_last_tx(rtp);
+ send_keepalive = interval >= keepalive;
+
+ ast_debug(3, "It has been %d seconds since RTP was last sent on instance %p. %sending keepalive\n",
+ (int) interval, rtp, send_keepalive ? "S" : "Not s");
+
+ if (send_keepalive) {
+ ast_rtp_instance_sendcng(rtp, 0);
+ return keepalive * 1000;
+ }
+
+ return (keepalive - interval) * 1000;
+}
+
/*! \brief Internal function which creates an RTP instance */
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
{
/* This purposely resets the encryption to the configured in case it gets added later */
session_media->encryption = session->endpoint->media.rtp.encryption;
+ if (session->endpoint->media.rtp.keepalive > 0 &&
+ stream_to_media_type(session_media->stream_type) == AST_MEDIA_TYPE_AUDIO) {
+ ast_rtp_instance_set_keepalive(session_media->rtp, session->endpoint->media.rtp.keepalive);
+ /* Schedule the initial keepalive early in case this is being used to punch holes through
+ * a NAT. This way there won't be an awkward delay before media starts flowing in some
+ * scenarios.
+ */
+ session_media->keepalive_sched_id = ast_sched_add_variable(sched, 500, send_keepalive,
+ session_media, 1);
+ }
+
return 1;
}
static void stream_destroy(struct ast_sip_session_media *session_media)
{
if (session_media->rtp) {
+ if (session_media->keepalive_sched_id != -1) {
+ AST_SCHED_DEL(sched, session_media->keepalive_sched_id);
+ }
ast_rtp_instance_stop(session_media->rtp);
ast_rtp_instance_destroy(session_media->rtp);
}
return CMP_STOP;
}
session_media->encryption = session->endpoint->media.rtp.encryption;
+ session_media->keepalive_sched_id = -1;
/* Safe use of strcpy */
strcpy(session_media->stream_type, handler_list->stream_type);
ao2_link(session->media, session_media);
void *temp = buf;
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
+ int res;
*ice = 0;
}
#endif
- return ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa);
+ res = ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa);
+ if (res > 0) {
+ ast_rtp_instance_set_last_tx(instance, time(NULL));
+ }
+ return res;
}
static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)