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