From cc1a6e87732bd99ba1bedeb54570484894047cec Mon Sep 17 00:00:00 2001
From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
Date: Thu, 17 Jun 2021 12:38:47 +0200
Subject: [PATCH] Implementation for getting RTP statistics and other call log
 parameters

There is an issue with copying RTP statistics from snapshot to cdr hence
call log does not contains RTP stats for incoming calls - for outgoing
call it works fine.

Signed-off-by: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
---
 cdr/cdr_beanstalkd.c               |  33 +++++-
 cdr/cdr_csv.c                      |  38 +++++++
 cdr/cdr_manager.c                  |  38 ++++++-
 cdr/cdr_odbc.c                     |  35 ++++++-
 cdr/cdr_radius.c                   | 102 +++++++++++++++++-
 cdr/cdr_tds.c                      |  29 ++++--
 channels/chan_brcm.c               | 160 ++++++++++++++++++++++++++++-
 include/asterisk/cdr.h             |  41 +++++++-
 include/asterisk/channel.h         |  38 +++++++
 include/asterisk/stasis_channels.h |   6 ++
 main/cdr.c                         | 114 +++++++++++++++++++-
 main/channel_internal_api.c        |  57 ++++++++++
 main/stasis_channels.c             |   6 ++
 res/res_pjsip_sdp_rtp.c            |   1 +
 res/res_pjsip_session.c            |  18 +++-
 15 files changed, 696 insertions(+), 20 deletions(-)

diff --git a/cdr/cdr_beanstalkd.c b/cdr/cdr_beanstalkd.c
index 524274ffb7..b797392518 100644
--- a/cdr/cdr_beanstalkd.c
+++ b/cdr/cdr_beanstalkd.c
@@ -195,7 +195,9 @@ static int beanstalk_put(struct ast_cdr *cdr) {
 
 	ast_rwlock_unlock(&config_lock);
 
-	t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}",
+	t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:i, s:s, s:s,
+							   s:i, s:s, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i,
+							   s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:i, s:s}",
 							   "AccountCode", S_OR(cdr->accountcode, ""),
 							   "Source", S_OR(cdr->src, ""),
 							   "Destination", S_OR(cdr->dst, ""),
@@ -213,6 +215,35 @@ static int beanstalk_put(struct ast_cdr *cdr) {
 							   "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""),
 							   "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""),
 							   "UniqueID", S_OR(cdr->uniqueid, ""),
+							   "SessionId", cdr->sessionId,
+							   "sipIpAddress", S_OR(cdr->sipIpAddress, ""),
+							   "farEndIPAddress", S_OR(cdr->farEndIPAddress, ""),
+							   "sipResponseCode", cdr->sipResponseCode,
+							   "codec", S_OR(cdr->codec, ""),
+							   "localBurstDensity", cdr->rtp_stats->localBurstDensity,
+							   "remoteBurstDensity", cdr->rtp_stats->remoteBurstDensity,
+							   "localBurstDuration", cdr->rtp_stats->localBurstDuration,
+							   "remoteBurstDuration", cdr->rtp_stats->remoteBurstDuration,
+							   "localGapDensity", cdr->rtp_stats->localGapDensity,
+							   "remoteGapDensity", cdr->rtp_stats->remoteGapDensity,
+							   "localGapDuration", cdr->rtp_stats->localGapDuration,
+							   "remoteGapDuration", cdr->rtp_stats->remoteGapDuration,
+							   "localJbRate", cdr->rtp_stats->localJbRate,
+							   "remoteJbRate", cdr->rtp_stats->remoteJbRate,
+							   "localJbMax", cdr->rtp_stats->localJbMax,
+							   "remoteJbMax", cdr->rtp_stats->remoteJbMax,
+							   "localJbNominal", cdr->rtp_stats->localJbNominal,
+							   "remoteJbNominal", cdr->rtp_stats->remoteJbNominal,
+							   "localJbAbsMax", cdr->rtp_stats->localJbAbsMax,
+							   "remoteJbAbsMax", cdr->rtp_stats->remoteJbAbsMax,
+							   "jbAvg", cdr->rtp_stats->jbAvg,
+							   "uLossRate", cdr->rtp_stats->uLossRate,
+							   "discarded", cdr->rtp_stats->discarded,
+							   "lost", cdr->rtp_stats->lost,
+							   "rxpkts", cdr->rtp_stats->rxpkts,
+							   "txpkts", cdr->rtp_stats->txpkts,
+							   "jitter", cdr->rtp_stats->jitter,
+							   "maxJitter", cdr->rtp_stats->maxJitter,
 							   "UserField", S_OR(cdr->userfield, ""));
 
 	cdr_buffer = ast_json_dump_string(t_cdr_json);
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index e4c74ff1ef..d8249e5f57 100644
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -242,6 +242,44 @@ static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr)
 	append_int(buf, cdr->billsec, bufsize);
 	/* Disposition */
 	append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
+	/* Session Id */
+	append_int(buf, cdr->sessionId, bufsize);
+	/* SIP IP Address */
+	append_string(buf, cdr->sipIpAddress, bufsize);
+	/* Far End IP Address */
+	append_string(buf, cdr->farEndIPAddress, bufsize);
+	/* Sip Response Code */
+	append_int(buf, cdr->sipResponseCode, bufsize);
+	/* codec */
+	append_string(buf, cdr->codec, bufsize);
+
+	/* RTP statistics */
+	if (cdr->rtp_stats) {
+		append_int(buf, cdr->rtp_stats->localBurstDensity, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteBurstDensity, bufsize);
+		append_int(buf, cdr->rtp_stats->localBurstDuration, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteBurstDuration, bufsize);
+		append_int(buf, cdr->rtp_stats->localGapDensity, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteGapDensity, bufsize);
+		append_int(buf, cdr->rtp_stats->localGapDuration, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteGapDuration, bufsize);
+		append_int(buf, cdr->rtp_stats->localJbRate, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteJbRate, bufsize);
+		append_int(buf, cdr->rtp_stats->localJbMax, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteJbMax, bufsize);
+		append_int(buf, cdr->rtp_stats->localJbNominal, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteJbNominal, bufsize);
+		append_int(buf, cdr->rtp_stats->localJbAbsMax, bufsize);
+		append_int(buf, cdr->rtp_stats->remoteJbAbsMax, bufsize);
+		append_int(buf, cdr->rtp_stats->jbAvg, bufsize);
+		append_int(buf, cdr->rtp_stats->uLossRate, bufsize);
+		append_int(buf, cdr->rtp_stats->discarded, bufsize);
+		append_int(buf, cdr->rtp_stats->lost, bufsize);
+		append_int(buf, cdr->rtp_stats->rxpkts, bufsize);
+		append_int(buf, cdr->rtp_stats->txpkts, bufsize);
+		append_int(buf, cdr->rtp_stats->jitter, bufsize);
+		append_int(buf, cdr->rtp_stats->maxJitter, bufsize);
+	}
 	/* AMA Flags */
 	append_string(buf, ast_channel_amaflags2string(cdr->amaflags), bufsize);
 	/* Unique ID */
diff --git a/cdr/cdr_manager.c b/cdr/cdr_manager.c
index 74f37d207f..ffb51ced18 100644
--- a/cdr/cdr_manager.c
+++ b/cdr/cdr_manager.c
@@ -324,12 +324,48 @@ static int manager_log(struct ast_cdr *cdr)
 	    "Disposition: %s\r\n"
 	    "AMAFlags: %s\r\n"
 	    "UniqueID: %s\r\n"
+	    "SessionId: %ld\r\n"
+	    "SipIpAddress: %s\r\n"
+	    "farEndIPAddress: %s\r\n"
+	    "sipResponseCode: %ld\r\n"
+	    "codec: %s\r\n"
+	    "localBurstDensity: %ld\r\n"
+	    "remoteBurstDensity: %ld\r\n"
+	    "localBurstDuration: %ld\r\n"
+	    "remoteBurstDuration: %ld\r\n"
+	    "localGapDensity: %ld\r\n"
+	    "remoteGapDensity: %ld\r\n"
+	    "localGapDuration: %ld\r\n"
+	    "remoteGapDuration: %ld\r\n"
+	    "localJbRate: %ld\r\n"
+	    "remoteJbRate: %ld\r\n"
+	    "localJbMax: %ld\r\n"
+	    "remoteJbMax: %ld\r\n"
+	    "localJbNominal: %ld\r\n"
+	    "remoteJbNominal: %ld\r\n"
+	    "localJbAbsMax: %ld\r\n"
+	    "remoteJbAbsMax: %ld\r\n"
+	    "jbAvg: %ld\r\n"
+	    "discarded: %ld\r\n"
+	    "discarded: %ld\r\n"
+	    "lost: %ld\r\n"
+	    "rxpkts: %ld\r\n"
+	    "txpkts: %ld\r\n"
+	    "jitter: %ld\r\n"
+	    "maxJitter: %ld\r\n"
 	    "UserField: %s\r\n"
 	    "%s",
 	    cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
 	    cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
 	    cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
-	    ast_channel_amaflags2string(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf);
+	    ast_channel_amaflags2string(cdr->amaflags), cdr->uniqueid, cdr->sessionId,
+		cdr->sipIpAddress, cdr->farEndIPAddress, cdr->sipResponseCode, cdr->codec, cdr->rtp_stats->localBurstDensity,
+		cdr->rtp_stats->remoteBurstDensity, cdr->rtp_stats->localBurstDuration, cdr->rtp_stats->remoteBurstDuration, cdr->rtp_stats->localGapDensity,
+		cdr->rtp_stats->remoteGapDensity, cdr->rtp_stats->localGapDuration, cdr->rtp_stats->remoteGapDuration, cdr->rtp_stats->localJbRate,
+		cdr->rtp_stats->remoteJbRate, cdr->rtp_stats->localJbMax, cdr->rtp_stats->remoteJbMax, cdr->rtp_stats->localJbNominal,
+		cdr->rtp_stats->remoteJbNominal, cdr->rtp_stats->localJbAbsMax, cdr->rtp_stats->remoteJbAbsMax, cdr->rtp_stats->jbAvg,
+		cdr->rtp_stats->uLossRate, cdr->rtp_stats->discarded, cdr->rtp_stats->lost, cdr->rtp_stats->rxpkts,
+		cdr->rtp_stats->txpkts, cdr->rtp_stats->jitter, cdr->rtp_stats->maxJitter, cdr->userfield, buf);
 
 	return 0;
 }
diff --git a/cdr/cdr_odbc.c b/cdr/cdr_odbc.c
index 43305869b1..0e09b5e810 100644
--- a/cdr/cdr_odbc.c
+++ b/cdr/cdr_odbc.c
@@ -149,10 +149,41 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
 
 	if (ast_test_flag(&config, CONFIG_NEWCDRCOLUMNS)) {
 		SQLBindParameter(stmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->peeraccount), 0, cdr->peeraccount, 0, NULL);
-		SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->linkedid), 0, cdr->linkedid, 0, NULL);
-		SQLBindParameter(stmt, i + 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sequence, 0, NULL);
+		SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->linkedid), 0, cdr->linkedid, 0, NULL);
+		SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sequence, 0, NULL);
 	}
 
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sessionId, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->sipIpAddress), 0, cdr->sipIpAddress, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->farEndIPAddress), 0, cdr->farEndIPAddress, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sipResponseCode, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->codec), 0, cdr->codec, 0, NULL);
+
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localBurstDensity, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteBurstDensity, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localBurstDuration, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteBurstDuration, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localGapDensity, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteGapDensity, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localGapDuration, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteGapDuration, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localJbRate, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteJbRate, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localJbMax, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteJbMax, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localJbNominal, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteJbNominal, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->localJbAbsMax, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->remoteJbAbsMax, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->jbAvg, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->uLossRate, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->discarded, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->lost, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->rxpkts, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->txpkts, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->jitter, 0, NULL);
+	SQLBindParameter(stmt, i++, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->rtp_stats->maxJitter, 0, NULL);
+
 	ODBC_res = ast_odbc_execute_sql(obj, stmt, sqlcmd);
 
 	if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
diff --git a/cdr/cdr_radius.c b/cdr/cdr_radius.c
index 0a5fa6371c..d68e76f344 100644
--- a/cdr/cdr_radius.c
+++ b/cdr/cdr_radius.c
@@ -69,7 +69,36 @@ enum {
 	PW_AST_DISPOSITION =  115,
 	PW_AST_AMA_FLAGS =    116,
 	PW_AST_UNIQUE_ID =    117,
-	PW_AST_USER_FIELD =   118
+	PW_AST_USER_FIELD =   118,
+	PW_AST_USER_SESSION_ID =   119,
+	PW_AST_SIP_IP_ADDR =   120,
+	PW_AST_FAR_END_IP_ADDR =   121,
+	PW_AST_SIP_RESPONSE_CODE =   122,
+	PW_AST_CODEC =   123,
+	PW_AST_RTP_LOCAL_BURST_DENSITY =   124,
+	PW_AST_RTP_REMOTE_BURST_DENSITY =   125,
+	PW_AST_RTP_LOCAL_BURST_DURATION =   126,
+	PW_AST_RTP_REMOTE_BURST_DURATION =   127,
+	PW_AST_RTP_LOCAL_GAP_DENSITY =   128,
+	PW_AST_RTP_REMOTE_GAP_DENSITY =   129,
+	PW_AST_RTP_LOCAL_GAP_DURATION =   130,
+	PW_AST_RTP_REMOTE_GAP_DURATION =   131,
+	PW_AST_RTP_LOCAL_JB_RATE =   132,
+	PW_AST_RTP_REMOTE_JB_RATE =   133,
+	PW_AST_RTP_LOCAL_JB_MAX =   134,
+	PW_AST_RTP_REMOTE_JB_MAX =   135,
+	PW_AST_RTP_LOCAL_JB_NOMINAL =   136,
+	PW_AST_RTP_REMOTE_JB_NOMINAL =   137,
+	PW_AST_RTP_LOCAL_JB_ABS_MAX =   138,
+	PW_AST_RTP_REMOTE_JB_ABS_MAX =   139,
+	PW_AST_RTP_JB_AVG =   140,
+	PW_AST_RTP_LOSS_RATE =   141,
+	PW_AST_RTP_DISCARDED =   142,
+	PW_AST_RTP_LOST =   143,
+	PW_AST_RTP_RX_PKTS =   144,
+	PW_AST_RTP_TX_PKTS =   145,
+	PW_AST_RTP_JITTER =   146,
+	PW_AST_RTP_MAX_JITTER =   147
 };
 
 enum {
@@ -193,6 +222,77 @@ static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr)
 			return -1;
 	}
 
+	/* Session Id */
+	if (!rc_avpair_add(rh, tosend, PW_AST_USER_SESSION_ID, &cdr->sessionId, 0, VENDOR_CODE))
+		return -1;
+
+	/* SIP IP Address */
+	if (!rc_avpair_add(rh, tosend, PW_AST_SIP_IP_ADDR, &cdr->sipIpAddress, strlen(cdr->sipIpAddress), VENDOR_CODE))
+		return -1;
+
+	/* Far End IP Address */
+	if (!rc_avpair_add(rh, tosend, PW_AST_FAR_END_IP_ADDR, &cdr->farEndIPAddress, strlen(cdr->farEndIPAddress), VENDOR_CODE))
+		return -1;
+
+	/* Sip Response Code */
+	if (!rc_avpair_add(rh, tosend, PW_AST_SIP_RESPONSE_CODE, &cdr->sipResponseCode, 0, VENDOR_CODE))
+		return -1;
+
+	/* codec */
+	if (!rc_avpair_add(rh, tosend, PW_AST_CODEC, &cdr->codec, strlen(cdr->codec), VENDOR_CODE))
+		return -1;
+
+	/* RTP statistics */
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_BURST_DENSITY, &cdr->rtp_stats->localBurstDensity, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_BURST_DENSITY, &cdr->rtp_stats->remoteBurstDensity, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_BURST_DURATION, &cdr->rtp_stats->localBurstDuration, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_BURST_DURATION, &cdr->rtp_stats->remoteBurstDuration, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_GAP_DENSITY, &cdr->rtp_stats->localGapDensity, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_GAP_DENSITY, &cdr->rtp_stats->remoteGapDensity, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_GAP_DURATION, &cdr->rtp_stats->localGapDuration, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_GAP_DURATION, &cdr->rtp_stats->remoteGapDuration, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_JB_RATE, &cdr->rtp_stats->localJbRate, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_JB_RATE, &cdr->rtp_stats->remoteJbRate, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_JB_MAX, &cdr->rtp_stats->localJbMax, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_JB_MAX, &cdr->rtp_stats->remoteJbMax, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_JB_NOMINAL, &cdr->rtp_stats->localJbNominal, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_JB_NOMINAL, &cdr->rtp_stats->remoteJbNominal, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOCAL_JB_ABS_MAX, &cdr->rtp_stats->localJbAbsMax, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_REMOTE_JB_ABS_MAX, &cdr->rtp_stats->remoteJbAbsMax, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_JB_AVG, &cdr->rtp_stats->jbAvg, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOSS_RATE, &cdr->rtp_stats->uLossRate, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_DISCARDED, &cdr->rtp_stats->discarded, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_LOST, &cdr->rtp_stats->lost, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_RX_PKTS, &cdr->rtp_stats->rxpkts, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_TX_PKTS, &cdr->rtp_stats->txpkts, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_JITTER, &cdr->rtp_stats->jitter, 0, VENDOR_CODE))
+		return -1;
+	if (!rc_avpair_add(rh, tosend, PW_AST_RTP_MAX_JITTER, &cdr->rtp_stats->maxJitter, 0, VENDOR_CODE))
+		return -1;
+
+
 	/* Setting Acct-Session-Id & User-Name attributes for proper generation
 	 * of Acct-Unique-Session-Id on server side
 	 */
diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c
index 2de4e426ae..5c6f743fc5 100644
--- a/cdr/cdr_tds.c
+++ b/cdr/cdr_tds.c
@@ -189,13 +189,22 @@ retry:
 					 "("
 					 "'%s', '%s', '%s', '%s', '%s', '%s', "
 					 "'%s', '%s', '%s', %s, %s, %s, %ld, "
-					 "%ld, '%s', '%s', '%s', '%s'"
-					 ")",
+					 "%ld, '%s', '%s', '%s', %ld , '%s' "
+					 "'%s', %ld , '%s', %ld , %ld , %ld ,
+					 %ld , %ld , %ld , %ld , %ld , %ld ,
+					 %ld , %ld , %ld , %ld , %ld , %ld ,
+					 %ld , %ld , %ld , %ld , %ld , %ld ,
+					 %ld , %ld , %ld ,'%s')",
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
 					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid,
-					 userfield
+					 cdr->sessionId, cdr->sipIpAddress, cdr->farEndIPAddress, cdr->sipResponseCode, cdr->codec, cdr->rtp_stats->localBurstDensity,
+					 cdr->rtp_stats->remoteBurstDensity, cdr->rtp_stats->localBurstDuration, cdr->rtp_stats->remoteBurstDuration, cdr->rtp_stats->localGapDensity, cdr->rtp_stats->remoteGapDensity,
+					 cdr->rtp_stats->localGapDuration, cdr->rtp_stats->remoteGapDuration, cdr->rtp_stats->localJbRate, cdr->rtp_stats->remoteJbRate, cdr->rtp_stats->localJbMax,
+					 cdr->rtp_stats->remoteJbMax, cdr->rtp_stats->localJbNominal, cdr->rtp_stats->remoteJbNominal, cdr->rtp_stats->localJbAbsMax, cdr->rtp_stats->remoteJbAbsMax,
+					 cdr->rtp_stats->jbAvg, cdr->rtp_stats->uLossRate, cdr->rtp_stats->discarded, cdr->rtp_stats->lost, cdr->rtp_stats->rxpkts,
+					 cdr->rtp_stats->txpkts, cdr->rtp_stats->jitter, cdr->rtp_stats->maxJitter, userfield
 			);
 		}
 	} else {
@@ -238,12 +247,20 @@ retry:
 					 "("
 					 "'%s', '%s', '%s', '%s', '%s', '%s', "
 					 "'%s', '%s', '%s', %s, %s, %s, %ld, "
-					 "%ld, '%s', '%s', '%s'"
-					 ")",
+					 "%ld, '%s', '%s', %ld , '%s', '%s', %ld, "
+					 "'%s', %ld, %ld, %ld, %ld, %ld, %ld, %ld,
+					 %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld,
+					 %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, '%s')",
 					 settings->table,
 					 accountcode, src, dst, dcontext, clid, channel,
 					 dstchannel, lastapp, lastdata, start, answer, end, cdr->duration,
-					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags), uniqueid
+					 cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_channel_amaflags2string(cdr->amaflags),
+					 cdr->sessionId, cdr->sipIpAddress, cdr->farEndIPAddress, cdr->sipResponseCode, cdr->codec,
+					 cdr->rtp_stats->localBurstDensity, cdr->rtp_stats->remoteBurstDensity, cdr->rtp_stats->localBurstDuration, cdr->rtp_stats->remoteBurstDuration,
+					 cdr->rtp_stats->localGapDensity, cdr->rtp_stats->remoteGapDensity, cdr->rtp_stats->localGapDuration, cdr->rtp_stats->remoteGapDuration,
+					 cdr->rtp_stats->localJbRate, cdr->rtp_stats->remoteJbRate, cdr->rtp_stats->localJbMax, cdr->rtp_stats->remoteJbMax, cdr->rtp_stats->localJbNominal,
+					 cdr->rtp_stats->remoteJbNominal, cdr->rtp_stats->localJbAbsMax, cdr->rtp_stats->remoteJbAbsMax, cdr->rtp_stats->jbAvg, cdr->rtp_stats->uLossRate,
+					 cdr->rtp_stats->discarded, cdr->rtp_stats->lost, cdr->rtp_stats->rxpkts, cdr->rtp_stats->txpkts, cdr->rtp_stats->jitter, cdr->rtp_stats->maxJitter, uniqueid
 			);
 		}
 	}
diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c
index b263432fb5..7a7e9fa0bd 100644
--- a/channels/chan_brcm.c
+++ b/channels/chan_brcm.c
@@ -123,6 +123,7 @@ static struct ast_channel *brcm_new(struct brcm_subchannel *subchan, int state,
 		const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
 		struct ast_format_cap *format);
 static int handle_dialtone_timeout(const void *data);
+static int endpt_get_rtp_stats(int line);
 
 /* Global brcm channel parameters */
 static const char tdesc[] = "Broadcom SLIC Driver";
@@ -135,6 +136,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;
 
@@ -427,7 +429,6 @@ static void ubus_call_complete(struct ubus_request *req, int ret)
 	free(req);
 }
 
-
 static void endpt_signal(int line, char *signal, char *state, char *data) {
 	struct blob_buf bb;
 	struct ubus_request *req;
@@ -817,7 +818,7 @@ static int brcm_call(struct ast_channel *chan, const char *dest, int timeout)
 		ast_debug(1, "Line is busy\n");
 		ast_channel_hangupcause_set(chan, AST_CAUSE_USER_BUSY);
 		ast_queue_control(chan, AST_CONTROL_BUSY);
-                send_ubus_event("USER_BUSY",p->line_id);
+		send_ubus_event("USER_BUSY",p->line_id);
 	}
 	else {
 		ast_debug(1, "Not call waiting\n");
@@ -830,7 +831,11 @@ static int brcm_call(struct ast_channel *chan, const char *dest, int timeout)
 		}
 	  	ast_setstate(chan, AST_STATE_RINGING);
 		ast_queue_control(chan, AST_CONTROL_RINGING);
-                send_ubus_event("RINGING",p->line_id);
+		send_ubus_event("RINGING",p->line_id);
+		if (!sub->connection_init) {
+			sub->connection_id = ast_atomic_fetchadd_int((int *)&current_connection_id, +1);
+			brcm_create_connection(sub);
+		}
 	}
 	//ast_mutex_unlock(&sub->parent->lock);
 	pvt_unlock(sub->parent);
@@ -882,6 +887,12 @@ static int brcm_hangup(struct ast_channel *ast)
 		ast_channel_name(ast), p->line_id, sub->connection_id, dialtone_map[p->dialtone].str,
 		state2str(sub->channel_state));
 
+	if (endpt_get_rtp_stats(p->line_id))
+		if (endpt_get_rtp_stats(p->line_id))	// retry once if failed
+			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 &&
@@ -2446,7 +2457,6 @@ static void *brcm_process_event(struct endpt_event *ev) {
 
 			if (owner) {
 				ast_queue_control(owner, AST_CONTROL_HANGUP);
-				endpt_connection(sub->parent->line_id, sub->connection_id, "destroy");
 			}
 
 			//TODO: possible bug below - we don't change the channel_state when hanging up
@@ -3383,6 +3393,61 @@ static const struct blobmsg_policy endpt_count_policy[__MAX_ENDPOINTS] = {
 	[NUM_DECT_ENDPOINTS] = { .name = "num_dect_endpoints", .type = BLOBMSG_TYPE_INT32 },
 };
 
+enum {
+	RTP_STATS_LOCAL_BURST_DENSITY,
+	RTP_STATS_REMOTE_BURST_DENSITY,
+	RTP_STATS_LOCAL_BURST_DURATION,
+	RTP_STATS_REMOTE_BURST_DURATION,
+	RTP_STATS_LOCAL_GAP_DENSITY,
+	RTP_STATS_REMOTE_GAP_DENSITY,
+	RTP_STATS_LOCAL_GAP_DURATION,
+	RTP_STATS_REMOTE_GAP_DURATION,
+	RTP_STATS_LOCAL_JB_RATE,
+	RTP_STATS_REMOTE_JB_RATE,
+	RTP_STATS_LOCAL_JB_MAX,
+	RTP_STATS_REMOTE_JB_MAX,
+	RTP_STATS_LOCAL_JB_NOMINAL,
+	RTP_STATS_REMOTE_JB_NOMINAL,
+	RTP_STATS_LOCAL_JB_ABS_MAX,
+	RTP_STATS_REMOTE_JB_ABS_MAX,
+	RTP_STATS_DISCARDED,
+	RTP_STATS_LOST,
+	RTP_STATS_RX_PKTS,
+	RTP_STATS_TX_PKTS,
+	RTP_STATS_JB_AVG,
+	RTP_STATS_JITTER,
+	RTP_STATS_LOSS_RATE,
+	RTP_STATS_MAX_JITTER,
+	__MAX_RTP_STATS,
+};
+
+static const struct blobmsg_policy endpt_rtp_stats_policy[__MAX_RTP_STATS] = {
+	[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 },
+	[RTP_STATS_REMOTE_BURST_DURATION] = { .name = "remoteBurstDuration", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_GAP_DENSITY] = { .name = "localGapDensity", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_GAP_DENSITY] = { .name = "remoteGapDensity", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_GAP_DURATION] = { .name = "localGapDuration", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_GAP_DURATION] = { .name = "remoteGapDuration", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_JB_RATE] = { .name = "localJbRate", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_JB_RATE] = { .name = "remoteJbRate", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_JB_MAX] = { .name = "localJbMax", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_JB_MAX] = { .name = "remoteJbMax", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_JB_NOMINAL] = { .name = "localJbNominal", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_JB_NOMINAL] = { .name = "remoteJbNominal", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_LOCAL_JB_ABS_MAX] = { .name = "localJbAbsMax", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_REMOTE_JB_ABS_MAX] = { .name = "remoteJbAbsMax", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_DISCARDED] = { .name = "discarded", .type = BLOBMSG_TYPE_INT32 },
+	[RTP_STATS_LOST] = { .name = "lost", .type = BLOBMSG_TYPE_INT32 },
+	[RTP_STATS_RX_PKTS] = { .name = "rxpkts", .type = BLOBMSG_TYPE_INT32 },
+	[RTP_STATS_TX_PKTS] = { .name = "txpkts", .type = BLOBMSG_TYPE_INT32 },
+	[RTP_STATS_JB_AVG] = { .name = "jbAvg", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_JITTER] = { .name = "jitter", .type = BLOBMSG_TYPE_INT32 },
+	[RTP_STATS_LOSS_RATE] = { .name = "uLossRate", .type = BLOBMSG_TYPE_INT16 },
+	[RTP_STATS_MAX_JITTER] = { .name = "maxJitter", .type = BLOBMSG_TYPE_INT32 },
+};
+
 // Reception of event
 // { "ubus.object.add": {"id":123, "path":"foo"} }
 static void ubus_event_new_obj(struct ubus_context *ctx __attribute__((unused)), struct ubus_event_handler *ev __attribute__((unused)),
@@ -3447,6 +3512,93 @@ static int endpt_get_count(void) {
 		endpt_get_count_cb, NULL, 2000) == UBUS_STATUS_OK ? 0 : -1);
 }
 
+static void ubus_call_answer_rtp_stats(struct ubus_request *req, int type, struct blob_attr *msg) {
+	struct blob_attr *tb[__MAX_RTP_STATS];
+
+	ast_log(LOG_DEBUG, "Got answer from endptmngr on rtp_stats ubus call.\n");
+	blobmsg_parse(endpt_rtp_stats_policy, __MAX_RTP_STATS, tb, blob_data(msg), blob_len(msg));
+
+	if (tb[RTP_STATS_LOCAL_BURST_DENSITY])
+		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]);
+	if (tb[RTP_STATS_LOCAL_BURST_DURATION])
+		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]);
+	if (tb[RTP_STATS_LOCAL_GAP_DENSITY])
+		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]);
+	if (tb[RTP_STATS_LOCAL_GAP_DURATION])
+		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]);
+	if (tb[RTP_STATS_LOCAL_JB_RATE])
+		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]);
+	if (tb[RTP_STATS_LOCAL_JB_MAX])
+		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]);
+	if (tb[RTP_STATS_LOCAL_JB_NOMINAL])
+		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]);
+	if (tb[RTP_STATS_LOCAL_JB_ABS_MAX])
+		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]);
+	if (tb[RTP_STATS_DISCARDED])
+		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]);
+	if (tb[RTP_STATS_RX_PKTS])
+		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]);
+	if (tb[RTP_STATS_JB_AVG])
+		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]);
+	if (tb[RTP_STATS_LOSS_RATE])
+		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]);
+
+	ast_log(LOG_DEBUG, "RTP stats received:\nlocalBurstDensity: %d\nremoteBurstDensity: %d\n"
+			"localBurstDuration: %d\nremoteBurstDuration: %d\nlocalGapDensity: %d\n"
+			"remoteGapDensity: %d\nlocalGapDuration: %d\nremoteGapDuration: %d\n"
+			"localJbRate: %d\nremoteJbRate: %d\nlocalJbMax: %d\nremoteJbMax: %d\n"
+			"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);
+}
+
+static int endpt_get_rtp_stats(int line) {
+	struct blob_buf bb;
+	int res;
+
+	if (endpt_id) {
+		memset(&bb, 0, sizeof(bb));
+		blob_buf_init(&bb, 0);
+
+		blobmsg_add_u32(&bb, "line", line);
+		blobmsg_add_u8(&bb, "reset", 1); // always reset RTP stats after get them
+
+		return (ubus_invoke(ctx, endpt_id, "rtp_stats", bb.head,
+			ubus_call_answer_rtp_stats, NULL, 2000) == UBUS_STATUS_OK ? 0 : -1);
+	}
+}
+
 // Reception of RPC call
 // ubus call asterisk event '{ "line" : 1, "event" : "EVENT_DTMF0" }'
 static int asterisk_event(struct ubus_context *ctx, struct ubus_object *obj,
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index c6b241315c..ce947bfc42 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -270,6 +270,34 @@ struct ast_cdr_config {
 	} batch_settings;
 };
 
+/*! \brief Struct for rtp statistics get from brcm */
+typedef struct {
+	uint16_t localBurstDensity;
+	uint16_t remoteBurstDensity;
+	uint16_t localBurstDuration;
+	uint16_t remoteBurstDuration;
+	uint16_t localGapDensity;
+	uint16_t remoteGapDensity;
+	uint16_t localGapDuration;
+	uint16_t remoteGapDuration;
+	uint16_t localJbRate;
+	uint16_t remoteJbRate;
+	uint16_t localJbMax;
+	uint16_t remoteJbMax;
+	uint16_t localJbNominal;
+	uint16_t remoteJbNominal;
+	uint16_t localJbAbsMax;
+	uint16_t remoteJbAbsMax;
+	uint16_t jbAvg;
+	uint16_t uLossRate;
+	uint32_t discarded;
+	uint32_t lost;
+	uint32_t rxpkts;
+	uint32_t txpkts;
+	uint32_t jitter;
+	uint32_t maxJitter;
+} cdr_rtp_statistics;
+
 /*!
  * \brief Responsible for call detail data
  */
@@ -318,7 +346,18 @@ struct ast_cdr {
 	char userfield[AST_MAX_USER_FIELD];
 	/*! Sequence field */
 	int sequence;
-
+	/*! SessionId */
+	int sessionId;
+	/*! sipIpAddress */
+	char sipIpAddress[40];
+	/*! farEndIPAddress */
+	char farEndIPAddress[40];
+	/*! Sip Response Code */
+	int sipResponseCode;
+	/*! codec */
+	char codec[40];
+	/*! RTP Statistics */
+	cdr_rtp_statistics *rtp_stats;
 	/*! A linked list for variables */
 	struct varshead varshead;
 
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 40069b0178..3bf020e1a4 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -598,6 +598,34 @@ typedef struct {
 	const char *value;
 } ast_chan_write_info_t;
 
+/*! \brief Struct for rtp statistics get from brcm */
+typedef struct {
+	uint16_t localBurstDensity;
+	uint16_t remoteBurstDensity;
+	uint16_t localBurstDuration;
+	uint16_t remoteBurstDuration;
+	uint16_t localGapDensity;
+	uint16_t remoteGapDensity;
+	uint16_t localGapDuration;
+	uint16_t remoteGapDuration;
+	uint16_t localJbRate;
+	uint16_t remoteJbRate;
+	uint16_t localJbMax;
+	uint16_t remoteJbMax;
+	uint16_t localJbNominal;
+	uint16_t remoteJbNominal;
+	uint16_t localJbAbsMax;
+	uint16_t remoteJbAbsMax;
+	uint16_t jbAvg;
+	uint16_t uLossRate;
+	uint32_t discarded;
+	uint32_t lost;
+	uint32_t rxpkts;
+	uint32_t txpkts;
+	uint32_t jitter;
+	uint32_t maxJitter;
+} rtp_statistics;
+
 /*!
  * \brief Structure to pass both assignedid values to channel drivers
  * \note The second value is used only by core_unreal (LOCAL)
@@ -4363,9 +4391,19 @@ enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan);
 void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value);
 enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 ast_callid ast_channel_callid(const struct ast_channel *chan);
+unsigned int ast_channel_sessionId(const struct ast_channel *chan);
+void ast_channel_sessionId_set(struct ast_channel *chan, unsigned int value);
+const char *ast_channel_sipIpAddress(const struct ast_channel *chan);
+void ast_channel_sipIpAddress_set(struct ast_channel *chan, const char *value, size_t size);
+const char *ast_channel_farEndIPAddress(const struct ast_channel *chan);
+void ast_channel_farEndIPAddress_set(struct ast_channel *chan, const char *value, size_t size);
+unsigned int ast_channel_sipResponseCode(const struct ast_channel *chan);
+void ast_channel_sipResponseCode_set(struct ast_channel *chan, unsigned int value);
 struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan);
 void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot);
 struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan);
+rtp_statistics *ast_channel_rtpStats(const struct ast_channel *chan);
+void ast_channel_rtpStats_set(struct ast_channel *chan, rtp_statistics *rtp_stats);
 
 /*!
  * \pre chan is locked
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index 61f1c213a9..0d0875ce89 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -156,6 +156,12 @@ struct ast_channel_snapshot {
 	struct ast_flags softhangup_flags;                /*!< softhangup channel flags */
 	struct varshead *manager_vars;                    /*!< Variables to be appended to manager events */
 	struct varshead *ari_vars;                        /*!< Variables to be appended to ARI events */
+	unsigned int sessionId;                           /*!< Session Id */
+	char sipIpAddress[40];                            /*!< SIP IP Address */
+	char farEndIPAddress[40];                         /*!< Far End IP Address */
+	unsigned int sipResponseCode;                     /*!< SIP Response Code for Invite */
+	char codec[40];                                   /*!< Codec used */
+	rtp_statistics *rtp_stats;                        /*!< Rtp statistics */
 };
 
 /*!
diff --git a/main/cdr.c b/main/cdr.c
index 6a823a9807..e549db6e92 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -731,7 +731,13 @@ struct cdr_object {
 		AST_STRING_FIELD(context);          /*!< The accepted context for Party A */
 		AST_STRING_FIELD(exten);            /*!< The accepted extension for Party A */
 		AST_STRING_FIELD(party_b_name);     /*!< Party B channel name. Cached here as it is the all CDRs container key */
+		AST_STRING_FIELD(sipIpAddress);     /*!< SIP IP Address */
+		AST_STRING_FIELD(farEndIPAddress);  /*!< Far End IP Address */
+		AST_STRING_FIELD(codec);     	    /*!< Codec used */
 	);
+	unsigned int sessionId;                 /*!< Session Id */
+	unsigned int sipResponseCode;           /*!< Sip Response Code on Invite */
+	cdr_rtp_statistics *rtp_stats;          /*!< RTP Statistics */
 	struct cdr_object *next;                /*!< The next CDR object in the chain */
 	struct cdr_object *last;                /*!< The last CDR object in the chain */
 	int is_root;                            /*!< True if this is the first CDR in the chain */
@@ -1324,6 +1330,28 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 		ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
 		ast_copy_string(cdr_copy->dcontext, it_cdr->context, sizeof(cdr_copy->dcontext));
 
+		if (party_a->sessionId)
+			cdr_copy->sessionId = party_a->sessionId;
+
+		if (ast_strlen_zero(cdr_copy->sipIpAddress) && !ast_strlen_zero(party_a->sipIpAddress)) {
+			ast_copy_string(cdr_copy->sipIpAddress, party_a->sipIpAddress, sizeof(cdr_copy->sipIpAddress));
+		}
+
+		if (ast_strlen_zero(cdr_copy->farEndIPAddress) && !ast_strlen_zero(party_a->farEndIPAddress)) {
+			ast_copy_string(cdr_copy->farEndIPAddress, party_a->farEndIPAddress, sizeof(cdr_copy->farEndIPAddress));
+		}
+
+		if (party_a->sipResponseCode) {
+			cdr_copy->sipResponseCode = party_a->sipResponseCode;
+
+		}
+		if (ast_strlen_zero(cdr_copy->codec) && !ast_strlen_zero(party_a->codec)) {
+			ast_copy_string(cdr_copy->codec, party_a->codec, sizeof(cdr_copy->codec));
+		}
+
+		if (party_a->rtp_stats)
+			cdr_copy->rtp_stats = party_a->rtp_stats;
+
 		/* Party B */
 		if (party_b) {
 			ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
@@ -1331,7 +1359,29 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 			if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
 				snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
 			}
+			if (party_b->sessionId)
+				cdr_copy->sessionId = party_b->sessionId;
+
+			if (ast_strlen_zero(cdr_copy->sipIpAddress) && !ast_strlen_zero(party_b->sipIpAddress)) {
+				ast_copy_string(cdr_copy->sipIpAddress, party_b->sipIpAddress, sizeof(cdr_copy->sipIpAddress));
+			}
+
+			if (ast_strlen_zero(cdr_copy->farEndIPAddress) && !ast_strlen_zero(party_b->farEndIPAddress)) {
+				ast_copy_string(cdr_copy->farEndIPAddress, party_b->farEndIPAddress, sizeof(cdr_copy->farEndIPAddress));
+			}
+
+			if (party_b->sipResponseCode) {
+				cdr_copy->sipResponseCode = party_b->sipResponseCode;
+			}
+
+			if (ast_strlen_zero(cdr_copy->codec) && !ast_strlen_zero(party_b->codec)) {
+				ast_copy_string(cdr_copy->codec, party_b->codec, sizeof(cdr_copy->codec));
+			}
+
+			if (party_b->rtp_stats)
+				cdr_copy->rtp_stats = party_b->rtp_stats;
 		}
+
 		if (ast_strlen_zero(cdr_copy->userfield) && !ast_strlen_zero(it_cdr->party_a.userfield)) {
 			ast_copy_string(cdr_copy->userfield, it_cdr->party_a.userfield, sizeof(cdr_copy->userfield));
 		}
@@ -2284,7 +2334,6 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 	if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
 		return;
 	}
-
 	if (update->new_snapshot && !update->old_snapshot) {
 		cdr = cdr_object_alloc(update->new_snapshot, stasis_message_timestamp(message));
 		if (!cdr) {
@@ -2295,7 +2344,9 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 	} else {
 		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;
+	}
 	/* Handle Party A */
 	if (!cdr) {
 		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
@@ -2347,7 +2398,6 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 		ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
 			cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
 	}
-
 	ao2_cleanup(cdr);
 }
 
@@ -3110,6 +3160,64 @@ void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char
 		snprintf(workspace, workspacelen, "%d", cdr->sequence);
 	} else if ((varbuf = cdr_format_var_internal(cdr, name))) {
 		ast_copy_string(workspace, varbuf, workspacelen);
+	} else if (!strcasecmp(name, "sessionId")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->sessionId);
+	} else if (!strcasecmp(name, "sipIpAddress")) {
+		ast_copy_string(workspace, cdr->sipIpAddress, workspacelen);
+	} else if (!strcasecmp(name, "farEndIPAddress")) {
+		ast_copy_string(workspace, cdr->farEndIPAddress, workspacelen);
+	} else if (!strcasecmp(name, "sipResponseCode")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->sipResponseCode);
+	} else if (!strcasecmp(name, "codec")) {
+		ast_copy_string(workspace, cdr->codec, workspacelen);
+	} else if (!strcasecmp(name, "localBurstDensity")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localBurstDensity);
+	} else if (!strcasecmp(name, "remoteBurstDensity")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteBurstDensity);
+	} else if (!strcasecmp(name, "localBurstDuration")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localBurstDuration);
+	} else if (!strcasecmp(name, "remoteBurstDuration")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteBurstDuration);
+	} else if (!strcasecmp(name, "localGapDensity")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localGapDensity);
+	} else if (!strcasecmp(name, "remoteGapDensity")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteGapDensity);
+	} else if (!strcasecmp(name, "localGapDuration")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localGapDuration);
+	} else if (!strcasecmp(name, "remoteGapDuration")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteGapDuration);
+	} else if (!strcasecmp(name, "localJbRate")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localJbRate);
+	} else if (!strcasecmp(name, "remoteJbRate")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteJbRate);
+	} else if (!strcasecmp(name, "localJbMax")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localJbMax);
+	} else if (!strcasecmp(name, "remoteJbMax")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteJbMax);
+	} else if (!strcasecmp(name, "localJbNominal")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localJbNominal);
+	} else if (!strcasecmp(name, "remoteJbNominal")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteJbNominal);
+	} else if (!strcasecmp(name, "localJbAbsMax")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->localJbAbsMax);
+	} else if (!strcasecmp(name, "remoteJbAbsMax")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->remoteJbAbsMax);
+	} else if (!strcasecmp(name, "jbAvg")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->jbAvg);
+	} else if (!strcasecmp(name, "uLossRate")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->uLossRate);
+	} else if (!strcasecmp(name, "discarded")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->discarded);
+	} else if (!strcasecmp(name, "lost")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->lost);
+	} else if (!strcasecmp(name, "rxpkts")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->rxpkts);
+	} else if (!strcasecmp(name, "txpkts")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->txpkts);
+	} else if (!strcasecmp(name, "jitter")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->jitter);
+	} else if (!strcasecmp(name, "maxJitter")) {
+		snprintf(workspace, workspacelen, "%ld", cdr->rtp_stats->maxJitter);
 	} else {
 		workspace[0] = '\0';
 	}
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index a84534aabf..1b3ebda9bb 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -222,6 +222,12 @@ struct ast_channel {
 	struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */
 	struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */
 	struct ast_flags snapshot_segment_flags; /*!< Flags regarding the segments of the snapshot */
+	unsigned int sessionId; /*!< Session Id from SDP for channel */
+	char sipIpAddress[40];  /*!< local IP address that sip client binds to */
+	char farEndIPAddress[40];  /*!< Far End IP Address */
+	unsigned int sipResponseCode; /*!< SIP response Code */
+	char codec[40];  /*!< Negotiated codec used */
+	rtp_statistics *rtp_stats; /*!< RTP statistics */
 };
 
 /*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -794,6 +800,57 @@ ast_callid ast_channel_callid(const struct ast_channel *chan)
 {
 	return chan->callid;
 }
+unsigned int ast_channel_sessionId(const struct ast_channel *chan)
+{
+	return chan->sessionId;
+}
+void ast_channel_sessionId_set(struct ast_channel *chan, unsigned int value)
+{
+	chan->sessionId = value;
+}
+const char *ast_channel_sipIpAddress(const struct ast_channel *chan)
+{
+	return chan->sipIpAddress;
+}
+void ast_channel_sipIpAddress_set(struct ast_channel *chan, const char *value, size_t size)
+{
+	ast_copy_string(chan->sipIpAddress, value, size+1);
+}
+const char *ast_channel_farEndIPAddress(const struct ast_channel *chan)
+{
+	return chan->farEndIPAddress;
+}
+void ast_channel_farEndIPAddress_set(struct ast_channel *chan, const char *value, size_t size)
+{
+	ast_copy_string(chan->farEndIPAddress, value, size+1);
+}
+unsigned int ast_channel_sipResponseCode(const struct ast_channel *chan)
+{
+	return chan->sipResponseCode;
+}
+void ast_channel_sipResponseCode_set(struct ast_channel *chan, unsigned int value)
+{
+	chan->sipResponseCode = value;
+}
+
+const char *ast_channel_codec_get(const struct ast_channel *chan)
+{
+	return chan->codec;
+}
+void ast_channel_codec_set(struct ast_channel *chan, const char *value)
+{
+	ast_copy_string(chan->codec, value, sizeof(chan->codec));
+}
+
+rtp_statistics *ast_channel_rtpStats_get(const struct ast_channel *chan)
+{
+	return chan->rtp_stats;
+}
+void ast_channel_rtpStats_set(struct ast_channel *chan, rtp_statistics *rtp_stats)
+{
+	chan->rtp_stats = rtp_stats;
+}
+
 void ast_channel_callid_set(struct ast_channel *chan, ast_callid callid)
 {
 	char call_identifier_from[AST_CALLID_BUFFER_LENGTH];
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index 5e39c07654..3cf6ff4d33 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -551,6 +551,12 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
 	/* These have to be recreated as they may have changed, unfortunately */
 	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
 	snapshot->ari_vars = ast_channel_get_ari_vars(chan);
+	snapshot->sessionId = ast_channel_sessionId(chan);
+	ast_copy_string(snapshot->sipIpAddress, ast_channel_sipIpAddress(chan), sizeof(snapshot->sipIpAddress));
+	ast_copy_string(snapshot->farEndIPAddress, ast_channel_farEndIPAddress(chan), sizeof(snapshot->farEndIPAddress));
+	snapshot->sipResponseCode = ast_channel_sipResponseCode(chan);
+	ast_copy_string(snapshot->codec, ast_channel_codec_get(chan), sizeof(snapshot->codec));
+	snapshot->rtp_stats = ast_channel_rtpStats_get(chan);
 
 	return snapshot;
 }
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index f00519b9c6..fe565f66de 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -2085,6 +2085,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session,
 		SCOPE_EXIT_RTN_VALUE(1, "No channel\n");
 	}
 
+	ast_channel_codec_set(session->channel, ast_format_get_codec_name(ast_channel_writeformat(session->channel)));
 	/* Ensure incoming transport is compatible with the endpoint's configuration */
 	if (!session->endpoint->media.rtp.use_received_transport &&
 		check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index da0b18b32f..85a64da289 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1067,6 +1067,9 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_
 	unsigned int changed = 0; /* 0 = unchanged, 1 = new source, 2 = new topology */
 	SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
 
+	if (session && session->channel)
+		ast_channel_farEndIPAddress_set(session->channel, pj_strbuf(&remote->origin.addr), pj_strlen(&remote->origin.addr));
+
 	if (!session->pending_media_state->topology) {
 		if (session->active_media_state->topology) {
 			/*
@@ -2805,7 +2808,6 @@ static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata)
 	}
 
 	pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
-
 	return PJ_TRUE;
 }
 
@@ -4073,6 +4075,11 @@ static int new_invite(struct new_invite *invite)
 	handle_incoming_request(invite->session, invite->rdata);
 
 end:
+	if (invite->session && invite->session->channel) {
+		ast_channel_sessionId_set(invite->session->channel, local->origin.id);
+		ast_channel_sipIpAddress_set(invite->session->channel, pj_strbuf(&local->origin.addr), pj_strlen(&local->origin.addr));
+	}
+
 	SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(invite->session));
 }
 
@@ -4491,6 +4498,8 @@ static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_d
 			supplement->incoming_response(session, rdata);
 		}
 	}
+	if (session && session->channel)
+		ast_channel_sipResponseCode_set(session->channel, status.code == 180 ? 487 : status.code);
 
 	SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
 }
@@ -4550,6 +4559,8 @@ static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_d
 			supplement->outgoing_response(session, tdata);
 		}
 	}
+	if (session && session->channel)
+		ast_channel_sipResponseCode_set(session->channel, status.code == 180 ? 487 : status.code);
 
 	SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
 }
@@ -5262,6 +5273,11 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru
 	pj_strassign(&local->origin.addr, &local->conn->addr);
 
 end:
+	if (session && session->channel) {
+		ast_channel_sessionId_set(session->channel, local->origin.id);
+		ast_channel_sipIpAddress_set(session->channel, pj_strbuf(&local->origin.addr), pj_strlen(&local->origin.addr));
+	}
+
 	SCOPE_EXIT_RTN_VALUE(local, "%s\n", ast_sip_session_get_name(session));
 }
 
-- 
GitLab