Asterisk - The Open Source Telephony Project  GIT-master-a1fa8df
chan_alsa.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * By Matthew Fredrickson <creslin@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  * \brief ALSA sound card channel driver
21  *
22  * \author Matthew Fredrickson <creslin@digium.com>
23  *
24  * \ingroup channel_drivers
25  */
26 
27 /*! \li \ref chan_alsa.c uses the configuration file \ref alsa.conf
28  * \addtogroup configuration_file
29  */
30 
31 /*! \page alsa.conf alsa.conf
32  * \verbinclude alsa.conf.sample
33  */
34 
35 /*** MODULEINFO
36  <depend>alsa</depend>
37  <defaultenabled>no</defaultenabled>
38  <support_level>deprecated</support_level>
39  <replacement>chan_console</replacement>
40  <deprecated_in>19</deprecated_in>
41  <removed_in>21</removed_in>
42  ***/
43 
44 #include "asterisk.h"
45 
46 #include <errno.h>
47 #ifndef ESTRPIPE
48 #define ESTRPIPE EPIPE
49 #endif
50 #include <fcntl.h>
51 #include <sys/ioctl.h>
52 #include <sys/time.h>
53 
54 #define ALSA_PCM_NEW_HW_PARAMS_API
55 #define ALSA_PCM_NEW_SW_PARAMS_API
56 #include <alsa/asoundlib.h>
57 
58 #include "asterisk/frame.h"
59 #include "asterisk/channel.h"
60 #include "asterisk/module.h"
61 #include "asterisk/pbx.h"
62 #include "asterisk/config.h"
63 #include "asterisk/cli.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/causes.h"
66 #include "asterisk/endian.h"
67 #include "asterisk/stringfields.h"
68 #include "asterisk/abstract_jb.h"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/poll-compat.h"
72 #include "asterisk/format_cache.h"
73 
74 /*! Global jitterbuffer configuration - by default, jb is disabled
75  * \note Values shown here match the defaults shown in alsa.conf.sample */
76 static struct ast_jb_conf default_jbconf = {
77  .flags = 0,
78  .max_size = 200,
79  .resync_threshold = 1000,
80  .impl = "fixed",
81  .target_extra = 40,
82 };
83 static struct ast_jb_conf global_jbconf;
84 
85 #define DEBUG 0
86 /* Which device to use */
87 #define ALSA_INDEV "default"
88 #define ALSA_OUTDEV "default"
89 #define DESIRED_RATE 8000
90 
91 /* Lets use 160 sample frames, just like GSM. */
92 #define FRAME_SIZE 160
93 #define PERIOD_FRAMES 80 /* 80 Frames, at 2 bytes each */
94 
95 /* When you set the frame size, you have to come up with
96  the right buffer format as well. */
97 /* 5 64-byte frames = one frame */
98 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
99 
100 /* Don't switch between read/write modes faster than every 300 ms */
101 #define MIN_SWITCH_TIME 600
102 
103 #if __BYTE_ORDER == __LITTLE_ENDIAN
104 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
105 #else
106 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
107 #endif
108 
109 static char indevname[50] = ALSA_INDEV;
110 static char outdevname[50] = ALSA_OUTDEV;
111 
112 static int silencesuppression = 0;
113 static int silencethreshold = 1000;
114 
116 
117 static const char tdesc[] = "ALSA Console Channel Driver";
118 static const char config[] = "alsa.conf";
119 
120 static char context[AST_MAX_CONTEXT] = "default";
121 static char language[MAX_LANGUAGE] = "";
122 static char exten[AST_MAX_EXTENSION] = "s";
124 
125 static int hookstate = 0;
126 
127 static struct chan_alsa_pvt {
128  /* We only have one ALSA structure -- near sighted perhaps, but it
129  keeps this driver as simple as possible -- as it should be. */
133  snd_pcm_t *icard, *ocard;
134 
135 } alsa;
136 
137 /* Number of buffers... Each is FRAMESIZE/8 ms long. For example
138  with 160 sample frames, and a buffer size of 3, we have a 60ms buffer,
139  usually plenty. */
140 
141 #define MAX_BUFFER_SIZE 100
142 
143 /* File descriptors for sound device */
144 static int readdev = -1;
145 static int writedev = -1;
146 
147 static int autoanswer = 1;
148 static int mute = 0;
149 static int noaudiocapture = 0;
150 
151 static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
152 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
153 static int alsa_text(struct ast_channel *c, const char *text);
154 static int alsa_hangup(struct ast_channel *c);
155 static int alsa_answer(struct ast_channel *c);
156 static struct ast_frame *alsa_read(struct ast_channel *chan);
157 static int alsa_call(struct ast_channel *c, const char *dest, int timeout);
158 static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
159 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
160 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
161 
162 static struct ast_channel_tech alsa_tech = {
163  .type = "Console",
164  .description = tdesc,
165  .requester = alsa_request,
166  .send_digit_end = alsa_digit,
167  .send_text = alsa_text,
168  .hangup = alsa_hangup,
169  .answer = alsa_answer,
170  .read = alsa_read,
171  .call = alsa_call,
172  .write = alsa_write,
173  .indicate = alsa_indicate,
174  .fixup = alsa_fixup,
175 };
176 
177 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
178 {
179  int err;
180  int direction;
181  snd_pcm_t *handle = NULL;
182  snd_pcm_hw_params_t *hwparams = NULL;
183  snd_pcm_sw_params_t *swparams = NULL;
184  struct pollfd pfd;
185  snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
186  snd_pcm_uframes_t buffer_size = 0;
187  unsigned int rate = DESIRED_RATE;
188  snd_pcm_uframes_t start_threshold, stop_threshold;
189 
190  err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
191  if (err < 0) {
192  ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
193  return NULL;
194  } else {
195  ast_debug(1, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
196  }
197 
198  hwparams = ast_alloca(snd_pcm_hw_params_sizeof());
199  memset(hwparams, 0, snd_pcm_hw_params_sizeof());
200  snd_pcm_hw_params_any(handle, hwparams);
201 
202  err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
203  if (err < 0)
204  ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
205 
206  err = snd_pcm_hw_params_set_format(handle, hwparams, format);
207  if (err < 0)
208  ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
209 
210  err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
211  if (err < 0)
212  ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
213 
214  direction = 0;
215  err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
216  if (rate != DESIRED_RATE)
217  ast_log(LOG_WARNING, "Rate not correct, requested %d, got %u\n", DESIRED_RATE, rate);
218 
219  direction = 0;
220  err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
221  if (err < 0)
222  ast_log(LOG_ERROR, "period_size(%lu frames) is bad: %s\n", period_size, snd_strerror(err));
223  else {
224  ast_debug(1, "Period size is %d\n", err);
225  }
226 
227  buffer_size = 4096 * 2; /* period_size * 16; */
228  err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
229  if (err < 0)
230  ast_log(LOG_WARNING, "Problem setting buffer size of %lu: %s\n", buffer_size, snd_strerror(err));
231  else {
232  ast_debug(1, "Buffer size is set to %d frames\n", err);
233  }
234 
235  err = snd_pcm_hw_params(handle, hwparams);
236  if (err < 0)
237  ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
238 
239  swparams = ast_alloca(snd_pcm_sw_params_sizeof());
240  memset(swparams, 0, snd_pcm_sw_params_sizeof());
241  snd_pcm_sw_params_current(handle, swparams);
242 
243  if (stream == SND_PCM_STREAM_PLAYBACK)
244  start_threshold = period_size;
245  else
246  start_threshold = 1;
247 
248  err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
249  if (err < 0)
250  ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
251 
252  if (stream == SND_PCM_STREAM_PLAYBACK)
253  stop_threshold = buffer_size;
254  else
255  stop_threshold = buffer_size;
256 
257  err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
258  if (err < 0)
259  ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
260 
261  err = snd_pcm_sw_params(handle, swparams);
262  if (err < 0)
263  ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
264 
265  err = snd_pcm_poll_descriptors_count(handle);
266  if (err <= 0)
267  ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
268  if (err != 1) {
269  ast_debug(1, "Can't handle more than one device\n");
270  }
271 
272  snd_pcm_poll_descriptors(handle, &pfd, err);
273  ast_debug(1, "Acquired fd %d from the poll descriptor\n", pfd.fd);
274 
275  if (stream == SND_PCM_STREAM_CAPTURE)
276  readdev = pfd.fd;
277  else
278  writedev = pfd.fd;
279 
280  return handle;
281 }
282 
283 static int soundcard_init(void)
284 {
285  if (!noaudiocapture) {
286  alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
287  if (!alsa.icard) {
288  ast_log(LOG_ERROR, "Problem opening alsa capture device\n");
289  return -1;
290  }
291  }
292 
293  alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
294 
295  if (!alsa.ocard) {
296  ast_log(LOG_ERROR, "Problem opening ALSA playback device\n");
297  return -1;
298  }
299 
300  return writedev;
301 }
302 
303 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
304 {
306  ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
307  digit, duration);
309 
310  return 0;
311 }
312 
313 static int alsa_text(struct ast_channel *c, const char *text)
314 {
316  ast_verbose(" << Console Received text %s >> \n", text);
318 
319  return 0;
320 }
321 
322 static void grab_owner(void)
323 {
324  while (alsa.owner && ast_channel_trylock(alsa.owner)) {
326  }
327 }
328 
329 static int alsa_call(struct ast_channel *c, const char *dest, int timeout)
330 {
331  struct ast_frame f = { AST_FRAME_CONTROL };
332 
334  ast_verbose(" << Call placed to '%s' on console >> \n", dest);
335  if (autoanswer) {
336  ast_verbose(" << Auto-answered >> \n");
337  if (mute) {
338  ast_verbose( " << Muted >> \n" );
339  }
340  grab_owner();
341  if (alsa.owner) {
345  }
346  } else {
347  ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
348  grab_owner();
349  if (alsa.owner) {
354  }
355  }
356  if (!noaudiocapture) {
357  snd_pcm_prepare(alsa.icard);
358  snd_pcm_start(alsa.icard);
359  }
361 
362  return 0;
363 }
364 
365 static int alsa_answer(struct ast_channel *c)
366 {
368  ast_verbose(" << Console call has been answered >> \n");
370  if (!noaudiocapture) {
371  snd_pcm_prepare(alsa.icard);
372  snd_pcm_start(alsa.icard);
373  }
375 
376  return 0;
377 }
378 
379 static int alsa_hangup(struct ast_channel *c)
380 {
383  alsa.owner = NULL;
384  ast_verbose(" << Hangup on console >> \n");
386  hookstate = 0;
387  if (!noaudiocapture) {
388  snd_pcm_drop(alsa.icard);
389  }
391 
392  return 0;
393 }
394 
395 static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
396 {
397  static char sizbuf[8000];
398  static int sizpos = 0;
399  int len = sizpos;
400  int res = 0;
401  /* size_t frames = 0; */
402  snd_pcm_state_t state;
403 
405 
406  /* We have to digest the frame in 160-byte portions */
407  if (f->datalen > sizeof(sizbuf) - sizpos) {
408  ast_log(LOG_WARNING, "Frame too large\n");
409  res = -1;
410  } else {
411  memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
412  len += f->datalen;
413  state = snd_pcm_state(alsa.ocard);
414  if (state == SND_PCM_STATE_XRUN)
415  snd_pcm_prepare(alsa.ocard);
416  while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
417  usleep(1);
418  }
419  if (res == -EPIPE) {
420 #if DEBUG
421  ast_debug(1, "XRUN write\n");
422 #endif
423  snd_pcm_prepare(alsa.ocard);
424  while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
425  usleep(1);
426  }
427  if (res != len / 2) {
428  ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
429  res = -1;
430  } else if (res < 0) {
431  ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
432  res = -1;
433  }
434  } else {
435  if (res == -ESTRPIPE)
436  ast_log(LOG_ERROR, "You've got some big problems\n");
437  else if (res < 0)
438  ast_log(LOG_NOTICE, "Error %d on write\n", res);
439  }
440  }
442 
443  return res >= 0 ? 0 : res;
444 }
445 
446 
447 static struct ast_frame *alsa_read(struct ast_channel *chan)
448 {
449  static struct ast_frame f;
450  static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
451  short *buf;
452  static int readpos = 0;
453  static int left = FRAME_SIZE;
454  snd_pcm_state_t state;
455  int r = 0;
456 
459  f.subclass.integer = 0;
460  f.samples = 0;
461  f.datalen = 0;
462  f.data.ptr = NULL;
463  f.offset = 0;
464  f.src = "Console";
465  f.mallocd = 0;
466  f.delivery.tv_sec = 0;
467  f.delivery.tv_usec = 0;
468 
469  if (noaudiocapture) {
470  /* Return null frame to asterisk*/
472  return &f;
473  }
474 
475  state = snd_pcm_state(alsa.icard);
476  if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
477  snd_pcm_prepare(alsa.icard);
478  }
479 
480  buf = __buf + AST_FRIENDLY_OFFSET / 2;
481 
482  r = snd_pcm_readi(alsa.icard, buf + readpos, left);
483  if (r == -EPIPE) {
484 #if DEBUG
485  ast_log(LOG_ERROR, "XRUN read\n");
486 #endif
487  snd_pcm_prepare(alsa.icard);
488  } else if (r == -ESTRPIPE) {
489  ast_log(LOG_ERROR, "-ESTRPIPE\n");
490  snd_pcm_prepare(alsa.icard);
491  } else if (r < 0) {
492  ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
493  }
494 
495  /* Return NULL frame on error */
496  if (r < 0) {
498  return &f;
499  }
500 
501  /* Update positions */
502  readpos += r;
503  left -= r;
504 
505  if (readpos >= FRAME_SIZE) {
506  /* A real frame */
507  readpos = 0;
508  left = FRAME_SIZE;
509  if (ast_channel_state(chan) != AST_STATE_UP) {
510  /* Don't transmit unless it's up */
512  return &f;
513  }
514  if (mute) {
515  /* Don't transmit if muted */
517  return &f;
518  }
519 
522  f.samples = FRAME_SIZE;
523  f.datalen = FRAME_SIZE * 2;
524  f.data.ptr = buf;
526  f.src = "Console";
527  f.mallocd = 0;
528 
529  }
531 
532  return &f;
533 }
534 
535 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
536 {
537  struct chan_alsa_pvt *p = ast_channel_tech_pvt(newchan);
538 
540  p->owner = newchan;
542 
543  return 0;
544 }
545 
546 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
547 {
548  int res = 0;
549 
551 
552  switch (cond) {
553  case AST_CONTROL_BUSY:
555  case AST_CONTROL_RINGING:
558  case -1:
559  res = -1; /* Ask for inband indications */
560  break;
565  break;
566  case AST_CONTROL_HOLD:
567  ast_verbose(" << Console Has Been Placed on Hold >> \n");
568  ast_moh_start(chan, data, mohinterpret);
569  break;
570  case AST_CONTROL_UNHOLD:
571  ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
572  ast_moh_stop(chan);
573  break;
574  default:
575  ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, ast_channel_name(chan));
576  res = -1;
577  }
578 
580 
581  return res;
582 }
583 
584 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
585 {
586  struct ast_channel *tmp = NULL;
587 
588  if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, assignedids, requestor, 0, "ALSA/%s", indevname)))
589  return NULL;
590 
592 
593  ast_channel_tech_set(tmp, &alsa_tech);
594  ast_channel_set_fd(tmp, 0, readdev);
598 
599  ast_channel_tech_pvt_set(tmp, p);
600  if (!ast_strlen_zero(p->context))
602  if (!ast_strlen_zero(p->exten))
603  ast_channel_exten_set(tmp, p->exten);
605  ast_channel_language_set(tmp, language);
606  p->owner = tmp;
609 
611  ast_channel_unlock(tmp);
612 
613  if (state != AST_STATE_DOWN) {
614  if (ast_pbx_start(tmp)) {
615  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
616  ast_hangup(tmp);
617  tmp = NULL;
618  }
619  }
620 
621  return tmp;
622 }
623 
624 static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
625 {
626  struct ast_channel *tmp = NULL;
627 
629  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
630  ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
631  return NULL;
632  }
633 
635 
636  if (alsa.owner) {
637  ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
638  *cause = AST_CAUSE_BUSY;
639  } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN, assignedids, requestor))) {
640  ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
641  }
642 
644 
645  return tmp;
646 }
647 
648 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
649 {
650  char *res = CLI_SUCCESS;
651 
652  switch (cmd) {
653  case CLI_INIT:
654  e->command = "console autoanswer [on|off]";
655  e->usage =
656  "Usage: console autoanswer [on|off]\n"
657  " Enables or disables autoanswer feature. If used without\n"
658  " argument, displays the current on/off status of autoanswer.\n"
659  " The default value of autoanswer is in 'alsa.conf'.\n";
660  return NULL;
661  case CLI_GENERATE:
662  return NULL;
663  }
664 
665  if ((a->argc != 2) && (a->argc != 3))
666  return CLI_SHOWUSAGE;
667 
669  if (a->argc == 2) {
670  ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
671  } else {
672  if (!strcasecmp(a->argv[2], "on"))
673  autoanswer = -1;
674  else if (!strcasecmp(a->argv[2], "off"))
675  autoanswer = 0;
676  else
677  res = CLI_SHOWUSAGE;
678  }
680 
681  return res;
682 }
683 
684 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
685 {
686  char *res = CLI_SUCCESS;
687 
688  switch (cmd) {
689  case CLI_INIT:
690  e->command = "console answer";
691  e->usage =
692  "Usage: console answer\n"
693  " Answers an incoming call on the console (ALSA) channel.\n";
694 
695  return NULL;
696  case CLI_GENERATE:
697  return NULL;
698  }
699 
700  if (a->argc != 2)
701  return CLI_SHOWUSAGE;
702 
704 
705  if (!alsa.owner) {
706  ast_cli(a->fd, "No one is calling us\n");
707  res = CLI_FAILURE;
708  } else {
709  if (mute) {
710  ast_verbose( " << Muted >> \n" );
711  }
712  hookstate = 1;
713  grab_owner();
714  if (alsa.owner) {
717  }
718  }
719 
720  if (!noaudiocapture) {
721  snd_pcm_prepare(alsa.icard);
722  snd_pcm_start(alsa.icard);
723  }
724 
726 
727  return res;
728 }
729 
730 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
731 {
732  int tmparg = 3;
733  char *res = CLI_SUCCESS;
734 
735  switch (cmd) {
736  case CLI_INIT:
737  e->command = "console send text";
738  e->usage =
739  "Usage: console send text <message>\n"
740  " Sends a text message for display on the remote terminal.\n";
741  return NULL;
742  case CLI_GENERATE:
743  return NULL;
744  }
745 
746  if (a->argc < 3)
747  return CLI_SHOWUSAGE;
748 
750 
751  if (!alsa.owner) {
752  ast_cli(a->fd, "No channel active\n");
753  res = CLI_FAILURE;
754  } else {
755  struct ast_frame f = { AST_FRAME_TEXT };
756  char text2send[256] = "";
757 
758  while (tmparg < a->argc) {
759  strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
760  strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
761  }
762 
763  text2send[strlen(text2send) - 1] = '\n';
764  f.data.ptr = text2send;
765  f.datalen = strlen(text2send) + 1;
766  grab_owner();
767  if (alsa.owner) {
771  }
772  }
773 
775 
776  return res;
777 }
778 
779 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
780 {
781  char *res = CLI_SUCCESS;
782 
783  switch (cmd) {
784  case CLI_INIT:
785  e->command = "console hangup";
786  e->usage =
787  "Usage: console hangup\n"
788  " Hangs up any call currently placed on the console.\n";
789  return NULL;
790  case CLI_GENERATE:
791  return NULL;
792  }
793 
794 
795  if (a->argc != 2)
796  return CLI_SHOWUSAGE;
797 
799 
800  if (!alsa.owner && !hookstate) {
801  ast_cli(a->fd, "No call to hangup\n");
802  res = CLI_FAILURE;
803  } else {
804  hookstate = 0;
805  grab_owner();
806  if (alsa.owner) {
809  }
810  }
811 
813 
814  return res;
815 }
816 
817 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
818 {
819  char tmp[256], *tmp2;
820  char *mye, *myc;
821  const char *d;
822  char *res = CLI_SUCCESS;
823 
824  switch (cmd) {
825  case CLI_INIT:
826  e->command = "console dial";
827  e->usage =
828  "Usage: console dial [extension[@context]]\n"
829  " Dials a given extension (and context if specified)\n";
830  return NULL;
831  case CLI_GENERATE:
832  return NULL;
833  }
834 
835  if ((a->argc != 2) && (a->argc != 3))
836  return CLI_SHOWUSAGE;
837 
839 
840  if (alsa.owner) {
841  if (a->argc == 3) {
842  if (alsa.owner) {
843  for (d = a->argv[2]; *d; d++) {
844  struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = *d };
845 
847  }
848  }
849  } else {
850  ast_cli(a->fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
851  res = CLI_FAILURE;
852  }
853  } else {
854  mye = exten;
855  myc = context;
856  if (a->argc == 3) {
857  char *stringp = NULL;
858 
859  ast_copy_string(tmp, a->argv[2], sizeof(tmp));
860  stringp = tmp;
861  strsep(&stringp, "@");
862  tmp2 = strsep(&stringp, "@");
863  if (!ast_strlen_zero(tmp))
864  mye = tmp;
865  if (!ast_strlen_zero(tmp2))
866  myc = tmp2;
867  }
868  if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
869  ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
870  ast_copy_string(alsa.context, myc, sizeof(alsa.context));
871  hookstate = 1;
873  } else
874  ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
875  }
876 
878 
879  return res;
880 }
881 
882 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
883 {
884  int toggle = 0;
885  char *res = CLI_SUCCESS;
886 
887  switch (cmd) {
888  case CLI_INIT:
889  e->command = "console {mute|unmute} [toggle]";
890  e->usage =
891  "Usage: console {mute|unmute} [toggle]\n"
892  " Mute/unmute the microphone.\n";
893  return NULL;
894  case CLI_GENERATE:
895  return NULL;
896  }
897 
898 
899  if (a->argc > 3) {
900  return CLI_SHOWUSAGE;
901  }
902 
903  if (a->argc == 3) {
904  if (strcasecmp(a->argv[2], "toggle"))
905  return CLI_SHOWUSAGE;
906  toggle = 1;
907  }
908 
909  if (a->argc < 2) {
910  return CLI_SHOWUSAGE;
911  }
912 
913  if (!strcasecmp(a->argv[1], "mute")) {
914  mute = toggle ? !mute : 1;
915  } else if (!strcasecmp(a->argv[1], "unmute")) {
916  mute = toggle ? !mute : 0;
917  } else {
918  return CLI_SHOWUSAGE;
919  }
920 
921  ast_cli(a->fd, "Console mic is %s\n", mute ? "off" : "on");
922 
923  return res;
924 }
925 
926 static struct ast_cli_entry cli_alsa[] = {
927  AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
928  AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
929  AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
930  AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
931  AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
932  AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
933 };
934 
935 static int unload_module(void)
936 {
937  ast_channel_unregister(&alsa_tech);
938  ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
939 
940  if (alsa.icard)
941  snd_pcm_close(alsa.icard);
942  if (alsa.ocard)
943  snd_pcm_close(alsa.ocard);
944  if (alsa.owner)
946  if (alsa.owner)
947  return -1;
948 
949  ao2_cleanup(alsa_tech.capabilities);
950  alsa_tech.capabilities = NULL;
951 
952  return 0;
953 }
954 
955 /*!
956  * \brief Load the module
957  *
958  * Module loading including tests for configuration or dependencies.
959  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
960  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
961  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
962  * configuration file or other non-critical problem return
963  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
964  */
965 static int load_module(void)
966 {
967  struct ast_config *cfg;
968  struct ast_variable *v;
969  struct ast_flags config_flags = { 0 };
970 
973  }
975 
976  /* Copy the default jb config over global_jbconf */
977  memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
978 
979  strcpy(mohinterpret, "default");
980 
981  if (!(cfg = ast_config_load(config, config_flags))) {
982  ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s. Aborting.\n", config);
984  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
985  ast_log(LOG_ERROR, "%s is in an invalid format. Aborting.\n", config);
987  }
988 
989  v = ast_variable_browse(cfg, "general");
990  for (; v; v = v->next) {
991  /* handle jb conf */
992  if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
993  continue;
994  }
995 
996  if (!strcasecmp(v->name, "autoanswer")) {
997  autoanswer = ast_true(v->value);
998  } else if (!strcasecmp(v->name, "mute")) {
999  mute = ast_true(v->value);
1000  } else if (!strcasecmp(v->name, "noaudiocapture")) {
1002  } else if (!strcasecmp(v->name, "silencesuppression")) {
1004  } else if (!strcasecmp(v->name, "silencethreshold")) {
1005  silencethreshold = atoi(v->value);
1006  } else if (!strcasecmp(v->name, "context")) {
1007  ast_copy_string(context, v->value, sizeof(context));
1008  } else if (!strcasecmp(v->name, "language")) {
1009  ast_copy_string(language, v->value, sizeof(language));
1010  } else if (!strcasecmp(v->name, "extension")) {
1011  ast_copy_string(exten, v->value, sizeof(exten));
1012  } else if (!strcasecmp(v->name, "input_device")) {
1013  ast_copy_string(indevname, v->value, sizeof(indevname));
1014  } else if (!strcasecmp(v->name, "output_device")) {
1016  } else if (!strcasecmp(v->name, "mohinterpret")) {
1018  }
1019  }
1020  ast_config_destroy(cfg);
1021 
1022  if (soundcard_init() < 0) {
1023  ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
1024  ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
1025  unload_module();
1026 
1027  return AST_MODULE_LOAD_DECLINE;
1028  }
1029 
1030  if (ast_channel_register(&alsa_tech)) {
1031  ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
1032  unload_module();
1033 
1034  return AST_MODULE_LOAD_DECLINE;
1035  }
1036 
1037  ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
1038 
1039  return AST_MODULE_LOAD_SUCCESS;
1040 }
1041 
1042 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver",
1043  .support_level = AST_MODULE_SUPPORT_DEPRECATED,
1044  .load = load_module,
1045  .unload = unload_module,
1046  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
1047 );
struct ast_variable * next
static char * console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:817
static const char type[]
Definition: chan_ooh323.c:109
struct ast_channel * owner
Definition: chan_alsa.c:130
enum sip_cc_notify_state state
Definition: chan_sip.c:963
char digit
static char mohinterpret[MAX_MUSICCLASS]
Definition: chan_alsa.c:123
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
#define FRAME_SIZE
Definition: chan_alsa.c:92
Main Channel structure associated with a channel.
Music on hold handling.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
const char *const type
Definition: channel.h:630
Asterisk main include file. File version handling, generic pbx functions.
#define ALSA_OUTDEV
Definition: chan_alsa.c:88
static const char tdesc[]
Definition: chan_alsa.c:117
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1227
static struct ast_channel_tech alsa_tech
Definition: chan_alsa.c:162
snd_pcm_t * icard
Definition: chan_alsa.c:133
snd_pcm_t * ocard
Definition: chan_alsa.c:133
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static int silencethreshold
Definition: chan_alsa.c:113
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4309
#define MAX_MUSICCLASS
Definition: channel.h:174
static struct chan_alsa_pvt alsa
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:566
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
Definition: chan_alsa.c:395
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:477
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
#define DESIRED_RATE
Definition: chan_alsa.c:89
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
static struct test_val d
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
Definition: abstract_jb.c:545
#define CONFIG_STATUS_FILEINVALID
static struct ast_jb_conf global_jbconf
Definition: chan_alsa.c:83
static int tmp()
Definition: bt_open.c:389
Structure for variables, used for configurations and for channel variables.
static int noaudiocapture
Definition: chan_alsa.c:149
static int alsa_text(struct ast_channel *c, const char *text)
Definition: chan_alsa.c:313
static int alsa_call(struct ast_channel *c, const char *dest, int timeout)
Definition: chan_alsa.c:329
static int autoanswer
Definition: chan_alsa.c:147
static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
Definition: chan_alsa.c:303
Definition: cli.h:152
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static struct ast_channel * alsa_new(struct chan_alsa_pvt *p, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_alsa.c:584
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static char * console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:730
#define ast_mutex_lock(a)
Definition: lock.h:187
static struct test_val c
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:535
char * text
Definition: app_queue.c:1514
#define ast_str_alloca(init_len)
Definition: strings.h:800
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
static char * console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:648
#define NULL
Definition: resample.c:96
const char * data
static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_alsa.c:535
Common implementation-independent jitterbuffer stuff.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_FRAME_DTMF
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7793
#define ast_verb(level,...)
Definition: logger.h:455
static int writedev
Definition: chan_alsa.c:145
struct ast_frame_subclass subclass
static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
Definition: chan_alsa.c:546
#define MAX_LANGUAGE
Definition: channel.h:173
static int mute
Definition: chan_alsa.c:148
Utility functions.
int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
Queue a hangup frame with hangupcause set.
Definition: channel.c:1162
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:583
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
Configuration File Parser.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
struct ast_module * self
Definition: module.h:342
General Asterisk PBX channel definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
const char * src
static struct ast_channel * alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Definition: chan_alsa.c:624
const int fd
Definition: cli.h:159
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Asterisk architecture endianess compatibility definitions.
ast_cond_t cond
Definition: app_meetme.c:1092
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
static int load_module(void)
Load the module.
Definition: chan_alsa.c:965
Asterisk internal frame definitions.
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2472
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
union ast_frame::@250 data
static int soundcard_init(void)
Definition: chan_alsa.c:283
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:121
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
#define ARRAY_LEN(a)
Definition: utils.h:639
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1135
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char *const * argv
Definition: cli.h:161
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
#define LOG_ERROR
Definition: logger.h:285
static char outdevname[50]
Definition: chan_alsa.c:110
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
#define CLI_SHOWUSAGE
Definition: cli.h:45
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static ast_mutex_t alsalock
Definition: chan_alsa.c:115
char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:132
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7783
char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:131
#define LOG_NOTICE
Definition: logger.h:263
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:736
struct ast_format_cap * capabilities
Definition: channel.h:633
static char indevname[50]
Definition: chan_alsa.c:109
#define ast_channel_unlock(chan)
Definition: channel.h:2914
#define CLI_FAILURE
Definition: cli.h:46
static struct ast_cli_entry cli_alsa[]
Definition: chan_alsa.c:926
#define AST_MAX_CONTEXT
Definition: channel.h:136
char * command
Definition: cli.h:186
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2544
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define PERIOD_FRAMES
Definition: chan_alsa.c:93
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition: abstract_jb.h:72
static char * console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:779
Structure used to handle boolean flags.
Definition: utils.h:199
static struct ast_frame * alsa_read(struct ast_channel *chan)
Definition: chan_alsa.c:447
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2427
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
struct timeval delivery
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
Definition: abstract_jb.c:593
const char * usage
Definition: cli.h:177
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
#define CLI_SUCCESS
Definition: cli.h:44
static char * console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:882
static void grab_owner(void)
Definition: chan_alsa.c:322
char * strsep(char **str, const char *delims)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
static snd_pcm_t * alsa_card_init(char *dev, snd_pcm_stream_t stream)
Definition: chan_alsa.c:177
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7403
static int hookstate
Definition: chan_alsa.c:125
#define AST_CAUSE_BUSY
Definition: causes.h:148
Data structure associated with a single frame of data.
#define ESTRPIPE
Definition: chan_alsa.c:48
Internal Asterisk hangup causes.
static const char config[]
Definition: chan_alsa.c:118
enum ast_frame_type frametype
#define ast_channel_trylock(chan)
Definition: channel.h:2915
static char * console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_alsa.c:684
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
struct ast_format * format
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
direction
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
static int alsa_answer(struct ast_channel *c)
Definition: chan_alsa.c:365
static snd_pcm_format_t format
Definition: chan_alsa.c:106
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
static int readdev
Definition: chan_alsa.c:144
General jitterbuffer configuration.
Definition: abstract_jb.h:69
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
static struct ast_jb_conf default_jbconf
Definition: chan_alsa.c:76
static int silencesuppression
Definition: chan_alsa.c:112
static int unload_module(void)
Definition: chan_alsa.c:935
Media Format Cache API.
#define ast_mutex_unlock(a)
Definition: lock.h:188
static struct test_val a
static int alsa_hangup(struct ast_channel *c)
Definition: chan_alsa.c:379
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
#define ALSA_INDEV
Definition: chan_alsa.c:87