[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