| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2019, CyCore Systems, Inc | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Seán C McCord <scm@cycoresys.com | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \file
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \brief AudioSocket support for Asterisk | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author Seán C McCord <scm@cycoresys.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>extended</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | #include "errno.h"
 | 
					
						
							|  |  |  | #include <uuid/uuid.h>
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | #include <arpa/inet.h>  /* For byte-order conversion. */
 | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/res_audiosocket.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/uuid.h"
 | 
					
						
							|  |  |  | #include "asterisk/format_cache.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define	MODULE_DESCRIPTION	"AudioSocket support functions for Asterisk"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MAX_CONNECT_TIMEOUT_MSEC 2000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Attempt to complete the audiosocket connection. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param server Url that we are trying to connect to. | 
					
						
							|  |  |  |  * \param addr Address that host was resolved to. | 
					
						
							|  |  |  |  * \param netsockfd File descriptor of socket. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 when connection is succesful. | 
					
						
							|  |  |  |  * \retval 1 when there is an error. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int handle_audiosocket_connection(const char *server, | 
					
						
							|  |  |  | 	const struct ast_sockaddr addr, const int netsockfd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pollfd pfds[1]; | 
					
						
							|  |  |  | 	int res, conresult; | 
					
						
							|  |  |  | 	socklen_t reslen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	reslen = sizeof(conresult); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pfds[0].fd = netsockfd; | 
					
						
							|  |  |  | 	pfds[0].events = POLLOUT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((res = ast_poll(pfds, 1, MAX_CONNECT_TIMEOUT_MSEC)) != 1) { | 
					
						
							|  |  |  | 		if (errno != EINTR) { | 
					
						
							|  |  |  | 			if (!res) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "AudioSocket connection to '%s' timed" | 
					
						
							|  |  |  | 					"out after MAX_CONNECT_TIMEOUT_MSEC (%d) milliseconds.\n", | 
					
						
							|  |  |  | 					server, MAX_CONNECT_TIMEOUT_MSEC); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", server, | 
					
						
							|  |  |  | 					strerror(errno)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 		ast_log(LOG_WARNING, "Connection to '%s' failed with error: %s\n", | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 			ast_sockaddr_stringify(&addr), strerror(errno)); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (conresult) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n", | 
					
						
							|  |  |  | 			ast_sockaddr_stringify(&addr), server, strerror(conresult)); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int ast_audiosocket_connect(const char *server, struct ast_channel *chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int s = -1; | 
					
						
							| 
									
										
										
										
											2020-04-13 18:38:37 +02:00
										 |  |  | 	struct ast_sockaddr *addrs = NULL; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	int num_addrs = 0, i = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (chan && ast_autoservice_start(chan) < 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Failed to start autoservice for channel " | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			"'%s'\n", ast_channel_name(chan)); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		goto end; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(server)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "No AudioSocket server provided\n"); | 
					
						
							|  |  |  | 		goto end; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(num_addrs = ast_sockaddr_resolve(&addrs, server, PARSE_PORT_REQUIRE, | 
					
						
							|  |  |  | 		AST_AF_UNSPEC))) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 		ast_log(LOG_ERROR, "Failed to resolve AudioSocket service using '%s' - " | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 			"requires a valid hostname and port\n", server); | 
					
						
							|  |  |  | 		goto end; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Connect to AudioSocket service */ | 
					
						
							|  |  |  | 	for (i = 0; i < num_addrs; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!ast_sockaddr_port(&addrs[i])) { | 
					
						
							|  |  |  | 			/* If there's no port, other addresses should have the
 | 
					
						
							|  |  |  | 			 * same problem. Stop here. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			ast_log(LOG_ERROR, "No port provided for '%s'\n", | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 				ast_sockaddr_stringify(&addrs[i])); | 
					
						
							|  |  |  | 			s = -1; | 
					
						
							|  |  |  | 			goto end; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM, | 
					
						
							|  |  |  | 			IPPROTO_TCP)) < 0) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			ast_log(LOG_WARNING, "Unable to create socket: '%s'\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-13 15:37:38 +02:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Disable Nagle's algorithm by setting the TCP_NODELAY socket option. | 
					
						
							|  |  |  | 		 * This reduces latency by preventing delays caused by packet buffering. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) < 0) { | 
					
						
							|  |  |  | 			ast_log(LOG_ERROR, "Failed to set TCP_NODELAY on AudioSocket: %s\n", strerror(errno)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (handle_audiosocket_connection(server, addrs[i], s)) { | 
					
						
							|  |  |  | 				close(s); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			ast_log(LOG_ERROR, "Connection to '%s' failed with unexpected error: %s\n", | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 				ast_sockaddr_stringify(&addrs[i]), strerror(errno)); | 
					
						
							|  |  |  | 			close(s); | 
					
						
							|  |  |  | 			s = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | end: | 
					
						
							|  |  |  | 	if (addrs) { | 
					
						
							|  |  |  | 		ast_free(addrs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (chan && ast_autoservice_stop(chan) < 0) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 		ast_log(LOG_WARNING, "Failed to stop autoservice for channel '%s'\n", | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		ast_channel_name(chan)); | 
					
						
							|  |  |  | 		close(s); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (i == num_addrs) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Failed to connect to AudioSocket service\n"); | 
					
						
							|  |  |  | 		close(s); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int ast_audiosocket_init(const int svc, const char *id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uuid_t uu; | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	uint8_t buf[3 + 16]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(id)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "No UUID for AudioSocket\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (uuid_parse(id, uu)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Failed to parse UUID '%s'\n", id); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	buf[0] = AST_AUDIOSOCKET_KIND_UUID; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	buf[1] = 0x00; | 
					
						
							|  |  |  | 	buf[2] = 0x10; | 
					
						
							|  |  |  | 	memcpy(buf + 3, uu, 16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (write(svc, buf, 3 + 16) != 3 + 16) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 		ast_log(LOG_WARNING, "Failed to write data to AudioSocket because: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		ret = -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const int ast_audiosocket_send_frame(const int svc, const struct ast_frame *f) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-02-28 08:47:18 +01:00
										 |  |  | 	int datalen = f->datalen; | 
					
						
							|  |  |  | 	if (f->frametype == AST_FRAME_DTMF) { | 
					
						
							|  |  |  | 		datalen = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-28 08:47:18 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		uint8_t buf[3 + datalen]; | 
					
						
							|  |  |  | 		uint16_t *length = (uint16_t *) &buf[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Audio format is 16-bit, 8kHz signed linear mono for dialplan app,
 | 
					
						
							|  |  |  | 			depends on agreed upon audio codec for channel driver interface. */ | 
					
						
							|  |  |  | 		switch (f->frametype) { | 
					
						
							|  |  |  | 			case AST_FRAME_VOICE: | 
					
						
							|  |  |  | 				buf[0] = AST_AUDIOSOCKET_KIND_AUDIO; | 
					
						
							|  |  |  | 				*length = htons(datalen); | 
					
						
							|  |  |  | 				memcpy(&buf[3], f->data.ptr, datalen); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case AST_FRAME_DTMF: | 
					
						
							|  |  |  | 				buf[0] = AST_AUDIOSOCKET_KIND_DTMF; | 
					
						
							|  |  |  | 				buf[3] = (uint8_t) f->subclass.integer; | 
					
						
							|  |  |  | 				*length = htons(1); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				ast_log(LOG_ERROR, "Unsupported frame type %d for AudioSocket\n", f->frametype); | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-28 08:47:18 +01:00
										 |  |  | 		if (write(svc, buf, 3 + datalen) != 3 + datalen) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Failed to write data to AudioSocket because: %s\n", strerror(errno)); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ast_frame *ast_audiosocket_receive_frame(const int svc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	return ast_audiosocket_receive_frame_with_hangup(svc, NULL); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | struct ast_frame *ast_audiosocket_receive_frame_with_hangup(const int svc, | 
					
						
							|  |  |  | 	int *const hangup) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i = 0, n = 0, ret = 0; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	struct ast_frame f = { | 
					
						
							|  |  |  | 		.frametype = AST_FRAME_VOICE, | 
					
						
							|  |  |  | 		.subclass.format = ast_format_slin, | 
					
						
							|  |  |  | 		.src = "AudioSocket", | 
					
						
							|  |  |  | 		.mallocd = AST_MALLOCD_DATA, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	uint8_t header[3]; | 
					
						
							|  |  |  | 	uint8_t *kind = &header[0]; | 
					
						
							|  |  |  | 	uint16_t *length = (uint16_t *) &header[1]; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	uint8_t *data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	if (hangup) { | 
					
						
							|  |  |  | 		*hangup = 0; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	n = read(svc, &header, 3); | 
					
						
							|  |  |  | 	if (n == -1) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Failed to read header from AudioSocket because: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	if (n == 0 || *kind == AST_AUDIOSOCKET_KIND_HANGUP) { | 
					
						
							|  |  |  | 		/* Socket closure or requested hangup. */ | 
					
						
							|  |  |  | 		if (hangup) { | 
					
						
							|  |  |  | 			*hangup = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (*kind != AST_AUDIOSOCKET_KIND_AUDIO) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Received AudioSocket message other than hangup or audio, refer to protocol specification for valid message types\n"); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	/* Swap endianess of length if needed. */ | 
					
						
							|  |  |  | 	*length = ntohs(*length); | 
					
						
							|  |  |  | 	if (*length < 1) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Invalid message length received from AudioSocket server. \n"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	data = ast_malloc(*length); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	if (!data) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Failed to allocate for data from AudioSocket\n"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 	n = 0; | 
					
						
							|  |  |  | 	i = 0; | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	while (i < *length) { | 
					
						
							|  |  |  | 		n = read(svc, data + i, *length - i); | 
					
						
							|  |  |  | 		if (n == -1) { | 
					
						
							| 
									
										
										
										
											2025-05-13 16:01:32 +02:00
										 |  |  | 			if (errno == EAGAIN || errno == EWOULDBLOCK) { | 
					
						
							|  |  |  | 				int poll_result = ast_wait_for_input(svc, 5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (poll_result == 1) { | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} else if (poll_result == 0) { | 
					
						
							|  |  |  | 					ast_log(LOG_WARNING, "Poll timed out while waiting for data\n"); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					ast_log(LOG_WARNING, "Poll error: %s\n", strerror(errno)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			ast_log(LOG_ERROR, "Failed to read payload from AudioSocket: %s\n", strerror(errno)); | 
					
						
							|  |  |  | 			ret = -1; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (n == 0) { | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 			ast_log(LOG_ERROR, "Insufficient payload read from AudioSocket\n"); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 			ret = -1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		i += n; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		ast_free(data); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f.data.ptr = data; | 
					
						
							| 
									
										
										
										
											2023-04-03 21:36:11 -05:00
										 |  |  | 	f.datalen = *length; | 
					
						
							|  |  |  | 	f.samples = *length / 2; | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* The frame steals data, so it doesn't need to be freed here */ | 
					
						
							|  |  |  | 	return ast_frisolate(&f); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int load_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-31 10:46:28 -07:00
										 |  |  | 	ast_verb(5, "Loading AudioSocket Support module\n"); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int unload_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-31 10:46:28 -07:00
										 |  |  | 	ast_verb(5, "Unloading AudioSocket Support module\n"); | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 16:44:35 -04:00
										 |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "AudioSocket support", | 
					
						
							| 
									
										
										
										
											2019-07-17 20:47:50 -04:00
										 |  |  | 	.support_level = AST_MODULE_SUPPORT_EXTENDED, | 
					
						
							|  |  |  | 	.load = load_module, | 
					
						
							|  |  |  | 	.unload = unload_module, | 
					
						
							|  |  |  | 	.load_pri = AST_MODPRI_CHANNEL_DEPEND, | 
					
						
							|  |  |  | ); |