diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c index d8249e5f57f054154b68d849579d7c741eeb3550..ee3785fed806dfa31d43bd2ea2e89e0b1f499369 100644 --- a/cdr/cdr_csv.c +++ b/cdr/cdr_csv.c @@ -336,6 +336,12 @@ static int csv_log(struct ast_cdr *cdr) { /* Make sure we have a big enough buf */ char buf[1024]; + + /* Don't create records for CDRs where dcontext = "hangup" */ + if (!strcasecmp(cdr->dcontext, "hangup")) { + return 0; + } + if (build_csv_record(buf, sizeof(buf), cdr)) { ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); return 0; diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c index bf4629e8dd8cd1d4fd19c012372fbc743e9d781b..9eb146a7f473ec4a3d10899e06ad8cc049022385 100644 --- a/channels/chan_brcm.c +++ b/channels/chan_brcm.c @@ -85,6 +85,7 @@ static int brcm_stop_conference(struct brcm_subchannel *p); static int brcm_finish_transfer(struct ast_channel *owner, struct brcm_subchannel *p, int result); static int brcm_call(struct ast_channel *ast, const char *dest, int timeout); static int brcm_hangup(struct ast_channel *ast); +static int brcm_getRtpStats(struct ast_channel *ast); static int brcm_answer(struct ast_channel *ast); static struct ast_frame *brcm_read(struct ast_channel *ast); static int brcm_write(struct ast_channel *ast, struct ast_frame *frame); @@ -136,7 +137,7 @@ static int num_fxo_endpoints = -1; static int num_dect_endpoints = -1; static int num_endpoints = -1; static int clip = 1; // Caller ID presentation -static rtp_statistics rtp_stats = {0}; + /* driver scheduler */ static struct ast_sched_context *sched = NULL; @@ -327,6 +328,7 @@ static struct ast_channel_tech brcm_tech = { .read = brcm_read, //Channel is locked .write = brcm_write, //Channel is locked .send_digit_begin = brcm_senddigit_begin, //Channel is NOT locked + .getRtpStats = brcm_getRtpStats, //Channel is NOT locked .send_digit_end = brcm_senddigit_end, //Channel is NOT locked .indicate = brcm_indicate, //Channel is locked .transfer = brcm_transfer // Channel is locked @@ -618,6 +620,28 @@ static int brcm_indicate(struct ast_channel *ast, int condition, const void *dat return res; } +static int brcm_getRtpStats(struct ast_channel *ast) +{ + struct brcm_subchannel *sub; + + sub = ast_channel_tech_pvt(ast); + if (!sub) { + ast_log(LOG_ERROR, "Failed to get peer subchannel\n"); + return -1; + } + + pvt_lock(sub->parent, "brcm_getRtpStats"); + if (sub->parent) { + if (endpt_get_rtp_stats(sub->parent->line_id)) { + ast_log(LOG_WARNING, "Unable to get RTP statistics\n"); + } + ast_channel_rtpStats_set(ast, &sub->rtp_stats); + } + pvt_unlock(sub->parent); + + return 0; +} + static int brcm_transfer(struct ast_channel *ast, const char *newdest) { struct brcm_pvt *pvt; @@ -894,11 +918,6 @@ static int brcm_hangup(struct ast_channel *ast) sub->conf_timer_id = -1; } - if (endpt_get_rtp_stats(p->line_id)) { - ast_log(LOG_WARNING, "Unable to get RTP statistics\n"); - } - ast_channel_rtpStats_set(ast, &rtp_stats); - if (sub->channel_state == CALLWAITING) { brcm_stop_callwaiting(p); } else if (sub_peer->channel_state == ONHOLD && @@ -2488,6 +2507,9 @@ static void *brcm_process_event(struct endpt_event *ev) { if (sub->channel_state == OFFHOOK || sub->channel_state == AWAITONHOOK) { /* Received EVENT_ONHOOK in state OFFHOOK/AWAITONHOOK, stop dial/congestion tone */ brcm_stop_dialtone(p); + } else if (sub->channel_state == RINGBACK) { + /* Outgoing unanswered call - rtp stats need to be collected */ + brcm_getRtpStats(owner); } sub->channel_state = ONHOOK; @@ -3429,6 +3451,7 @@ static const struct blobmsg_policy endpt_count_policy[__MAX_ENDPOINTS] = { }; enum { + RTP_STATS_LINE_ID, RTP_STATS_LOCAL_BURST_DENSITY, RTP_STATS_REMOTE_BURST_DENSITY, RTP_STATS_LOCAL_BURST_DURATION, @@ -3457,6 +3480,7 @@ enum { }; static const struct blobmsg_policy endpt_rtp_stats_policy[__MAX_RTP_STATS] = { + [RTP_STATS_LINE_ID] = { .name = "lineId", .type = BLOBMSG_TYPE_INT16 }, [RTP_STATS_LOCAL_BURST_DENSITY] = { .name = "localBurstDensity", .type = BLOBMSG_TYPE_INT16 }, [RTP_STATS_REMOTE_BURST_DENSITY] = { .name = "remoteBurstDensity", .type = BLOBMSG_TYPE_INT16 }, [RTP_STATS_LOCAL_BURST_DURATION] = { .name = "localBurstDuration", .type = BLOBMSG_TYPE_INT16 }, @@ -3549,58 +3573,76 @@ static int endpt_get_count(void) { static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struct blob_attr *msg) { struct blob_attr *tb[__MAX_RTP_STATS]; + uint16_t lineId = 0; + struct brcm_pvt *p = NULL; + struct brcm_subchannel *sub = NULL; ast_log(LOG_DEBUG, "thread %d: got answer from endptmngr on rtp_stats ubus call.\n", ast_get_tid()); blobmsg_parse(endpt_rtp_stats_policy, __MAX_RTP_STATS, tb, blob_data(msg), blob_len(msg)); + if (tb[RTP_STATS_LINE_ID]) + lineId = blobmsg_get_u16(tb[RTP_STATS_LINE_ID]); + + p = brcm_get_pvt_from_lineid(iflist, lineId); + if (!p) { + ast_log(LOG_ERROR, "No pvt with the line_id %d found!\n", lineId); + return; + } + + sub = brcm_get_active_subchannel(p); + if (!sub) { + ast_log(LOG_ERROR, "No active subchannel to write rtp stats!\n"); + return; + } + if (tb[RTP_STATS_LOCAL_BURST_DENSITY]) - rtp_stats.localBurstDensity = blobmsg_get_u16(tb[RTP_STATS_LOCAL_BURST_DENSITY]); + sub->rtp_stats.localBurstDensity = blobmsg_get_u16(tb[RTP_STATS_LOCAL_BURST_DENSITY]); if (tb[RTP_STATS_REMOTE_BURST_DENSITY]) - rtp_stats.remoteBurstDensity = blobmsg_get_u16(tb[RTP_STATS_REMOTE_BURST_DENSITY]); + sub->rtp_stats.remoteBurstDensity = blobmsg_get_u16(tb[RTP_STATS_REMOTE_BURST_DENSITY]); if (tb[RTP_STATS_LOCAL_BURST_DURATION]) - rtp_stats.localBurstDuration = blobmsg_get_u16(tb[RTP_STATS_LOCAL_BURST_DURATION]); + sub->rtp_stats.localBurstDuration = blobmsg_get_u16(tb[RTP_STATS_LOCAL_BURST_DURATION]); if (tb[RTP_STATS_REMOTE_BURST_DURATION]) - rtp_stats.remoteBurstDuration = blobmsg_get_u16(tb[RTP_STATS_REMOTE_BURST_DURATION]); + sub->rtp_stats.remoteBurstDuration = blobmsg_get_u16(tb[RTP_STATS_REMOTE_BURST_DURATION]); if (tb[RTP_STATS_LOCAL_GAP_DENSITY]) - rtp_stats.localGapDensity = blobmsg_get_u16(tb[RTP_STATS_LOCAL_GAP_DENSITY]); + sub->rtp_stats.localGapDensity = blobmsg_get_u16(tb[RTP_STATS_LOCAL_GAP_DENSITY]); if (tb[RTP_STATS_REMOTE_GAP_DENSITY]) - rtp_stats.remoteGapDensity = blobmsg_get_u16(tb[RTP_STATS_REMOTE_GAP_DENSITY]); + sub->rtp_stats.remoteGapDensity = blobmsg_get_u16(tb[RTP_STATS_REMOTE_GAP_DENSITY]); if (tb[RTP_STATS_LOCAL_GAP_DURATION]) - rtp_stats.localGapDuration = blobmsg_get_u16(tb[RTP_STATS_LOCAL_GAP_DURATION]); + sub->rtp_stats.localGapDuration = blobmsg_get_u16(tb[RTP_STATS_LOCAL_GAP_DURATION]); if (tb[RTP_STATS_REMOTE_GAP_DURATION]) - rtp_stats.remoteGapDuration = blobmsg_get_u16(tb[RTP_STATS_REMOTE_GAP_DURATION]); + sub->rtp_stats.remoteGapDuration = blobmsg_get_u16(tb[RTP_STATS_REMOTE_GAP_DURATION]); if (tb[RTP_STATS_LOCAL_JB_RATE]) - rtp_stats.localJbRate = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_RATE]); + sub->rtp_stats.localJbRate = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_RATE]); if (tb[RTP_STATS_REMOTE_JB_RATE]) - rtp_stats.remoteJbRate = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_RATE]); + sub->rtp_stats.remoteJbRate = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_RATE]); if (tb[RTP_STATS_LOCAL_JB_MAX]) - rtp_stats.localJbMax = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_MAX]); + sub->rtp_stats.localJbMax = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_MAX]); if (tb[RTP_STATS_REMOTE_JB_MAX]) - rtp_stats.remoteJbMax = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_MAX]); + sub->rtp_stats.remoteJbMax = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_MAX]); if (tb[RTP_STATS_LOCAL_JB_NOMINAL]) - rtp_stats.localJbNominal = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_NOMINAL]); + sub->rtp_stats.localJbNominal = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_NOMINAL]); if (tb[RTP_STATS_REMOTE_JB_NOMINAL]) - rtp_stats.remoteJbNominal = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_NOMINAL]); + sub->rtp_stats.remoteJbNominal = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_NOMINAL]); if (tb[RTP_STATS_LOCAL_JB_ABS_MAX]) - rtp_stats.localJbAbsMax = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_ABS_MAX]); + sub->rtp_stats.localJbAbsMax = blobmsg_get_u16(tb[RTP_STATS_LOCAL_JB_ABS_MAX]); if (tb[RTP_STATS_REMOTE_JB_ABS_MAX]) - rtp_stats.remoteJbAbsMax = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_ABS_MAX]); + sub->rtp_stats.remoteJbAbsMax = blobmsg_get_u16(tb[RTP_STATS_REMOTE_JB_ABS_MAX]); if (tb[RTP_STATS_DISCARDED]) - rtp_stats.discarded = blobmsg_get_u32(tb[RTP_STATS_DISCARDED]); + sub->rtp_stats.discarded = blobmsg_get_u32(tb[RTP_STATS_DISCARDED]); if (tb[RTP_STATS_LOST]) - rtp_stats.lost = blobmsg_get_u32(tb[RTP_STATS_LOST]); + sub->rtp_stats.lost = blobmsg_get_u32(tb[RTP_STATS_LOST]); if (tb[RTP_STATS_RX_PKTS]) - rtp_stats.rxpkts = blobmsg_get_u32(tb[RTP_STATS_RX_PKTS]); + sub->rtp_stats.rxpkts = blobmsg_get_u32(tb[RTP_STATS_RX_PKTS]); if (tb[RTP_STATS_TX_PKTS]) - rtp_stats.txpkts = blobmsg_get_u32(tb[RTP_STATS_TX_PKTS]); + sub->rtp_stats.txpkts = blobmsg_get_u32(tb[RTP_STATS_TX_PKTS]); if (tb[RTP_STATS_JB_AVG]) - rtp_stats.jbAvg = blobmsg_get_u16(tb[RTP_STATS_JB_AVG]); + sub->rtp_stats.jbAvg = blobmsg_get_u16(tb[RTP_STATS_JB_AVG]); if (tb[RTP_STATS_JITTER]) - rtp_stats.jitter = blobmsg_get_u32(tb[RTP_STATS_JITTER]); + sub->rtp_stats.jitter = blobmsg_get_u32(tb[RTP_STATS_JITTER]); if (tb[RTP_STATS_LOSS_RATE]) - rtp_stats.uLossRate = blobmsg_get_u16(tb[RTP_STATS_LOSS_RATE]); + sub->rtp_stats.uLossRate = blobmsg_get_u16(tb[RTP_STATS_LOSS_RATE]); if (tb[RTP_STATS_MAX_JITTER]) - rtp_stats.maxJitter = blobmsg_get_u32(tb[RTP_STATS_MAX_JITTER]); + sub->rtp_stats.maxJitter = blobmsg_get_u32(tb[RTP_STATS_MAX_JITTER]); ast_log(LOG_DEBUG, "RTP stats received:\nlocalBurstDensity: %d\nremoteBurstDensity: %d\n" "localBurstDuration: %d\nremoteBurstDuration: %d\nlocalGapDensity: %d\n" @@ -3609,13 +3651,13 @@ static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struc "localJbNominal: %d\nremoteJbNominal: %d\nlocalJbAbsMax: %d\n" "remoteJbAbsMax: %d\ndiscarded: %d\nlost: %d\nrxpkts: %d\ntxpkts: %d\n" "jbAvg: %d\njitter: %d\nuLossRate: %d\nmaxJitter: %d\n", - rtp_stats.localBurstDensity, rtp_stats.remoteBurstDensity, rtp_stats.localBurstDuration, - rtp_stats.remoteBurstDuration, rtp_stats.localGapDensity, rtp_stats.remoteGapDensity, - rtp_stats.localGapDuration, rtp_stats.remoteGapDuration, rtp_stats.localJbRate, - rtp_stats.remoteJbRate, rtp_stats.localJbMax, rtp_stats.remoteJbMax, rtp_stats.localJbNominal, - rtp_stats.remoteJbNominal, rtp_stats.localJbAbsMax, rtp_stats.remoteJbAbsMax, rtp_stats.discarded, - rtp_stats.lost, rtp_stats.rxpkts, rtp_stats.txpkts, rtp_stats.jbAvg, rtp_stats.jitter, - rtp_stats.uLossRate, rtp_stats.maxJitter); + sub->rtp_stats.localBurstDensity, sub->rtp_stats.remoteBurstDensity, sub->rtp_stats.localBurstDuration, + sub->rtp_stats.remoteBurstDuration, sub->rtp_stats.localGapDensity, sub->rtp_stats.remoteGapDensity, + sub->rtp_stats.localGapDuration, sub->rtp_stats.remoteGapDuration, sub->rtp_stats.localJbRate, + sub->rtp_stats.remoteJbRate, sub->rtp_stats.localJbMax, sub->rtp_stats.remoteJbMax, sub->rtp_stats.localJbNominal, + sub->rtp_stats.remoteJbNominal, sub->rtp_stats.localJbAbsMax, sub->rtp_stats.remoteJbAbsMax, sub->rtp_stats.discarded, + sub->rtp_stats.lost, sub->rtp_stats.rxpkts, sub->rtp_stats.txpkts, sub->rtp_stats.jbAvg, sub->rtp_stats.jitter, + sub->rtp_stats.uLossRate, sub->rtp_stats.maxJitter); } static int endpt_get_rtp_stats(int line) { @@ -3623,13 +3665,26 @@ static int endpt_get_rtp_stats(int line) { struct blob_buf bb; struct ubus_request *req; int ret; + struct brcm_pvt *p = NULL; + struct brcm_subchannel *sub = NULL; /* * Reset rtp_stats first because ubus_call_answer_rtp_stats() will not be called if "ubus call endpt rtp_stats" fails, * e.g. an unanswered incoming call on which the connection is not created. In this case, all RTP statistics counters * shall be zeros. */ - memset(&rtp_stats, 0, sizeof(rtp_stats)); + p = brcm_get_pvt_from_lineid(iflist, line); + if (!p) { + ast_log(LOG_ERROR, "No pvt with the line %d found!\n", line); + return -1; + } + + sub = brcm_get_active_subchannel(p); + if (!sub) { + ast_log(LOG_ERROR, "No active subchannel to get rtp stats!\n"); + return -1; + } + memset(&sub->rtp_stats, 0, sizeof(sub->rtp_stats)); if (!endpt_id) { return -1; diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h index 5e1eca20d0733d234b886497c4aaaf48d4b84cc6..33a7da3fa1bc6fe355efea4ac6150bfee564cc50 100644 --- a/channels/chan_brcm.h +++ b/channels/chan_brcm.h @@ -111,7 +111,8 @@ struct brcm_subchannel { int onhold_hangup_timer_id; /* Current onhold hangup timer id, -1 if no active timer */ int conference_initiator; /* True if this subchannel is the original leg in a 3-way conference */ char *conference_id; /* uuid of the conference initiated by this subchannel */ - int conf_timer_id; /* Current conference call timer id, -1 if no active timer */ + int conf_timer_id; /* Current conference call timer id, -1 if no active timer */ + rtp_statistics rtp_stats; /* RTP statistics for currently hanging up channel */ }; diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index b091bad6281c9e50b193a4378a2c8d0eaea1bf07..ba8d74e1f9a90dd75edcccc4e1409dd01b3227cd 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -91,6 +91,7 @@ static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *t static int chan_pjsip_sendtext_data(struct ast_channel *ast, struct ast_msg_data *msg); static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text); static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit); +static int chan_pjsip_getRtpStats(struct ast_channel *ast); static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration); static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeout); static int chan_pjsip_hangup(struct ast_channel *ast); @@ -114,6 +115,7 @@ struct ast_channel_tech chan_pjsip_tech = { .send_text = chan_pjsip_sendtext, .send_text_data = chan_pjsip_sendtext_data, .send_digit_begin = chan_pjsip_digit_begin, + .getRtpStats = chan_pjsip_getRtpStats, .send_digit_end = chan_pjsip_digit_end, .call = chan_pjsip_call, .hangup = chan_pjsip_hangup, @@ -2220,6 +2222,12 @@ static int chan_pjsip_transfer(struct ast_channel *chan, const char *target) return 0; } +/*! \brief Dummy function for getting RTP stats for PJSIP tech channel */ +static int chan_pjsip_getRtpStats(struct ast_channel *chan) +{ + return 0; +} + /*! \brief Function called by core to start a DTMF digit */ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit) { diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 3bf020e1a4492b43532494a19992158411ef853f..1b7510606f96c62ed04538e100daffc92a0dadd6 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -711,6 +711,13 @@ struct ast_channel_tech { */ int (* const send_digit_begin)(struct ast_channel *chan, char digit); + /*! + * \brief Get RTP stats for currently hanging up channel + * + * \note The channel is not locked when this function gets called. + */ + int (* const getRtpStats)(struct ast_channel *chan); + /*! * \brief Stop sending a literal DTMF digit * diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 9d3934fae5d77d9a4b873c7802ff20788bbb69a6..d39e3e16ee0cbd648f08f03f0ef404d02f573f84 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -315,6 +315,7 @@ void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, { ast_bridge_channel_lock(bridge_channel); ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state, cause); + ast_channel_tech(bridge_channel->chan)->getRtpStats(bridge_channel->chan); ast_bridge_channel_unlock(bridge_channel); } diff --git a/main/cdr.c b/main/cdr.c index e549db6e92bd0db0847cd50e5966010b3e9014a6..5490291d91cd528185ae5dddc6b28ae7a709652f 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -2345,7 +2345,11 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY); } if (update->new_snapshot->rtp_stats){ - cdr->party_a.snapshot->rtp_stats = update->new_snapshot->rtp_stats; + if (cdr->party_a.snapshot) + cdr->party_a.snapshot->rtp_stats = update->new_snapshot->rtp_stats; + if (cdr->party_b.snapshot) + cdr->party_b.snapshot->rtp_stats = update->new_snapshot->rtp_stats; + } /* Handle Party A */ if (!cdr) {