[Asterisk-code-review] res_pjsip: Add the option to send on-hold sdp instead of MOH (...asterisk[13])

Torrey Searle asteriskteam at digium.com
Wed Sep 18 02:33:06 CDT 2019


Torrey Searle has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/12890


Change subject: res_pjsip: Add the option to send on-hold sdp instead of MOH
......................................................................

res_pjsip: Add the option to send on-hold sdp instead of MOH

Add a new endpoint config option to have asterisk generate on
hold re-invites when a channen is put on hold instead of
generating music on hold.  Additionally a new dialplan
function has been added so this behavior can be controlled on
a per-call basis

ASTERISK-28542 #close

Change-Id: Ifb23a8b61e6788647ecb77495f5acf35d88bc113
---
M channels/chan_pjsip.c
M channels/pjsip/dialplan_functions.c
M channels/pjsip/include/dialplan_functions.h
A contrib/ast-db-manage/config/versions/d9d244af5882_send_hold_mode.py
M include/asterisk/res_pjsip.h
M include/asterisk/res_pjsip_session.h
M res/res_pjsip.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_sdp_rtp.c
9 files changed, 160 insertions(+), 5 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/90/12890/1

diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index b0d5fda..4aa21c9 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1493,7 +1493,12 @@
 		device_buf = alloca(device_buf_size);
 		ast_channel_get_device_name(ast, device_buf, device_buf_size);
 		ast_devstate_changed_literal(AST_DEVICE_ONHOLD, 1, device_buf);
-		ast_moh_start(ast, data, NULL);
+		if (channel->session && channel->session->send_hold) {
+			ast_sip_session_refresh(channel->session, NULL, NULL, NULL,
+				AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
+		} else {
+			ast_moh_start(ast, data, NULL);
+		}
 		break;
 	case AST_CONTROL_UNHOLD:
 		chan_pjsip_remove_hold(ast_channel_uniqueid(ast));
@@ -1501,7 +1506,12 @@
 		device_buf = alloca(device_buf_size);
 		ast_channel_get_device_name(ast, device_buf, device_buf_size);
 		ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, 1, device_buf);
-		ast_moh_stop(ast);
+		if (channel->session && channel->session->send_hold) {
+			ast_sip_session_refresh(channel->session, NULL, NULL, NULL,
+				AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
+		} else {
+			ast_moh_stop(ast);
+		}
 		break;
 	case AST_CONTROL_SRCUPDATE:
 		break;
@@ -2810,6 +2820,12 @@
 	.write = pjsip_acf_dtmf_mode_write
 };
 
+static struct ast_custom_function hold_mode_function = {
+	.name = "PJSIP_SEND_HOLD_MODE",
+	.read = pjsip_acf_send_hold_mode_read,
+	.write = pjsip_acf_send_hold_mode_write
+};
+
 static struct ast_custom_function session_refresh_function = {
 	.name = "PJSIP_SEND_SESSION_REFRESH",
 	.write = pjsip_acf_session_refresh_write,
@@ -2864,6 +2880,11 @@
 		goto end;
 	}
 
+	if (ast_custom_function_register(&hold_mode_function)) {
+		ast_log(LOG_WARNING, "Unable to register PJSIP_HOLD_MODE dialplan function\n");
+		goto end;
+	}
+
 	if (ast_custom_function_register(&session_refresh_function)) {
 		ast_log(LOG_WARNING, "Unable to register PJSIP_SEND_SESSION_REFRESH dialplan function\n");
 		goto end;
@@ -2924,6 +2945,7 @@
 	ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
 	ast_sip_session_unregister_supplement(&call_pickup_supplement);
 	ast_custom_function_unregister(&dtmf_mode_function);
+	ast_custom_function_unregister(&hold_mode_function);
 	ast_custom_function_unregister(&media_offer_function);
 	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index 76f351f..e18f134 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -1303,6 +1303,37 @@
 	return 0;
 }
 
+int pjsip_acf_send_hold_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	struct ast_sip_channel_pvt *channel;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	if (len < 3) {
+		ast_log(LOG_WARNING, "%s: buffer too small\n", cmd);
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+
+	channel = ast_channel_tech_pvt(chan);
+
+	strncpy(buf, AST_YESNO(channel->session->send_hold), len);
+
+	ast_channel_unlock(chan);
+	return 0;
+}
+
 struct refresh_data {
 	struct ast_sip_session *session;
 	enum ast_sip_session_refresh_method method;
@@ -1445,6 +1476,30 @@
 	return ast_sip_push_task_wait_serializer(channel->session->serializer, dtmf_mode_refresh_cb, &rdata);
 }
 
+int pjsip_acf_send_hold_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+	struct ast_sip_channel_pvt *channel;
+
+	if (!chan) {
+		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
+		ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	channel = ast_channel_tech_pvt(chan);
+
+	channel->session->send_hold = ast_true(value);
+
+	ast_channel_unlock(chan);
+	return 0;
+}
+
 static int refresh_write_cb(void *obj)
 {
 	struct refresh_data *data = obj;
diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h
index a9332a2..e41e2f1 100644
--- a/channels/pjsip/include/dialplan_functions.h
+++ b/channels/pjsip/include/dialplan_functions.h
@@ -73,6 +73,31 @@
 int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
 
 /*!
+ * \brief PJSIP_SEND_HOLD function read callback
+ * \param chan The channel the function is called on
+ * \param cmd The name of the function
+ * \param data Arguments passed to the function
+ * \param buf Out buffer that should be populated with the data
+ * \param len Size of the buffer
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_send_hold_mode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+
+/*!
+ * \brief PJSIP_SEND_HOLD_MODE function write callback
+ * \param chan The channel the function is called on
+ * \param cmd The name of the function
+ * \param data Arguments passed to the function
+ * \param value Value to be set by the function
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_send_hold_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
+
+/*!
  * \brief PJSIP_MEDIA_OFFER function read callback
  * \param chan The channel the function is called on
  * \param cmd The name of the function
@@ -123,4 +148,4 @@
  */
 int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
 
-#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
\ No newline at end of file
+#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
diff --git a/contrib/ast-db-manage/config/versions/d9d244af5882_send_hold_mode.py b/contrib/ast-db-manage/config/versions/d9d244af5882_send_hold_mode.py
new file mode 100644
index 0000000..9428181
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/d9d244af5882_send_hold_mode.py
@@ -0,0 +1,38 @@
+"""send_hold_mode
+
+Revision ID: d9d244af5882
+Revises: 3a094a18e75b
+Create Date: 2019-09-18 08:47:46.231663
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'd9d244af5882'
+down_revision = '3a094a18e75b'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+AST_BOOL_NAME = 'ast_bool_values'
+# We'll just ignore the n/y and f/t abbreviations as Asterisk does not write
+# those aliases.
+AST_BOOL_VALUES = [ '0', '1',
+                    'off', 'on',
+                    'false', 'true',
+                    'no', 'yes' ]
+
+
+def upgrade():
+    ############################# Enums ##############################
+
+    # yesno_values have already been created, so use postgres enum object
+    # type to get around "already created" issue - works okay with mysql
+    ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
+
+    op.add_column('ps_endpoints', sa.Column('send_hold_mode', ast_bool_values))
+
+def downgrade():
+    if op.get_context().bind.dialect.name == 'mssql':
+        op.drop_constraint('ck_ps_endpoints_send_hold_mode_ast_bool_values', 'ps_endpoints')
+    op.drop_column('ps_endpoints', 'send_hold_mode')
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 5e8dd3a..91ba08e 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -802,6 +802,8 @@
 	unsigned int send_connected_line;
 	/*! Ignore 183 if no SDP is present */
 	unsigned int ignore_183_without_sdp;
+	/*! Send On-Hold Re-Invite intead of music on hold */
+	unsigned int send_hold;
 };
 
 /*! URI parameter for symmetric transport */
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index e2d4fcd..4a7e9e0 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -159,6 +159,8 @@
 	unsigned int defer_end:1;
 	/*! Session end (remote hangup) requested while termination deferred */
 	unsigned int ended_while_deferred:1;
+	/*! Send hold re-invite instead of music on hold */
+	unsigned int send_hold:1;
 	/*! DTMF mode to use with this session, from endpoint but can change */
 	enum ast_sip_dtmf_mode dtmf;
 	/*! Initial incoming INVITE Request-URI.  NULL otherwise. */
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index c41b545..08a1c48 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -104,6 +104,9 @@
 				<configOption name="allow_overlap" default="yes">
 					<synopsis>Enable RFC3578 overlap dialing support.</synopsis>
 				</configOption>
+				<configOption name="send_hold_mode" default="no">
+					<synopsis>If yes, send On-Hold Re-Invites.  If no, generate music on hold</synopsis>
+				</configOption>
 				<configOption name="aors">
 					<synopsis>AoR(s) to be used with the endpoint</synopsis>
 					<description><para>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index b5525be..5b07624 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1904,6 +1904,7 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accept_multiple_sdp_answers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, accept_multiple_sdp_answers));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_hold_reinvite", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_hold));
 
 	if (ast_sip_initialize_sorcery_transport()) {
 		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index 76d47a3..eacf4e4 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -1184,6 +1184,7 @@
 	static const pj_str_t STR_IP4 = { "IP4", 3};
 	static const pj_str_t STR_IP6 = { "IP6", 3};
 	static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
+	static const pj_str_t STR_SENDONLY = { "sendonly", 8 };
 	pjmedia_sdp_media *media;
 	const char *hostip = NULL;
 	struct ast_sockaddr addr;
@@ -1367,9 +1368,15 @@
 		media->attr[media->attr_count++] = attr;
 	}
 
-	/* Add the sendrecv attribute - we purposely don't keep track because pjmedia-sdp will automatically change our offer for us */
 	attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
-	attr->name = STR_SENDRECV;
+
+	if(session->channel && session->send_hold && ast_channel_hold_state(session->channel)) {
+		/* Hint to pjmedia-sdp that we want to initate hold */
+		attr->name = STR_SENDONLY;
+	} else {
+		/* Else add the sendrecv attribute pjmedia-sdp will automatically change our offer for us if needed */
+		attr->name = STR_SENDRECV;
+	}
 	media->attr[media->attr_count++] = attr;
 
 	/* If we've got rtcp-mux enabled, add it unless we received an offer without it */

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

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: Ifb23a8b61e6788647ecb77495f5acf35d88bc113
Gerrit-Change-Number: 12890
Gerrit-PatchSet: 1
Gerrit-Owner: Torrey Searle <tsearle at gmail.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190918/2c6f4e46/attachment-0001.html>


More information about the asterisk-code-review mailing list