Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Macros | Functions | Variables
res_audiosocket.c File Reference

AudioSocket support for Asterisk. More...

#include "asterisk.h"
#include "errno.h"
#include <uuid/uuid.h>
#include <arpa/inet.h>
#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"
Include dependency graph for res_audiosocket.c:

Go to the source code of this file.

Macros

#define MAX_CONNECT_TIMEOUT_MSEC   2000
 
#define MODULE_DESCRIPTION   "AudioSocket support functions for Asterisk"
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
const int ast_audiosocket_connect (const char *server, struct ast_channel *chan)
 Send the initial message to an AudioSocket server. More...
 
const int ast_audiosocket_init (const int svc, const char *id)
 Send the initial message to an AudioSocket server. More...
 
struct ast_frameast_audiosocket_receive_frame (const int svc)
 Receive an Asterisk frame from an AudioSocket server. More...
 
struct ast_frameast_audiosocket_receive_frame_with_hangup (const int svc, int *const hangup)
 Receive an Asterisk frame from an AudioSocket server. More...
 
const int ast_audiosocket_send_frame (const int svc, const struct ast_frame *f)
 Send an Asterisk audio frame to an AudioSocket server. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int handle_audiosocket_connection (const char *server, const struct ast_sockaddr addr, const int netsockfd)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AudioSocket support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 

Detailed Description

AudioSocket support for Asterisk.

Author
Seán C McCord scm@c.nosp@m.ycor.nosp@m.esys..nosp@m.com

Definition in file res_audiosocket.c.

Macro Definition Documentation

◆ MAX_CONNECT_TIMEOUT_MSEC

#define MAX_CONNECT_TIMEOUT_MSEC   2000

Definition at line 45 of file res_audiosocket.c.

◆ MODULE_DESCRIPTION

#define MODULE_DESCRIPTION   "AudioSocket support functions for Asterisk"

Definition at line 43 of file res_audiosocket.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 352 of file res_audiosocket.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 352 of file res_audiosocket.c.

◆ ast_audiosocket_connect()

const int ast_audiosocket_connect ( const char *  server,
struct ast_channel chan 
)

Send the initial message to an AudioSocket server.

Parameters
serverThe server address, including port.
chanAn optional channel which will be put into autoservice during the connection period. If there is no channel to be autoserviced, pass NULL instead.
Return values
socketfile descriptor for AudioSocket on success
-1on error

Definition at line 100 of file res_audiosocket.c.

101{
102 int s = -1;
103 struct ast_sockaddr *addrs = NULL;
104 int num_addrs = 0, i = 0;
105
106 if (chan && ast_autoservice_start(chan) < 0) {
107 ast_log(LOG_WARNING, "Failed to start autoservice for channel "
108 "'%s'\n", ast_channel_name(chan));
109 goto end;
110 }
111
112 if (ast_strlen_zero(server)) {
113 ast_log(LOG_ERROR, "No AudioSocket server provided\n");
114 goto end;
115 }
116
117 if (!(num_addrs = ast_sockaddr_resolve(&addrs, server, PARSE_PORT_REQUIRE,
118 AST_AF_UNSPEC))) {
119 ast_log(LOG_ERROR, "Failed to resolve AudioSocket service using '%s' - "
120 "requires a valid hostname and port\n", server);
121 goto end;
122 }
123
124 /* Connect to AudioSocket service */
125 for (i = 0; i < num_addrs; i++) {
126
127 if (!ast_sockaddr_port(&addrs[i])) {
128 /* If there's no port, other addresses should have the
129 * same problem. Stop here.
130 */
131 ast_log(LOG_ERROR, "No port provided for '%s'\n",
132 ast_sockaddr_stringify(&addrs[i]));
133 s = -1;
134 goto end;
135 }
136
137 if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM,
138 IPPROTO_TCP)) < 0) {
139 ast_log(LOG_WARNING, "Unable to create socket: '%s'\n", strerror(errno));
140 continue;
141 }
142
143 if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
144
145 if (handle_audiosocket_connection(server, addrs[i], s)) {
146 close(s);
147 continue;
148 }
149
150 } else {
151 ast_log(LOG_ERROR, "Connection to '%s' failed with unexpected error: %s\n",
152 ast_sockaddr_stringify(&addrs[i]), strerror(errno));
153 close(s);
154 s = -1;
155 }
156
157 break;
158 }
159
160end:
161 if (addrs) {
162 ast_free(addrs);
163 }
164
165 if (chan && ast_autoservice_stop(chan) < 0) {
166 ast_log(LOG_WARNING, "Failed to stop autoservice for channel '%s'\n",
167 ast_channel_name(chan));
168 close(s);
169 return -1;
170 }
171
172 if (i == num_addrs) {
173 ast_log(LOG_ERROR, "Failed to connect to AudioSocket service\n");
174 close(s);
175 return -1;
176 }
177
178 return s;
179}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
char * end
Definition: eagi_proxy.c:73
@ PARSE_PORT_REQUIRE
#define LOG_ERROR
#define LOG_WARNING
int errno
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:595
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition: netsock2.c:280
@ AST_AF_UNSPEC
Definition: netsock2.h:54
static int handle_audiosocket_connection(const char *server, const struct ast_sockaddr addr, const int netsockfd)
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Socket address structure.
Definition: netsock2.h:97
struct sockaddr_storage ss
Definition: netsock2.h:98
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition: utils.h:1073

References AST_AF_UNSPEC, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_connect(), ast_free, ast_log, ast_sockaddr_port, ast_sockaddr_resolve(), ast_sockaddr_stringify(), ast_socket_nonblock, ast_strlen_zero(), end, errno, handle_audiosocket_connection(), LOG_ERROR, LOG_WARNING, NULL, PARSE_PORT_REQUIRE, and ast_sockaddr::ss.

Referenced by audiosocket_exec(), and audiosocket_request().

◆ ast_audiosocket_init()

const int ast_audiosocket_init ( const int  svc,
const char *  id 
)

Send the initial message to an AudioSocket server.

Parameters
svcThe file descriptor of the network socket to the AudioSocket server.
idThe UUID to send to the AudioSocket server to uniquely identify this connection.
Return values
0on success
-1on error

Definition at line 181 of file res_audiosocket.c.

182{
183 uuid_t uu;
184 int ret = 0;
185 uint8_t buf[3 + 16];
186
187 if (ast_strlen_zero(id)) {
188 ast_log(LOG_ERROR, "No UUID for AudioSocket\n");
189 return -1;
190 }
191
192 if (uuid_parse(id, uu)) {
193 ast_log(LOG_ERROR, "Failed to parse UUID '%s'\n", id);
194 return -1;
195 }
196
198 buf[1] = 0x00;
199 buf[2] = 0x10;
200 memcpy(buf + 3, uu, 16);
201
202 if (write(svc, buf, 3 + 16) != 3 + 16) {
203 ast_log(LOG_WARNING, "Failed to write data to AudioSocket because: %s\n", strerror(errno));
204 ret = -1;
205 }
206
207 return ret;
208}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
@ AST_AUDIOSOCKET_KIND_UUID
Message contains the connection's UUID, direction: Received only.

References AST_AUDIOSOCKET_KIND_UUID, ast_log, ast_strlen_zero(), buf, errno, LOG_ERROR, and LOG_WARNING.

Referenced by audiosocket_call(), and audiosocket_run().

◆ ast_audiosocket_receive_frame()

struct ast_frame * ast_audiosocket_receive_frame ( const int  svc)

Receive an Asterisk frame from an AudioSocket server.

This returned object is a pointer to an Asterisk frame which must be manually freed by the caller.

Parameters
svcThe file descriptor of the network socket to the AudioSocket server.
Return values
Aast_frame on success
NULLon error

Definition at line 248 of file res_audiosocket.c.

249{
251}
struct ast_frame * ast_audiosocket_receive_frame_with_hangup(const int svc, int *const hangup)
Receive an Asterisk frame from an AudioSocket server.

References ast_audiosocket_receive_frame_with_hangup(), and NULL.

◆ ast_audiosocket_receive_frame_with_hangup()

struct ast_frame * ast_audiosocket_receive_frame_with_hangup ( const int  svc,
int *const  hangup 
)

Receive an Asterisk frame from an AudioSocket server.

This returned object is a pointer to an Asterisk frame which must be manually freed by the caller.

Parameters
svcThe file descriptor of the network socket to the AudioSocket server.
hangupWill be true if the AudioSocket server requested the channel be hung up, otherwise false. Used as an out-parameter only, pass NULL if not needed. The function return value will always be NULL when true.
Return values
Aast_frame on success
NULLon error or when the hungup parameter is true.

Definition at line 253 of file res_audiosocket.c.

255{
256 int i = 0, n = 0, ret = 0;
257 struct ast_frame f = {
259 .subclass.format = ast_format_slin,
260 .src = "AudioSocket",
261 .mallocd = AST_MALLOCD_DATA,
262 };
263 uint8_t header[3];
264 uint8_t *kind = &header[0];
265 uint16_t *length = (uint16_t *) &header[1];
266 uint8_t *data;
267
268 if (hangup) {
269 *hangup = 0;
270 }
271
272 n = read(svc, &header, 3);
273 if (n == -1) {
274 ast_log(LOG_WARNING, "Failed to read header from AudioSocket because: %s\n", strerror(errno));
275 return NULL;
276 }
277
278 if (n == 0 || *kind == AST_AUDIOSOCKET_KIND_HANGUP) {
279 /* Socket closure or requested hangup. */
280 if (hangup) {
281 *hangup = 1;
282 }
283 return NULL;
284 }
285
286 if (*kind != AST_AUDIOSOCKET_KIND_AUDIO) {
287 ast_log(LOG_ERROR, "Received AudioSocket message other than hangup or audio, refer to protocol specification for valid message types\n");
288 return NULL;
289 }
290
291 /* Swap endianess of length if needed. */
292 *length = ntohs(*length);
293 if (*length < 1) {
294 ast_log(LOG_ERROR, "Invalid message length received from AudioSocket server. \n");
295 return NULL;
296 }
297
298 data = ast_malloc(*length);
299 if (!data) {
300 ast_log(LOG_ERROR, "Failed to allocate for data from AudioSocket\n");
301 return NULL;
302 }
303
304 ret = 0;
305 n = 0;
306 i = 0;
307 while (i < *length) {
308 n = read(svc, data + i, *length - i);
309 if (n == -1) {
310 ast_log(LOG_ERROR, "Failed to read payload from AudioSocket: %s\n", strerror(errno));
311 ret = -1;
312 break;
313 }
314 if (n == 0) {
315 ast_log(LOG_ERROR, "Insufficient payload read from AudioSocket\n");
316 ret = -1;
317 break;
318 }
319 i += n;
320 }
321
322 if (ret != 0) {
323 ast_free(data);
324 return NULL;
325 }
326
327 f.data.ptr = data;
328 f.datalen = *length;
329 f.samples = *length / 2;
330
331 /* The frame steals data, so it doesn't need to be freed here */
332 return ast_frisolate(&f);
333}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
static int hangup(void *data)
Definition: chan_pjsip.c:2520
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define AST_MALLOCD_DATA
@ AST_FRAME_VOICE
@ AST_AUDIOSOCKET_KIND_AUDIO
Messages contains audio data, direction: Sent and received.
@ AST_AUDIOSOCKET_KIND_HANGUP
Message indicates the channel should be hung up, direction: Sent only.
Data structure associated with a single frame of data.
union ast_frame::@228 data
enum ast_frame_type frametype

References AST_AUDIOSOCKET_KIND_AUDIO, AST_AUDIOSOCKET_KIND_HANGUP, ast_format_slin, AST_FRAME_VOICE, ast_free, ast_frisolate, ast_log, ast_malloc, AST_MALLOCD_DATA, ast_frame::data, ast_frame::datalen, errno, ast_frame::frametype, hangup(), LOG_ERROR, LOG_WARNING, NULL, ast_frame::ptr, and ast_frame::samples.

Referenced by ast_audiosocket_receive_frame(), audiosocket_read(), and audiosocket_run().

◆ ast_audiosocket_send_frame()

const int ast_audiosocket_send_frame ( const int  svc,
const struct ast_frame f 
)

Send an Asterisk audio frame to an AudioSocket server.

Parameters
svcThe file descriptor of the network socket to the AudioSocket server.
fThe Asterisk audio frame to send.
Return values
0on success
-1on error

Definition at line 210 of file res_audiosocket.c.

211{
212 int datalen = f->datalen;
213 if (f->frametype == AST_FRAME_DTMF) {
214 datalen = 1;
215 }
216
217 {
218 uint8_t buf[3 + datalen];
219 uint16_t *length = (uint16_t *) &buf[1];
220
221 /* Audio format is 16-bit, 8kHz signed linear mono for dialplan app,
222 depends on agreed upon audio codec for channel driver interface. */
223 switch (f->frametype) {
224 case AST_FRAME_VOICE:
226 *length = htons(datalen);
227 memcpy(&buf[3], f->data.ptr, datalen);
228 break;
229 case AST_FRAME_DTMF:
231 buf[3] = (uint8_t) f->subclass.integer;
232 *length = htons(1);
233 break;
234 default:
235 ast_log(LOG_ERROR, "Unsupported frame type %d for AudioSocket\n", f->frametype);
236 return -1;
237 }
238
239 if (write(svc, buf, 3 + datalen) != 3 + datalen) {
240 ast_log(LOG_WARNING, "Failed to write data to AudioSocket because: %s\n", strerror(errno));
241 return -1;
242 }
243 }
244
245 return 0;
246}
#define AST_FRAME_DTMF
@ AST_AUDIOSOCKET_KIND_DTMF
Message contains a DTMF digit, direction: Received only.
struct ast_frame_subclass subclass

References AST_AUDIOSOCKET_KIND_AUDIO, AST_AUDIOSOCKET_KIND_DTMF, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_log, buf, ast_frame::data, ast_frame::datalen, errno, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, ast_frame::ptr, and ast_frame::subclass.

Referenced by audiosocket_run(), audiosocket_send_dtmf(), and audiosocket_write().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 352 of file res_audiosocket.c.

◆ handle_audiosocket_connection()

static int handle_audiosocket_connection ( const char *  server,
const struct ast_sockaddr  addr,
const int  netsockfd 
)
static

Definition at line 58 of file res_audiosocket.c.

60{
61 struct pollfd pfds[1];
62 int res, conresult;
63 socklen_t reslen;
64
65 reslen = sizeof(conresult);
66
67 pfds[0].fd = netsockfd;
68 pfds[0].events = POLLOUT;
69
70 while ((res = ast_poll(pfds, 1, MAX_CONNECT_TIMEOUT_MSEC)) != 1) {
71 if (errno != EINTR) {
72 if (!res) {
73 ast_log(LOG_WARNING, "AudioSocket connection to '%s' timed"
74 "out after MAX_CONNECT_TIMEOUT_MSEC (%d) milliseconds.\n",
76 } else {
77 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", server,
78 strerror(errno));
79 }
80
81 return -1;
82 }
83 }
84
85 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
86 ast_log(LOG_WARNING, "Connection to '%s' failed with error: %s\n",
87 ast_sockaddr_stringify(&addr), strerror(errno));
88 return -1;
89 }
90
91 if (conresult) {
92 ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n",
93 ast_sockaddr_stringify(&addr), server, strerror(conresult));
94 return -1;
95 }
96
97 return 0;
98}
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
#define MAX_CONNECT_TIMEOUT_MSEC

References ast_log, ast_poll, ast_sockaddr_stringify(), errno, LOG_WARNING, and MAX_CONNECT_TIMEOUT_MSEC.

Referenced by ast_audiosocket_connect().

◆ load_module()

static int load_module ( void  )
static

Definition at line 335 of file res_audiosocket.c.

336{
337 ast_verb(5, "Loading AudioSocket Support module\n");
339}
#define ast_verb(level,...)
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70

References AST_MODULE_LOAD_SUCCESS, and ast_verb.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 341 of file res_audiosocket.c.

342{
343 ast_verb(5, "Unloading AudioSocket Support module\n");
345}

References AST_MODULE_LOAD_SUCCESS, and ast_verb.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "AudioSocket support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static

Definition at line 352 of file res_audiosocket.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 352 of file res_audiosocket.c.