Asterisk - The Open Source Telephony Project  18.5.0
chan_console.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006 - 2008, Digium, Inc.
5  *
6  * Russell Bryant <[email protected]>
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 /*!
20  * \file
21  * \brief Cross-platform console channel driver
22  *
23  * \author Russell Bryant <[email protected]>
24  *
25  * \note Some of the code in this file came from chan_oss and chan_alsa.
26  * chan_oss, Mark Spencer <[email protected]>
27  * chan_oss, Luigi Rizzo
28  * chan_alsa, Matthew Fredrickson <[email protected]>
29  *
30  * \ingroup channel_drivers
31  *
32  * Portaudio http://www.portaudio.com/
33  *
34  * To install portaudio v19 from svn, check it out using the following command:
35  * - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel
36  *
37  * \note Since this works with any audio system that libportaudio supports,
38  * including ALSA and OSS, this may someday deprecate chan_alsa and chan_oss.
39  * However, before that can be done, it needs to *at least* have all of the
40  * features that these other channel drivers have. The features implemented
41  * in at least one of the other console channel drivers that are not yet
42  * implemented here are:
43  *
44  * - Set Auto-answer from the dialplan
45  * - transfer CLI command
46  * - boost CLI command and .conf option
47  * - console_video support
48  */
49 
50 /*! \li \ref chan_console.c uses the configuration file \ref console.conf
51  * \addtogroup configuration_file
52  */
53 
54 /*! \page console.conf console.conf
55  * \verbinclude console.conf.sample
56  */
57 
58 /*** MODULEINFO
59  <depend>portaudio</depend>
60  <support_level>extended</support_level>
61  ***/
62 
63 #include "asterisk.h"
64 
65 #include <signal.h> /* SIGURG */
66 
67 #include <portaudio.h>
68 
69 #include "asterisk/module.h"
70 #include "asterisk/channel.h"
71 #include "asterisk/pbx.h"
72 #include "asterisk/causes.h"
73 #include "asterisk/cli.h"
74 #include "asterisk/musiconhold.h"
75 #include "asterisk/callerid.h"
76 #include "asterisk/astobj2.h"
78 #include "asterisk/format_cache.h"
79 
80 /*!
81  * \brief The sample rate to request from PortAudio
82  *
83  * \todo Make this optional. If this is only going to talk to 8 kHz endpoints,
84  * then it makes sense to use 8 kHz natively.
85  */
86 #define SAMPLE_RATE 16000
87 
88 /*!
89  * \brief The number of samples to configure the portaudio stream for
90  *
91  * 320 samples (20 ms) is the most common frame size in Asterisk. So, the code
92  * in this module reads 320 sample frames from the portaudio stream and queues
93  * them up on the Asterisk channel. Frames of any size can be written to a
94  * portaudio stream, but the portaudio documentation does say that for high
95  * performance applications, the data should be written to Pa_WriteStream in
96  * the same size as what is used to initialize the stream.
97  */
98 #define NUM_SAMPLES 320
99 
100 /*! \brief Mono Input */
101 #define INPUT_CHANNELS 1
102 
103 /*! \brief Mono Output */
104 #define OUTPUT_CHANNELS 1
105 
106 /*!
107  * \brief Maximum text message length
108  * \note This should be changed if there is a common definition somewhere
109  * that defines the maximum length of a text message.
110  */
111 #define TEXT_SIZE 256
112 
113 /*! \brief Dance, Kirby, Dance! @{ */
114 #define V_BEGIN " --- <(\"<) --- "
115 #define V_END " --- (>\")> ---\n"
116 /*! @} */
117 
118 static const char config_file[] = "console.conf";
119 
120 /*!
121  * \brief Console pvt structure
122  *
123  * Currently, this is a singleton object. However, multiple instances will be
124  * needed when this module is updated for multiple device support.
125  */
126 static struct console_pvt {
128  /*! Name of the device */
132  /*! Default context for outgoing calls */
134  /*! Default extension for outgoing calls */
136  /*! Default CallerID number */
138  /*! Default CallerID name */
140  /*! Default MOH class to listen to, if:
141  * - No MOH class set on the channel
142  * - Peer channel putting this device on hold did not suggest a class */
144  /*! Default language */
146  /*! Default parkinglot */
148  );
149  /*! Current channel for this device */
151  /*! Current PortAudio stream for this device */
152  PaStream *stream;
153  /*! A frame for preparing to queue on to the channel */
154  struct ast_frame fr;
155  /*! Running = 1, Not running = 0 */
156  unsigned int streamstate:1;
157  /*! On-hook = 0, Off-hook = 1 */
158  unsigned int hookstate:1;
159  /*! Unmuted = 0, Muted = 1 */
160  unsigned int muted:1;
161  /*! Automatically answer incoming calls */
162  unsigned int autoanswer:1;
163  /*! Ignore context in the console dial CLI command */
164  unsigned int overridecontext:1;
165  /*! Set during a reload so that we know to destroy this if it is no longer
166  * in the configuration file. */
167  unsigned int destroy:1;
168  /*! ID for the stream monitor thread */
169  pthread_t thread;
170 } globals;
171 
173 
174 static struct ao2_container *pvts;
175 #define NUM_PVT_BUCKETS 7
176 
177 static struct console_pvt *active_pvt;
179 
180 /*!
181  * \brief Global jitterbuffer configuration
182  *
183  * \note Disabled by default.
184  * \note Values shown here match the defaults shown in console.conf.sample
185  */
186 static struct ast_jb_conf default_jbconf = {
187  .flags = 0,
188  .max_size = 200,
189  .resync_threshold = 1000,
190  .impl = "fixed",
191  .target_extra = 40,
192 };
194 
195 /*! Channel Technology Callbacks @{ */
196 static struct ast_channel *console_request(const char *type, struct ast_format_cap *cap,
197  const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
198 static int console_digit_begin(struct ast_channel *c, char digit);
199 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration);
200 static int console_text(struct ast_channel *c, const char *text);
201 static int console_hangup(struct ast_channel *c);
202 static int console_answer(struct ast_channel *c);
203 static struct ast_frame *console_read(struct ast_channel *chan);
204 static int console_call(struct ast_channel *c, const char *dest, int timeout);
205 static int console_write(struct ast_channel *chan, struct ast_frame *f);
206 static int console_indicate(struct ast_channel *chan, int cond,
207  const void *data, size_t datalen);
208 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
209 /*! @} */
210 
212  .type = "Console",
213  .description = "Console Channel Driver",
214  .requester = console_request,
215  .send_digit_begin = console_digit_begin,
216  .send_digit_end = console_digit_end,
217  .send_text = console_text,
218  .hangup = console_hangup,
219  .answer = console_answer,
220  .read = console_read,
221  .call = console_call,
222  .write = console_write,
223  .indicate = console_indicate,
224  .fixup = console_fixup,
225 };
226 
227 /*! \brief lock a console_pvt struct */
228 #define console_pvt_lock(pvt) ao2_lock(pvt)
229 
230 /*! \brief unlock a console_pvt struct */
231 #define console_pvt_unlock(pvt) ao2_unlock(pvt)
232 
233 static inline struct console_pvt *ref_pvt(struct console_pvt *pvt)
234 {
235  if (pvt)
236  ao2_ref(pvt, +1);
237  return pvt;
238 }
239 
240 static inline struct console_pvt *unref_pvt(struct console_pvt *pvt)
241 {
242  ao2_ref(pvt, -1);
243  return NULL;
244 }
245 
246 static struct console_pvt *find_pvt(const char *name)
247 {
248  struct console_pvt tmp_pvt = {
249  .name = name,
250  };
251 
252  return ao2_find(pvts, &tmp_pvt, OBJ_POINTER);
253 }
254 
255 /*!
256  * \brief Stream monitor thread
257  *
258  * \arg data A pointer to the console_pvt structure that contains the portaudio
259  * stream that needs to be monitored.
260  *
261  * This function runs in its own thread to monitor data coming in from a
262  * portaudio stream. When enough data is available, it is queued up to
263  * be read from the Asterisk channel.
264  */
265 static void *stream_monitor(void *data)
266 {
267  struct console_pvt *pvt = data;
268  char buf[NUM_SAMPLES * sizeof(int16_t)];
269  PaError res;
270  struct ast_frame f = {
272  .subclass.format = ast_format_slin16,
273  .src = "console_stream_monitor",
274  .data.ptr = buf,
275  .datalen = sizeof(buf),
276  .samples = sizeof(buf) / sizeof(int16_t),
277  };
278 
279  for (;;) {
280  pthread_testcancel();
281  console_pvt_lock(pvt);
282  res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
283  console_pvt_unlock(pvt);
284  pthread_testcancel();
285 
286  if (!pvt->owner) {
287  return NULL;
288  }
289 
290  if (res == paNoError)
291  ast_queue_frame(pvt->owner, &f);
292  }
293 
294  return NULL;
295 }
296 
297 static int open_stream(struct console_pvt *pvt)
298 {
299  int res = paInternalError;
300 
301  if (!strcasecmp(pvt->input_device, "default") &&
302  !strcasecmp(pvt->output_device, "default")) {
303  res = Pa_OpenDefaultStream(&pvt->stream, INPUT_CHANNELS, OUTPUT_CHANNELS,
304  paInt16, SAMPLE_RATE, NUM_SAMPLES, NULL, NULL);
305  } else {
306  PaStreamParameters input_params = {
307  .channelCount = 1,
308  .sampleFormat = paInt16,
309  .suggestedLatency = (1.0 / 50.0), /* 20 ms */
310  .device = paNoDevice,
311  };
312  PaStreamParameters output_params = {
313  .channelCount = 1,
314  .sampleFormat = paInt16,
315  .suggestedLatency = (1.0 / 50.0), /* 20 ms */
316  .device = paNoDevice,
317  };
318  PaDeviceIndex idx, num_devices, def_input, def_output;
319 
320  if (!(num_devices = Pa_GetDeviceCount()))
321  return res;
322 
323  def_input = Pa_GetDefaultInputDevice();
324  def_output = Pa_GetDefaultOutputDevice();
325 
326  for (idx = 0;
327  idx < num_devices && (input_params.device == paNoDevice
328  || output_params.device == paNoDevice);
329  idx++)
330  {
331  const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
332 
333  if (dev->maxInputChannels) {
334  if ( (idx == def_input && !strcasecmp(pvt->input_device, "default")) ||
335  !strcasecmp(pvt->input_device, dev->name) )
336  input_params.device = idx;
337  }
338 
339  if (dev->maxOutputChannels) {
340  if ( (idx == def_output && !strcasecmp(pvt->output_device, "default")) ||
341  !strcasecmp(pvt->output_device, dev->name) )
342  output_params.device = idx;
343  }
344  }
345 
346  if (input_params.device == paNoDevice)
347  ast_log(LOG_ERROR, "No input device found for console device '%s'\n", pvt->name);
348  if (output_params.device == paNoDevice)
349  ast_log(LOG_ERROR, "No output device found for console device '%s'\n", pvt->name);
350 
351  res = Pa_OpenStream(&pvt->stream, &input_params, &output_params,
352  SAMPLE_RATE, NUM_SAMPLES, paNoFlag, NULL, NULL);
353  }
354 
355  return res;
356 }
357 
358 static int start_stream(struct console_pvt *pvt)
359 {
360  PaError res;
361  int ret_val = 0;
362 
363  console_pvt_lock(pvt);
364 
365  /* It is possible for console_hangup to be called before the
366  * stream is started, if this is the case pvt->owner will be NULL
367  * and start_stream should be aborted. */
368  if (pvt->streamstate || !pvt->owner)
369  goto return_unlock;
370 
371  pvt->streamstate = 1;
372  ast_debug(1, "Starting stream\n");
373 
374  res = open_stream(pvt);
375  if (res != paNoError) {
376  ast_log(LOG_WARNING, "Failed to open stream - (%d) %s\n",
377  res, Pa_GetErrorText(res));
378  ret_val = -1;
379  goto return_unlock;
380  }
381 
382  res = Pa_StartStream(pvt->stream);
383  if (res != paNoError) {
384  ast_log(LOG_WARNING, "Failed to start stream - (%d) %s\n",
385  res, Pa_GetErrorText(res));
386  ret_val = -1;
387  goto return_unlock;
388  }
389 
391  ast_log(LOG_ERROR, "Failed to start stream monitor thread\n");
392  ret_val = -1;
393  }
394 
395 return_unlock:
396  console_pvt_unlock(pvt);
397 
398  return ret_val;
399 }
400 
401 static int stop_stream(struct console_pvt *pvt)
402 {
403  if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
404  return 0;
405 
406  pthread_cancel(pvt->thread);
407  pthread_kill(pvt->thread, SIGURG);
408  pthread_join(pvt->thread, NULL);
409 
410  console_pvt_lock(pvt);
411  Pa_AbortStream(pvt->stream);
412  Pa_CloseStream(pvt->stream);
413  pvt->stream = NULL;
414  pvt->streamstate = 0;
415  console_pvt_unlock(pvt);
416 
417  return 0;
418 }
419 
420 /*!
421  * \note Called with the pvt struct locked
422  */
423 static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
424 {
425  struct ast_format_cap *caps;
426  struct ast_channel *chan;
427 
429  if (!caps) {
430  return NULL;
431  }
432 
433  if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL,
434  ext, ctx, assignedids, requestor, 0, "Console/%s", pvt->name))) {
435  ao2_ref(caps, -1);
436  return NULL;
437  }
438 
440 
441  ast_channel_tech_set(chan, &console_tech);
445  ast_channel_nativeformats_set(chan, caps);
446  ao2_ref(caps, -1);
447  ast_channel_tech_pvt_set(chan, ref_pvt(pvt));
448 
449  pvt->owner = chan;
450 
451  if (!ast_strlen_zero(pvt->language))
452  ast_channel_language_set(chan, pvt->language);
453 
455 
457  ast_channel_unlock(chan);
458 
459  if (state != AST_STATE_DOWN) {
460  if (ast_pbx_start(chan)) {
462  ast_hangup(chan);
463  chan = NULL;
464  } else
465  start_stream(pvt);
466  }
467 
468  return chan;
469 }
470 
471 static struct ast_channel *console_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)
472 {
473  struct ast_channel *chan = NULL;
474  struct console_pvt *pvt;
475 
476  if (!(pvt = find_pvt(data))) {
477  ast_log(LOG_ERROR, "Console device '%s' not found\n", data);
478  return NULL;
479  }
480 
481  if (!(ast_format_cap_iscompatible(cap, console_tech.capabilities))) {
483  ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n",
484  ast_format_cap_get_names(cap, &cap_buf));
485  goto return_unref;
486  }
487 
488  if (pvt->owner) {
489  ast_log(LOG_NOTICE, "Console channel already active!\n");
490  *cause = AST_CAUSE_BUSY;
491  goto return_unref;
492  }
493 
494  console_pvt_lock(pvt);
495  chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, assignedids, requestor);
496  console_pvt_unlock(pvt);
497 
498  if (!chan)
499  ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
500 
501 return_unref:
502  unref_pvt(pvt);
503 
504  return chan;
505 }
506 
507 static int console_digit_begin(struct ast_channel *c, char digit)
508 {
509  ast_verb(1, V_BEGIN "Console Received Beginning of Digit %c" V_END, digit);
510 
511  return -1; /* non-zero to request inband audio */
512 }
513 
514 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration)
515 {
516  ast_verb(1, V_BEGIN "Console Received End of Digit %c (duration %u)" V_END,
517  digit, duration);
518 
519  return -1; /* non-zero to request inband audio */
520 }
521 
522 static int console_text(struct ast_channel *c, const char *text)
523 {
524  ast_verb(1, V_BEGIN "Console Received Text '%s'" V_END, text);
525 
526  return 0;
527 }
528 
529 static int console_hangup(struct ast_channel *c)
530 {
531  struct console_pvt *pvt = ast_channel_tech_pvt(c);
532 
533  ast_verb(1, V_BEGIN "Hangup on Console" V_END);
534 
535  pvt->hookstate = 0;
536  pvt->owner = NULL;
537  stop_stream(pvt);
538 
540 
541  return 0;
542 }
543 
544 static int console_answer(struct ast_channel *c)
545 {
546  struct console_pvt *pvt = ast_channel_tech_pvt(c);
547 
548  ast_verb(1, V_BEGIN "Call from Console has been Answered" V_END);
549 
551 
552  return start_stream(pvt);
553 }
554 
555 /*
556  * \brief Implementation of the ast_channel_tech read() callback
557  *
558  * Calling this function is harmless. However, if it does get called, it
559  * is an indication that something weird happened that really shouldn't
560  * have and is worth looking into.
561  *
562  * Why should this function not get called? Well, let me explain. There are
563  * a couple of ways to pass on audio that has come from this channel. The way
564  * that this channel driver uses is that once the audio is available, it is
565  * wrapped in an ast_frame and queued onto the channel using ast_queue_frame().
566  *
567  * The other method would be signalling to the core that there is audio waiting,
568  * and that it needs to call the channel's read() callback to get it. The way
569  * the channel gets signalled is that one or more file descriptors are placed
570  * in the fds array on the ast_channel which the core will poll() on. When the
571  * fd indicates that input is available, the read() callback is called. This
572  * is especially useful when there is a dedicated file descriptor where the
573  * audio is read from. An example would be the socket for an RTP stream.
574  */
575 static struct ast_frame *console_read(struct ast_channel *chan)
576 {
577  ast_debug(1, "I should not be called ...\n");
578 
579  return &ast_null_frame;
580 }
581 
582 static int console_call(struct ast_channel *c, const char *dest, int timeout)
583 {
584  struct console_pvt *pvt = ast_channel_tech_pvt(c);
585  enum ast_control_frame_type ctrl;
586 
587  ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
588  dest,
589  S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
590  S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""));
591 
592  console_pvt_lock(pvt);
593 
594  if (pvt->autoanswer) {
595  pvt->hookstate = 1;
596  console_pvt_unlock(pvt);
597  ast_verb(1, V_BEGIN "Auto-answered" V_END);
598  ctrl = AST_CONTROL_ANSWER;
599  } else {
600  console_pvt_unlock(pvt);
601  ast_verb(1, V_BEGIN "Type 'console answer' to answer, or use the 'autoanswer' option "
602  "for future calls" V_END);
603  ctrl = AST_CONTROL_RINGING;
605  }
606 
607  ast_queue_control(c, ctrl);
608 
609  return start_stream(pvt);
610 }
611 
612 static int console_write(struct ast_channel *chan, struct ast_frame *f)
613 {
614  struct console_pvt *pvt = ast_channel_tech_pvt(chan);
615 
616  console_pvt_lock(pvt);
617  Pa_WriteStream(pvt->stream, f->data.ptr, f->samples);
618  console_pvt_unlock(pvt);
619 
620  return 0;
621 }
622 
623 static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
624 {
625  struct console_pvt *pvt = ast_channel_tech_pvt(chan);
626  int res = 0;
627 
628  switch (cond) {
629  case AST_CONTROL_BUSY:
631  case AST_CONTROL_RINGING:
634  case -1:
635  res = -1; /* Ask for inband indications */
636  break;
641  break;
642  case AST_CONTROL_HOLD:
643  ast_verb(1, V_BEGIN "Console Has Been Placed on Hold" V_END);
644  ast_moh_start(chan, data, pvt->mohinterpret);
645  break;
646  case AST_CONTROL_UNHOLD:
647  ast_verb(1, V_BEGIN "Console Has Been Retrieved from Hold" V_END);
648  ast_moh_stop(chan);
649  break;
650  default:
651  ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n",
652  cond, ast_channel_name(chan));
653  /* The core will play inband indications for us if appropriate */
654  res = -1;
655  }
656 
657  return res;
658 }
659 
660 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
661 {
662  struct console_pvt *pvt = ast_channel_tech_pvt(newchan);
663 
664  pvt->owner = newchan;
665 
666  return 0;
667 }
668 
669 /*!
670  * split a string in extension-context, returns pointers to malloc'ed
671  * strings.
672  * If we do not have 'overridecontext' then the last @ is considered as
673  * a context separator, and the context is overridden.
674  * This is usually not very necessary as you can play with the dialplan,
675  * and it is nice not to need it because you have '@' in SIP addresses.
676  * Return value is the buffer address.
677  *
678  * \note came from chan_oss
679  */
680 static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
681 {
682  if (ext == NULL || ctx == NULL)
683  return NULL; /* error */
684 
685  *ext = *ctx = NULL;
686 
687  if (src && *src != '\0')
688  *ext = ast_strdup(src);
689 
690  if (*ext == NULL)
691  return NULL;
692 
693  if (!pvt->overridecontext) {
694  /* parse from the right */
695  *ctx = strrchr(*ext, '@');
696  if (*ctx)
697  *(*ctx)++ = '\0';
698  }
699 
700  return *ext;
701 }
702 
703 static struct console_pvt *get_active_pvt(void)
704 {
705  struct console_pvt *pvt;
706 
708  pvt = ref_pvt(active_pvt);
710 
711  return pvt;
712 }
713 
714 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
715  struct ast_cli_args *a)
716 {
717  struct console_pvt *pvt;
718  char *res = CLI_SUCCESS;
719 
720  switch (cmd) {
721  case CLI_INIT:
722  e->command = "console {set|show} autoanswer [on|off]";
723  e->usage =
724  "Usage: console {set|show} autoanswer [on|off]\n"
725  " Enables or disables autoanswer feature. If used without\n"
726  " argument, displays the current on/off status of autoanswer.\n"
727  " The default value of autoanswer is in 'oss.conf'.\n";
728  return NULL;
729 
730  case CLI_GENERATE:
731  return NULL;
732  }
733 
734  pvt = get_active_pvt();
735  if (!pvt) {
736  ast_cli(a->fd, "No console device is set as active.\n");
737  return CLI_FAILURE;
738  }
739 
740  if (a->argc == e->args - 1) {
741  ast_cli(a->fd, "Auto answer is %s.\n", pvt->autoanswer ? "on" : "off");
742  unref_pvt(pvt);
743  return CLI_SUCCESS;
744  }
745 
746  if (a->argc != e->args) {
747  unref_pvt(pvt);
748  return CLI_SHOWUSAGE;
749  }
750 
751  if (!strcasecmp(a->argv[e->args-1], "on"))
752  pvt->autoanswer = 1;
753  else if (!strcasecmp(a->argv[e->args - 1], "off"))
754  pvt->autoanswer = 0;
755  else
756  res = CLI_SHOWUSAGE;
757 
758  unref_pvt(pvt);
759 
760  return res;
761 }
762 
763 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
764 {
765  struct console_pvt *pvt;
766 
767  if (cmd == CLI_INIT) {
768  e->command = "console flash";
769  e->usage =
770  "Usage: console flash\n"
771  " Flashes the call currently placed on the console.\n";
772  return NULL;
773  } else if (cmd == CLI_GENERATE) {
774  return NULL;
775  }
776 
777  if (a->argc != e->args) {
778  return CLI_SHOWUSAGE;
779  }
780 
781  pvt = get_active_pvt();
782  if (!pvt) {
783  ast_cli(a->fd, "No console device is set as active\n");
784  return CLI_FAILURE;
785  }
786 
787  if (!pvt->owner) {
788  ast_cli(a->fd, "No call to flash\n");
789  unref_pvt(pvt);
790  return CLI_FAILURE;
791  }
792 
793  pvt->hookstate = 0;
794 
796 
797  unref_pvt(pvt);
798 
799  return CLI_SUCCESS;
800 }
801 
802 static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
803 {
804  char *s = NULL;
805  const char *mye = NULL, *myc = NULL;
806  struct console_pvt *pvt;
807 
808  if (cmd == CLI_INIT) {
809  e->command = "console dial";
810  e->usage =
811  "Usage: console dial [extension[@context]]\n"
812  " Dials a given extension (and context if specified)\n";
813  return NULL;
814  } else if (cmd == CLI_GENERATE) {
815  return NULL;
816  }
817 
818  if (a->argc > e->args + 1) {
819  return CLI_SHOWUSAGE;
820  }
821 
822  pvt = get_active_pvt();
823  if (!pvt) {
824  ast_cli(a->fd, "No console device is currently set as active\n");
825  return CLI_FAILURE;
826  }
827 
828  if (pvt->owner) { /* already in a call */
829  int i;
830  struct ast_frame f = { AST_FRAME_DTMF };
831  const char *s;
832 
833  if (a->argc == e->args) { /* argument is mandatory here */
834  ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
835  unref_pvt(pvt);
836  return CLI_FAILURE;
837  }
838  s = a->argv[e->args];
839  /* send the string one char at a time */
840  for (i = 0; i < strlen(s); i++) {
841  f.subclass.integer = s[i];
842  ast_queue_frame(pvt->owner, &f);
843  }
844  unref_pvt(pvt);
845  return CLI_SUCCESS;
846  }
847 
848  /* if we have an argument split it into extension and context */
849  if (a->argc == e->args + 1) {
850  char *ext = NULL, *con = NULL;
851  s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
852  mye = ext;
853  myc = con;
854  ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
855  a->argv[e->args], mye, myc);
856  }
857 
858  /* supply default values if needed */
859  if (ast_strlen_zero(mye))
860  mye = pvt->exten;
861  if (ast_strlen_zero(myc))
862  myc = pvt->context;
863 
864  if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
865  console_pvt_lock(pvt);
866  pvt->hookstate = 1;
867  console_new(pvt, mye, myc, AST_STATE_RINGING, NULL, NULL);
868  console_pvt_unlock(pvt);
869  } else
870  ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
871 
872  ast_free(s);
873 
874  unref_pvt(pvt);
875 
876  return CLI_SUCCESS;
877 }
878 
879 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
880 {
881  struct console_pvt *pvt;
882 
883  if (cmd == CLI_INIT) {
884  e->command = "console hangup";
885  e->usage =
886  "Usage: console hangup\n"
887  " Hangs up any call currently placed on the console.\n";
888  return NULL;
889  } else if (cmd == CLI_GENERATE) {
890  return NULL;
891  }
892 
893  if (a->argc != e->args) {
894  return CLI_SHOWUSAGE;
895  }
896 
897  pvt = get_active_pvt();
898  if (!pvt) {
899  ast_cli(a->fd, "No console device is set as active\n");
900  return CLI_FAILURE;
901  }
902 
903  if (!pvt->owner && !pvt->hookstate) {
904  ast_cli(a->fd, "No call to hang up\n");
905  unref_pvt(pvt);
906  return CLI_FAILURE;
907  }
908 
909  pvt->hookstate = 0;
910  if (pvt->owner)
911  ast_queue_hangup(pvt->owner);
912 
913  unref_pvt(pvt);
914 
915  return CLI_SUCCESS;
916 }
917 
918 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
919 {
920  const char *s;
921  struct console_pvt *pvt;
922  char *res = CLI_SUCCESS;
923 
924  if (cmd == CLI_INIT) {
925  e->command = "console {mute|unmute}";
926  e->usage =
927  "Usage: console {mute|unmute}\n"
928  " Mute/unmute the microphone.\n";
929  return NULL;
930  } else if (cmd == CLI_GENERATE) {
931  return NULL;
932  }
933 
934  if (a->argc != e->args) {
935  return CLI_SHOWUSAGE;
936  }
937 
938  pvt = get_active_pvt();
939  if (!pvt) {
940  ast_cli(a->fd, "No console device is set as active\n");
941  return CLI_FAILURE;
942  }
943 
944  s = a->argv[e->args-1];
945  if (!strcasecmp(s, "mute"))
946  pvt->muted = 1;
947  else if (!strcasecmp(s, "unmute"))
948  pvt->muted = 0;
949  else
950  res = CLI_SHOWUSAGE;
951 
952  ast_verb(1, V_BEGIN "The Console is now %s" V_END,
953  pvt->muted ? "Muted" : "Unmuted");
954 
955  unref_pvt(pvt);
956 
957  return res;
958 }
959 
960 static char *cli_list_available(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
961 {
962  PaDeviceIndex idx, num, def_input, def_output;
963 
964  if (cmd == CLI_INIT) {
965  e->command = "console list available";
966  e->usage =
967  "Usage: console list available\n"
968  " List all available devices.\n";
969  return NULL;
970  } else if (cmd == CLI_GENERATE)
971  return NULL;
972 
973  if (a->argc != e->args)
974  return CLI_SHOWUSAGE;
975 
976  ast_cli(a->fd, "\n"
977  "=============================================================\n"
978  "=== Available Devices =======================================\n"
979  "=============================================================\n"
980  "===\n");
981 
982  num = Pa_GetDeviceCount();
983  if (!num) {
984  ast_cli(a->fd, "(None)\n");
985  return CLI_SUCCESS;
986  }
987 
988  def_input = Pa_GetDefaultInputDevice();
989  def_output = Pa_GetDefaultOutputDevice();
990  for (idx = 0; idx < num; idx++) {
991  const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
992  if (!dev)
993  continue;
994  ast_cli(a->fd, "=== ---------------------------------------------------------\n"
995  "=== Device Name: %s\n", dev->name);
996  if (dev->maxInputChannels)
997  ast_cli(a->fd, "=== ---> %sInput Device\n", (idx == def_input) ? "Default " : "");
998  if (dev->maxOutputChannels)
999  ast_cli(a->fd, "=== ---> %sOutput Device\n", (idx == def_output) ? "Default " : "");
1000  ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
1001  }
1002 
1003  ast_cli(a->fd, "=============================================================\n\n");
1004 
1005  return CLI_SUCCESS;
1006 }
1007 
1008 static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1009 {
1010  struct ao2_iterator i;
1011  struct console_pvt *pvt;
1012 
1013  if (cmd == CLI_INIT) {
1014  e->command = "console list devices";
1015  e->usage =
1016  "Usage: console list devices\n"
1017  " List all configured devices.\n";
1018  return NULL;
1019  } else if (cmd == CLI_GENERATE)
1020  return NULL;
1021 
1022  if (a->argc != e->args)
1023  return CLI_SHOWUSAGE;
1024 
1025  ast_cli(a->fd, "\n"
1026  "=============================================================\n"
1027  "=== Configured Devices ======================================\n"
1028  "=============================================================\n"
1029  "===\n");
1030 
1031  i = ao2_iterator_init(pvts, 0);
1032  while ((pvt = ao2_iterator_next(&i))) {
1033  console_pvt_lock(pvt);
1034 
1035  ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1036  "=== Device Name: %s\n"
1037  "=== ---> Active: %s\n"
1038  "=== ---> Input Device: %s\n"
1039  "=== ---> Output Device: %s\n"
1040  "=== ---> Context: %s\n"
1041  "=== ---> Extension: %s\n"
1042  "=== ---> CallerID Num: %s\n"
1043  "=== ---> CallerID Name: %s\n"
1044  "=== ---> MOH Interpret: %s\n"
1045  "=== ---> Language: %s\n"
1046  "=== ---> Parkinglot: %s\n"
1047  "=== ---> Muted: %s\n"
1048  "=== ---> Auto-Answer: %s\n"
1049  "=== ---> Override Context: %s\n"
1050  "=== ---------------------------------------------------------\n===\n",
1051  pvt->name, (pvt == active_pvt) ? "Yes" : "No",
1052  pvt->input_device, pvt->output_device, pvt->context,
1053  pvt->exten, pvt->cid_num, pvt->cid_name, pvt->mohinterpret,
1054  pvt->language, pvt->parkinglot, pvt->muted ? "Yes" : "No", pvt->autoanswer ? "Yes" : "No",
1055  pvt->overridecontext ? "Yes" : "No");
1056 
1057  console_pvt_unlock(pvt);
1058  unref_pvt(pvt);
1059  }
1061 
1062  ast_cli(a->fd, "=============================================================\n\n");
1063 
1064  return CLI_SUCCESS;
1065 }
1066 /*!
1067  * \brief answer command from the console
1068  */
1069 static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1070 {
1071  struct console_pvt *pvt;
1072 
1073  switch (cmd) {
1074  case CLI_INIT:
1075  e->command = "console answer";
1076  e->usage =
1077  "Usage: console answer\n"
1078  " Answers an incoming call on the console channel.\n";
1079  return NULL;
1080 
1081  case CLI_GENERATE:
1082  return NULL; /* no completion */
1083  }
1084 
1085  pvt = get_active_pvt();
1086  if (!pvt) {
1087  ast_cli(a->fd, "No console device is set as active\n");
1088  return CLI_FAILURE;
1089  }
1090 
1091  if (a->argc != e->args) {
1092  unref_pvt(pvt);
1093  return CLI_SHOWUSAGE;
1094  }
1095 
1096  if (!pvt->owner) {
1097  ast_cli(a->fd, "No one is calling us\n");
1098  unref_pvt(pvt);
1099  return CLI_FAILURE;
1100  }
1101 
1102  pvt->hookstate = 1;
1103 
1104  ast_indicate(pvt->owner, -1);
1105 
1107 
1108  unref_pvt(pvt);
1109 
1110  return CLI_SUCCESS;
1111 }
1112 
1113 /*!
1114  * \brief Console send text CLI command
1115  *
1116  * \note concatenate all arguments into a single string. argv is NULL-terminated
1117  * so we can use it right away
1118  */
1119 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1120 {
1121  char buf[TEXT_SIZE];
1122  struct console_pvt *pvt;
1123  struct ast_frame f = {
1125  .data.ptr = buf,
1126  .src = "console_send_text",
1127  };
1128  int len;
1129 
1130  if (cmd == CLI_INIT) {
1131  e->command = "console send text";
1132  e->usage =
1133  "Usage: console send text <message>\n"
1134  " Sends a text message for display on the remote terminal.\n";
1135  return NULL;
1136  } else if (cmd == CLI_GENERATE) {
1137  return NULL;
1138  }
1139 
1140  pvt = get_active_pvt();
1141  if (!pvt) {
1142  ast_cli(a->fd, "No console device is set as active\n");
1143  return CLI_FAILURE;
1144  }
1145 
1146  if (a->argc < e->args + 1) {
1147  unref_pvt(pvt);
1148  return CLI_SHOWUSAGE;
1149  }
1150 
1151  if (!pvt->owner) {
1152  ast_cli(a->fd, "Not in a call\n");
1153  unref_pvt(pvt);
1154  return CLI_FAILURE;
1155  }
1156 
1157  ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
1158  if (ast_strlen_zero(buf)) {
1159  unref_pvt(pvt);
1160  return CLI_SHOWUSAGE;
1161  }
1162 
1163  len = strlen(buf);
1164  buf[len] = '\n';
1165  f.datalen = len + 1;
1166 
1167  ast_queue_frame(pvt->owner, &f);
1168 
1169  unref_pvt(pvt);
1170 
1171  return CLI_SUCCESS;
1172 }
1173 
1174 static void set_active(struct console_pvt *pvt, const char *value)
1175 {
1176  if (pvt == &globals) {
1177  ast_log(LOG_ERROR, "active is only valid as a per-device setting\n");
1178  return;
1179  }
1180 
1181  if (!ast_true(value))
1182  return;
1183 
1185  if (active_pvt)
1186  unref_pvt(active_pvt);
1187  active_pvt = ref_pvt(pvt);
1189 }
1190 
1191 static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1192 {
1193  struct console_pvt *pvt;
1194 
1195  switch (cmd) {
1196  case CLI_INIT:
1197  e->command = "console {set|show} active";
1198  e->usage =
1199  "Usage: console {set|show} active [<device>]\n"
1200  " Set or show the active console device for the Asterisk CLI.\n";
1201  return NULL;
1202  case CLI_GENERATE:
1203  if (a->pos == e->args) {
1204  struct ao2_iterator i;
1205  int x = 0;
1206  char *res = NULL;
1207  i = ao2_iterator_init(pvts, 0);
1208  while ((pvt = ao2_iterator_next(&i))) {
1209  if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
1210  res = ast_strdup(pvt->name);
1211  unref_pvt(pvt);
1212  if (res) {
1214  return res;
1215  }
1216  }
1218  }
1219  return NULL;
1220  }
1221 
1222  if (a->argc < e->args)
1223  return CLI_SHOWUSAGE;
1224 
1225  if (a->argc == 3) {
1226  pvt = get_active_pvt();
1227 
1228  if (!pvt)
1229  ast_cli(a->fd, "No device is currently set as the active console device.\n");
1230  else {
1231  console_pvt_lock(pvt);
1232  ast_cli(a->fd, "The active console device is '%s'.\n", pvt->name);
1233  console_pvt_unlock(pvt);
1234  pvt = unref_pvt(pvt);
1235  }
1236 
1237  return CLI_SUCCESS;
1238  }
1239 
1240  if (!(pvt = find_pvt(a->argv[e->args]))) {
1241  ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
1242  return CLI_FAILURE;
1243  }
1244 
1245  set_active(pvt, "yes");
1246 
1247  console_pvt_lock(pvt);
1248  ast_cli(a->fd, "The active console device has been set to '%s'\n", pvt->name);
1249  console_pvt_unlock(pvt);
1250 
1251  unref_pvt(pvt);
1252 
1253  return CLI_SUCCESS;
1254 }
1255 
1256 static struct ast_cli_entry cli_console[] = {
1257  AST_CLI_DEFINE(cli_console_dial, "Dial an extension from the console"),
1258  AST_CLI_DEFINE(cli_console_hangup, "Hangup a call on the console"),
1259  AST_CLI_DEFINE(cli_console_mute, "Disable/Enable mic input"),
1260  AST_CLI_DEFINE(cli_console_answer, "Answer an incoming console call"),
1261  AST_CLI_DEFINE(cli_console_sendtext, "Send text to a connected party"),
1262  AST_CLI_DEFINE(cli_console_flash, "Send a flash to the connected party"),
1263  AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
1264  AST_CLI_DEFINE(cli_list_available, "List available devices"),
1265  AST_CLI_DEFINE(cli_list_devices, "List configured devices"),
1266  AST_CLI_DEFINE(cli_console_active, "View or Set the active console device"),
1267 };
1268 
1269 /*!
1270  * \brief Set default values for a pvt struct
1271  *
1272  * \note This function expects the pvt lock to be held.
1273  */
1274 static void set_pvt_defaults(struct console_pvt *pvt)
1275 {
1276  if (pvt == &globals) {
1277  ast_string_field_set(pvt, mohinterpret, "default");
1278  ast_string_field_set(pvt, context, "default");
1279  ast_string_field_set(pvt, exten, "s");
1280  ast_string_field_set(pvt, language, "");
1281  ast_string_field_set(pvt, cid_num, "");
1282  ast_string_field_set(pvt, cid_name, "");
1283  ast_string_field_set(pvt, parkinglot, "");
1284 
1285  pvt->overridecontext = 0;
1286  pvt->autoanswer = 0;
1287  } else {
1289 
1297 
1299  pvt->autoanswer = globals.autoanswer;
1300 
1302  }
1303 }
1304 
1305 static void store_callerid(struct console_pvt *pvt, const char *value)
1306 {
1307  char cid_name[256];
1308  char cid_num[256];
1309 
1310  ast_callerid_split(value, cid_name, sizeof(cid_name),
1311  cid_num, sizeof(cid_num));
1312 
1313  ast_string_field_set(pvt, cid_name, cid_name);
1314  ast_string_field_set(pvt, cid_num, cid_num);
1315 }
1316 
1317 /*!
1318  * \brief Store a configuration parameter in a pvt struct
1319  *
1320  * \note This function expects the pvt lock to be held.
1321  */
1322 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
1323 {
1324  if (pvt == &globals && !ast_jb_read_conf(&global_jbconf, var, value))
1325  return;
1326 
1327  CV_START(var, value);
1328 
1329  CV_STRFIELD("context", pvt, context);
1330  CV_STRFIELD("extension", pvt, exten);
1331  CV_STRFIELD("mohinterpret", pvt, mohinterpret);
1332  CV_STRFIELD("language", pvt, language);
1333  CV_F("callerid", store_callerid(pvt, value));
1334  CV_BOOL("overridecontext", pvt->overridecontext);
1335  CV_BOOL("autoanswer", pvt->autoanswer);
1336  CV_STRFIELD("parkinglot", pvt, parkinglot);
1337 
1338  if (pvt != &globals) {
1339  CV_F("active", set_active(pvt, value))
1340  CV_STRFIELD("input_device", pvt, input_device);
1341  CV_STRFIELD("output_device", pvt, output_device);
1342  }
1343 
1344  ast_log(LOG_WARNING, "Unknown option '%s'\n", var);
1345 
1346  CV_END;
1347 }
1348 
1349 static void pvt_destructor(void *obj)
1350 {
1351  struct console_pvt *pvt = obj;
1352 
1354 }
1355 
1356 static int init_pvt(struct console_pvt *pvt, const char *name)
1357 {
1358  pvt->thread = AST_PTHREADT_NULL;
1359 
1360  if (ast_string_field_init(pvt, 32))
1361  return -1;
1362 
1363  ast_string_field_set(pvt, name, S_OR(name, ""));
1364 
1365  return 0;
1366 }
1367 
1368 static void build_device(struct ast_config *cfg, const char *name)
1369 {
1370  struct ast_variable *v;
1371  struct console_pvt *pvt;
1372  int new = 0;
1373 
1374  if ((pvt = find_pvt(name))) {
1375  console_pvt_lock(pvt);
1376  set_pvt_defaults(pvt);
1377  pvt->destroy = 0;
1378  } else {
1379  if (!(pvt = ao2_alloc(sizeof(*pvt), pvt_destructor)))
1380  return;
1381  init_pvt(pvt, name);
1382  set_pvt_defaults(pvt);
1383  new = 1;
1384  }
1385 
1386  for (v = ast_variable_browse(cfg, name); v; v = v->next)
1387  store_config_core(pvt, v->name, v->value);
1388 
1389  if (new)
1390  ao2_link(pvts, pvt);
1391  else
1392  console_pvt_unlock(pvt);
1393 
1394  unref_pvt(pvt);
1395 }
1396 
1397 static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
1398 {
1399  struct console_pvt *pvt = obj;
1400  pvt->destroy = 1;
1401  return 0;
1402 }
1403 
1404 static void destroy_pvts(void)
1405 {
1406  struct ao2_iterator i;
1407  struct console_pvt *pvt;
1408 
1409  i = ao2_iterator_init(pvts, 0);
1410  while ((pvt = ao2_iterator_next(&i))) {
1411  if (pvt->destroy) {
1412  ao2_unlink(pvts, pvt);
1414  if (active_pvt == pvt)
1415  active_pvt = unref_pvt(pvt);
1417  }
1418  unref_pvt(pvt);
1419  }
1421 }
1422 
1423 /*!
1424  * \brief Load the configuration
1425  * \param reload if this was called due to a reload
1426  * \retval 0 success
1427  * \retval -1 failure
1428  */
1429 static int load_config(int reload)
1430 {
1431  struct ast_config *cfg;
1432  struct ast_variable *v;
1433  struct ast_flags config_flags = { 0 };
1434  char *context = NULL;
1435 
1436  /* default values */
1437  memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
1441 
1442  if (!(cfg = ast_config_load(config_file, config_flags))) {
1443  ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
1444  return -1;
1445  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1446  ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file);
1447  return -1;
1448  }
1449 
1451 
1453  for (v = ast_variable_browse(cfg, "general"); v; v = v->next)
1454  store_config_core(&globals, v->name, v->value);
1456 
1457  while ((context = ast_category_browse(cfg, context))) {
1458  if (strcasecmp(context, "general"))
1459  build_device(cfg, context);
1460  }
1461 
1462  ast_config_destroy(cfg);
1463 
1464  destroy_pvts();
1465 
1466  return 0;
1467 }
1468 
1469 static int pvt_hash_cb(const void *obj, const int flags)
1470 {
1471  const struct console_pvt *pvt = obj;
1472 
1473  return ast_str_case_hash(pvt->name);
1474 }
1475 
1476 static int pvt_cmp_cb(void *obj, void *arg, int flags)
1477 {
1478  struct console_pvt *pvt = obj, *pvt2 = arg;
1479 
1480  return !strcasecmp(pvt->name, pvt2->name) ? CMP_MATCH | CMP_STOP : 0;
1481 }
1482 
1483 static void stop_streams(void)
1484 {
1485  struct console_pvt *pvt;
1486  struct ao2_iterator i;
1487 
1488  i = ao2_iterator_init(pvts, 0);
1489  while ((pvt = ao2_iterator_next(&i))) {
1490  if (pvt->hookstate)
1491  stop_stream(pvt);
1492  unref_pvt(pvt);
1493  }
1495 }
1496 
1497 static int unload_module(void)
1498 {
1499  ao2_ref(console_tech.capabilities, -1);
1500  console_tech.capabilities = NULL;
1501  ast_channel_unregister(&console_tech);
1502  ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
1503 
1504  stop_streams();
1505 
1506  Pa_Terminate();
1507 
1508  /* Will unref all the pvts so they will get destroyed, too */
1509  ao2_ref(pvts, -1);
1510 
1512 
1513  return 0;
1514 }
1515 
1516 /*!
1517  * \brief Load the module
1518  *
1519  * Module loading including tests for configuration or dependencies.
1520  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1521  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1522  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1523  * configuration file or other non-critical problem return
1524  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1525  */
1526 static int load_module(void)
1527 {
1528  PaError res;
1529 
1531  return AST_MODULE_LOAD_DECLINE;
1532  }
1534 
1535  init_pvt(&globals, NULL);
1536 
1539  if (!pvts)
1540  goto return_error;
1541 
1542  if (load_config(0))
1543  goto return_error;
1544 
1545  res = Pa_Initialize();
1546  if (res != paNoError) {
1547  ast_log(LOG_WARNING, "Failed to initialize audio system - (%d) %s\n",
1548  res, Pa_GetErrorText(res));
1549  goto return_error_pa_init;
1550  }
1551 
1552  if (ast_channel_register(&console_tech)) {
1553  ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
1554  goto return_error_chan_reg;
1555  }
1556 
1557  if (ast_cli_register_multiple(cli_console, ARRAY_LEN(cli_console)))
1558  goto return_error_cli_reg;
1559 
1560  return AST_MODULE_LOAD_SUCCESS;
1561 
1562 return_error_cli_reg:
1563  ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
1564 return_error_chan_reg:
1565  ast_channel_unregister(&console_tech);
1566 return_error_pa_init:
1567  Pa_Terminate();
1568 return_error:
1569  if (pvts)
1570  ao2_ref(pvts, -1);
1571  pvts = NULL;
1572  ao2_ref(console_tech.capabilities, -1);
1573  console_tech.capabilities = NULL;
1575 
1576  return AST_MODULE_LOAD_DECLINE;
1577 }
1578 
1579 static int reload(void)
1580 {
1581  return load_config(1);
1582 }
1583 
1584 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
1585  .support_level = AST_MODULE_SUPPORT_EXTENDED,
1586  .load = load_module,
1587  .unload = unload_module,
1588  .reload = reload,
1589  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
1590 );
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_variable * next
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
static const char type[]
Definition: chan_ooh323.c:109
static int open_stream(struct console_pvt *pvt)
Definition: chan_console.c:297
struct ast_frame fr
Definition: chan_console.c:154
static char * cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Console send text CLI command.
char digit
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
Main Channel structure associated with a channel.
static int pvt_hash_cb(const void *obj, const int flags)
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 AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int console_call(struct ast_channel *c, const char *dest, int timeout)
Definition: chan_console.c:582
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
static void stop_streams(void)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1092
static void build_device(struct ast_config *cfg, const char *name)
unsigned int muted
Definition: chan_console.c:160
const ast_string_field cid_num
Definition: chan_console.c:148
static char * cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:802
static char * cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
#define ast_join(s, len, w)
Definition: strings.h:483
short int16_t
Definition: db.h:59
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)
PaStream * stream
Definition: chan_console.c:152
static char * cli_console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:714
#define AST_CAUSE_SWITCH_CONGESTION
Definition: causes.h:122
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:4322
static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_console.c:660
const ast_string_field context
Definition: chan_console.c:148
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
static int reload(void)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
static void set_pvt_defaults(struct console_pvt *pvt)
Set default values for a pvt struct.
unsigned int destroy
Definition: chan_console.c:167
#define OBJ_POINTER
Definition: astobj2.h:1154
static struct ast_jb_conf global_jbconf
Definition: chan_console.c:193
static char * cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:918
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 AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
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 int timeout
Definition: cdr_mysql.c:86
static char * cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:879
unsigned int flags
Definition: utils.h:200
Structure for variables, used for configurations and for channel variables.
unsigned int overridecontext
Definition: chan_console.c:164
#define var
Definition: ast_expr2f.c:614
Definition: cli.h:152
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
Definition: chan_console.c:623
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int load_config(int reload)
Load the configuration.
ast_control_frame_type
Internal control frame subtype field values.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
static int start_stream(struct console_pvt *pvt)
Definition: chan_console.c:358
#define ast_mutex_lock(a)
Definition: lock.h:187
struct ast_channel * owner
Definition: chan_console.c:150
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:539
static int console_digit_begin(struct ast_channel *c, char digit)
Definition: chan_console.c:507
char * text
Definition: app_queue.c:1508
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const ast_string_field parkinglot
Definition: chan_console.c:148
static int unload_module(void)
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
static ast_mutex_t globals_lock
Definition: chan_console.c:172
static struct console_pvt * unref_pvt(struct console_pvt *pvt)
Definition: chan_console.c:240
#define NULL
Definition: resample.c:96
const char * data
#define CV_END
close a variable parsing block
static char * cli_list_available(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:960
#define SAMPLE_RATE
The sample rate to request from PortAudio.
Definition: chan_console.c:86
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static int console_hangup(struct ast_channel *c)
Definition: chan_console.c:529
#define AST_FRAME_DTMF
#define ast_rwlock_unlock(a)
Definition: lock.h:232
const char * ext
Definition: http.c:147
#define CV_START(__in_var, __in_val)
the macro to open a block for variable parsing
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
#define ast_verb(level,...)
Definition: logger.h:463
unsigned int autoanswer
Definition: chan_console.c:162
struct ast_frame_subclass subclass
static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration)
Definition: chan_console.c:514
static void store_callerid(struct console_pvt *pvt, const char *value)
int args
This gets set in ast_cli_register()
Definition: cli.h:185
Console pvt structure.
Definition: chan_console.c:126
static struct ast_frame * console_read(struct ast_channel *chan)
Definition: chan_console.c:575
#define ast_strlen_zero(foo)
Definition: strings.h:52
static char * ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
Definition: chan_console.c:680
static struct ast_jb_conf default_jbconf
Global jitterbuffer configuration.
Definition: chan_console.c:186
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
Number structure.
Definition: app_followme.c:154
static struct ast_channel_tech console_tech
Definition: chan_console.c:211
#define CV_F(__pattern, __body)
call a generic function if the name matches.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static struct ast_cli_entry cli_console[]
static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
General Asterisk PBX channel definitions.
#define TEXT_SIZE
Maximum text message length.
Definition: chan_console.c:111
const int fd
Definition: cli.h:159
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
#define AST_PTHREADT_NULL
Definition: lock.h:66
const int n
Definition: cli.h:165
ast_cond_t cond
Definition: app_meetme.c:1090
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define NUM_SAMPLES
The number of samples to configure the portaudio stream for.
Definition: chan_console.c:98
#define console_pvt_unlock(pvt)
unlock a console_pvt struct
Definition: chan_console.c:231
#define CV_STRFIELD(__x, __obj, __field)
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static struct ast_channel * console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_console.c:423
static struct console_pvt globals
static struct ao2_container * pvts
Definition: chan_console.c:174
unsigned int hookstate
Definition: chan_console.c:158
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
static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
Store a configuration parameter in a pvt struct.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
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:1139
#define OUTPUT_CHANNELS
Mono Output.
Definition: chan_console.c:104
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.
const ast_string_field language
Definition: chan_console.c:148
static void * stream_monitor(void *data)
Stream monitor thread.
Definition: chan_console.c:265
static int init_pvt(struct console_pvt *pvt, const char *name)
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
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 ao2_unlink(container, obj)
Definition: astobj2.h:1598
static char * cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
answer command from the console
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CV_BOOL(__x, __dst)
helper macros to assign the value to a BOOL, UINT, static string and dynamic string ...
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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:7866
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define V_END
Definition: chan_console.c:115
#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
pthread_t thread
Definition: chan_console.c:169
struct ast_format_cap * capabilities
Definition: channel.h:633
static void set_active(struct console_pvt *pvt, const char *value)
static int load_module(void)
Load the module.
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static int console_write(struct ast_channel *chan, struct ast_frame *f)
Definition: chan_console.c:612
static ast_rwlock_t active_lock
Definition: chan_console.c:178
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int console_text(struct ast_channel *c, const char *text)
Definition: chan_console.c:522
static struct console_pvt * ref_pvt(struct console_pvt *pvt)
Definition: chan_console.c:233
const ast_string_field input_device
Definition: chan_console.c:148
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
#define INPUT_CHANNELS
Mono Input.
Definition: chan_console.c:101
const char * word
Definition: cli.h:163
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define V_BEGIN
Dance, Kirby, Dance!
Definition: chan_console.c:114
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition: abstract_jb.h:72
#define NUM_PVT_BUCKETS
Definition: chan_console.c:175
Structure used to handle boolean flags.
Definition: utils.h:199
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",)
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
static struct ast_channel * console_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_console.c:471
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
static void destroy_pvts(void)
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define CLI_SUCCESS
Definition: cli.h:44
static struct console_pvt * active_pvt
Definition: chan_console.c:177
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
Standard Command Line Interface.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
const int pos
Definition: cli.h:164
unsigned int streamstate
Definition: chan_console.c:156
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
static int pvt_cmp_cb(void *obj, void *arg, int flags)
#define AST_CAUSE_BUSY
Definition: causes.h:148
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
const ast_string_field mohinterpret
Definition: chan_console.c:148
static char * cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_console.c:763
struct ast_format * ast_format_slin16
Built-in cached signed linear 16kHz format.
Definition: format_cache.c:51
static struct console_pvt * get_active_pvt(void)
Definition: chan_console.c:703
union ast_frame::@263 data
const ast_string_field output_device
Definition: chan_console.c:148
enum ast_frame_type frametype
#define console_pvt_lock(pvt)
lock a console_pvt struct
Definition: chan_console.c:228
Generic container type.
static int console_answer(struct ast_channel *c)
Definition: chan_console.c:544
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
Asterisk module definitions.
static struct console_pvt * find_pvt(const char *name)
Definition: chan_console.c:246
const ast_string_field name
Definition: chan_console.c:148
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
General jitterbuffer configuration.
Definition: abstract_jb.h:69
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int stop_stream(struct console_pvt *pvt)
Definition: chan_console.c:401
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
const ast_string_field cid_name
Definition: chan_console.c:148
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250
const ast_string_field exten
Definition: chan_console.c:148
static const char config_file[]
Definition: chan_console.c:118
Media Format Cache API.
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549
static void pvt_destructor(void *obj)
int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
Determine if any joint capabilities exist between two capabilities structures.
Definition: format_cap.c:655