[Asterisk-code-review] Added RTT Support for PJSIP (asterisk[master])

Bharat Ramaswamy-Nandakumar asteriskteam at digium.com
Wed Dec 11 15:32:55 CST 2019


Bharat Ramaswamy-Nandakumar has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/13419 )


Change subject: Added RTT Support for PJSIP
......................................................................

Added RTT Support for PJSIP

Changes are:
1. chan_pjsip - added write_text function to the pjsip_tech driver
Added case for AST_FRAME_TEXT in chan_pjsip_write_stream
Added case to handle text in chan_pjsip_write

2. pjsip/dialplan_functions.c: added logic to handle media for TEXT

3.  res_pjsip.h: added variables to deal with endpoint media

4. channel.c: added  logic to add a stream_num for a frame

5.  frame.c: added code to handle and fix issues with red.

6. res_pjsip_sdp_rtp.c: added logic to setup SDP.
Added logic to handle tos and cos text
Added logic to RED for red enabled

7. res_pjsip_session.c: aded logic for max_text_streams

8. res_rtp_asterisk.c: Added logic to hanle Red and dealing with
a repeating RTP issue

9. pjsip_configuration.c: Added logic to handle text for PJSIP library

Issue ID: ASTERISK-28654

Reported-by: Bharat Ramaswamy Nandakumar(bharatram1)

Fixed by: Bharat Ramaswamy Nandakumar(bharatram1)

Change-Id: I8938313e457a6c2253db13609c647aeae77aa5ed
---
M channels/chan_pjsip.c
M channels/pjsip/dialplan_functions.c
M include/asterisk/res_pjsip.h
M main/channel.c
M main/frame.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_sdp_rtp.c
M res/res_pjsip_session.c
M res/res_rtp_asterisk.c
9 files changed, 108 insertions(+), 5 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/19/13419/1

diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index f2f6cf8..87488b2 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -121,6 +121,7 @@
 	.read_stream = chan_pjsip_read_stream,
 	.write = chan_pjsip_write,
 	.write_stream = chan_pjsip_write_stream,
+	.write_text = chan_pjsip_write,
 	.exception = chan_pjsip_read_stream,
 	.indicate = chan_pjsip_indicate,
 	.transfer = chan_pjsip_transfer,
@@ -986,6 +987,19 @@
 		break;
 	case AST_FRAME_CNG:
 		break;
+	case AST_FRAME_TEXT:
+		if (!media) {
+			return 0;
+		} else if (media->type != AST_MEDIA_TYPE_TEXT) {
+			ast_debug(3, "Channel %s stream %d is of type '%s', not text!\n",
+				ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));
+			return 0;
+        } else if(session->endpoint->media.red_enabled) {
+            ast_rtp_red_buffer(media->rtp, frame);
+        } else if (media->write_callback) {
+			res = media->write_callback(session, media, frame);
+		}
+		break;
 	case AST_FRAME_RTCP:
 		/* We only support writing out feedback */
 		if (frame->subclass.integer != AST_RTP_RTCP_PSFB || !media) {
@@ -1008,6 +1022,9 @@
 
 static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame)
 {
+	if (frame->frametype == AST_FRAME_TEXT && frame->stream_num != -1){
+		return chan_pjsip_write_stream(ast, frame->stream_num, frame);
+	}
 	return chan_pjsip_write_stream(ast, -1, frame);
 }
 
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index 7cc4506..21296ed 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -576,7 +576,9 @@
 		media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
 	} else if (!strcmp(field, "video")) {
 		media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];
-	} else {
+	} else if (ast_strlen_zero(field) || !strcmp(field, "text")){
+        media = session->active_media_state->default_session[AST_MEDIA_TYPE_TEXT];
+    } else {
 		ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);
 		return -1;
 	}
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index b26aba9..ad54a2d 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -736,6 +736,12 @@
 	unsigned int tos_video;
 	/*! Priority for video streams */
 	unsigned int cos_video;
+	/*! DSCP TOS bits for text streams */
+	unsigned int tos_text;
+	/*! Priority for text streams */
+	unsigned int cos_text;
+    /*! DSCP indicate if text stream supports RED */
+	unsigned int red_enabled;
 	/*! Is g.726 packed in a non standard way */
 	unsigned int g726_non_standard;
 	/*! Bind the RTP instance to the media_address */
@@ -746,6 +752,8 @@
 	unsigned int max_audio_streams;
 	/*! Maximum number of video streams to offer/accept */
 	unsigned int max_video_streams;
+	/*! Maximum number of text streams to offer/accept */
+	unsigned int max_text_streams;
 	/*! Use BUNDLE */
 	unsigned int bundle;
 	/*! Enable webrtc settings and defaults */
diff --git a/main/channel.c b/main/channel.c
index c350177..86859a8 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4762,6 +4762,8 @@
 		f.frametype = AST_FRAME_TEXT;
 		f.datalen = body_len;
 		f.mallocd = AST_MALLOCD_DATA;
+		struct ast_stream *default_streams = ast_channel_get_default_stream(chan, AST_MEDIA_TYPE_TEXT);
+		f.stream_num = ast_stream_get_position(default_streams);
 		f.data.ptr = ast_strdup(body);
 		if (f.data.ptr) {
 			res = ast_channel_tech(chan)->write_text(chan, &f);
diff --git a/main/frame.c b/main/frame.c
index f7a5222..96511f9 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -305,7 +305,7 @@
 #endif
 
 	/* Start with standard stuff */
-	len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
+	len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen + 1;
 	/* If we have a source, add space for it */
 	/*
 	 * XXX Watch out here - if we receive a src which is not terminated
@@ -363,13 +363,16 @@
 	if (out->datalen || f->frametype == AST_FRAME_TEXT) {
 		out->data.ptr = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
 		memcpy(out->data.ptr, f->data.ptr, out->datalen);
+		if(f->frametype == AST_FRAME_TEXT) {
+			((char*)out->data.ptr)[out->datalen] = '\0';
+		}
 	} else {
 		out->data.uint32 = f->data.uint32;
 	}
 	if (srclen > 0) {
 		/* This may seem a little strange, but it's to avoid a gcc (4.2.4) compiler warning */
 		char *src;
-		out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
+		out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen + 1;
 		src = (char *) out->src;
 		/* Must have space since we allocated for it */
 		strcpy(src, f->src);
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 355b595..4bd887a 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -960,6 +960,8 @@
 		endpoint->media.tos_audio = value;
 	} else if (!strcmp(var->name, "tos_video")) {
 		endpoint->media.tos_video = value;
+	} else if (!strcmp(var->name, "tos_text")){
+		endpoint->media.tos_text = value;
 	} else {
 		/* If we reach this point, someone called the tos_handler when they shouldn't have. */
 		ast_assert(0);
@@ -988,6 +990,16 @@
 	return 0;
 }
 
+static int tos_text_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+	const struct ast_sip_endpoint *endpoint = obj;
+
+	if (ast_asprintf(buf, "%u", endpoint->media.tos_text) == -1) {
+		return -1;
+	}
+	return 0;
+}
+
 static int from_user_handler(const struct aco_option *opt,
 	struct ast_variable *var, void *obj)
 {
@@ -1904,8 +1916,10 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_text", "0", tos_handler, tos_text_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_text", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_text));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "from_user", "", from_user_handler, from_user_to_str, NULL, 0, 0);
@@ -1945,6 +1959,7 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_text_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_text_streams));	
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox));
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index 8d9cece..5f4b556 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -65,6 +65,7 @@
 
 static const char STR_AUDIO[] = "audio";
 static const char STR_VIDEO[] = "video";
+static const char STR_TEXT[] = "text";
 
 static int send_keepalive(const void *data)
 {
@@ -268,7 +269,12 @@
 			(session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) {
 		ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio,
 				session->endpoint->media.cos_audio, "SIP RTP Audio");
-	} else if (session_media->type == AST_MEDIA_TYPE_VIDEO) {
+	} else if (session_media->type == AST_MEDIA_TYPE_TEXT) {
+		if (session->endpoint->media.tos_text || session->endpoint->media.cos_text) {
+			ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_text,
+				session->endpoint->media.cos_text, "SIP RTP Text");
+		}
+    } else if (session_media->type == AST_MEDIA_TYPE_VIDEO) {
 		ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_RECV, session->endpoint->media.webrtc);
 		ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_SEND, session->endpoint->media.webrtc);
 		ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_REMB, session->endpoint->media.webrtc);
@@ -340,7 +346,32 @@
 				struct ast_format *format_parsed;
 
 				ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param));
+				if (strncasecmp(name, "RED", 3) == 0) {
+						int red_data_pt[10];		/* For T.140 RED */
+						char red_cp_data[30];
+						char *red_cp = red_cp_data;
+						char *rest = NULL;
+						int red_num_gen = -1;
 
+						strcpy(red_cp,fmt_param);
+						red_cp = strtok_r(red_cp, "/", &rest);
+						while (red_cp && (red_num_gen)++ < AST_RED_MAX_GENERATION) {
+							sscanf(red_cp, "%30u", (unsigned *)&red_data_pt[red_num_gen]);
+							red_cp = strtok_r(NULL, "/", &rest);
+						}
+
+						if(red_num_gen > 0) {
+							session->endpoint->media.red_enabled=1;
+							ast_rtp_red_init(session_media->rtp, 300, red_data_pt, red_num_gen);
+						}
+						else {
+							session->endpoint->media.red_enabled=0;
+						}
+
+					}
+					else {
+						session->endpoint->media.red_enabled=0;
+					}
 				format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param);
 				if (format_parsed) {
 					ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed);
@@ -2109,6 +2140,17 @@
 	.stream_destroy = stream_destroy,
 };
 
+/*! \brief SDP handler for 'text' media stream */
+static struct ast_sip_session_sdp_handler text_sdp_handler = {
+        .id = STR_TEXT,
+        .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
+        .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
+        .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
+        .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
+        .stream_stop = stream_stop,
+        .stream_destroy = stream_destroy,
+};
+
 static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 {
 	struct pjsip_transaction *tsx;
@@ -2143,6 +2185,7 @@
 	ast_sip_session_unregister_supplement(&video_info_supplement);
 	ast_sip_session_unregister_sdp_handler(&video_sdp_handler, STR_VIDEO);
 	ast_sip_session_unregister_sdp_handler(&audio_sdp_handler, STR_AUDIO);
+	ast_sip_session_unregister_sdp_handler(&text_sdp_handler, STR_TEXT);
 
 	if (sched) {
 		ast_sched_context_destroy(sched);
@@ -2189,6 +2232,11 @@
 		goto end;
 	}
 
+	if (ast_sip_session_register_sdp_handler(&text_sdp_handler, STR_TEXT)) {
+        ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_TEXT);
+        goto end;
+    }
+	
 	ast_sip_session_register_supplement(&video_info_supplement);
 
 	return AST_MODULE_LOAD_SUCCESS;
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index bc01548..8d6454f 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -545,6 +545,7 @@
 		return (type_streams[type] > 0);
 	case AST_MEDIA_TYPE_UNKNOWN:
 	case AST_MEDIA_TYPE_TEXT:
+		return !(type_streams[type] < endpoint->media.max_text_streams);
 	default:
 		/* We don't want any unknown or "other" streams on our endpoint,
 		 * so always just say we've reached the limit
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index c870fce..5fa7c89 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -7128,6 +7128,10 @@
 		*data++ = 0xEF;
 		*data++ = 0xBF;
 		*data = 0xBD;
+
+		if(rtp->f.datalen <= 0) {
+			return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+		}
 	}
 
 	if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
@@ -8056,9 +8060,12 @@
 {
 	struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	if(!rtp || !rtp->red) {
+		return (0);
+	}
 
 	ao2_lock(instance);
-	if (rtp->red->t140.datalen > 0) {
+	if (rtp && rtp->red && rtp->red->t140.datalen > 0) {
 		ast_rtp_write(instance, &rtp->red->t140);
 	}
 	ao2_unlock(instance);

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/13419
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I8938313e457a6c2253db13609c647aeae77aa5ed
Gerrit-Change-Number: 13419
Gerrit-PatchSet: 1
Gerrit-Owner: Bharat Ramaswamy-Nandakumar <bharat at indigital.net>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20191211/34430a95/attachment-0001.html>


More information about the asterisk-code-review mailing list