00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include "asterisk.h"
00056
00057 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00058
00059 #include <sys/signal.h>
00060
00061 #include <portaudio.h>
00062
00063 #include "asterisk/module.h"
00064 #include "asterisk/channel.h"
00065 #include "asterisk/pbx.h"
00066 #include "asterisk/causes.h"
00067 #include "asterisk/cli.h"
00068 #include "asterisk/musiconhold.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/astobj2.h"
00071
00072
00073
00074
00075
00076
00077
00078 #define SAMPLE_RATE 16000
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 #define NUM_SAMPLES 320
00091
00092
00093 #define INPUT_CHANNELS 1
00094
00095
00096 #define OUTPUT_CHANNELS 1
00097
00098
00099
00100
00101
00102
00103 #define TEXT_SIZE 256
00104
00105
00106 #define V_BEGIN " --- <(\"<) --- "
00107 #define V_END " --- (>\")> ---\n"
00108
00109
00110 static const char config_file[] = "console.conf";
00111
00112
00113
00114
00115
00116
00117
00118 static struct console_pvt {
00119 AST_DECLARE_STRING_FIELDS(
00120
00121 AST_STRING_FIELD(name);
00122 AST_STRING_FIELD(input_device);
00123 AST_STRING_FIELD(output_device);
00124
00125 AST_STRING_FIELD(context);
00126
00127 AST_STRING_FIELD(exten);
00128
00129 AST_STRING_FIELD(cid_num);
00130
00131 AST_STRING_FIELD(cid_name);
00132
00133
00134
00135 AST_STRING_FIELD(mohinterpret);
00136
00137 AST_STRING_FIELD(language);
00138
00139 AST_STRING_FIELD(parkinglot);
00140 );
00141
00142 struct ast_channel *owner;
00143
00144 PaStream *stream;
00145
00146 struct ast_frame fr;
00147
00148 unsigned int streamstate:1;
00149
00150 unsigned int hookstate:1;
00151
00152 unsigned int muted:1;
00153
00154 unsigned int autoanswer:1;
00155
00156 unsigned int overridecontext:1;
00157
00158
00159 unsigned int destroy:1;
00160
00161 pthread_t thread;
00162 } globals;
00163
00164 AST_MUTEX_DEFINE_STATIC(globals_lock);
00165
00166 static struct ao2_container *pvts;
00167 #define NUM_PVT_BUCKETS 7
00168
00169 static struct console_pvt *active_pvt;
00170 AST_RWLOCK_DEFINE_STATIC(active_lock);
00171
00172
00173
00174
00175
00176
00177
00178 static struct ast_jb_conf default_jbconf = {
00179 .flags = 0,
00180 .max_size = 200,
00181 .resync_threshold = 1000,
00182 .impl = "fixed",
00183 .target_extra = 40,
00184 };
00185 static struct ast_jb_conf global_jbconf;
00186
00187
00188 static struct ast_channel *console_request(const char *type, format_t format,
00189 const struct ast_channel *requestor, void *data, int *cause);
00190 static int console_digit_begin(struct ast_channel *c, char digit);
00191 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration);
00192 static int console_text(struct ast_channel *c, const char *text);
00193 static int console_hangup(struct ast_channel *c);
00194 static int console_answer(struct ast_channel *c);
00195 static struct ast_frame *console_read(struct ast_channel *chan);
00196 static int console_call(struct ast_channel *c, char *dest, int timeout);
00197 static int console_write(struct ast_channel *chan, struct ast_frame *f);
00198 static int console_indicate(struct ast_channel *chan, int cond,
00199 const void *data, size_t datalen);
00200 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00201
00202
00203
00204
00205
00206 #define SUPPORTED_FORMATS ( AST_FORMAT_SLINEAR16 )
00207
00208 static const struct ast_channel_tech console_tech = {
00209 .type = "Console",
00210 .description = "Console Channel Driver",
00211 .capabilities = SUPPORTED_FORMATS,
00212 .requester = console_request,
00213 .send_digit_begin = console_digit_begin,
00214 .send_digit_end = console_digit_end,
00215 .send_text = console_text,
00216 .hangup = console_hangup,
00217 .answer = console_answer,
00218 .read = console_read,
00219 .call = console_call,
00220 .write = console_write,
00221 .indicate = console_indicate,
00222 .fixup = console_fixup,
00223 };
00224
00225
00226 #define console_pvt_lock(pvt) ao2_lock(pvt)
00227
00228
00229 #define console_pvt_unlock(pvt) ao2_unlock(pvt)
00230
00231 static inline struct console_pvt *ref_pvt(struct console_pvt *pvt)
00232 {
00233 if (pvt)
00234 ao2_ref(pvt, +1);
00235 return pvt;
00236 }
00237
00238 static inline struct console_pvt *unref_pvt(struct console_pvt *pvt)
00239 {
00240 ao2_ref(pvt, -1);
00241 return NULL;
00242 }
00243
00244 static struct console_pvt *find_pvt(const char *name)
00245 {
00246 struct console_pvt tmp_pvt = {
00247 .name = name,
00248 };
00249
00250 return ao2_find(pvts, &tmp_pvt, OBJ_POINTER);
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 static void *stream_monitor(void *data)
00264 {
00265 struct console_pvt *pvt = data;
00266 char buf[NUM_SAMPLES * sizeof(int16_t)];
00267 PaError res;
00268 struct ast_frame f = {
00269 .frametype = AST_FRAME_VOICE,
00270 .subclass.codec = AST_FORMAT_SLINEAR16,
00271 .src = "console_stream_monitor",
00272 .data.ptr = buf,
00273 .datalen = sizeof(buf),
00274 .samples = sizeof(buf) / sizeof(int16_t),
00275 };
00276
00277 for (;;) {
00278 pthread_testcancel();
00279 res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
00280 pthread_testcancel();
00281
00282 if (!pvt->owner) {
00283 return NULL;
00284 }
00285
00286 if (res == paNoError)
00287 ast_queue_frame(pvt->owner, &f);
00288 }
00289
00290 return NULL;
00291 }
00292
00293 static int open_stream(struct console_pvt *pvt)
00294 {
00295 int res = paInternalError;
00296
00297 if (!strcasecmp(pvt->input_device, "default") &&
00298 !strcasecmp(pvt->output_device, "default")) {
00299 res = Pa_OpenDefaultStream(&pvt->stream, INPUT_CHANNELS, OUTPUT_CHANNELS,
00300 paInt16, SAMPLE_RATE, NUM_SAMPLES, NULL, NULL);
00301 } else {
00302 PaStreamParameters input_params = {
00303 .channelCount = 1,
00304 .sampleFormat = paInt16,
00305 .suggestedLatency = (1.0 / 50.0),
00306 .device = paNoDevice,
00307 };
00308 PaStreamParameters output_params = {
00309 .channelCount = 1,
00310 .sampleFormat = paInt16,
00311 .suggestedLatency = (1.0 / 50.0),
00312 .device = paNoDevice,
00313 };
00314 PaDeviceIndex idx, num_devices, def_input, def_output;
00315
00316 if (!(num_devices = Pa_GetDeviceCount()))
00317 return res;
00318
00319 def_input = Pa_GetDefaultInputDevice();
00320 def_output = Pa_GetDefaultOutputDevice();
00321
00322 for (idx = 0;
00323 idx < num_devices && (input_params.device == paNoDevice
00324 || output_params.device == paNoDevice);
00325 idx++)
00326 {
00327 const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
00328
00329 if (dev->maxInputChannels) {
00330 if ( (idx == def_input && !strcasecmp(pvt->input_device, "default")) ||
00331 !strcasecmp(pvt->input_device, dev->name) )
00332 input_params.device = idx;
00333 }
00334
00335 if (dev->maxOutputChannels) {
00336 if ( (idx == def_output && !strcasecmp(pvt->output_device, "default")) ||
00337 !strcasecmp(pvt->output_device, dev->name) )
00338 output_params.device = idx;
00339 }
00340 }
00341
00342 if (input_params.device == paNoDevice)
00343 ast_log(LOG_ERROR, "No input device found for console device '%s'\n", pvt->name);
00344 if (output_params.device == paNoDevice)
00345 ast_log(LOG_ERROR, "No output device found for console device '%s'\n", pvt->name);
00346
00347 res = Pa_OpenStream(&pvt->stream, &input_params, &output_params,
00348 SAMPLE_RATE, NUM_SAMPLES, paNoFlag, NULL, NULL);
00349 }
00350
00351 return res;
00352 }
00353
00354 static int start_stream(struct console_pvt *pvt)
00355 {
00356 PaError res;
00357 int ret_val = 0;
00358
00359 console_pvt_lock(pvt);
00360
00361
00362
00363
00364 if (pvt->streamstate || !pvt->owner)
00365 goto return_unlock;
00366
00367 pvt->streamstate = 1;
00368 ast_debug(1, "Starting stream\n");
00369
00370 res = open_stream(pvt);
00371 if (res != paNoError) {
00372 ast_log(LOG_WARNING, "Failed to open stream - (%d) %s\n",
00373 res, Pa_GetErrorText(res));
00374 ret_val = -1;
00375 goto return_unlock;
00376 }
00377
00378 res = Pa_StartStream(pvt->stream);
00379 if (res != paNoError) {
00380 ast_log(LOG_WARNING, "Failed to start stream - (%d) %s\n",
00381 res, Pa_GetErrorText(res));
00382 ret_val = -1;
00383 goto return_unlock;
00384 }
00385
00386 if (ast_pthread_create_background(&pvt->thread, NULL, stream_monitor, pvt)) {
00387 ast_log(LOG_ERROR, "Failed to start stream monitor thread\n");
00388 ret_val = -1;
00389 }
00390
00391 return_unlock:
00392 console_pvt_unlock(pvt);
00393
00394 return ret_val;
00395 }
00396
00397 static int stop_stream(struct console_pvt *pvt)
00398 {
00399 if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
00400 return 0;
00401
00402 pthread_cancel(pvt->thread);
00403 pthread_kill(pvt->thread, SIGURG);
00404 pthread_join(pvt->thread, NULL);
00405
00406 console_pvt_lock(pvt);
00407 Pa_AbortStream(pvt->stream);
00408 Pa_CloseStream(pvt->stream);
00409 pvt->stream = NULL;
00410 pvt->streamstate = 0;
00411 console_pvt_unlock(pvt);
00412
00413 return 0;
00414 }
00415
00416
00417
00418
00419 static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, const char *ctx, int state, const char *linkedid)
00420 {
00421 struct ast_channel *chan;
00422
00423 if (!(chan = ast_channel_alloc(1, state, pvt->cid_num, pvt->cid_name, NULL,
00424 ext, ctx, linkedid, 0, "Console/%s", pvt->name))) {
00425 return NULL;
00426 }
00427
00428 chan->tech = &console_tech;
00429 chan->nativeformats = AST_FORMAT_SLINEAR16;
00430 chan->readformat = AST_FORMAT_SLINEAR16;
00431 chan->writeformat = AST_FORMAT_SLINEAR16;
00432 chan->tech_pvt = ref_pvt(pvt);
00433
00434 pvt->owner = chan;
00435
00436 if (!ast_strlen_zero(pvt->language))
00437 ast_string_field_set(chan, language, pvt->language);
00438
00439 ast_jb_configure(chan, &global_jbconf);
00440
00441 if (state != AST_STATE_DOWN) {
00442 if (ast_pbx_start(chan)) {
00443 chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
00444 ast_hangup(chan);
00445 chan = NULL;
00446 } else
00447 start_stream(pvt);
00448 }
00449
00450 return chan;
00451 }
00452
00453 static struct ast_channel *console_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
00454 {
00455 format_t oldformat = format;
00456 struct ast_channel *chan = NULL;
00457 struct console_pvt *pvt;
00458 char buf[512];
00459
00460 if (!(pvt = find_pvt(data))) {
00461 ast_log(LOG_ERROR, "Console device '%s' not found\n", (char *) data);
00462 return NULL;
00463 }
00464
00465 format &= SUPPORTED_FORMATS;
00466 if (!format) {
00467 ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), oldformat));
00468 goto return_unref;
00469 }
00470
00471 if (pvt->owner) {
00472 ast_log(LOG_NOTICE, "Console channel already active!\n");
00473 *cause = AST_CAUSE_BUSY;
00474 goto return_unref;
00475 }
00476
00477 console_pvt_lock(pvt);
00478 chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00479 console_pvt_unlock(pvt);
00480
00481 if (!chan)
00482 ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
00483
00484 return_unref:
00485 unref_pvt(pvt);
00486
00487 return chan;
00488 }
00489
00490 static int console_digit_begin(struct ast_channel *c, char digit)
00491 {
00492 ast_verb(1, V_BEGIN "Console Received Beginning of Digit %c" V_END, digit);
00493
00494 return -1;
00495 }
00496
00497 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00498 {
00499 ast_verb(1, V_BEGIN "Console Received End of Digit %c (duration %u)" V_END,
00500 digit, duration);
00501
00502 return -1;
00503 }
00504
00505 static int console_text(struct ast_channel *c, const char *text)
00506 {
00507 ast_verb(1, V_BEGIN "Console Received Text '%s'" V_END, text);
00508
00509 return 0;
00510 }
00511
00512 static int console_hangup(struct ast_channel *c)
00513 {
00514 struct console_pvt *pvt = c->tech_pvt;
00515
00516 ast_verb(1, V_BEGIN "Hangup on Console" V_END);
00517
00518 pvt->hookstate = 0;
00519 pvt->owner = NULL;
00520 stop_stream(pvt);
00521
00522 c->tech_pvt = unref_pvt(pvt);
00523
00524 return 0;
00525 }
00526
00527 static int console_answer(struct ast_channel *c)
00528 {
00529 struct console_pvt *pvt = c->tech_pvt;
00530
00531 ast_verb(1, V_BEGIN "Call from Console has been Answered" V_END);
00532
00533 ast_setstate(c, AST_STATE_UP);
00534
00535 return start_stream(pvt);
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 static struct ast_frame *console_read(struct ast_channel *chan)
00559 {
00560 ast_debug(1, "I should not be called ...\n");
00561
00562 return &ast_null_frame;
00563 }
00564
00565 static int console_call(struct ast_channel *c, char *dest, int timeout)
00566 {
00567 struct console_pvt *pvt = c->tech_pvt;
00568 enum ast_control_frame_type ctrl;
00569
00570 ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
00571 dest,
00572 S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00573 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
00574
00575 console_pvt_lock(pvt);
00576
00577 if (pvt->autoanswer) {
00578 pvt->hookstate = 1;
00579 console_pvt_unlock(pvt);
00580 ast_verb(1, V_BEGIN "Auto-answered" V_END);
00581 ctrl = AST_CONTROL_ANSWER;
00582 } else {
00583 console_pvt_unlock(pvt);
00584 ast_verb(1, V_BEGIN "Type 'console answer' to answer, or use the 'autoanswer' option "
00585 "for future calls" V_END);
00586 ctrl = AST_CONTROL_RINGING;
00587 ast_indicate(c, AST_CONTROL_RINGING);
00588 }
00589
00590 ast_queue_control(c, ctrl);
00591
00592 return start_stream(pvt);
00593 }
00594
00595 static int console_write(struct ast_channel *chan, struct ast_frame *f)
00596 {
00597 struct console_pvt *pvt = chan->tech_pvt;
00598
00599 Pa_WriteStream(pvt->stream, f->data.ptr, f->samples);
00600
00601 return 0;
00602 }
00603
00604 static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
00605 {
00606 struct console_pvt *pvt = chan->tech_pvt;
00607 int res = 0;
00608
00609 switch (cond) {
00610 case AST_CONTROL_BUSY:
00611 case AST_CONTROL_CONGESTION:
00612 case AST_CONTROL_RINGING:
00613 case -1:
00614 res = -1;
00615 break;
00616 case AST_CONTROL_PROGRESS:
00617 case AST_CONTROL_PROCEEDING:
00618 case AST_CONTROL_VIDUPDATE:
00619 case AST_CONTROL_SRCUPDATE:
00620 break;
00621 case AST_CONTROL_HOLD:
00622 ast_verb(1, V_BEGIN "Console Has Been Placed on Hold" V_END);
00623 ast_moh_start(chan, data, pvt->mohinterpret);
00624 break;
00625 case AST_CONTROL_UNHOLD:
00626 ast_verb(1, V_BEGIN "Console Has Been Retrieved from Hold" V_END);
00627 ast_moh_stop(chan);
00628 break;
00629 default:
00630 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n",
00631 cond, chan->name);
00632
00633 res = -1;
00634 }
00635
00636 return res;
00637 }
00638
00639 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00640 {
00641 struct console_pvt *pvt = newchan->tech_pvt;
00642
00643 pvt->owner = newchan;
00644
00645 return 0;
00646 }
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659 static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
00660 {
00661 if (ext == NULL || ctx == NULL)
00662 return NULL;
00663
00664 *ext = *ctx = NULL;
00665
00666 if (src && *src != '\0')
00667 *ext = ast_strdup(src);
00668
00669 if (*ext == NULL)
00670 return NULL;
00671
00672 if (!pvt->overridecontext) {
00673
00674 *ctx = strrchr(*ext, '@');
00675 if (*ctx)
00676 *(*ctx)++ = '\0';
00677 }
00678
00679 return *ext;
00680 }
00681
00682 static struct console_pvt *get_active_pvt(void)
00683 {
00684 struct console_pvt *pvt;
00685
00686 ast_rwlock_rdlock(&active_lock);
00687 pvt = ref_pvt(active_pvt);
00688 ast_rwlock_unlock(&active_lock);
00689
00690 return pvt;
00691 }
00692
00693 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
00694 struct ast_cli_args *a)
00695 {
00696 struct console_pvt *pvt = get_active_pvt();
00697 char *res = CLI_SUCCESS;
00698
00699 switch (cmd) {
00700 case CLI_INIT:
00701 e->command = "console {set|show} autoanswer [on|off]";
00702 e->usage =
00703 "Usage: console {set|show} autoanswer [on|off]\n"
00704 " Enables or disables autoanswer feature. If used without\n"
00705 " argument, displays the current on/off status of autoanswer.\n"
00706 " The default value of autoanswer is in 'oss.conf'.\n";
00707 return NULL;
00708
00709 case CLI_GENERATE:
00710 return NULL;
00711 }
00712
00713 if (!pvt) {
00714 ast_cli(a->fd, "No console device is set as active.\n");
00715 return CLI_FAILURE;
00716 }
00717
00718 if (a->argc == e->args - 1) {
00719 ast_cli(a->fd, "Auto answer is %s.\n", pvt->autoanswer ? "on" : "off");
00720 unref_pvt(pvt);
00721 return CLI_SUCCESS;
00722 }
00723
00724 if (a->argc != e->args) {
00725 unref_pvt(pvt);
00726 return CLI_SHOWUSAGE;
00727 }
00728
00729 if (!strcasecmp(a->argv[e->args-1], "on"))
00730 pvt->autoanswer = 1;
00731 else if (!strcasecmp(a->argv[e->args - 1], "off"))
00732 pvt->autoanswer = 0;
00733 else
00734 res = CLI_SHOWUSAGE;
00735
00736 unref_pvt(pvt);
00737
00738 return res;
00739 }
00740
00741 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00742 {
00743 struct console_pvt *pvt = get_active_pvt();
00744
00745 if (cmd == CLI_INIT) {
00746 e->command = "console flash";
00747 e->usage =
00748 "Usage: console flash\n"
00749 " Flashes the call currently placed on the console.\n";
00750 return NULL;
00751 } else if (cmd == CLI_GENERATE)
00752 return NULL;
00753
00754 if (!pvt) {
00755 ast_cli(a->fd, "No console device is set as active\n");
00756 return CLI_FAILURE;
00757 }
00758
00759 if (a->argc != e->args)
00760 return CLI_SHOWUSAGE;
00761
00762 if (!pvt->owner) {
00763 ast_cli(a->fd, "No call to flash\n");
00764 unref_pvt(pvt);
00765 return CLI_FAILURE;
00766 }
00767
00768 pvt->hookstate = 0;
00769
00770 ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
00771
00772 unref_pvt(pvt);
00773
00774 return CLI_SUCCESS;
00775 }
00776
00777 static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00778 {
00779 char *s = NULL;
00780 const char *mye = NULL, *myc = NULL;
00781 struct console_pvt *pvt = get_active_pvt();
00782
00783 if (cmd == CLI_INIT) {
00784 e->command = "console dial";
00785 e->usage =
00786 "Usage: console dial [extension[@context]]\n"
00787 " Dials a given extension (and context if specified)\n";
00788 return NULL;
00789 } else if (cmd == CLI_GENERATE)
00790 return NULL;
00791
00792 if (!pvt) {
00793 ast_cli(a->fd, "No console device is currently set as active\n");
00794 return CLI_FAILURE;
00795 }
00796
00797 if (a->argc > e->args + 1)
00798 return CLI_SHOWUSAGE;
00799
00800 if (pvt->owner) {
00801 int i;
00802 struct ast_frame f = { AST_FRAME_DTMF };
00803 const char *s;
00804
00805 if (a->argc == e->args) {
00806 ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
00807 unref_pvt(pvt);
00808 return CLI_FAILURE;
00809 }
00810 s = a->argv[e->args];
00811
00812 for (i = 0; i < strlen(s); i++) {
00813 f.subclass.integer = s[i];
00814 ast_queue_frame(pvt->owner, &f);
00815 }
00816 unref_pvt(pvt);
00817 return CLI_SUCCESS;
00818 }
00819
00820
00821 if (a->argc == e->args + 1) {
00822 char *ext = NULL, *con = NULL;
00823 s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
00824 ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
00825 a->argv[e->args], mye, myc);
00826 mye = ext;
00827 myc = con;
00828 }
00829
00830
00831 if (ast_strlen_zero(mye))
00832 mye = pvt->exten;
00833 if (ast_strlen_zero(myc))
00834 myc = pvt->context;
00835
00836 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00837 console_pvt_lock(pvt);
00838 pvt->hookstate = 1;
00839 console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
00840 console_pvt_unlock(pvt);
00841 } else
00842 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00843
00844 free(s);
00845
00846 unref_pvt(pvt);
00847
00848 return CLI_SUCCESS;
00849 }
00850
00851 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00852 {
00853 struct console_pvt *pvt = get_active_pvt();
00854
00855 if (cmd == CLI_INIT) {
00856 e->command = "console hangup";
00857 e->usage =
00858 "Usage: console hangup\n"
00859 " Hangs up any call currently placed on the console.\n";
00860 return NULL;
00861 } else if (cmd == CLI_GENERATE)
00862 return NULL;
00863
00864 if (!pvt) {
00865 ast_cli(a->fd, "No console device is set as active\n");
00866 return CLI_FAILURE;
00867 }
00868
00869 if (a->argc != e->args)
00870 return CLI_SHOWUSAGE;
00871
00872 if (!pvt->owner && !pvt->hookstate) {
00873 ast_cli(a->fd, "No call to hang up\n");
00874 unref_pvt(pvt);
00875 return CLI_FAILURE;
00876 }
00877
00878 pvt->hookstate = 0;
00879 if (pvt->owner)
00880 ast_queue_hangup(pvt->owner);
00881
00882 unref_pvt(pvt);
00883
00884 return CLI_SUCCESS;
00885 }
00886
00887 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00888 {
00889 const char *s;
00890 struct console_pvt *pvt = get_active_pvt();
00891 char *res = CLI_SUCCESS;
00892
00893 if (cmd == CLI_INIT) {
00894 e->command = "console {mute|unmute}";
00895 e->usage =
00896 "Usage: console {mute|unmute}\n"
00897 " Mute/unmute the microphone.\n";
00898 return NULL;
00899 } else if (cmd == CLI_GENERATE)
00900 return NULL;
00901
00902 if (!pvt) {
00903 ast_cli(a->fd, "No console device is set as active\n");
00904 return CLI_FAILURE;
00905 }
00906
00907 if (a->argc != e->args)
00908 return CLI_SHOWUSAGE;
00909
00910 s = a->argv[e->args-1];
00911 if (!strcasecmp(s, "mute"))
00912 pvt->muted = 1;
00913 else if (!strcasecmp(s, "unmute"))
00914 pvt->muted = 0;
00915 else
00916 res = CLI_SHOWUSAGE;
00917
00918 ast_verb(1, V_BEGIN "The Console is now %s" V_END,
00919 pvt->muted ? "Muted" : "Unmuted");
00920
00921 unref_pvt(pvt);
00922
00923 return res;
00924 }
00925
00926 static char *cli_list_available(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00927 {
00928 PaDeviceIndex idx, num, def_input, def_output;
00929
00930 if (cmd == CLI_INIT) {
00931 e->command = "console list available";
00932 e->usage =
00933 "Usage: console list available\n"
00934 " List all available devices.\n";
00935 return NULL;
00936 } else if (cmd == CLI_GENERATE)
00937 return NULL;
00938
00939 if (a->argc != e->args)
00940 return CLI_SHOWUSAGE;
00941
00942 ast_cli(a->fd, "\n"
00943 "=============================================================\n"
00944 "=== Available Devices =======================================\n"
00945 "=============================================================\n"
00946 "===\n");
00947
00948 num = Pa_GetDeviceCount();
00949 if (!num) {
00950 ast_cli(a->fd, "(None)\n");
00951 return CLI_SUCCESS;
00952 }
00953
00954 def_input = Pa_GetDefaultInputDevice();
00955 def_output = Pa_GetDefaultOutputDevice();
00956 for (idx = 0; idx < num; idx++) {
00957 const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
00958 if (!dev)
00959 continue;
00960 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
00961 "=== Device Name: %s\n", dev->name);
00962 if (dev->maxInputChannels)
00963 ast_cli(a->fd, "=== ---> %sInput Device\n", (idx == def_input) ? "Default " : "");
00964 if (dev->maxOutputChannels)
00965 ast_cli(a->fd, "=== ---> %sOutput Device\n", (idx == def_output) ? "Default " : "");
00966 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
00967 }
00968
00969 ast_cli(a->fd, "=============================================================\n\n");
00970
00971 return CLI_SUCCESS;
00972 }
00973
00974 static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00975 {
00976 struct ao2_iterator i;
00977 struct console_pvt *pvt;
00978
00979 if (cmd == CLI_INIT) {
00980 e->command = "console list devices";
00981 e->usage =
00982 "Usage: console list devices\n"
00983 " List all configured devices.\n";
00984 return NULL;
00985 } else if (cmd == CLI_GENERATE)
00986 return NULL;
00987
00988 if (a->argc != e->args)
00989 return CLI_SHOWUSAGE;
00990
00991 ast_cli(a->fd, "\n"
00992 "=============================================================\n"
00993 "=== Configured Devices ======================================\n"
00994 "=============================================================\n"
00995 "===\n");
00996
00997 i = ao2_iterator_init(pvts, 0);
00998 while ((pvt = ao2_iterator_next(&i))) {
00999 console_pvt_lock(pvt);
01000
01001 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01002 "=== Device Name: %s\n"
01003 "=== ---> Active: %s\n"
01004 "=== ---> Input Device: %s\n"
01005 "=== ---> Output Device: %s\n"
01006 "=== ---> Context: %s\n"
01007 "=== ---> Extension: %s\n"
01008 "=== ---> CallerID Num: %s\n"
01009 "=== ---> CallerID Name: %s\n"
01010 "=== ---> MOH Interpret: %s\n"
01011 "=== ---> Language: %s\n"
01012 "=== ---> Parkinglot: %s\n"
01013 "=== ---> Muted: %s\n"
01014 "=== ---> Auto-Answer: %s\n"
01015 "=== ---> Override Context: %s\n"
01016 "=== ---------------------------------------------------------\n===\n",
01017 pvt->name, (pvt == active_pvt) ? "Yes" : "No",
01018 pvt->input_device, pvt->output_device, pvt->context,
01019 pvt->exten, pvt->cid_num, pvt->cid_name, pvt->mohinterpret,
01020 pvt->language, pvt->parkinglot, pvt->muted ? "Yes" : "No", pvt->autoanswer ? "Yes" : "No",
01021 pvt->overridecontext ? "Yes" : "No");
01022
01023 console_pvt_unlock(pvt);
01024 unref_pvt(pvt);
01025 }
01026 ao2_iterator_destroy(&i);
01027
01028 ast_cli(a->fd, "=============================================================\n\n");
01029
01030 return CLI_SUCCESS;
01031 }
01032
01033
01034
01035 static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01036 {
01037 struct console_pvt *pvt = get_active_pvt();
01038
01039 switch (cmd) {
01040 case CLI_INIT:
01041 e->command = "console answer";
01042 e->usage =
01043 "Usage: console answer\n"
01044 " Answers an incoming call on the console channel.\n";
01045 return NULL;
01046
01047 case CLI_GENERATE:
01048 return NULL;
01049 }
01050
01051 if (!pvt) {
01052 ast_cli(a->fd, "No console device is set as active\n");
01053 return CLI_FAILURE;
01054 }
01055
01056 if (a->argc != e->args) {
01057 unref_pvt(pvt);
01058 return CLI_SHOWUSAGE;
01059 }
01060
01061 if (!pvt->owner) {
01062 ast_cli(a->fd, "No one is calling us\n");
01063 unref_pvt(pvt);
01064 return CLI_FAILURE;
01065 }
01066
01067 pvt->hookstate = 1;
01068
01069 ast_indicate(pvt->owner, -1);
01070
01071 ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
01072
01073 unref_pvt(pvt);
01074
01075 return CLI_SUCCESS;
01076 }
01077
01078
01079
01080
01081
01082
01083
01084 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01085 {
01086 char buf[TEXT_SIZE];
01087 struct console_pvt *pvt = get_active_pvt();
01088 struct ast_frame f = {
01089 .frametype = AST_FRAME_TEXT,
01090 .data.ptr = buf,
01091 .src = "console_send_text",
01092 };
01093 int len;
01094
01095 if (cmd == CLI_INIT) {
01096 e->command = "console send text";
01097 e->usage =
01098 "Usage: console send text <message>\n"
01099 " Sends a text message for display on the remote terminal.\n";
01100 return NULL;
01101 } else if (cmd == CLI_GENERATE)
01102 return NULL;
01103
01104 if (!pvt) {
01105 ast_cli(a->fd, "No console device is set as active\n");
01106 return CLI_FAILURE;
01107 }
01108
01109 if (a->argc < e->args + 1) {
01110 unref_pvt(pvt);
01111 return CLI_SHOWUSAGE;
01112 }
01113
01114 if (!pvt->owner) {
01115 ast_cli(a->fd, "Not in a call\n");
01116 unref_pvt(pvt);
01117 return CLI_FAILURE;
01118 }
01119
01120 ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01121 if (ast_strlen_zero(buf)) {
01122 unref_pvt(pvt);
01123 return CLI_SHOWUSAGE;
01124 }
01125
01126 len = strlen(buf);
01127 buf[len] = '\n';
01128 f.datalen = len + 1;
01129
01130 ast_queue_frame(pvt->owner, &f);
01131
01132 unref_pvt(pvt);
01133
01134 return CLI_SUCCESS;
01135 }
01136
01137 static void set_active(struct console_pvt *pvt, const char *value)
01138 {
01139 if (pvt == &globals) {
01140 ast_log(LOG_ERROR, "active is only valid as a per-device setting\n");
01141 return;
01142 }
01143
01144 if (!ast_true(value))
01145 return;
01146
01147 ast_rwlock_wrlock(&active_lock);
01148 if (active_pvt)
01149 unref_pvt(active_pvt);
01150 active_pvt = ref_pvt(pvt);
01151 ast_rwlock_unlock(&active_lock);
01152 }
01153
01154 static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01155 {
01156 struct console_pvt *pvt;
01157
01158 switch (cmd) {
01159 case CLI_INIT:
01160 e->command = "console {set|show} active";
01161 e->usage =
01162 "Usage: console {set|show} active [<device>]\n"
01163 " Set or show the active console device for the Asterisk CLI.\n";
01164 return NULL;
01165 case CLI_GENERATE:
01166 if (a->pos == e->args) {
01167 struct ao2_iterator i;
01168 int x = 0;
01169 char *res = NULL;
01170 i = ao2_iterator_init(pvts, 0);
01171 while ((pvt = ao2_iterator_next(&i))) {
01172 if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
01173 res = ast_strdup(pvt->name);
01174 unref_pvt(pvt);
01175 if (res) {
01176 ao2_iterator_destroy(&i);
01177 return res;
01178 }
01179 }
01180 ao2_iterator_destroy(&i);
01181 }
01182 return NULL;
01183 }
01184
01185 if (a->argc < e->args)
01186 return CLI_SHOWUSAGE;
01187
01188 if (a->argc == 3) {
01189 pvt = get_active_pvt();
01190
01191 if (!pvt)
01192 ast_cli(a->fd, "No device is currently set as the active console device.\n");
01193 else {
01194 console_pvt_lock(pvt);
01195 ast_cli(a->fd, "The active console device is '%s'.\n", pvt->name);
01196 console_pvt_unlock(pvt);
01197 pvt = unref_pvt(pvt);
01198 }
01199
01200 return CLI_SUCCESS;
01201 }
01202
01203 if (!(pvt = find_pvt(a->argv[e->args - 1]))) {
01204 ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
01205 return CLI_FAILURE;
01206 }
01207
01208 set_active(pvt, "yes");
01209
01210 console_pvt_lock(pvt);
01211 ast_cli(a->fd, "The active console device has been set to '%s'\n", pvt->name);
01212 console_pvt_unlock(pvt);
01213
01214 unref_pvt(pvt);
01215
01216 return CLI_SUCCESS;
01217 }
01218
01219 static struct ast_cli_entry cli_console[] = {
01220 AST_CLI_DEFINE(cli_console_dial, "Dial an extension from the console"),
01221 AST_CLI_DEFINE(cli_console_hangup, "Hangup a call on the console"),
01222 AST_CLI_DEFINE(cli_console_mute, "Disable/Enable mic input"),
01223 AST_CLI_DEFINE(cli_console_answer, "Answer an incoming console call"),
01224 AST_CLI_DEFINE(cli_console_sendtext, "Send text to a connected party"),
01225 AST_CLI_DEFINE(cli_console_flash, "Send a flash to the connected party"),
01226 AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
01227 AST_CLI_DEFINE(cli_list_available, "List available devices"),
01228 AST_CLI_DEFINE(cli_list_devices, "List configured devices"),
01229 AST_CLI_DEFINE(cli_console_active, "View or Set the active console device"),
01230 };
01231
01232
01233
01234
01235
01236
01237 static void set_pvt_defaults(struct console_pvt *pvt)
01238 {
01239 if (pvt == &globals) {
01240 ast_string_field_set(pvt, mohinterpret, "default");
01241 ast_string_field_set(pvt, context, "default");
01242 ast_string_field_set(pvt, exten, "s");
01243 ast_string_field_set(pvt, language, "");
01244 ast_string_field_set(pvt, cid_num, "");
01245 ast_string_field_set(pvt, cid_name, "");
01246 ast_string_field_set(pvt, parkinglot, "");
01247
01248 pvt->overridecontext = 0;
01249 pvt->autoanswer = 0;
01250 } else {
01251 ast_mutex_lock(&globals_lock);
01252
01253 ast_string_field_set(pvt, mohinterpret, globals.mohinterpret);
01254 ast_string_field_set(pvt, context, globals.context);
01255 ast_string_field_set(pvt, exten, globals.exten);
01256 ast_string_field_set(pvt, language, globals.language);
01257 ast_string_field_set(pvt, cid_num, globals.cid_num);
01258 ast_string_field_set(pvt, cid_name, globals.cid_name);
01259 ast_string_field_set(pvt, parkinglot, globals.parkinglot);
01260
01261 pvt->overridecontext = globals.overridecontext;
01262 pvt->autoanswer = globals.autoanswer;
01263
01264 ast_mutex_unlock(&globals_lock);
01265 }
01266 }
01267
01268 static void store_callerid(struct console_pvt *pvt, const char *value)
01269 {
01270 char cid_name[256];
01271 char cid_num[256];
01272
01273 ast_callerid_split(value, cid_name, sizeof(cid_name),
01274 cid_num, sizeof(cid_num));
01275
01276 ast_string_field_set(pvt, cid_name, cid_name);
01277 ast_string_field_set(pvt, cid_num, cid_num);
01278 }
01279
01280
01281
01282
01283
01284
01285 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
01286 {
01287 if (pvt == &globals && !ast_jb_read_conf(&global_jbconf, var, value))
01288 return;
01289
01290 CV_START(var, value);
01291
01292 CV_STRFIELD("context", pvt, context);
01293 CV_STRFIELD("extension", pvt, exten);
01294 CV_STRFIELD("mohinterpret", pvt, mohinterpret);
01295 CV_STRFIELD("language", pvt, language);
01296 CV_F("callerid", store_callerid(pvt, value));
01297 CV_BOOL("overridecontext", pvt->overridecontext);
01298 CV_BOOL("autoanswer", pvt->autoanswer);
01299 CV_STRFIELD("parkinglot", pvt, parkinglot);
01300
01301 if (pvt != &globals) {
01302 CV_F("active", set_active(pvt, value))
01303 CV_STRFIELD("input_device", pvt, input_device);
01304 CV_STRFIELD("output_device", pvt, output_device);
01305 }
01306
01307 ast_log(LOG_WARNING, "Unknown option '%s'\n", var);
01308
01309 CV_END;
01310 }
01311
01312 static void pvt_destructor(void *obj)
01313 {
01314 struct console_pvt *pvt = obj;
01315
01316 ast_string_field_free_memory(pvt);
01317 }
01318
01319 static int init_pvt(struct console_pvt *pvt, const char *name)
01320 {
01321 pvt->thread = AST_PTHREADT_NULL;
01322
01323 if (ast_string_field_init(pvt, 32))
01324 return -1;
01325
01326 ast_string_field_set(pvt, name, S_OR(name, ""));
01327
01328 return 0;
01329 }
01330
01331 static void build_device(struct ast_config *cfg, const char *name)
01332 {
01333 struct ast_variable *v;
01334 struct console_pvt *pvt;
01335 int new = 0;
01336
01337 if ((pvt = find_pvt(name))) {
01338 console_pvt_lock(pvt);
01339 set_pvt_defaults(pvt);
01340 pvt->destroy = 0;
01341 } else {
01342 if (!(pvt = ao2_alloc(sizeof(*pvt), pvt_destructor)))
01343 return;
01344 init_pvt(pvt, name);
01345 set_pvt_defaults(pvt);
01346 new = 1;
01347 }
01348
01349 for (v = ast_variable_browse(cfg, name); v; v = v->next)
01350 store_config_core(pvt, v->name, v->value);
01351
01352 if (new)
01353 ao2_link(pvts, pvt);
01354 else
01355 console_pvt_unlock(pvt);
01356
01357 unref_pvt(pvt);
01358 }
01359
01360 static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
01361 {
01362 struct console_pvt *pvt = obj;
01363 pvt->destroy = 1;
01364 return 0;
01365 }
01366
01367 static void destroy_pvts(void)
01368 {
01369 struct ao2_iterator i;
01370 struct console_pvt *pvt;
01371
01372 i = ao2_iterator_init(pvts, 0);
01373 while ((pvt = ao2_iterator_next(&i))) {
01374 if (pvt->destroy) {
01375 ao2_unlink(pvts, pvt);
01376 ast_rwlock_wrlock(&active_lock);
01377 if (active_pvt == pvt)
01378 active_pvt = unref_pvt(pvt);
01379 ast_rwlock_unlock(&active_lock);
01380 }
01381 unref_pvt(pvt);
01382 }
01383 ao2_iterator_destroy(&i);
01384 }
01385
01386
01387
01388
01389
01390
01391
01392 static int load_config(int reload)
01393 {
01394 struct ast_config *cfg;
01395 struct ast_variable *v;
01396 struct ast_flags config_flags = { 0 };
01397 char *context = NULL;
01398
01399
01400 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
01401 ast_mutex_lock(&globals_lock);
01402 set_pvt_defaults(&globals);
01403 ast_mutex_unlock(&globals_lock);
01404
01405 if (!(cfg = ast_config_load(config_file, config_flags))) {
01406 ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
01407 return -1;
01408 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01409 ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file);
01410 return -1;
01411 }
01412
01413 ao2_callback(pvts, OBJ_NODATA, pvt_mark_destroy_cb, NULL);
01414
01415 ast_mutex_lock(&globals_lock);
01416 for (v = ast_variable_browse(cfg, "general"); v; v = v->next)
01417 store_config_core(&globals, v->name, v->value);
01418 ast_mutex_unlock(&globals_lock);
01419
01420 while ((context = ast_category_browse(cfg, context))) {
01421 if (strcasecmp(context, "general"))
01422 build_device(cfg, context);
01423 }
01424
01425 ast_config_destroy(cfg);
01426
01427 destroy_pvts();
01428
01429 return 0;
01430 }
01431
01432 static int pvt_hash_cb(const void *obj, const int flags)
01433 {
01434 const struct console_pvt *pvt = obj;
01435
01436 return ast_str_case_hash(pvt->name);
01437 }
01438
01439 static int pvt_cmp_cb(void *obj, void *arg, int flags)
01440 {
01441 struct console_pvt *pvt = obj, *pvt2 = arg;
01442
01443 return !strcasecmp(pvt->name, pvt2->name) ? CMP_MATCH | CMP_STOP : 0;
01444 }
01445
01446 static void stop_streams(void)
01447 {
01448 struct console_pvt *pvt;
01449 struct ao2_iterator i;
01450
01451 i = ao2_iterator_init(pvts, 0);
01452 while ((pvt = ao2_iterator_next(&i))) {
01453 if (pvt->hookstate)
01454 stop_stream(pvt);
01455 unref_pvt(pvt);
01456 }
01457 ao2_iterator_destroy(&i);
01458 }
01459
01460 static int unload_module(void)
01461 {
01462 ast_channel_unregister(&console_tech);
01463 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01464
01465 stop_streams();
01466
01467 Pa_Terminate();
01468
01469
01470 ao2_ref(pvts, -1);
01471
01472 pvt_destructor(&globals);
01473
01474 return 0;
01475 }
01476
01477 static int load_module(void)
01478 {
01479 PaError res;
01480
01481 init_pvt(&globals, NULL);
01482
01483 if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
01484 goto return_error;
01485
01486 if (load_config(0))
01487 goto return_error;
01488
01489 res = Pa_Initialize();
01490 if (res != paNoError) {
01491 ast_log(LOG_WARNING, "Failed to initialize audio system - (%d) %s\n",
01492 res, Pa_GetErrorText(res));
01493 goto return_error_pa_init;
01494 }
01495
01496 if (ast_channel_register(&console_tech)) {
01497 ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
01498 goto return_error_chan_reg;
01499 }
01500
01501 if (ast_cli_register_multiple(cli_console, ARRAY_LEN(cli_console)))
01502 goto return_error_cli_reg;
01503
01504 return AST_MODULE_LOAD_SUCCESS;
01505
01506 return_error_cli_reg:
01507 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01508 return_error_chan_reg:
01509 ast_channel_unregister(&console_tech);
01510 return_error_pa_init:
01511 Pa_Terminate();
01512 return_error:
01513 if (pvts)
01514 ao2_ref(pvts, -1);
01515 pvts = NULL;
01516 pvt_destructor(&globals);
01517
01518 return AST_MODULE_LOAD_DECLINE;
01519 }
01520
01521 static int reload(void)
01522 {
01523 return load_config(1);
01524 }
01525
01526 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
01527 .load = load_module,
01528 .unload = unload_module,
01529 .reload = reload,
01530 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01531 );