mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	channel/chan_pjsip: add dialplan function for music on hold
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
This commit is contained in:
		
				
					committed by
					
						 Torrey Searle
						Torrey Searle
					
				
			
			
				
	
			
			
			
						parent
						
							1b6513c5dd
						
					
				
				
					commit
					b43cdc7f1e
				
			| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										5
									
								
								doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								doc/CHANGES-staging/chan_pjsip_moh_passthrough.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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. | ||||
| @@ -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. */ | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user