summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_gtalk.c21
-rw-r--r--channels/chan_gulp.c43
-rw-r--r--channels/chan_h323.c17
-rw-r--r--channels/chan_jingle.c21
-rw-r--r--channels/chan_mgcp.c16
-rw-r--r--channels/chan_motif.c20
-rw-r--r--channels/chan_multicast_rtp.c2
-rw-r--r--channels/chan_sip.c26
-rw-r--r--channels/chan_skinny.c20
-rw-r--r--channels/chan_unistim.c16
-rw-r--r--include/asterisk/cdr.h7
-rw-r--r--include/asterisk/channel.h6
-rw-r--r--include/asterisk/json.h28
-rw-r--r--include/asterisk/rtp_engine.h160
-rw-r--r--main/asterisk.c10
-rw-r--r--main/json.c14
-rw-r--r--main/manager.c9
-rw-r--r--main/rtp_engine.c391
-rw-r--r--res/res_rtp_asterisk.c675
19 files changed, 1073 insertions, 429 deletions
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index 8a7083eb2..639de4749 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -210,6 +210,7 @@ static char *gtalk_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cl
static int gtalk_update_externip(void);
static int gtalk_parser(void *data, ikspak *pak);
static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to);
+static void gtalk_set_owner(struct gtalk_pvt *p, struct ast_channel *chan);
/*! \brief PBX interface structure for channel registration */
static struct ast_channel_tech gtalk_tech = {
@@ -1007,6 +1008,17 @@ safeout:
return 1;
}
+static void gtalk_set_owner(struct gtalk_pvt *p, struct ast_channel *chan)
+{
+ p->owner = chan;
+ if (p->rtp) {
+ ast_rtp_instance_set_channel_id(p->rtp, chan ? ast_channel_uniqueid(chan) : "");
+ }
+ if (p->vrtp) {
+ ast_rtp_instance_set_channel_id(p->vrtp, chan ? ast_channel_uniqueid(chan) : "");
+ }
+}
+
static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
{
struct gtalk_pvt *tmp = NULL;
@@ -1198,7 +1210,7 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i,
ast_channel_musicclass_set(tmp, client->musicclass);
if (!ast_strlen_zero(client->parkinglot))
ast_channel_parkinglot_set(tmp, client->parkinglot);
- i->owner = tmp;
+ gtalk_set_owner(i, tmp);
ast_module_ref(ast_module_info->self);
ast_channel_context_set(tmp, client->context);
ast_channel_exten_set(tmp, i->exten);
@@ -1712,8 +1724,9 @@ static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
ast_mutex_unlock(&p->lock);
return -1;
}
- if (p->owner == oldchan)
- p->owner = newchan;
+ if (p->owner == oldchan) {
+ gtalk_set_owner(p, newchan);
+ }
ast_mutex_unlock(&p->lock);
return 0;
}
@@ -1889,7 +1902,7 @@ static int gtalk_hangup(struct ast_channel *ast)
ast_mutex_lock(&p->lock);
client = p->parent;
- p->owner = NULL;
+ gtalk_set_owner(p, NULL);
ast_channel_tech_pvt_set(ast, NULL);
if (!p->alreadygone) {
gtalk_action(client, p, "terminate");
diff --git a/channels/chan_gulp.c b/channels/chan_gulp.c
index 6a80651cf..144fb6aaa 100644
--- a/channels/chan_gulp.c
+++ b/channels/chan_gulp.c
@@ -429,7 +429,7 @@ static int direct_media_mitigate_glare(struct ast_sip_session *session)
{
RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
- if (session->endpoint->direct_media_glare_mitigation ==
+ if (session->endpoint->direct_media_glare_mitigation ==
AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
return 0;
}
@@ -563,6 +563,13 @@ static struct ast_channel *gulp_new(struct ast_sip_session *session, int state,
pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
ast_channel_tech_pvt_set(chan, pvt);
+ if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(chan));
+ }
+ if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(chan));
+ }
+
if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->codecs)) {
ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->codecs);
@@ -742,8 +749,15 @@ struct fixup_data {
static int fixup(void *data)
{
struct fixup_data *fix_data = data;
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(fix_data->chan);
fix_data->session->channel = fix_data->chan;
+ if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(fix_data->chan));
+ }
+ if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(fix_data->chan));
+ }
return 0;
}
@@ -1434,6 +1448,19 @@ static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan
return h_data;
}
+/*! \brief Clear a channel from a session along with its PVT */
+static void clear_session_and_channel(struct ast_sip_session *session, struct ast_channel *ast, struct gulp_pvt *pvt)
+{
+ session->channel = NULL;
+ if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, "");
+ }
+ if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, "");
+ }
+ ast_channel_tech_pvt_set(ast, NULL);
+}
+
static int hangup(void *data)
{
pj_status_t status;
@@ -1453,9 +1480,7 @@ static int hangup(void *data)
}
}
- session->channel = NULL;
- ast_channel_tech_pvt_set(ast, NULL);
-
+ clear_session_and_channel(session, ast, pvt);
ao2_cleanup(pvt);
ao2_cleanup(h_data);
@@ -1485,11 +1510,9 @@ failure:
/* Go ahead and do our cleanup of the session and channel even if we're not going
* to be able to send our SIP request/response
*/
- ao2_cleanup(h_data);
- session->channel = NULL;
- ast_channel_tech_pvt_set(ast, NULL);
-
+ clear_session_and_channel(session, ast, pvt);
ao2_cleanup(pvt);
+ ao2_cleanup(h_data);
return -1;
}
@@ -1859,8 +1882,8 @@ static int gulp_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_da
* Module loading including tests for configuration or dependencies.
* This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
* or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
- * configuration file or other non-critical problem return
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
+ * configuration file or other non-critical problem return
* AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
*/
static int load_module(void)
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index e26bb5fb6..5ed1c8970 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -250,6 +250,8 @@ static void delete_users(void);
static void delete_aliases(void);
static void prune_peers(void);
+static void oh323_set_owner(struct oh323_pvt *pvt, struct ast_channel *c);
+
static struct ast_channel *oh323_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, int *cause);
static int oh323_digit_begin(struct ast_channel *c, char digit);
static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration);
@@ -719,7 +721,7 @@ static int oh323_hangup(struct ast_channel *c)
return 0;
}
- pvt->owner = NULL;
+ oh323_set_owner(pvt, NULL);
ast_channel_tech_pvt_set(c, NULL);
if (ast_channel_hangupcause(c)) {
@@ -974,7 +976,7 @@ static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, pvt->owner);
return -1;
}
- pvt->owner = newchan;
+ oh323_set_owner(p, newchan);
ast_mutex_unlock(&pvt->lock);
return 0;
}
@@ -1007,6 +1009,7 @@ static int __oh323_rtp_create(struct oh323_pvt *pvt)
ast_debug(1, "Created RTP channel\n");
ast_rtp_instance_set_qos(pvt->rtp, tos, cos, "H323 RTP");
+ ast_rtp_instance_set_channel_id(pvt->rtp, pvt->owner ? ast_channel_uniqueid(pvt->owner), "");
if (h323debug)
ast_debug(1, "Setting NAT on RTP to %d\n", pvt->options.nat);
@@ -1100,7 +1103,7 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
/* Register channel functions. */
ast_channel_tech_pvt_set(ch, pvt);
/* Set the owner of this channel */
- pvt->owner = ch;
+ oh323_set_owner(pvt, ch);
ast_channel_context_set(ch, pvt->context);
ast_channel_exten_set(ch, pvt->exten);
@@ -1189,6 +1192,14 @@ static struct oh323_pvt *oh323_alloc(int callid)
return pvt;
}
+static void oh323_set_owner(struct oh323_pvt *pvt, struct ast_channel *chan)
+{
+ pvt->owner = chan;
+ if (pvt->rtp) {
+ ast_rtp_instance_set_channel_id(pvt, chan ? ast_channel_uniqueid(chan) : "");
+ }
+}
+
static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
{
struct oh323_pvt *pvt;
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
index 42dccf666..e5fd02506 100644
--- a/channels/chan_jingle.c
+++ b/channels/chan_jingle.c
@@ -196,6 +196,7 @@ static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *da
static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid);
static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static void jingle_set_owner(struct jingle_pvt *pvt, struct ast_channel *chan);
/*! \brief PBX interface structure for channel registration */
static struct ast_channel_tech jingle_tech = {
@@ -833,6 +834,17 @@ static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from,
return tmp;
}
+static void jingle_set_owner(struct jingle_pvt *pvt, struct ast_channel *chan)
+{
+ pvt->owner = chan;
+ if (pvt->rtp) {
+ ast_rtp_instance_set_channel_id(pvt->rtp, pvt->owner ? ast_channel_uniqueid(pvt->owner) : "");
+ }
+ if (pvt->vrtp) {
+ ast_rtp_instance_set_channel_id(pvt->vrtp, pvt->owner ? ast_channel_uniqueid(pvt->owner) : "");
+ }
+}
+
/*! \brief Start new jingle channel */
static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const char *linkedid)
{
@@ -908,7 +920,7 @@ static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *
ast_channel_language_set(tmp, client->language);
if (!ast_strlen_zero(client->musicclass))
ast_channel_musicclass_set(tmp, client->musicclass);
- i->owner = tmp;
+ jingle_set_owner(i, tmp);
ast_channel_context_set(tmp, client->context);
ast_channel_exten_set(tmp, i->exten);
/* Don't use ast_set_callerid() here because it will
@@ -1321,8 +1333,9 @@ static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
ast_mutex_unlock(&p->lock);
return -1;
}
- if (p->owner == oldchan)
- p->owner = newchan;
+ if (p->owner == oldchan) {
+ jingle_set_owner(p, newchan);
+ }
ast_mutex_unlock(&p->lock);
return 0;
}
@@ -1540,7 +1553,7 @@ static int jingle_hangup(struct ast_channel *ast)
ast_mutex_lock(&p->lock);
client = p->parent;
- p->owner = NULL;
+ jingle_set_owner(p, NULL);
ast_channel_tech_pvt_set(ast, NULL);
if (!p->alreadygone)
jingle_action(client, p, JINGLE_TERMINATE);
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 5a0b7ad84..da3fefa8a 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -431,6 +431,7 @@ static int mgcpsock = -1;
static struct sockaddr_in bindaddr;
+static void mgcp_set_owner(struct mgcp_subchannel *sub, struct ast_channel *chan);
static struct ast_frame *mgcp_read(struct ast_channel *ast);
static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
@@ -528,7 +529,7 @@ static int unalloc_sub(struct mgcp_subchannel *sub)
}
ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
- sub->owner = NULL;
+ mgcp_set_owner(sub, NULL);
if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
@@ -945,7 +946,7 @@ static int mgcp_hangup(struct ast_channel *ast)
}
}
- sub->owner = NULL;
+ mgcp_set_owner(sub, NULL);
/* for deleting gate */
if (p->pktcgatealloc && sub->gate) {
@@ -1225,6 +1226,13 @@ static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
return f;
}
+static void mgcp_set_owner(struct mgcp_subchannel *sub, struct ast_channel *chan)
+{
+ sub->owner = chan;
+ if (sub->rtp) {
+ ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(chan) : "");
+ }
+}
static struct ast_frame *mgcp_read(struct ast_channel *ast)
{
@@ -1288,7 +1296,7 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
return -1;
}
- sub->owner = newchan;
+ mgcp_set_owner(sub, newchan);
ast_mutex_unlock(&sub->lock);
return 0;
}
@@ -1529,7 +1537,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, cons
ast_channel_accountcode_set(tmp, i->accountcode);
if (i->amaflags)
ast_channel_amaflags_set(tmp, i->amaflags);
- sub->owner = tmp;
+ mgcp_set_owner(sub, tmp);
ast_module_ref(ast_module_info->self);
ast_channel_callgroup_set(tmp, i->callgroup);
ast_channel_pickupgroup_set(tmp, i->pickupgroup);
diff --git a/channels/chan_motif.c b/channels/chan_motif.c
index 22b5eaec8..c77d0c0d2 100644
--- a/channels/chan_motif.c
+++ b/channels/chan_motif.c
@@ -656,6 +656,18 @@ static struct ast_rtp_glue jingle_rtp_glue = {
.update_peer = jingle_set_rtp_peer,
};
+/*! \brief Set the channel owner on the \ref jingle_session object and related objects */
+static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
+{
+ session->owner = chan;
+ if (session->rtp) {
+ ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
+ }
+ if (session->vrtp) {
+ ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
+ }
+}
+
/*! \brief Internal helper function which enables video support on a sesson if possible */
static void jingle_enable_video(struct jingle_session *session)
{
@@ -679,7 +691,7 @@ static void jingle_enable_video(struct jingle_session *session)
}
ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
-
+ ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
@@ -775,7 +787,7 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j
ast_channel_tech_set(chan, &jingle_tech);
ast_channel_tech_pvt_set(chan, session);
- session->owner = chan;
+ jingle_set_owner(session, chan);
ast_channel_callid_set(chan, session->callid);
@@ -1712,7 +1724,7 @@ static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
ao2_lock(session);
- session->owner = newchan;
+ jingle_set_owner(session, newchan);
ao2_unlock(session);
@@ -1862,7 +1874,7 @@ static int jingle_hangup(struct ast_channel *ast)
}
ast_channel_tech_pvt_set(ast, NULL);
- session->owner = NULL;
+ jingle_set_owner(session, NULL);
ao2_unlink(session->state->sessions, session);
ao2_ref(session->state, -1);
diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c
index dfa068018..462982969 100644
--- a/channels/chan_multicast_rtp.c
+++ b/channels/chan_multicast_rtp.c
@@ -153,7 +153,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo
ast_rtp_instance_destroy(instance);
goto failure;
}
-
+ ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan));
ast_rtp_instance_set_remote_address(instance, &destination_address);
ast_channel_tech_set(chan, &multicast_rtp_tech);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 9a5f086ad..9373a6435 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1240,6 +1240,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
static int get_sip_pvt_from_replaces(const char *callid, const char *totag, const char *fromtag,
struct sip_pvt **out_pvt, struct ast_channel **out_chan);
static void check_pendings(struct sip_pvt *p);
+static void sip_set_owner(struct sip_pvt *p, struct ast_channel *chan);
static void *sip_pickup_thread(void *stuff);
static int sip_pickup(struct ast_channel *chan);
@@ -3494,7 +3495,7 @@ void dialog_unlink_all(struct sip_pvt *dialog)
ast_channel_tech_pvt_set(owner, dialog_unref(ast_channel_tech_pvt(owner), "resetting channel dialog ptr in unlink_all"));
ast_channel_unlock(owner);
ast_channel_unref(owner);
- dialog->owner = NULL;
+ sip_set_owner(dialog, NULL);
}
sip_pvt_unlock(dialog);
@@ -7183,7 +7184,7 @@ static int sip_hangup(struct ast_channel *ast)
ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Really hang up next time */
ast_channel_tech_pvt_set(p->owner, dialog_unref(ast_channel_tech_pvt(p->owner), "unref p->owner->tech_pvt"));
sip_pvt_lock(p);
- p->owner = NULL; /* Owner will be gone after we return, so take it away */
+ sip_set_owner(p, NULL); /* Owner will be gone after we return, so take it away */
sip_pvt_unlock(p);
ast_module_unref(ast_module_info->self);
return 0;
@@ -7218,7 +7219,7 @@ static int sip_hangup(struct ast_channel *ast)
/* Disconnect */
disable_dsp_detect(p);
- p->owner = NULL;
+ sip_set_owner(p, NULL);
ast_channel_tech_pvt_set(ast, dialog_unref(ast_channel_tech_pvt(ast), "unref ast->tech_pvt"));
ast_module_unref(ast_module_info->self);
@@ -7544,7 +7545,7 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
if (p->owner != oldchan)
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
else {
- p->owner = newchan;
+ sip_set_owner(p, newchan);
/* Re-invite RTP back to Asterisk. Needed if channel is masqueraded out of a native
RTP bridge (i.e., RTP not going through Asterisk): RTP bridge code might not be
able to do this if the masquerade happens before the bridge breaks (e.g., AMI
@@ -8190,7 +8191,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
}
ast_channel_zone_set(tmp, zone);
}
- i->owner = tmp;
+ sip_set_owner(i, tmp);
ast_module_ref(ast_module_info->self);
ast_channel_context_set(tmp, i->context);
/*Since it is valid to have extensions in the dialplan that have unescaped characters in them
@@ -9252,6 +9253,21 @@ static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt)
return pvt->owner;
}
+/*! \brief Set the owning channel on the \ref sip_pvt object */
+static void sip_set_owner(struct sip_pvt *p, struct ast_channel *chan)
+{
+ p->owner = chan;
+ if (p->rtp) {
+ ast_rtp_instance_set_channel_id(p->rtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
+ }
+ if (p->vrtp) {
+ ast_rtp_instance_set_channel_id(p->vrtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
+ }
+ if (p->trtp) {
+ ast_rtp_instance_set_channel_id(p->trtp, p->owner ? ast_channel_uniqueid(p->owner) : "");
+ }
+}
+
/*! \brief find or create a dialog structure for an incoming SIP message.
* Connect incoming SIP message to current dialog or create new dialog structure
* Returns a reference to the sip_pvt object, remember to give it back once done.
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 647213228..bb0888f26 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1638,6 +1638,7 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
static int skinny_dialer_cb(const void *data);
static int skinny_reload(void);
+static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan);
static void setsubstate(struct skinny_subchannel *sub, int state);
static void dumpsub(struct skinny_subchannel *sub, int forcehangup);
static void activatesub(struct skinny_subchannel *sub, int state);
@@ -4797,10 +4798,12 @@ static void start_rtp(struct skinny_subchannel *sub)
}
if (sub->rtp && sub->owner) {
+ ast_rtp_instance_set_channel_id(sub->rtp, ast_channel_uniqueid(sub->owner));
ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
}
if (hasvideo && sub->vrtp && sub->owner) {
+ ast_rtp_instance_set_channel_id(sub->vrtp, ast_channel_uniqueid(sub->owner));
ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
}
@@ -5009,7 +5012,7 @@ static int skinny_hangup(struct ast_channel *ast)
SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Destroying\n", sub->callid);
ast_mutex_lock(&sub->lock);
- sub->owner = NULL;
+ skinny_set_owner(sub, NULL);
ast_channel_tech_pvt_set(ast, NULL);
destroy_rtp(sub);
ast_free(sub->origtonum);
@@ -5133,7 +5136,7 @@ static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
return -1;
}
- sub->owner = newchan;
+ skinny_set_owner(sub, newchan);
return 0;
}
@@ -5361,6 +5364,17 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
return 0;
}
+static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan)
+{
+ sub->owner = chan;
+ if (sub->rtp) {
+ ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
+ }
+ if (sub->vrtp) {
+ ast_rtp_instance_set_channel_id(sub->vrtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
+ }
+}
+
static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subline *subline, int state, const char *linkedid, int direction)
{
struct ast_channel *tmp;
@@ -5386,7 +5400,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
} else {
ast_mutex_init(&sub->lock);
- sub->owner = tmp;
+ skinny_set_owner(sub, tmp);
sub->callid = callnums++;
d->lastlineinstance = l->instance;
d->lastcallreference = sub->callid;
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index 5a5674daa..53ffa0044 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -675,6 +675,7 @@ static int load_module(void);
static int reload(void);
static int unload_module(void);
static int reload_config(void);
+static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan);
static void show_main_page(struct unistimsession *pte);
static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor,
const char *dest, int *cause);
@@ -2749,6 +2750,7 @@ static void start_rtp(struct unistim_subchannel *sub)
return;
}
ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ ast_rtp_instance_set_channel_id(sub->rtp, ast_channel_uniqueid(sub->owner));
ast_channel_internal_fd_set(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
ast_channel_internal_fd_set(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
@@ -4736,7 +4738,7 @@ static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchannel *sub) {
ast_mutex_lock(&sub->lock);
ast_channel_tech_pvt_set(ast, NULL);
- sub->owner = NULL;
+ unistim_set_owner(sub, NULL);
sub->alreadygone = 0;
ast_mutex_unlock(&sub->lock);
if (sub->rtp) {
@@ -5072,7 +5074,7 @@ static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newcha
return -1;
}
- p->owner = newchan;
+ unistim_set_owner(p, newchan);
ast_mutex_unlock(&p->lock);
@@ -5589,7 +5591,7 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
if (!ast_strlen_zero(l->parent->language)) {
ast_channel_language_set(tmp, l->parent->language);
}
- sub->owner = tmp;
+ unistim_set_owner(sub, tmp);
ast_update_use_count();
ast_channel_callgroup_set(tmp, l->callgroup);
ast_channel_pickupgroup_set(tmp, l->pickupgroup);
@@ -5623,6 +5625,14 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
return tmp;
}
+static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan)
+{
+ sub->owner = chan;
+ if (sub->rtp) {
+ ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
+ }
+}
+
static void *do_monitor(void *data)
{
struct unistimsession *cur = NULL;
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 9d1f6d72d..cd0501f06 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -330,11 +330,10 @@ struct ast_cdr {
char peeraccount[AST_MAX_ACCOUNT_CODE];
/*! flags */
unsigned int flags;
- /*! Unique Channel Identifier
- * 150 = 127 (max systemname) + "-" + 10 (epoch timestamp) + "." + 10 (monotonically incrementing integer) + NULL */
- char uniqueid[150];
+ /*! Unique Channel Identifier */
+ char uniqueid[AST_MAX_UNIQUEID];
/* Linked group Identifier */
- char linkedid[32];
+ char linkedid[AST_MAX_UNIQUEID];
/*! User field */
char userfield[AST_MAX_USER_FIELD];
/*! Sequence field */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 2e7468418..0f5549108 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -133,6 +133,12 @@ extern "C" {
#define AST_MAX_EXTENSION 80 /*!< Max length of an extension */
#define AST_MAX_CONTEXT 80 /*!< Max length of a context */
+#define AST_MAX_UNIQUEID 150 /*!< Max length of a channel uniqueid */
+/* 150 = 127 (max systemname) + "-" + 10 (epoch
+ * timestamp) + "." + 10 (monotonically incrementing
+ * integer) + NULL. Note that if this value is ever
+ * changed, MAX_CHANNEL_ID should be updated in
+ * rtp_engine.h */
#define AST_MAX_ACCOUNT_CODE 20 /*!< Max length of an account code */
#define AST_CHANNEL_NAME 80 /*!< Max length of an ast_channel name */
#define MAX_LANGUAGE 40 /*!< Max length of the language setting */
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 0584c99af..a735fd36b 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -330,6 +330,34 @@ intmax_t ast_json_integer_get(const struct ast_json *integer);
*/
int ast_json_integer_set(struct ast_json *integer, intmax_t value);
+/*!
+ * \brief Create a JSON real number.
+ * \since 12.0.0
+ * \param value Value of the new JSON real number.
+ * \return Newly allocated real number.
+ * \return \c NULL on error.
+ */
+struct ast_json *ast_json_real_create(double value);
+
+/*!
+ * \brief Get the value from a JSON real number.
+ * \since 12.0.0
+ * \param real JSON real number.
+ * \return Value of a JSON real number.
+ * \return 0 if \a real is not a JSON real number.
+ */
+double ast_json_real_get(const struct ast_json *real);
+
+/*!
+ * \brief Set the value of a JSON real number.
+ * \since 12.0.0
+ * \param integer JSON real number to modify.
+ * \param value New value for \a real.
+ * \return 0 on success.
+ * \return -1 on error.
+ */
+int ast_json_real_set(struct ast_json *real, double value);
+
/*!@}*/
/*!@{*/
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index e2567f508..bda13e891 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -74,6 +74,7 @@ extern "C" {
#include "asterisk/netsock2.h"
#include "asterisk/sched.h"
#include "asterisk/res_srtp.h"
+#include "asterisk/stasis.h"
/* Maximum number of payloads supported */
#if defined(LOW_MEMORY)
@@ -85,6 +86,12 @@ extern "C" {
/* Maximum number of generations */
#define AST_RED_MAX_GENERATION 5
+/* Maximum size of an Asterisk channel unique ID. Should match AST_MAX_UNIQUEID.
+ * Note that we don't use that defined value directly here to avoid a hard dependency
+ * on channel.h
+ */
+#define MAX_CHANNEL_ID 150
+
struct ast_rtp_instance;
struct ast_rtp_glue;
@@ -215,6 +222,8 @@ enum ast_rtp_instance_stat {
AST_RTP_INSTANCE_STAT_LOCAL_SSRC,
/*! Retrieve remote SSRC */
AST_RTP_INSTANCE_STAT_REMOTE_SSRC,
+ /*! Retrieve channel unique ID */
+ AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID,
};
/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
@@ -240,6 +249,46 @@ struct ast_rtp_payload_type {
int payload;
};
+/* Common RTCP report types */
+/*! Sender Report */
+#define AST_RTP_RTCP_SR 200
+/*! Receiver Report */
+#define AST_RTP_RTCP_RR 201
+
+/*!
+ * \since 12
+ * \brief A report block within a SR/RR report */
+struct ast_rtp_rtcp_report_block {
+ unsigned int source_ssrc; /*< The SSRC of the source for this report block */
+ struct {
+ unsigned short fraction; /*< The fraction of packets lost since last SR/RR */
+ unsigned int packets; /*< The cumulative packets since the beginning */
+ } lost_count; /*< Statistics regarding missed packets */
+ unsigned int highest_seq_no; /*< Extended highest sequence number received */
+ unsigned int ia_jitter; /*< Calculated interarrival jitter */
+ unsigned int lsr; /*< The time the last SR report was received */
+ unsigned int dlsr; /*< Delay in sending this report */
+};
+
+/*!
+ * \since 12
+ * \brief An object that represents data sent during a SR/RR RTCP report */
+struct ast_rtp_rtcp_report {
+ unsigned short reception_report_count; /*< The number of report blocks */
+ unsigned int ssrc; /*< Our SSRC */
+ unsigned int type; /*< The type of report. 200=SR; 201=RR */
+ struct {
+ struct timeval ntp_timestamp; /*< Our NTP timestamp */
+ unsigned int rtp_timestamp; /*< Our last RTP timestamp */
+ unsigned int packet_count; /*< Number of packets sent */
+ unsigned int octet_count; /*< Number of bytes sent */
+ } sender_information; /*< Sender information for SR */
+ /*! A dynamic array of report blocks. The number of elements is given by
+ * \c reception_report_count.
+ */
+ struct ast_rtp_rtcp_report_block *report_block[0];
+};
+
/*! Structure that represents statistics from an RTP instance */
struct ast_rtp_instance_stats {
/*! Number of packets transmitted */
@@ -300,6 +349,8 @@ struct ast_rtp_instance_stats {
unsigned int local_ssrc;
/*! Their SSRC */
unsigned int remote_ssrc;
+ /*! The Asterisk channel's unique ID that owns this instance */
+ char channel_uniqueid[MAX_CHANNEL_ID];
};
#define AST_RTP_STAT_SET(current_stat, combined, placement, value) \
@@ -310,6 +361,14 @@ return 0; \
} \
}
+#define AST_RTP_STAT_STRCPY(current_stat, combined, placement, value) \
+if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \
+ ast_copy_string(placement, value, sizeof(placement)); \
+ if (stat == current_stat) { \
+ return 0; \
+ } \
+}
+
#define AST_RTP_STAT_TERMINATOR(combined) \
if (stat == combined) { \
return 0; \
@@ -1541,6 +1600,30 @@ int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp);
struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type);
/*!
+ * \brief Get the unique ID of the channel that owns this RTP instance
+ *
+ * Note that this should remain valid for the lifetime of the RTP instance.
+ *
+ * \param instance The RTP instance
+ *
+ * \retval The unique ID of the channel
+ * \retval Empty string if no channel owns this RTP instance
+ *
+ * \since 12
+ */
+const char *ast_rtp_instance_get_channel_id(struct ast_rtp_instance *instance);
+
+/*!
+ * \brief Set the channel that owns this RTP instance
+ *
+ * \param instance The RTP instance
+ * \param uniqueid The uniqueid of the channel
+ *
+ * \since 12
+ */
+void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid);
+
+/*!
* \brief Get the other RTP instance that an instance is bridged to
*
* \param instance The RTP instance that we want
@@ -1965,27 +2048,6 @@ struct ast_rtp_engine *ast_rtp_instance_get_engine(struct ast_rtp_instance *inst
struct ast_rtp_glue *ast_rtp_instance_get_active_glue(struct ast_rtp_instance *instance);
/*!
- * \brief Get the channel that is associated with an RTP instance while in a bridge
- *
- * \param instance The RTP instance
- *
- * \retval pointer to the channel
- *
- * Example:
- *
- * \code
- * struct ast_channel *chan = ast_rtp_instance_get_chan(instance);
- * \endcode
- *
- * This gets the channel associated with the RTP instance pointed to by 'instance'.
- *
- * \note This will only return a channel while in a local or remote bridge.
- *
- * \since 1.8
- */
-struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance);
-
-/*!
* \brief Send a comfort noise packet to the RTP instance
*
* \param instance The RTP instance
@@ -2073,6 +2135,62 @@ void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rt
*/
void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg);
+struct ast_json;
+
+/*!
+ * \brief Allocate an ao2 ref counted instance of \ref ast_rtp_rtcp_report
+ *
+ * \param report_blocks The number of report blocks to allocate
+ * \retval An ao2 ref counted \ref ast_rtp_rtcp_report object on success
+ * \retval NULL on error
+ */
+struct ast_rtp_rtcp_report *ast_rtp_rtcp_report_alloc(unsigned int report_blocks);
+
+/*!
+ * \since 12
+ * \brief Publish an RTCP message to \ref stasis
+ *
+ * \param rtp The rtp instance object
+ * \param message_type The RTP message type to publish
+ * \param report The RTCP report object to publish. This should be an ao2 ref counted
+ * object. This routine will increase the reference count of the object.
+ * \param blob Additional JSON objects to publish along with the RTCP information
+ */
+void ast_rtp_publish_rtcp_message(struct ast_rtp_instance *rtp,
+ struct stasis_message_type *message_type,
+ struct ast_rtp_rtcp_report *report,
+ struct ast_json *blob);
+
+/*! \addtogroup StasisTopicsAndMessages
+ * @{
+ */
+
+/*!
+ * \since 12
+ * \brief Message type for an RTCP message sent from this Asterisk instance
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_rtp_rtcp_sent_type(void);
+
+/*!
+ * \since 12
+ * \brief Message type for an RTCP message received from some external source
+ *
+ * \retval A stasis message type
+ */
+struct stasis_message_type *ast_rtp_rtcp_received_type(void);
+
+/*!
+ * \since 12
+ * \brief \ref stasis topic for RTP and RTCP related messages
+ *
+ * \retval A \ref stasis topic
+ */
+struct stasis_topic *ast_rtp_topic(void);
+
+/* }@ */
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/main/asterisk.c b/main/asterisk.c
index aa33f31e4..b8cf43e37 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -27,7 +27,7 @@
* internals of the Asterisk software. This documentation contains basic
* examples, developer documentation, support information, and information
* for upgrading.
- *
+ *
* \section community Community
* Asterisk is a big project and has a busy community. Look at the
* resources for questions and stick around to help answer questions.
@@ -120,7 +120,7 @@
* \par
* Use http://www.freenode.net IRC server to connect with Asterisk
* developers and users in realtime.
- *
+ *
* \li \verbatim #asterisk \endverbatim Asterisk Users Room
* \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
*
@@ -4217,6 +4217,7 @@ int main(int argc, char *argv[])
printf("Stasis initialization failed.\n%s", term_quit());
exit(1);
}
+
if (stasis_system_topic_init()) {
printf("Stasis system-level information initialization failed.\n%s", term_quit());
exit(1);
@@ -4258,7 +4259,10 @@ int main(int argc, char *argv[])
ast_format_attr_init();
ast_format_list_init();
- ast_rtp_engine_init();
+ if (ast_rtp_engine_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
ast_autoservice_init();
diff --git a/main/json.c b/main/json.c
index c185b053f..1b0e41275 100644
--- a/main/json.c
+++ b/main/json.c
@@ -214,6 +214,20 @@ int ast_json_integer_set(struct ast_json *integer, intmax_t value)
return json_integer_set((json_t *)integer, value);
}
+struct ast_json *ast_json_real_create(double value)
+{
+ return (struct ast_json *)json_real(value);
+}
+
+double ast_json_real_get(const struct ast_json *real)
+{
+ return json_real_value((json_t *)real);
+}
+
+int ast_json_real_set(struct ast_json *real, double value)
+{
+ return json_real_set((json_t *)real, value);
+}
int ast_json_equal(const struct ast_json *lhs, const struct ast_json *rhs)
{
diff --git a/main/manager.c b/main/manager.c
index 02d61dad5..b1c7b5361 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -98,6 +98,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/json.h"
#include "asterisk/bridging.h"
#include "asterisk/features_config.h"
+#include "asterisk/rtp_engine.h"
/*** DOCUMENTATION
<manager name="Ping" language="en_US">
@@ -1071,6 +1072,9 @@ static struct stasis_topic *manager_topic;
/*! \brief The \ref stasis_message_router for all \ref stasis messages */
static struct stasis_message_router *stasis_router;
+/*! \brief The \ref stasis_subscription for forwarding the RTP topic to the AMI topic */
+static struct stasis_subscription *rtp_topic_forwarder;
+
#define MGR_SHOW_TERMINAL_WIDTH 80
#define MAX_VARS 128
@@ -7775,6 +7779,11 @@ static int manager_subscriptions_init(void)
if (!manager_topic) {
return -1;
}
+ rtp_topic_forwarder = stasis_forward_all(ast_rtp_topic(), manager_topic);
+ if (!rtp_topic_forwarder) {
+ return -1;
+ }
+
stasis_router = stasis_message_router_create(manager_topic);
if (!stasis_router) {
return -1;
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 8e58f658d..4dd4d46de 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -25,6 +25,114 @@
/*** MODULEINFO
<support_level>core</support_level>
+***/
+
+/*** DOCUMENTATION
+ <managerEvent language="en_US" name="RTCPSent">
+ <managerEventInstance class="EVENT_FLAG_REPORTING">
+ <synopsis>Raised when an RTCP packet is sent.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="SSRC">
+ <para>The SSRC identifier for our stream</para>
+ </parameter>
+ <parameter name="PT">
+ <para>The type of packet for this RTCP report.</para>
+ <enumlist>
+ <enum name="200(SR)"/>
+ <enum name="201(RR)"/>
+ </enumlist>
+ </parameter>
+ <parameter name="To">
+ <para>The address the report is sent to.</para>
+ </parameter>
+ <parameter name="ReportCount">
+ <para>The number of reports that were sent.</para>
+ <para>The report count determines the number of ReportX headers in
+ the message. The X for each set of report headers will range from 0 to
+ <literal>ReportCount - 1</literal>.</para>
+ </parameter>
+ <parameter name="SentNTP" required="false">
+ <para>The time the sender generated the report. Only valid when
+ PT is <literal>200(SR)</literal>.</para>
+ </parameter>
+ <parameter name="SentRTP" required="false">
+ <para>The sender's last RTP timestamp. Only valid when PT is
+ <literal>200(SR)</literal>.</para>
+ </parameter>
+ <parameter name="SentPackets" required="false">
+ <para>The number of packets the sender has sent. Only valid when PT
+ is <literal>200(SR)</literal>.</para>
+ </parameter>
+ <parameter name="SentOctets" required="false">
+ <para>The number of bytes the sender has sent. Only valid when PT is
+ <literal>200(SR)</literal>.</para>
+ </parameter>
+ <parameter name="ReportXSourceSSRC">
+ <para>The SSRC for the source of this report block.</para>
+ </parameter>
+ <parameter name="ReportXFractionLost">
+ <para>The fraction of RTP data packets from <literal>ReportXSourceSSRC</literal>
+ lost since the previous SR or RR report was sent.</para>
+ </parameter>
+ <parameter name="ReportXCumulativeLost">
+ <para>The total number of RTP data packets from <literal>ReportXSourceSSRC</literal>
+ lost since the beginning of reception.</para>
+ </parameter>
+ <parameter name="ReportXHighestSequence">
+ <para>The highest sequence number received in an RTP data packet from
+ <literal>ReportXSourceSSRC</literal>.</para>
+ </parameter>
+ <parameter name="ReportXSequenceNumberCycles">
+ <para>The number of sequence number cycles seen for the RTP data
+ received from <literal>ReportXSourceSSRC</literal>.</para>
+ </parameter>
+ <parameter name="ReportXIAJitter">
+ <para>An estimate of the statistical variance of the RTP data packet
+ interarrival time, measured in timestamp units.</para>
+ </parameter>
+ <parameter name="ReportXLSR">
+ <para>The last SR timestamp received from <literal>ReportXSourceSSRC</literal>.
+ If no SR has been received from <literal>ReportXSourceSSRC</literal>,
+ then 0.</para>
+ </parameter>
+ <parameter name="ReportXDLSR">
+ <para>The delay, expressed in units of 1/65536 seconds, between
+ receiving the last SR packet from <literal>ReportXSourceSSRC</literal>
+ and sending this report.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="RTCPReceived">
+ <managerEventInstance class="EVENT_FLAG_REPORTING">
+ <synopsis>Raised when an RTCP packet is received.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="SSRC">
+ <para>The SSRC identifier for the remote system</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='PT'])" />
+ <parameter name="From">
+ <para>The address the report was received from.</para>
+ </parameter>
+ <parameter name="RTT">
+ <para>Calculated Round-Trip Time in seconds</para>
+ </parameter>
+ <parameter name="ReportCount">
+ <para>The number of reports that were received.</para>
+ <para>The report count determines the number of ReportX headers in
+ the message. The X for each set of report headers will range from 0 to
+ <literal>ReportCount - 1</literal>.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentNTP'])" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentRTP'])" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentPackets'])" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentOctets'])" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[contains(@name, 'ReportX')])" />
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
#include "asterisk.h"
@@ -45,6 +153,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/netsock2.h"
#include "asterisk/_private.h"
#include "asterisk/framehook.h"
+#include "asterisk/stasis.h"
+#include "asterisk/json.h"
+#include "asterisk/stasis_channels.h"
struct ast_srtp_res *res_srtp = NULL;
struct ast_srtp_policy_res *res_srtp_policy = NULL;
@@ -73,10 +184,10 @@ struct ast_rtp_instance {
int keepalive;
/*! Glue currently in use */
struct ast_rtp_glue *glue;
- /*! Channel associated with the instance */
- struct ast_channel *chan;
/*! SRTP info associated with the instance */
struct ast_srtp *srtp;
+ /*! Channel unique ID */
+ char channel_uniqueid[AST_MAX_UNIQUEID];
};
/*! List of RTP engines that are currently registered */
@@ -109,6 +220,9 @@ static int mime_types_len = 0;
static struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT];
static ast_rwlock_t static_RTP_PT_lock;
+/*! \brief \ref stasis topic for RTP related messages */
+static struct stasis_topic *rtp_topic;
+
int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
{
struct ast_rtp_engine *current_engine;
@@ -292,6 +406,16 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
return instance;
}
+const char *ast_rtp_instance_get_channel_id(struct ast_rtp_instance *instance)
+{
+ return instance->channel_uniqueid;
+}
+
+void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid)
+{
+ ast_copy_string(instance->channel_uniqueid, uniqueid, sizeof(instance->channel_uniqueid));
+}
+
void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data)
{
instance->data = data;
@@ -1317,11 +1441,6 @@ struct ast_rtp_glue *ast_rtp_instance_get_active_glue(struct ast_rtp_instance *i
return instance->glue;
}
-struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance)
-{
- return instance->chan;
-}
-
int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res)
{
if (res_srtp || res_srtp_policy) {
@@ -1552,6 +1671,256 @@ int ast_rtp_engine_unload_format(const struct ast_format *format)
return 0;
}
+/*! \internal \brief \ref stasis message payload for RTCP messages */
+struct rtcp_message_payload {
+ struct ast_channel_snapshot *snapshot; /*< The channel snapshot, if available */
+ struct ast_rtp_rtcp_report *report; /*< The RTCP report */
+ struct ast_json *blob; /*< Extra JSON data to publish */
+};
+
+static void rtcp_message_payload_dtor(void *obj)
+{
+ struct rtcp_message_payload *payload = obj;
+
+ ao2_cleanup(payload->report);
+ ao2_cleanup(payload->snapshot);
+ ast_json_unref(payload->blob);
+}
+
+static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *msg)
+{
+ struct rtcp_message_payload *payload = stasis_message_data(msg);
+ RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, packet_string, ast_str_create(512), ast_free);
+ unsigned int ssrc = payload->report->ssrc;
+ unsigned int type = payload->report->type;
+ unsigned int report_count = payload->report->reception_report_count;
+ int i;
+
+ if (!packet_string) {
+ return NULL;
+ }
+
+ if (payload->snapshot) {
+ channel_string = ast_manager_build_channel_state_string(payload->snapshot);
+ if (!channel_string) {
+ return NULL;
+ }
+ }
+
+ if (payload->blob) {
+ /* Optional data */
+ struct ast_json *to = ast_json_object_get(payload->blob, "to");
+ struct ast_json *from = ast_json_object_get(payload->blob, "from");
+ struct ast_json *rtt = ast_json_object_get(payload->blob, "rtt");
+ if (to) {
+ ast_str_append(&packet_string, 0, "To: %s\r\n", ast_json_string_get(to));
+ }
+ if (from) {
+ ast_str_append(&packet_string, 0, "From: %s\r\n", ast_json_string_get(from));
+ }
+ if (rtt) {
+ ast_str_append(&packet_string, 0, "RTT: %4.4f\r\n", ast_json_real_get(rtt));
+ }
+ }
+
+ ast_str_append(&packet_string, 0, "SSRC: 0x%.8x\r\n", ssrc);
+ ast_str_append(&packet_string, 0, "PT: %u(%s)\r\n", type, type== AST_RTP_RTCP_SR ? "SR" : "RR");
+ ast_str_append(&packet_string, 0, "ReportCount: %u\r\n", report_count);
+ if (type == AST_RTP_RTCP_SR) {
+ ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n",
+ (unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec,
+ (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096);
+ ast_str_append(&packet_string, 0, "SentRTP: %u\r\n",
+ payload->report->sender_information.rtp_timestamp);
+ ast_str_append(&packet_string, 0, "SentPackets: %u\r\n",
+ payload->report->sender_information.packet_count);
+ ast_str_append(&packet_string, 0, "SentOctets: %u\r\n",
+ payload->report->sender_information.octet_count);
+ }
+
+ for (i = 0; i < report_count; i++) {
+ RAII_VAR(struct ast_str *, report_string, NULL, ast_free);
+
+ if (!payload->report->report_block[i]) {
+ break;
+ }
+
+ report_string = ast_str_create(256);
+ if (!report_string) {
+ return NULL;
+ }
+
+ ast_str_append(&report_string, 0, "Report%dSourceSSRC: 0x%.8x\r\n",
+ i, payload->report->report_block[i]->source_ssrc);
+ ast_str_append(&report_string, 0, "Report%dFractionLost: %u\r\n",
+ i, payload->report->report_block[i]->lost_count.fraction);
+ ast_str_append(&report_string, 0, "Report%dCumulativeLost: %u\r\n",
+ i, payload->report->report_block[i]->lost_count.packets);
+ ast_str_append(&report_string, 0, "Report%dHighestSequence: %u\r\n",
+ i, payload->report->report_block[i]->highest_seq_no & 0xffff);
+ ast_str_append(&report_string, 0, "Report%dSequenceNumberCycles: %u\r\n",
+ i, payload->report->report_block[i]->highest_seq_no >> 16);
+ ast_str_append(&report_string, 0, "Report%dIAJitter: %u\r\n",
+ i, payload->report->report_block[i]->ia_jitter);
+ ast_str_append(&report_string, 0, "Report%dLSR: %u\r\n",
+ i, payload->report->report_block[i]->lsr);
+ ast_str_append(&report_string, 0, "Report%dDLSR: %4.4f\r\n",
+ i, ((double)payload->report->report_block[i]->dlsr) / 65536);
+ ast_str_append(&packet_string, 0, "%s", ast_str_buffer(report_string));
+ }
+
+ return ast_manager_event_blob_create(EVENT_FLAG_REPORTING,
+ stasis_message_type(msg) == ast_rtp_rtcp_received_type() ? "RTCPReceived" : "RTCPSent",
+ "%s%s",
+ AS_OR(channel_string, ""),
+ ast_str_buffer(packet_string));
+}
+
+static struct ast_json *rtcp_report_to_json(struct stasis_message *msg)
+{
+ struct rtcp_message_payload *payload = stasis_message_data(msg);
+ RAII_VAR(struct ast_json *, json_rtcp_report, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, json_rtcp_report_blocks, NULL, ast_json_unref);
+ RAII_VAR(struct ast_json *, json_rtcp_sender_info, NULL, ast_json_unref);
+ struct ast_json * json_payload;
+ int i;
+
+ json_rtcp_report_blocks = ast_json_array_create();
+ if (!json_rtcp_report_blocks) {
+ return NULL;
+ }
+
+ for (i = 0; i < payload->report->reception_report_count; i++) {
+ struct ast_json *json_report_block;
+ json_report_block = ast_json_pack("{s: i, s: i, s: i, s: i, s: i, s: i, s: i}",
+ "source_ssrc", payload->report->report_block[i]->source_ssrc,
+ "fraction_lost", payload->report->report_block[i]->lost_count.fraction,
+ "packets_lost", payload->report->report_block[i]->lost_count.packets,
+ "highest_seq_no", payload->report->report_block[i]->highest_seq_no,
+ "ia_jitter", payload->report->report_block[i]->ia_jitter,
+ "lsr", payload->report->report_block[i]->lsr,
+ "dlsr", payload->report->report_block[i]->dlsr);
+ if (!json_report_block) {
+ return NULL;
+ }
+
+ if (ast_json_array_append(json_rtcp_report_blocks, json_report_block)) {
+ return NULL;
+ }
+ }
+
+ if (payload->report->type == AST_RTP_RTCP_SR) {
+ json_rtcp_sender_info = ast_json_pack("{s: i, s: i, s: i, s: i, s: i}",
+ "ntp_timestamp_sec", payload->report->sender_information.ntp_timestamp.tv_sec,
+ "ntp_timestamp_usec", payload->report->sender_information.ntp_timestamp.tv_usec,
+ "rtp_timestamp", payload->report->sender_information.rtp_timestamp,
+ "packets", payload->report->sender_information.packet_count,
+ "octets", payload->report->sender_information.octet_count);
+ if (!json_rtcp_sender_info) {
+ return NULL;
+ }
+ }
+
+ json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: O, s: O}",
+ "ssrc", payload->report->ssrc,
+ "type", payload->report->type,
+ "report_count", payload->report->reception_report_count,
+ "sender_information", json_rtcp_sender_info ? json_rtcp_sender_info : ast_json_null(),
+ "report_blocks", json_rtcp_report_blocks);
+ if (!json_rtcp_report) {
+ return NULL;
+ }
+
+ json_payload = ast_json_pack("{s: O, s: O, s: O}",
+ "channel", payload->snapshot ? ast_channel_snapshot_to_json(payload->snapshot) : ast_json_null(),
+ "rtcp_report", json_rtcp_report,
+ "blob", payload->blob);
+ return json_payload;
+}
+
+static void rtp_rtcp_report_dtor(void *obj)
+{
+ int i;
+ struct ast_rtp_rtcp_report *rtcp_report = obj;
+
+ for (i = 0; i < rtcp_report->reception_report_count; i++) {
+ ast_free(rtcp_report->report_block[i]);
+ }
+}
+
+struct ast_rtp_rtcp_report *ast_rtp_rtcp_report_alloc(unsigned int report_blocks)
+{
+ struct ast_rtp_rtcp_report *rtcp_report;
+
+ /* Size of object is sizeof the report + the number of report_blocks * sizeof pointer */
+ rtcp_report = ao2_alloc((sizeof(*rtcp_report) + report_blocks * sizeof(struct ast_rtp_rtcp_report_block *)),
+ rtp_rtcp_report_dtor);
+
+ return rtcp_report;
+}
+
+void ast_rtp_publish_rtcp_message(struct ast_rtp_instance *rtp,
+ struct stasis_message_type *message_type,
+ struct ast_rtp_rtcp_report *report,
+ struct ast_json *blob)
+{
+ RAII_VAR(struct rtcp_message_payload *, payload,
+ ao2_alloc(sizeof(*payload), rtcp_message_payload_dtor), ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+ if (!payload || !report) {
+ return;
+ }
+
+ if (!ast_strlen_zero(rtp->channel_uniqueid)) {
+ snapshot = ast_channel_snapshot_get_latest(rtp->channel_uniqueid);
+ if (snapshot) {
+ ao2_ref(snapshot, +1);
+ }
+ }
+
+ if (blob) {
+ ast_json_ref(blob);
+ }
+ ao2_ref(report, 1);
+ payload->snapshot = snapshot;
+ payload->blob = blob;
+ payload->report = report;
+
+ message = stasis_message_create(message_type, payload);
+ if (!message) {
+ return;
+ }
+
+ stasis_publish(ast_rtp_topic(), message);
+}
+
+/*!
+ * @{ \brief Define RTCP/RTP message types.
+ */
+STASIS_MESSAGE_TYPE_DEFN(ast_rtp_rtcp_sent_type,
+ .to_ami = rtcp_report_to_ami,
+ .to_json = rtcp_report_to_json,);
+STASIS_MESSAGE_TYPE_DEFN(ast_rtp_rtcp_received_type,
+ .to_ami = rtcp_report_to_ami,
+ .to_json = rtcp_report_to_json,);
+/*! @} */
+
+struct stasis_topic *ast_rtp_topic(void)
+{
+ return rtp_topic;
+}
+
+static void rtp_engine_shutdown(void)
+{
+ ao2_cleanup(rtp_topic);
+ rtp_topic = NULL;
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_received_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(ast_rtp_rtcp_sent_type);
+}
+
int ast_rtp_engine_init()
{
struct ast_format tmpfmt;
@@ -1559,6 +1928,14 @@ int ast_rtp_engine_init()
ast_rwlock_init(&mime_types_lock);
ast_rwlock_init(&static_RTP_PT_lock);
+ rtp_topic = stasis_topic_create("rtp_topic");
+ if (!rtp_topic) {
+ return -1;
+ }
+ STASIS_MESSAGE_TYPE_INIT(ast_rtp_rtcp_sent_type);
+ STASIS_MESSAGE_TYPE_INIT(ast_rtp_rtcp_received_type);
+ ast_register_atexit(rtp_engine_shutdown);
+
/* Define all the RTP mime types available */
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0, "audio", "G723", 8000);
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0, "audio", "GSM", 8000);
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 3f19dbdeb..efe5b967e 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -85,8 +85,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define TURN_ALLOCATION_WAIT_TIME 2000
#define RTCP_PT_FUR 192
-#define RTCP_PT_SR 200
-#define RTCP_PT_RR 201
+#define RTCP_PT_SR AST_RTP_RTCP_SR
+#define RTCP_PT_RR AST_RTP_RTCP_RR
#define RTCP_PT_SDES 202
#define RTCP_PT_BYE 203
#define RTCP_PT_APP 204
@@ -2182,52 +2182,46 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
*lsw = frac;
}
-/*! \brief Send RTCP recipient's report */
-static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
+static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv)
{
- struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
- int res;
- int len = 32;
- unsigned int lost;
- unsigned int extended;
- unsigned int expected;
+ tv->tv_sec = msw - 2208988800u;
+ tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8);
+}
+
+static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
+ unsigned int *lost_packets,
+ int *fraction_lost)
+{
+ unsigned int extended_seq_no;
+ unsigned int expected_packets;
unsigned int expected_interval;
unsigned int received_interval;
- int lost_interval;
- struct timeval now;
- unsigned int *rtcpheader;
- char bdata[1024];
- struct timeval dlsr;
- int fraction;
- int rate = rtp_get_rate(&rtp->f.subclass.format);
- int ice;
double rxlost_current;
- struct ast_sockaddr remote_address = { {0,} };
+ int lost_interval;
- if (!rtp || !rtp->rtcp) {
- return 0;
+ /* Compute statistics */
+ extended_seq_no = rtp->cycles + rtp->lastrxseqno;
+ expected_packets = extended_seq_no - rtp->seedrxseqno + 1;
+ if (rtp->rxcount > expected_packets) {
+ expected_packets += rtp->rxcount - expected_packets;
}
-
- if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
- /*
- * RTCP was stopped.
- */
- return 0;
- }
-
- extended = rtp->cycles + rtp->lastrxseqno;
- expected = extended - rtp->seedrxseqno + 1;
- lost = expected - rtp->rxcount;
- expected_interval = expected - rtp->rtcp->expected_prior;
- rtp->rtcp->expected_prior = expected;
+ *lost_packets = expected_packets - rtp->rxcount;
+ expected_interval = expected_packets - rtp->rtcp->expected_prior;
received_interval = rtp->rxcount - rtp->rtcp->received_prior;
- rtp->rtcp->received_prior = rtp->rxcount;
lost_interval = expected_interval - received_interval;
+ if (expected_interval == 0 || lost_interval <= 0) {
+ *fraction_lost = 0;
+ } else {
+ *fraction_lost = (lost_interval << 8) / expected_interval;
+ }
+ /* Update RTCP statistics */
+ rtp->rtcp->received_prior = rtp->rxcount;
+ rtp->rtcp->expected_prior = expected_packets;
if (lost_interval <= 0) {
rtp->rtcp->rxlost = 0;
} else {
- rtp->rtcp->rxlost = rtp->rtcp->rxlost;
+ rtp->rtcp->rxlost = lost_interval;
}
if (rtp->rtcp->rxlost_count == 0) {
rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
@@ -2238,200 +2232,162 @@ static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
if (lost_interval > rtp->rtcp->maxrxlost) {
rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
}
-
- rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
- rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
+ rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost,
+ rtp->rtcp->rxlost,
+ rtp->rtcp->rxlost_count);
+ rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost,
+ rtp->rtcp->rxlost,
+ rtp->rtcp->normdev_rxlost,
+ rxlost_current,
+ rtp->rtcp->rxlost_count);
rtp->rtcp->normdev_rxlost = rxlost_current;
rtp->rtcp->rxlost_count++;
-
- if (expected_interval == 0 || lost_interval <= 0) {
- fraction = 0;
- } else {
- fraction = (lost_interval << 8) / expected_interval;
- }
- gettimeofday(&now, NULL);
- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
- rtcpheader = (unsigned int *)bdata;
- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
- rtcpheader[1] = htonl(rtp->ssrc);
- rtcpheader[2] = htonl(rtp->themssrc);
- rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
- rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
- rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * rate));
- rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
- rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
-
- /*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
- it can change mid call, and SDES can't) */
- rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
- len += 12;
-
- ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
-
- res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
-
- if (res < 0) {
- ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
- return 0;
- }
-
- rtp->rtcp->rr_count++;
-
- update_address_with_ice_candidate(rtp, COMPONENT_RTCP, &remote_address);
-
- if (rtcp_debug_test_addr(&remote_address)) {
- ast_verbose("\n* Sending RTCP RR to %s%s\n"
- " Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n"
- " IA jitter: %.4f\n"
- " Their last SR: %u\n"
- " DLSR: %4.4f (sec)\n\n",
- ast_sockaddr_stringify(&remote_address),
- ice ? " (via ICE)" : "",
- rtp->ssrc, rtp->themssrc, fraction, lost,
- rtp->rxjitter,
- rtp->rtcp->themrxlsr,
- (double)(ntohl(rtcpheader[7])/65536.0));
- }
-
- return res;
}
-/*! \brief Send RTCP sender's report */
-static int ast_rtcp_write_sr(struct ast_rtp_instance *instance)
+/*! \brief Send RTCP SR or RR report */
+static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
int res;
int len = 0;
struct timeval now;
unsigned int now_lsw;
unsigned int now_msw;
unsigned int *rtcpheader;
- unsigned int lost;
- unsigned int extended;
- unsigned int expected;
- unsigned int expected_interval;
- unsigned int received_interval;
- int lost_interval;
- int fraction;
- struct timeval dlsr;
+ unsigned int lost_packets;
+ int fraction_lost;
+ struct timeval dlsr = { 0, };
char bdata[512];
int rate = rtp_get_rate(&rtp->f.subclass.format);
int ice;
+ int header_offset = 0;
struct ast_sockaddr remote_address = { {0,} };
+ struct ast_rtp_rtcp_report_block *report_block;
+ RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+ ast_rtp_rtcp_report_alloc(1),
+ ao2_cleanup);
if (!rtp || !rtp->rtcp) {
return 0;
}
if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */
- /*
- * RTCP was stopped.
- */
+ /* RTCP was stopped. */
return 0;
}
+ if (!rtcp_report) {
+ return 1;
+ }
+
+ report_block = ast_calloc(1, sizeof(*report_block));
+ if (!report_block) {
+ return 1;
+ }
+
+ /* Compute statistics */
+ calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);
+
gettimeofday(&now, NULL);
- timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
+ rtcp_report->reception_report_count = 1;
+ rtcp_report->ssrc = rtp->ssrc;
+ rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR;
+ if (sr) {
+ rtcp_report->sender_information.ntp_timestamp = now;
+ rtcp_report->sender_information.rtp_timestamp = rtp->lastts;
+ rtcp_report->sender_information.packet_count = rtp->txcount;
+ rtcp_report->sender_information.octet_count = rtp->txoctetcount;
+ }
+ rtcp_report->report_block[0] = report_block;
+ report_block->source_ssrc = rtp->themssrc;
+ report_block->lost_count.fraction = (fraction_lost & 0xff);
+ report_block->lost_count.packets = (lost_packets & 0xffffff);
+ report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));
+ report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rate);
+ report_block->lsr = rtp->rtcp->themrxlsr;
+ /* If we haven't received an SR report, DLSR should be 0 */
+ if (!ast_tvzero(rtp->rtcp->rxlsr)) {
+ timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+ report_block->dlsr = (((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000;
+ }
+ timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw);
rtcpheader = (unsigned int *)bdata;
- rtcpheader[1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
- rtcpheader[3] = htonl(now_lsw); /* now, LSW */
- rtcpheader[4] = htonl(rtp->lastts); /* FIXME shouldn't be that, it should be now */
- rtcpheader[5] = htonl(rtp->txcount); /* No. packets sent */
- rtcpheader[6] = htonl(rtp->txoctetcount); /* No. bytes sent */
- len += 28;
-
- extended = rtp->cycles + rtp->lastrxseqno;
- expected = extended - rtp->seedrxseqno + 1;
- if (rtp->rxcount > expected) {
- expected += rtp->rxcount - expected;
- }
- lost = expected - rtp->rxcount;
- expected_interval = expected - rtp->rtcp->expected_prior;
- rtp->rtcp->expected_prior = expected;
- received_interval = rtp->rxcount - rtp->rtcp->received_prior;
- rtp->rtcp->received_prior = rtp->rxcount;
- lost_interval = expected_interval - received_interval;
- if (expected_interval == 0 || lost_interval <= 0) {
- fraction = 0;
- } else {
- fraction = (lost_interval << 8) / expected_interval;
- }
- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
- rtcpheader[7] = htonl(rtp->themssrc);
- rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
- rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
- rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * rate));
- rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
- rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+ rtcpheader[1] = htonl(rtcp_report->ssrc); /* Our SSRC */
+ len += 8;
+ if (sr) {
+ header_offset = 5;
+ rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
+ rtcpheader[3] = htonl(now_lsw); /* now, LSW */
+ rtcpheader[4] = htonl(rtcp_report->sender_information.rtp_timestamp);
+ rtcpheader[5] = htonl(rtcp_report->sender_information.packet_count);
+ rtcpheader[6] = htonl(rtcp_report->sender_information.octet_count);
+ len += 20;
+ }
+ rtcpheader[2 + header_offset] = htonl(report_block->source_ssrc); /* Their SSRC */
+ rtcpheader[3 + header_offset] = htonl((report_block->lost_count.fraction << 24) | report_block->lost_count.packets);
+ rtcpheader[4 + header_offset] = htonl(report_block->highest_seq_no);
+ rtcpheader[5 + header_offset] = htonl(report_block->ia_jitter);
+ rtcpheader[6 + header_offset] = htonl(report_block->lsr);
+ rtcpheader[7 + header_offset] = htonl(report_block->dlsr);
len += 24;
-
- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 16) | ((len/4)-1));
+ rtcpheader[0] = htonl((2 << 30) | (1 << 24) | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1));
/* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
/* it can change mid call, and SDES can't) */
rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
+ rtcpheader[(len/4)+1] = htonl(rtcp_report->ssrc);
+ rtcpheader[(len/4)+2] = htonl(0x01 << 24);
len += 12;
ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
-
res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
if (res < 0) {
- ast_log(LOG_ERROR, "RTCP SR transmission error to %s, rtcp halted %s\n",
+ ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",
+ sr ? "SR" : "RR",
ast_sockaddr_stringify(&rtp->rtcp->them),
strerror(errno));
return 0;
}
- /* FIXME Don't need to get a new one */
- gettimeofday(&rtp->rtcp->txlsr, NULL);
- rtp->rtcp->sr_count++;
-
- rtp->rtcp->lastsrtxcount = rtp->txcount;
+ /* Update RTCP SR/RR statistics */
+ if (sr) {
+ rtp->rtcp->txlsr = rtcp_report->sender_information.ntp_timestamp;
+ rtp->rtcp->sr_count++;
+ rtp->rtcp->lastsrtxcount = rtp->txcount;
+ } else {
+ rtp->rtcp->rr_count++;
+ }
update_address_with_ice_candidate(rtp, COMPONENT_RTCP, &remote_address);
if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
- ast_verbose("* Sent RTCP SR to %s%s\n", ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
- ast_verbose(" Our SSRC: %u\n", rtp->ssrc);
- ast_verbose(" Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096);
- ast_verbose(" Sent(RTP): %u\n", rtp->lastts);
- ast_verbose(" Sent packets: %u\n", rtp->txcount);
- ast_verbose(" Sent octets: %u\n", rtp->txoctetcount);
+ ast_verbose("* Sent RTCP %s to %s%s\n", sr ? "SR" : "RR",
+ ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
+ ast_verbose(" Our SSRC: %u\n", rtcp_report->ssrc);
+ if (sr) {
+ ast_verbose(" Sent(NTP): %u.%010u\n",
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ ast_verbose(" Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp);
+ ast_verbose(" Sent packets: %u\n", rtcp_report->sender_information.packet_count);
+ ast_verbose(" Sent octets: %u\n", rtcp_report->sender_information.octet_count);
+ }
ast_verbose(" Report block:\n");
- ast_verbose(" Fraction lost: %u\n", fraction);
- ast_verbose(" Cumulative loss: %u\n", lost);
- ast_verbose(" IA jitter: %.4f\n", rtp->rxjitter);
- ast_verbose(" Their last SR: %u\n", rtp->rtcp->themrxlsr);
- ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0));
- }
- manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To: %s\r\n"
- "OurSSRC: %u\r\n"
- "SentNTP: %u.%010u\r\n"
- "SentRTP: %u\r\n"
- "SentPackets: %u\r\n"
- "SentOctets: %u\r\n"
- "ReportBlock:\r\n"
- "FractionLost: %u\r\n"
- "CumulativeLoss: %u\r\n"
- "IAJitter: %.4f\r\n"
- "TheirLastSR: %u\r\n"
- "DLSR: %4.4f (sec)\r\n",
- ast_sockaddr_stringify(&remote_address),
- rtp->ssrc,
- (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096,
- rtp->lastts,
- rtp->txcount,
- rtp->txoctetcount,
- fraction,
- lost,
- rtp->rxjitter,
- rtp->rtcp->themrxlsr,
- (double)(ntohl(rtcpheader[12])/65536.0));
+ ast_verbose(" Their SSRC: %u\n", report_block->source_ssrc);
+ ast_verbose(" Fraction lost: %u\n", report_block->lost_count.fraction);
+ ast_verbose(" Cumulative loss: %u\n", report_block->lost_count.packets);
+ ast_verbose(" Highest seq no: %u\n", report_block->highest_seq_no);
+ ast_verbose(" IA jitter: %.4f\n", (double)report_block->ia_jitter / rate);
+ ast_verbose(" Their last SR: %u\n", report_block->lsr);
+ ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));
+ }
+
+ message_blob = ast_json_pack("{s: s}",
+ "to", ast_sockaddr_stringify(&remote_address));
+ ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),
+ rtcp_report,
+ message_blob);
return res;
}
@@ -2450,9 +2406,11 @@ static int ast_rtcp_write(const void *data)
}
if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
- res = ast_rtcp_write_sr(instance);
+ /* Send an SR */
+ res = ast_rtcp_write_report(instance, 1);
} else {
- res = ast_rtcp_write_rr(instance);
+ /* Send an RR */
+ res = ast_rtcp_write_report(instance, 0);
}
if (!res) {
@@ -2791,7 +2749,6 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t
d=-d;
}
rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
-
if (rtp->rtcp) {
if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
rtp->rtcp->maxrxjitter = rtp->rxjitter;
@@ -3100,6 +3057,98 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
return &rtp->f;
}
+static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int dlsr)
+{
+ struct timeval now;
+ struct timeval rtt_tv;
+ unsigned int msw;
+ unsigned int lsw;
+ unsigned int rtt_msw;
+ unsigned int rtt_lsw;
+ unsigned int lsr_a;
+ unsigned int rtt;
+ double normdevrtt_current;
+
+ gettimeofday(&now, NULL);
+ timeval2ntp(now, &msw, &lsw);
+
+ lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16);
+ rtt = lsr_a - lsr - dlsr;
+ rtt_msw = (rtt & 0xffff0000) >> 16;
+ rtt_lsw = (rtt & 0x0000ffff) << 16;
+ rtt_tv.tv_sec = rtt_msw;
+ rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8);
+ rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000);
+ if (lsr_a - dlsr < lsr) {
+ return 1;
+ }
+
+ rtp->rtcp->accumulated_transit += rtp->rtcp->rtt;
+ if (rtp->rtcp->rtt_count == 0 || rtp->rtcp->minrtt > rtp->rtcp->rtt) {
+ rtp->rtcp->minrtt = rtp->rtcp->rtt;
+ }
+ if (rtp->rtcp->maxrtt < rtp->rtcp->rtt) {
+ rtp->rtcp->maxrtt = rtp->rtcp->rtt;
+ }
+
+ normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt,
+ rtp->rtcp->rtt,
+ rtp->rtcp->rtt_count);
+ rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt,
+ rtp->rtcp->rtt,
+ rtp->rtcp->normdevrtt,
+ normdevrtt_current,
+ rtp->rtcp->rtt_count);
+ rtp->rtcp->normdevrtt = normdevrtt_current;
+ rtp->rtcp->rtt_count++;
+
+ return 0;
+}
+
+/*! \internal \brief Update RTCP interarrival jitter stats */
+static void update_jitter_stats(struct ast_rtp *rtp, unsigned int ia_jitter)
+{
+ double reported_jitter;
+ double reported_normdev_jitter_current;
+
+ rtp->rtcp->reported_jitter = ia_jitter;
+ reported_jitter = (double) rtp->rtcp->reported_jitter;
+ if (rtp->rtcp->reported_jitter_count == 0) {
+ rtp->rtcp->reported_minjitter = reported_jitter;
+ }
+ if (reported_jitter < rtp->rtcp->reported_minjitter) {
+ rtp->rtcp->reported_minjitter = reported_jitter;
+ }
+ if (reported_jitter > rtp->rtcp->reported_maxjitter) {
+ rtp->rtcp->reported_maxjitter = reported_jitter;
+ }
+ reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
+}
+
+/*! \internal \brief Update RTCP lost packet stats */
+static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
+{
+ double reported_lost;
+ double reported_normdev_lost_current;
+
+ rtp->rtcp->reported_lost = lost_packets;
+ reported_lost = (double)rtp->rtcp->reported_lost;
+ if (rtp->rtcp->reported_jitter_count == 0) {
+ rtp->rtcp->reported_minlost = reported_lost;
+ }
+ if (reported_lost < rtp->rtcp->reported_minlost) {
+ rtp->rtcp->reported_minlost = reported_lost;
+ }
+ if (reported_lost > rtp->rtcp->reported_maxlost) {
+ rtp->rtcp->reported_maxlost = reported_lost;
+ }
+ reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
+}
+
static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -3107,6 +3156,12 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
int res, packetwords, position = 0;
+ int report_counter = 0;
+ struct ast_rtp_rtcp_report_block *report_block;
+ RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+ NULL,
+ ao2_cleanup);
+ RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
struct ast_frame *f = &ast_null_frame;
/* Read in RTCP data from the socket */
@@ -3166,10 +3221,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
while (position < packetwords) {
int i, pt, rc;
- unsigned int length, dlsr, lsr, msw, lsw, comp;
- struct timeval now;
- double rttsec, reported_jitter, reported_normdev_jitter_current, normdevrtt_current, reported_lost, reported_normdev_lost_current;
- uint64_t rtt = 0;
+ unsigned int length;
i = position;
length = ntohl(rtcpheader[i]);
@@ -3177,6 +3229,13 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
rc = (length & 0x1f000000) >> 24;
length &= 0xffff;
+ rtcp_report = ast_rtp_rtcp_report_alloc(rc);
+ if (!rtcp_report) {
+ return &ast_null_frame;
+ }
+ rtcp_report->reception_report_count = rc;
+ rtcp_report->ssrc = ntohl(rtcpheader[i + 1]);
+
if ((i + length) > packetwords) {
if (rtpdebug) {
ast_debug(1, "RTCP Read too short\n");
@@ -3187,28 +3246,41 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
if (rtcp_debug_test_addr(&addr)) {
ast_verbose("\n\nGot RTCP from %s\n",
ast_sockaddr_stringify(&addr));
- ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
+ ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
+ (pt == RTCP_PT_RR) ? "Receiver Report" :
+ (pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
ast_verbose("Reception reports: %d\n", rc);
- ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
+ ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc);
}
i += 2; /* Advance past header and ssrc */
- if (rc == 0 && pt == RTCP_PT_RR) { /* We're receiving a receiver report with no reports, which is ok */
+ if (rc == 0 && pt == RTCP_PT_RR) {
+ /* We're receiving a receiver report with no reports, which is ok */
position += (length + 1);
continue;
}
-
switch (pt) {
case RTCP_PT_SR:
- gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
- rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
+ gettimeofday(&rtp->rtcp->rxlsr, NULL);
+ rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16);
+ rtp->rtcp->spc = ntohl(rtcpheader[i + 3]);
rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
- rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
+ rtcp_report->type = RTCP_PT_SR;
+ rtcp_report->sender_information.packet_count = rtp->rtcp->spc;
+ rtcp_report->sender_information.octet_count = rtp->rtcp->soc;
+ ntp2timeval((unsigned int)ntohl(rtcpheader[i]),
+ (unsigned int)ntohl(rtcpheader[i + 1]),
+ &rtcp_report->sender_information.ntp_timestamp);
+ rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
if (rtcp_debug_test_addr(&addr)) {
- ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
- ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
- ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
+ ast_verbose("NTP timestamp: %u.%010u\n",
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp);
+ ast_verbose("SPC: %u\tSOC: %u\n",
+ rtcp_report->sender_information.packet_count,
+ rtcp_report->sender_information.octet_count);
}
i += 5;
if (rc < 1) {
@@ -3216,166 +3288,63 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
}
/* Intentional fall through */
case RTCP_PT_RR:
- /* Don't handle multiple reception reports (rc > 1) yet */
- /* Calculate RTT per RFC */
- gettimeofday(&now, NULL);
- timeval2ntp(now, &msw, &lsw);
- if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
- comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
- lsr = ntohl(rtcpheader[i + 4]);
- dlsr = ntohl(rtcpheader[i + 5]);
- rtt = comp - lsr - dlsr;
-
- /* Convert end to end delay to usec (keeping the calculation in 64bit space)
- sess->ee_delay = (eedelay * 1000) / 65536; */
- if (rtt < 4294) {
- rtt = (rtt * 1000000) >> 16;
- } else {
- rtt = (rtt * 1000) >> 16;
- rtt *= 1000;
- }
- rtt = rtt / 1000.;
- rttsec = rtt / 1000.;
- rtp->rtcp->rtt = rttsec;
-
- if (comp - dlsr >= lsr) {
- rtp->rtcp->accumulated_transit += rttsec;
-
- if (rtp->rtcp->rtt_count == 0) {
- rtp->rtcp->minrtt = rttsec;
- }
-
- if (rtp->rtcp->maxrtt<rttsec) {
- rtp->rtcp->maxrtt = rttsec;
- }
- if (rtp->rtcp->minrtt>rttsec) {
- rtp->rtcp->minrtt = rttsec;
- }
-
- normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
-
- rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
-
- rtp->rtcp->normdevrtt = normdevrtt_current;
-
- rtp->rtcp->rtt_count++;
- } else if (rtcp_debug_test_addr(&addr)) {
- ast_verbose("Internal RTCP NTP clock skew detected: "
- "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
- "diff=%d\n",
- lsr, comp, dlsr, dlsr / 65536,
- (dlsr % 65536) * 1000 / 65536,
- dlsr - (comp - lsr));
- }
- }
-
- rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
- reported_jitter = (double) rtp->rtcp->reported_jitter;
-
- if (rtp->rtcp->reported_jitter_count == 0) {
- rtp->rtcp->reported_minjitter = reported_jitter;
- }
-
- if (reported_jitter < rtp->rtcp->reported_minjitter) {
- rtp->rtcp->reported_minjitter = reported_jitter;
- }
-
- if (reported_jitter > rtp->rtcp->reported_maxjitter) {
- rtp->rtcp->reported_maxjitter = reported_jitter;
- }
-
- reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
-
- rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
-
- reported_lost = (double) rtp->rtcp->reported_lost;
-
- /* using same counter as for jitter */
- if (rtp->rtcp->reported_jitter_count == 0) {
- rtp->rtcp->reported_minlost = reported_lost;
+ if (rtcp_report->type != RTCP_PT_SR) {
+ rtcp_report->type = RTCP_PT_RR;
}
- if (reported_lost < rtp->rtcp->reported_minlost) {
- rtp->rtcp->reported_minlost = reported_lost;
+ /* Don't handle multiple reception reports (rc > 1) yet */
+ report_block = ast_calloc(1, sizeof(*report_block));
+ if (!report_block) {
+ return &ast_null_frame;
}
-
- if (reported_lost > rtp->rtcp->reported_maxlost) {
- rtp->rtcp->reported_maxlost = reported_lost;
+ rtcp_report->report_block[report_counter] = report_block;
+ report_block->source_ssrc = ntohl(rtcpheader[i]);
+ report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff;
+ report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24);
+ report_block->highest_seq_no = ntohl(rtcpheader[i + 2]);
+ report_block->ia_jitter = ntohl(rtcpheader[i + 3]);
+ report_block->lsr = ntohl(rtcpheader[i + 4]);
+ report_block->dlsr = ntohl(rtcpheader[i + 5]);
+ if (report_block->lsr
+ && update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
+ && rtcp_debug_test_addr(&addr)) {
+ struct timeval now;
+ unsigned int lsr_now, lsw, msw;
+ gettimeofday(&now, NULL);
+ timeval2ntp(now, &msw, &lsw);
+ lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));
+ ast_verbose("Internal RTCP NTP clock skew detected: "
+ "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
+ "diff=%d\n",
+ report_block->lsr, lsr_now, report_block->dlsr, report_block->dlsr / 65536,
+ (report_block->dlsr % 65536) * 1000 / 65536,
+ report_block->dlsr - (lsr_now - report_block->lsr));
}
- reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
-
+ update_jitter_stats(rtp, report_block->ia_jitter);
+ update_lost_stats(rtp, report_block->lost_count.packets);
rtp->rtcp->reported_jitter_count++;
if (rtcp_debug_test_addr(&addr)) {
- ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
- ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost);
- ast_verbose(" Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
- ast_verbose(" Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2])) >> 16);
- ast_verbose(" Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
- ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
- ast_verbose(" DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
- if (rtt) {
- ast_verbose(" RTT: %lu(sec)\n", (unsigned long) rtt);
- }
- }
- if (rtt) {
- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
- "PT: %d(%s)\r\n"
- "ReceptionReports: %d\r\n"
- "SenderSSRC: %u\r\n"
- "FractionLost: %ld\r\n"
- "PacketsLost: %d\r\n"
- "HighestSequence: %ld\r\n"
- "SequenceNumberCycles: %ld\r\n"
- "IAJitter: %u\r\n"
- "LastSR: %lu.%010lu\r\n"
- "DLSR: %4.4f(sec)\r\n"
- "RTT: %llu(sec)\r\n",
- ast_sockaddr_stringify(&addr),
- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
- rc,
- rtcpheader[i + 1],
- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
- rtp->rtcp->reported_lost,
- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
- (long) (ntohl(rtcpheader[i + 2])) >> 16,
- rtp->rtcp->reported_jitter,
- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16, ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
- ntohl(rtcpheader[i + 5])/65536.0,
- (unsigned long long)rtt);
- } else {
- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
- "PT: %d(%s)\r\n"
- "ReceptionReports: %d\r\n"
- "SenderSSRC: %u\r\n"
- "FractionLost: %ld\r\n"
- "PacketsLost: %d\r\n"
- "HighestSequence: %ld\r\n"
- "SequenceNumberCycles: %ld\r\n"
- "IAJitter: %u\r\n"
- "LastSR: %lu.%010lu\r\n"
- "DLSR: %4.4f(sec)\r\n",
- ast_sockaddr_stringify(&addr),
- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
- rc,
- rtcpheader[i + 1],
- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
- rtp->rtcp->reported_lost,
- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
- (long) (ntohl(rtcpheader[i + 2])) >> 16,
- rtp->rtcp->reported_jitter,
- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16,
- ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
- ntohl(rtcpheader[i + 5])/65536.0);
+ ast_verbose(" Fraction lost: %u\n", report_block->lost_count.fraction);
+ ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets);
+ ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
+ ast_verbose(" Sequence number cycles: %u\n", report_block->highest_seq_no >> 16);
+ ast_verbose(" Interarrival jitter: %u\n", report_block->ia_jitter);
+ ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long)(report_block->lsr) >> 16,((unsigned long)(report_block->lsr) << 16) * 4096);
+ ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);
+ ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt);
}
+ report_counter++;
+
+ /* If and when we handle more than one report block, this should occur outside
+ * this loop.
+ */
+ message_blob = ast_json_pack("{s: s, s: f}",
+ "from", ast_sockaddr_stringify(&addr),
+ "rtt", rtp->rtcp->rtt);
+ ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),
+ rtcp_report,
+ message_blob);
break;
case RTCP_PT_FUR:
if (rtcp_debug_test_addr(&addr)) {
@@ -3408,7 +3377,6 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
}
position += (length + 1);
}
-
rtp->rtcp->rtcp_info = 1;
return f;
@@ -4111,6 +4079,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);
+ AST_RTP_STAT_STRCPY(AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, -1, stats->channel_uniqueid, ast_rtp_instance_get_channel_id(instance));
return 0;
}