]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
channel/chan_pjsip: add dialplan function for music on hold
authorTorrey Searle <torrey@voxbone.com>
Thu, 19 Sep 2019 08:56:26 +0000 (10:56 +0200)
committerTorrey Searle <tsearle@gmail.com>
Tue, 1 Oct 2019 07:06:28 +0000 (02:06 -0500)
Add a new dialplan function PJSIP_MOH_PASSTHROUGH that allows
the on-hold behavior to be controlled on a per-call basis

ASTERISK-28542 #close

Change-Id: Iebe905b2ad6dbaa87ab330267147180b05a3c3a8

channels/chan_pjsip.c
channels/pjsip/dialplan_functions.c
channels/pjsip/include/dialplan_functions.h
doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt [new file with mode: 0644]
include/asterisk/res_pjsip_session.h
res/res_pjsip_session.c

index 6853bd3b2e9d6a06fc22c868fc20d7810575c4c8..9e0aa8559137437f452adf74b47854b84a61c2d4 100644 (file)
@@ -1738,7 +1738,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
                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);
-               if (!channel->session->endpoint->moh_passthrough) {
+               if (!channel->session->moh_passthrough) {
                        ast_moh_start(ast, data, NULL);
                } else {
                        if (ast_sip_push_task(channel->session->serializer, remote_send_hold, ao2_bump(channel->session))) {
@@ -1754,7 +1754,7 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
                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);
-               if (!channel->session->endpoint->moh_passthrough) {
+               if (!channel->session->moh_passthrough) {
                        ast_moh_stop(ast);
                } else {
                        if (ast_sip_push_task(channel->session->serializer, remote_send_unhold, ao2_bump(channel->session))) {
@@ -3222,6 +3222,12 @@ static struct ast_custom_function dtmf_mode_function = {
        .write = pjsip_acf_dtmf_mode_write
 };
 
+static struct ast_custom_function moh_passthrough_function = {
+       .name = "PJSIP_MOH_PASSTHROUGH",
+       .read = pjsip_acf_moh_passthrough_read,
+       .write = pjsip_acf_moh_passthrough_write
+};
+
 static struct ast_custom_function session_refresh_function = {
        .name = "PJSIP_SEND_SESSION_REFRESH",
        .write = pjsip_acf_session_refresh_write,
@@ -3274,6 +3280,11 @@ static int load_module(void)
                goto end;
        }
 
+       if (ast_custom_function_register(&moh_passthrough_function)) {
+               ast_log(LOG_WARNING, "Unable to register PJSIP_MOH_PASSTHROUGH 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;
@@ -3319,6 +3330,7 @@ end:
        ast_sip_session_unregister_supplement(&call_pickup_supplement);
        ast_sip_unregister_service(&refer_callback_module);
        ast_custom_function_unregister(&dtmf_mode_function);
+       ast_custom_function_unregister(&moh_passthrough_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);
@@ -3346,6 +3358,7 @@ static int unload_module(void)
        ast_sip_unregister_service(&refer_callback_module);
 
        ast_custom_function_unregister(&dtmf_mode_function);
+       ast_custom_function_unregister(&moh_passthrough_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);
index 2081bad9c8fc1e317865ce11fce178a6506b024b..7cc4506a5e8b4ca0fc0515c08b4ea4cbe73082ff 100644 (file)
                <para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
        </description>
 </function>
+<function name="PJSIP_MOH_PASSTHROUGH" language="en_US">
+       <synopsis>
+               Get or change the on-hold behavior for a SIP call.
+       </synopsis>
+       <syntax>
+       </syntax>
+       <description>
+               <para>When read, returns the current moh passthrough mode</para>
+               <para>When written, sets the current moh passthrough mode</para>
+               <para>If <replaceable>yes</replaceable>, on-hold re-INVITEs are sent. If <replaceable>no</replaceable>, music on hold is generated.</para>
+               <para>This function can be used to override the moh_passthrough configuration option</para>
+       </description>
+</function>
 <function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
        <synopsis>
                W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
@@ -1431,6 +1444,34 @@ int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *da
        return 0;
 }
 
+int pjsip_acf_moh_passthrough_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;
+       }
+
+       if (len < 3) {
+               ast_log(LOG_WARNING, "%s: buffer too small\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);
+       strncpy(buf, AST_YESNO(channel->session->moh_passthrough), len);
+
+       ast_channel_unlock(chan);
+       return 0;
+}
+
 struct refresh_data {
        struct ast_sip_session *session;
        enum ast_sip_session_refresh_method method;
@@ -1574,6 +1615,30 @@ int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *d
        return ast_sip_push_task_wait_serializer(channel->session->serializer, dtmf_mode_refresh_cb, &rdata);
 }
 
+int pjsip_acf_moh_passthrough_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->moh_passthrough = ast_true(value);
+
+       ast_channel_unlock(chan);
+
+       return 0;
+}
+
 static int refresh_write_cb(void *obj)
 {
        struct refresh_data *data = obj;
index a9332a24ca2d34dc197cf34bf31d5678974c5599..d0bf130fe8fccde5ba8ee9a49b56ad8de4f44c0d 100644 (file)
@@ -72,6 +72,31 @@ int pjsip_acf_dtmf_mode_read(struct ast_channel *chan, const char *cmd, char *da
  */
 int pjsip_acf_dtmf_mode_write(struct ast_channel *chan, const char *cmd, char *data, const char *value);
 
+/*!
+ * \brief PJSIP_MOH_PASSTHROUGH 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_moh_passthrough_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+
+/*!
+ * \brief PJSIP_MOH_PASSTHROUGH 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_moh_passthrough_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
diff --git a/doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt b/doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt
new file mode 100644 (file)
index 0000000..cb874a5
--- /dev/null
@@ -0,0 +1,5 @@
+Subject: chan_pjsip
+
+A new dialplan function, PJSIP_MOH_PASSTRHOUGH, has been added to chan_pjsip. This
+allows the behaviour of the moh_passthrough endpoint option to be read or changed
+in the dialplan. This allows control on a per-call basis.
index 6e23f8eab397286e04159488e018937fad7dc531..485cbd31b031647e1a06add2c468efd2b5d82c8b 100644 (file)
@@ -211,6 +211,8 @@ struct ast_sip_session {
        unsigned int defer_end:1;
        /*! Session end (remote hangup) requested while termination deferred */
        unsigned int ended_while_deferred:1;
+       /*! Whether to pass through hold and unhold using re-invites with recvonly and sendrecv */
+       unsigned int moh_passthrough: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. */
index c248670b7d213534d0214049c018cf6baccb39db..a620719623621ac9e7c4151953995829c5b56cfc 100644 (file)
@@ -2306,6 +2306,7 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
        session->inv_session = inv_session;
 
        session->dtmf = endpoint->dtmf;
+       session->moh_passthrough = endpoint->moh_passthrough;
 
        if (ast_sip_session_add_supplements(session)) {
                /* Release the ref held by session->inv_session */