Asterisk - The Open Source Telephony Project  18.5.0
Macros | Functions | Variables
res_audiosocket.c File Reference

AudioSocket support for Asterisk. More...

#include "asterisk.h"
#include "errno.h"
#include <uuid/uuid.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...
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 44 of file res_audiosocket.c.

Referenced by handle_audiosocket_connection().

◆ MODULE_DESCRIPTION

#define MODULE_DESCRIPTION   "AudioSocket support functions for Asterisk"

Definition at line 42 of file res_audiosocket.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 344 of file res_audiosocket.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 344 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 99 of file res_audiosocket.c.

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().

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

References ast_log, ast_strlen_zero, buf, LOG_ERROR, and LOG_WARNING.

Referenced by audiosocket_call(), and audiosocket_run().

181 {
182  uuid_t uu;
183  int ret = 0;
184  uint8_t buf[3 + 16];
185 
186  if (ast_strlen_zero(id)) {
187  ast_log(LOG_ERROR, "No UUID for AudioSocket\n");
188  return -1;
189  }
190 
191  if (uuid_parse(id, uu)) {
192  ast_log(LOG_ERROR, "Failed to parse UUID '%s'\n", id);
193  return -1;
194  }
195 
196  buf[0] = 0x01;
197  buf[1] = 0x00;
198  buf[2] = 0x10;
199  memcpy(buf + 3, uu, 16);
200 
201  if (write(svc, buf, 3 + 16) != 3 + 16) {
202  ast_log(LOG_WARNING, "Failed to write data to AudioSocket\n");
203  ret = -1;
204  }
205 
206  return ret;
207 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285

◆ 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 231 of file res_audiosocket.c.

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

Referenced by audiosocket_read(), and audiosocket_run().

232 {
233 
234  int i = 0, n = 0, ret = 0, not_audio = 0;
235  struct ast_frame f = {
237  .subclass.format = ast_format_slin,
238  .src = "AudioSocket",
239  .mallocd = AST_MALLOCD_DATA,
240  };
241  uint8_t kind;
242  uint8_t len_high;
243  uint8_t len_low;
244  uint16_t len = 0;
245  uint8_t *data;
246 
247  n = read(svc, &kind, 1);
248  if (n < 0 && errno == EAGAIN) {
249  return &ast_null_frame;
250  }
251  if (n == 0) {
252  return &ast_null_frame;
253  }
254  if (n != 1) {
255  ast_log(LOG_WARNING, "Failed to read type header from AudioSocket\n");
256  return NULL;
257  }
258  if (kind == 0x00) {
259  /* AudioSocket ended by remote */
260  return NULL;
261  }
262  if (kind != 0x10) {
263  /* read but ignore non-audio message */
264  ast_log(LOG_WARNING, "Received non-audio AudioSocket message\n");
265  not_audio = 1;
266  }
267 
268  n = read(svc, &len_high, 1);
269  if (n != 1) {
270  ast_log(LOG_WARNING, "Failed to read data length from AudioSocket\n");
271  return NULL;
272  }
273  len += len_high * 256;
274  n = read(svc, &len_low, 1);
275  if (n != 1) {
276  ast_log(LOG_WARNING, "Failed to read data length from AudioSocket\n");
277  return NULL;
278  }
279  len += len_low;
280 
281  if (len < 1) {
282  return &ast_null_frame;
283  }
284 
285  data = ast_malloc(len);
286  if (!data) {
287  ast_log(LOG_ERROR, "Failed to allocate for data from AudioSocket\n");
288  return NULL;
289  }
290 
291  ret = 0;
292  n = 0;
293  i = 0;
294  while (i < len) {
295  n = read(svc, data + i, len - i);
296  if (n < 0) {
297  ast_log(LOG_ERROR, "Failed to read data from AudioSocket\n");
298  ret = n;
299  break;
300  }
301  if (n == 0) {
302  ast_log(LOG_ERROR, "Insufficient data read from AudioSocket\n");
303  ret = -1;
304  break;
305  }
306  i += n;
307  }
308 
309  if (ret != 0) {
310  ast_free(data);
311  return NULL;
312  }
313 
314  if (not_audio) {
315  ast_free(data);
316  return &ast_null_frame;
317  }
318 
319  f.data.ptr = data;
320  f.datalen = len;
321  f.samples = len / 2;
322 
323  /* The frame steals data, so it doesn't need to be freed here */
324  return ast_frisolate(&f);
325 }
#define LOG_WARNING
Definition: logger.h:274
#define AST_MALLOCD_DATA
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
#define ast_free(a)
Definition: astmm.h:182
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Data structure associated with a single frame of data.
union ast_frame::@263 data
enum ast_frame_type frametype
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ 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 209 of file res_audiosocket.c.

References ast_log, buf, ast_frame::data, ast_frame::datalen, LOG_WARNING, and ast_frame::ptr.

Referenced by audiosocket_run(), and audiosocket_write().

210 {
211  int ret = 0;
212  uint8_t kind = 0x10; /* always 16-bit, 8kHz signed linear mono, for now */
213  uint8_t *p;
214  uint8_t buf[3 + f->datalen];
215 
216  p = buf;
217 
218  *(p++) = kind;
219  *(p++) = f->datalen >> 8;
220  *(p++) = f->datalen & 0xff;
221  memcpy(p, f->data.ptr, f->datalen);
222 
223  if (write(svc, buf, 3 + f->datalen) != 3 + f->datalen) {
224  ast_log(LOG_WARNING, "Failed to write data to AudioSocket\n");
225  ret = -1;
226  }
227 
228  return ret;
229 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
union ast_frame::@263 data

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 344 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 57 of file res_audiosocket.c.

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

Referenced by ast_audiosocket_connect().

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 327 of file res_audiosocket.c.

References AST_MODULE_LOAD_SUCCESS, and ast_verb.

Referenced by unload_module().

328 {
329  ast_verb(1, "Loading AudioSocket Support module\n");
331 }
#define ast_verb(level,...)
Definition: logger.h:463

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 333 of file res_audiosocket.c.

References AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DEPEND, AST_MODULE_INFO(), AST_MODULE_LOAD_SUCCESS, AST_MODULE_SUPPORT_EXTENDED, ast_verb, ASTERISK_GPL_KEY, and load_module().

334 {
335  ast_verb(1, "Unloading AudioSocket Support module\n");
337 }
#define ast_verb(level,...)
Definition: logger.h:463

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static

Definition at line 344 of file res_audiosocket.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 344 of file res_audiosocket.c.