<p>Bharat Ramaswamy-Nandakumar has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/13419">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Added RTT Support for PJSIP<br><br>Changes are:<br>1. chan_pjsip - added write_text function to the pjsip_tech driver<br>Added case for AST_FRAME_TEXT in chan_pjsip_write_stream<br>Added case to handle text in chan_pjsip_write<br><br>2. pjsip/dialplan_functions.c: added logic to handle media for TEXT<br><br>3. res_pjsip.h: added variables to deal with endpoint media<br><br>4. channel.c: added logic to add a stream_num for a frame<br><br>5. frame.c: added code to handle and fix issues with red.<br><br>6. res_pjsip_sdp_rtp.c: added logic to setup SDP.<br>Added logic to handle tos and cos text<br>Added logic to RED for red enabled<br><br>7. res_pjsip_session.c: aded logic for max_text_streams<br><br>8. res_rtp_asterisk.c: Added logic to hanle Red and dealing with<br>a repeating RTP issue<br><br>9. pjsip_configuration.c: Added logic to handle text for PJSIP library<br><br>Issue ID: ASTERISK-28654<br><br>Reported-by: Bharat Ramaswamy Nandakumar(bharatram1)<br><br>Fixed by: Bharat Ramaswamy Nandakumar(bharatram1)<br><br>Change-Id: I8938313e457a6c2253db13609c647aeae77aa5ed<br>---<br>M channels/chan_pjsip.c<br>M channels/pjsip/dialplan_functions.c<br>M include/asterisk/res_pjsip.h<br>M main/channel.c<br>M main/frame.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_session.c<br>M res/res_rtp_asterisk.c<br>9 files changed, 108 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/19/13419/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c</span><br><span>index f2f6cf8..87488b2 100644</span><br><span>--- a/channels/chan_pjsip.c</span><br><span>+++ b/channels/chan_pjsip.c</span><br><span>@@ -121,6 +121,7 @@</span><br><span> .read_stream = chan_pjsip_read_stream,</span><br><span> .write = chan_pjsip_write,</span><br><span> .write_stream = chan_pjsip_write_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+ .write_text = chan_pjsip_write,</span><br><span> .exception = chan_pjsip_read_stream,</span><br><span> .indicate = chan_pjsip_indicate,</span><br><span> .transfer = chan_pjsip_transfer,</span><br><span>@@ -986,6 +987,19 @@</span><br><span> break;</span><br><span> case AST_FRAME_CNG:</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_FRAME_TEXT:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!media) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (media->type != AST_MEDIA_TYPE_TEXT) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Channel %s stream %d is of type '%s', not text!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_name(ast), stream_num, ast_codec_media_type2str(media->type));</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if(session->endpoint->media.red_enabled) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rtp_red_buffer(media->rtp, frame);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (media->write_callback) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = media->write_callback(session, media, frame);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> case AST_FRAME_RTCP:</span><br><span> /* We only support writing out feedback */</span><br><span> if (frame->subclass.integer != AST_RTP_RTCP_PSFB || !media) {</span><br><span>@@ -1008,6 +1022,9 @@</span><br><span> </span><br><span> static int chan_pjsip_write(struct ast_channel *ast, struct ast_frame *frame)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (frame->frametype == AST_FRAME_TEXT && frame->stream_num != -1){</span><br><span style="color: hsl(120, 100%, 40%);">+ return chan_pjsip_write_stream(ast, frame->stream_num, frame);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> return chan_pjsip_write_stream(ast, -1, frame);</span><br><span> }</span><br><span> </span><br><span>diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c</span><br><span>index 7cc4506..21296ed 100644</span><br><span>--- a/channels/pjsip/dialplan_functions.c</span><br><span>+++ b/channels/pjsip/dialplan_functions.c</span><br><span>@@ -576,7 +576,9 @@</span><br><span> media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];</span><br><span> } else if (!strcmp(field, "video")) {</span><br><span> media = session->active_media_state->default_session[AST_MEDIA_TYPE_VIDEO];</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strlen_zero(field) || !strcmp(field, "text")){</span><br><span style="color: hsl(120, 100%, 40%);">+ media = session->active_media_state->default_session[AST_MEDIA_TYPE_TEXT];</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span> ast_log(AST_LOG_WARNING, "Unknown media type field '%s' for 'rtp' information\n", field);</span><br><span> return -1;</span><br><span> }</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index b26aba9..ad54a2d 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -736,6 +736,12 @@</span><br><span> unsigned int tos_video;</span><br><span> /*! Priority for video streams */</span><br><span> unsigned int cos_video;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! DSCP TOS bits for text streams */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int tos_text;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Priority for text streams */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int cos_text;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! DSCP indicate if text stream supports RED */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int red_enabled;</span><br><span> /*! Is g.726 packed in a non standard way */</span><br><span> unsigned int g726_non_standard;</span><br><span> /*! Bind the RTP instance to the media_address */</span><br><span>@@ -746,6 +752,8 @@</span><br><span> unsigned int max_audio_streams;</span><br><span> /*! Maximum number of video streams to offer/accept */</span><br><span> unsigned int max_video_streams;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Maximum number of text streams to offer/accept */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int max_text_streams;</span><br><span> /*! Use BUNDLE */</span><br><span> unsigned int bundle;</span><br><span> /*! Enable webrtc settings and defaults */</span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index c350177..86859a8 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -4762,6 +4762,8 @@</span><br><span> f.frametype = AST_FRAME_TEXT;</span><br><span> f.datalen = body_len;</span><br><span> f.mallocd = AST_MALLOCD_DATA;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_stream *default_streams = ast_channel_get_default_stream(chan, AST_MEDIA_TYPE_TEXT);</span><br><span style="color: hsl(120, 100%, 40%);">+ f.stream_num = ast_stream_get_position(default_streams);</span><br><span> f.data.ptr = ast_strdup(body);</span><br><span> if (f.data.ptr) {</span><br><span> res = ast_channel_tech(chan)->write_text(chan, &f);</span><br><span>diff --git a/main/frame.c b/main/frame.c</span><br><span>index f7a5222..96511f9 100644</span><br><span>--- a/main/frame.c</span><br><span>+++ b/main/frame.c</span><br><span>@@ -305,7 +305,7 @@</span><br><span> #endif</span><br><span> </span><br><span> /* Start with standard stuff */</span><br><span style="color: hsl(0, 100%, 40%);">- len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;</span><br><span style="color: hsl(120, 100%, 40%);">+ len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen + 1;</span><br><span> /* If we have a source, add space for it */</span><br><span> /*</span><br><span> * XXX Watch out here - if we receive a src which is not terminated</span><br><span>@@ -363,13 +363,16 @@</span><br><span> if (out->datalen || f->frametype == AST_FRAME_TEXT) {</span><br><span> out->data.ptr = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;</span><br><span> memcpy(out->data.ptr, f->data.ptr, out->datalen);</span><br><span style="color: hsl(120, 100%, 40%);">+ if(f->frametype == AST_FRAME_TEXT) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ((char*)out->data.ptr)[out->datalen] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> } else {</span><br><span> out->data.uint32 = f->data.uint32;</span><br><span> }</span><br><span> if (srclen > 0) {</span><br><span> /* This may seem a little strange, but it's to avoid a gcc (4.2.4) compiler warning */</span><br><span> char *src;</span><br><span style="color: hsl(0, 100%, 40%);">- out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;</span><br><span style="color: hsl(120, 100%, 40%);">+ out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen + 1;</span><br><span> src = (char *) out->src;</span><br><span> /* Must have space since we allocated for it */</span><br><span> strcpy(src, f->src);</span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index 355b595..4bd887a 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -960,6 +960,8 @@</span><br><span> endpoint->media.tos_audio = value;</span><br><span> } else if (!strcmp(var->name, "tos_video")) {</span><br><span> endpoint->media.tos_video = value;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcmp(var->name, "tos_text")){</span><br><span style="color: hsl(120, 100%, 40%);">+ endpoint->media.tos_text = value;</span><br><span> } else {</span><br><span> /* If we reach this point, someone called the tos_handler when they shouldn't have. */</span><br><span> ast_assert(0);</span><br><span>@@ -988,6 +990,16 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int tos_text_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_asprintf(buf, "%u", endpoint->media.tos_text) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int from_user_handler(const struct aco_option *opt,</span><br><span> struct ast_variable *var, void *obj)</span><br><span> {</span><br><span>@@ -1904,8 +1916,10 @@</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_text", "0", tos_handler, tos_text_to_str, NULL, 0, 0);</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_text", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_text));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "from_user", "", from_user_handler, from_user_to_str, NULL, 0, 0);</span><br><span>@@ -1945,6 +1959,7 @@</span><br><span> 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));</span><br><span> 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));</span><br><span> 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));</span><br><span style="color: hsl(120, 100%, 40%);">+ 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)); </span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox));</span><br><span>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c</span><br><span>index 8d9cece..5f4b556 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -65,6 +65,7 @@</span><br><span> </span><br><span> static const char STR_AUDIO[] = "audio";</span><br><span> static const char STR_VIDEO[] = "video";</span><br><span style="color: hsl(120, 100%, 40%);">+static const char STR_TEXT[] = "text";</span><br><span> </span><br><span> static int send_keepalive(const void *data)</span><br><span> {</span><br><span>@@ -268,7 +269,12 @@</span><br><span> (session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) {</span><br><span> ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio,</span><br><span> session->endpoint->media.cos_audio, "SIP RTP Audio");</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (session_media->type == AST_MEDIA_TYPE_VIDEO) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (session_media->type == AST_MEDIA_TYPE_TEXT) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (session->endpoint->media.tos_text || session->endpoint->media.cos_text) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_text,</span><br><span style="color: hsl(120, 100%, 40%);">+ session->endpoint->media.cos_text, "SIP RTP Text");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (session_media->type == AST_MEDIA_TYPE_VIDEO) {</span><br><span> ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_RECV, session->endpoint->media.webrtc);</span><br><span> ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_SEND, session->endpoint->media.webrtc);</span><br><span> ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_REMB, session->endpoint->media.webrtc);</span><br><span>@@ -340,7 +346,32 @@</span><br><span> struct ast_format *format_parsed;</span><br><span> </span><br><span> ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strncasecmp(name, "RED", 3) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int red_data_pt[10]; /* For T.140 RED */</span><br><span style="color: hsl(120, 100%, 40%);">+ char red_cp_data[30];</span><br><span style="color: hsl(120, 100%, 40%);">+ char *red_cp = red_cp_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *rest = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ int red_num_gen = -1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ strcpy(red_cp,fmt_param);</span><br><span style="color: hsl(120, 100%, 40%);">+ red_cp = strtok_r(red_cp, "/", &rest);</span><br><span style="color: hsl(120, 100%, 40%);">+ while (red_cp && (red_num_gen)++ < AST_RED_MAX_GENERATION) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sscanf(red_cp, "%30u", (unsigned *)&red_data_pt[red_num_gen]);</span><br><span style="color: hsl(120, 100%, 40%);">+ red_cp = strtok_r(NULL, "/", &rest);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if(red_num_gen > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ session->endpoint->media.red_enabled=1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rtp_red_init(session_media->rtp, 300, red_data_pt, red_num_gen);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ session->endpoint->media.red_enabled=0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ session->endpoint->media.red_enabled=0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> format_parsed = ast_format_parse_sdp_fmtp(format, fmt_param);</span><br><span> if (format_parsed) {</span><br><span> ast_rtp_codecs_payload_replace_format(codecs, num, format_parsed);</span><br><span>@@ -2109,6 +2140,17 @@</span><br><span> .stream_destroy = stream_destroy,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief SDP handler for 'text' media stream */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_sip_session_sdp_handler text_sdp_handler = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .id = STR_TEXT,</span><br><span style="color: hsl(120, 100%, 40%);">+ .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+ .create_outgoing_sdp_stream = create_outgoing_sdp_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+ .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+ .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,</span><br><span style="color: hsl(120, 100%, 40%);">+ .stream_stop = stream_stop,</span><br><span style="color: hsl(120, 100%, 40%);">+ .stream_destroy = stream_destroy,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)</span><br><span> {</span><br><span> struct pjsip_transaction *tsx;</span><br><span>@@ -2143,6 +2185,7 @@</span><br><span> ast_sip_session_unregister_supplement(&video_info_supplement);</span><br><span> ast_sip_session_unregister_sdp_handler(&video_sdp_handler, STR_VIDEO);</span><br><span> ast_sip_session_unregister_sdp_handler(&audio_sdp_handler, STR_AUDIO);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_session_unregister_sdp_handler(&text_sdp_handler, STR_TEXT);</span><br><span> </span><br><span> if (sched) {</span><br><span> ast_sched_context_destroy(sched);</span><br><span>@@ -2189,6 +2232,11 @@</span><br><span> goto end;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_sip_session_register_sdp_handler(&text_sdp_handler, STR_TEXT)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_TEXT);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto end;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span> ast_sip_session_register_supplement(&video_info_supplement);</span><br><span> </span><br><span> return AST_MODULE_LOAD_SUCCESS;</span><br><span>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c</span><br><span>index bc01548..8d6454f 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -545,6 +545,7 @@</span><br><span> return (type_streams[type] > 0);</span><br><span> case AST_MEDIA_TYPE_UNKNOWN:</span><br><span> case AST_MEDIA_TYPE_TEXT:</span><br><span style="color: hsl(120, 100%, 40%);">+ return !(type_streams[type] < endpoint->media.max_text_streams);</span><br><span> default:</span><br><span> /* We don't want any unknown or "other" streams on our endpoint,</span><br><span> * so always just say we've reached the limit</span><br><span>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c</span><br><span>index c870fce..5fa7c89 100644</span><br><span>--- a/res/res_rtp_asterisk.c</span><br><span>+++ b/res/res_rtp_asterisk.c</span><br><span>@@ -7128,6 +7128,10 @@</span><br><span> *data++ = 0xEF;</span><br><span> *data++ = 0xBF;</span><br><span> *data = 0xBD;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if(rtp->f.datalen <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {</span><br><span>@@ -8056,9 +8060,12 @@</span><br><span> {</span><br><span> struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data;</span><br><span> struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ if(!rtp || !rtp->red) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return (0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> ao2_lock(instance);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rtp->red->t140.datalen > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rtp && rtp->red && rtp->red->t140.datalen > 0) {</span><br><span> ast_rtp_write(instance, &rtp->red->t140);</span><br><span> }</span><br><span> ao2_unlock(instance);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/13419">change 13419</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/13419"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I8938313e457a6c2253db13609c647aeae77aa5ed </div>
<div style="display:none"> Gerrit-Change-Number: 13419 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Bharat Ramaswamy-Nandakumar <bharat@indigital.net> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>