diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 6853bd3b2e9d6a06fc22c868fc20d7810575c4c8..9e0aa8559137437f452adf74b47854b84a61c2d4 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -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); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 2081bad9c8fc1e317865ce11fce178a6506b024b..7cc4506a5e8b4ca0fc0515c08b4ea4cbe73082ff 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -80,6 +80,19 @@ <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; diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h index a9332a24ca2d34dc197cf34bf31d5678974c5599..d0bf130fe8fccde5ba8ee9a49b56ad8de4f44c0d 100644 --- a/channels/pjsip/include/dialplan_functions.h +++ b/channels/pjsip/include/dialplan_functions.h @@ -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 index 0000000000000000000000000000000000000000..cb874a580ad969b51fc99b034d6b8749c7037af8 --- /dev/null +++ b/doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt @@ -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. diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 6e23f8eab397286e04159488e018937fad7dc531..485cbd31b031647e1a06add2c468efd2b5d82c8b 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -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. */ diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index c248670b7d213534d0214049c018cf6baccb39db..a620719623621ac9e7c4151953995829c5b56cfc 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -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 */