diff options
-rw-r--r-- | channels/chan_gtalk.c | 21 | ||||
-rw-r--r-- | channels/chan_gulp.c | 43 | ||||
-rw-r--r-- | channels/chan_h323.c | 17 | ||||
-rw-r--r-- | channels/chan_jingle.c | 21 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 16 | ||||
-rw-r--r-- | channels/chan_motif.c | 20 | ||||
-rw-r--r-- | channels/chan_multicast_rtp.c | 2 | ||||
-rw-r--r-- | channels/chan_sip.c | 26 | ||||
-rw-r--r-- | channels/chan_skinny.c | 20 | ||||
-rw-r--r-- | channels/chan_unistim.c | 16 | ||||
-rw-r--r-- | include/asterisk/cdr.h | 7 | ||||
-rw-r--r-- | include/asterisk/channel.h | 6 | ||||
-rw-r--r-- | include/asterisk/json.h | 28 | ||||
-rw-r--r-- | include/asterisk/rtp_engine.h | 160 | ||||
-rw-r--r-- | main/asterisk.c | 10 | ||||
-rw-r--r-- | main/json.c | 14 | ||||
-rw-r--r-- | main/manager.c | 9 | ||||
-rw-r--r-- | main/rtp_engine.c | 391 | ||||
-rw-r--r-- | res/res_rtp_asterisk.c | 675 |
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; } |