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: 297535 $")
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, format_t format,
00187 const struct ast_channel *requestor, 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.codec = 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, const char *linkedid)
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, linkedid, 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, format_t format, const struct ast_channel *requestor, void *data, int *cause)
00452 {
00453 format_t oldformat = format;
00454 struct ast_channel *chan = NULL;
00455 struct console_pvt *pvt;
00456 char buf[512];
00457
00458 if (!(pvt = find_pvt(data))) {
00459 ast_log(LOG_ERROR, "Console device '%s' not found\n", (char *) data);
00460 return NULL;
00461 }
00462
00463 format &= SUPPORTED_FORMATS;
00464 if (!format) {
00465 ast_log(LOG_NOTICE, "Channel requested with unsupported format(s): '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), oldformat));
00466 goto return_unref;
00467 }
00468
00469 if (pvt->owner) {
00470 ast_log(LOG_NOTICE, "Console channel already active!\n");
00471 *cause = AST_CAUSE_BUSY;
00472 goto return_unref;
00473 }
00474
00475 console_pvt_lock(pvt);
00476 chan = console_new(pvt, NULL, NULL, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00477 console_pvt_unlock(pvt);
00478
00479 if (!chan)
00480 ast_log(LOG_WARNING, "Unable to create new Console channel!\n");
00481
00482 return_unref:
00483 unref_pvt(pvt);
00484
00485 return chan;
00486 }
00487
00488 static int console_digit_begin(struct ast_channel *c, char digit)
00489 {
00490 ast_verb(1, V_BEGIN "Console Received Beginning of Digit %c" V_END, digit);
00491
00492 return -1;
00493 }
00494
00495 static int console_digit_end(struct ast_channel *c, char digit, unsigned int duration)
00496 {
00497 ast_verb(1, V_BEGIN "Console Received End of Digit %c (duration %u)" V_END,
00498 digit, duration);
00499
00500 return -1;
00501 }
00502
00503 static int console_text(struct ast_channel *c, const char *text)
00504 {
00505 ast_verb(1, V_BEGIN "Console Received Text '%s'" V_END, text);
00506
00507 return 0;
00508 }
00509
00510 static int console_hangup(struct ast_channel *c)
00511 {
00512 struct console_pvt *pvt = c->tech_pvt;
00513
00514 ast_verb(1, V_BEGIN "Hangup on Console" V_END);
00515
00516 pvt->hookstate = 0;
00517 pvt->owner = NULL;
00518 stop_stream(pvt);
00519
00520 c->tech_pvt = unref_pvt(pvt);
00521
00522 return 0;
00523 }
00524
00525 static int console_answer(struct ast_channel *c)
00526 {
00527 struct console_pvt *pvt = c->tech_pvt;
00528
00529 ast_verb(1, V_BEGIN "Call from Console has been Answered" V_END);
00530
00531 ast_setstate(c, AST_STATE_UP);
00532
00533 return start_stream(pvt);
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 static struct ast_frame *console_read(struct ast_channel *chan)
00557 {
00558 ast_debug(1, "I should not be called ...\n");
00559
00560 return &ast_null_frame;
00561 }
00562
00563 static int console_call(struct ast_channel *c, char *dest, int timeout)
00564 {
00565 struct console_pvt *pvt = c->tech_pvt;
00566 enum ast_control_frame_type ctrl;
00567
00568 ast_verb(1, V_BEGIN "Call to device '%s' on console from '%s' <%s>" V_END,
00569 dest,
00570 S_COR(c->caller.id.name.valid, c->caller.id.name.str, ""),
00571 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""));
00572
00573 console_pvt_lock(pvt);
00574
00575 if (pvt->autoanswer) {
00576 pvt->hookstate = 1;
00577 console_pvt_unlock(pvt);
00578 ast_verb(1, V_BEGIN "Auto-answered" V_END);
00579 ctrl = AST_CONTROL_ANSWER;
00580 } else {
00581 console_pvt_unlock(pvt);
00582 ast_verb(1, V_BEGIN "Type 'console answer' to answer, or use the 'autoanswer' option "
00583 "for future calls" V_END);
00584 ctrl = AST_CONTROL_RINGING;
00585 ast_indicate(c, AST_CONTROL_RINGING);
00586 }
00587
00588 ast_queue_control(c, ctrl);
00589
00590 return start_stream(pvt);
00591 }
00592
00593 static int console_write(struct ast_channel *chan, struct ast_frame *f)
00594 {
00595 struct console_pvt *pvt = chan->tech_pvt;
00596
00597 Pa_WriteStream(pvt->stream, f->data.ptr, f->samples);
00598
00599 return 0;
00600 }
00601
00602 static int console_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
00603 {
00604 struct console_pvt *pvt = chan->tech_pvt;
00605 int res = 0;
00606
00607 switch (cond) {
00608 case AST_CONTROL_BUSY:
00609 case AST_CONTROL_CONGESTION:
00610 case AST_CONTROL_RINGING:
00611 case -1:
00612 res = -1;
00613 break;
00614 case AST_CONTROL_PROGRESS:
00615 case AST_CONTROL_PROCEEDING:
00616 case AST_CONTROL_VIDUPDATE:
00617 case AST_CONTROL_SRCUPDATE:
00618 break;
00619 case AST_CONTROL_HOLD:
00620 ast_verb(1, V_BEGIN "Console Has Been Placed on Hold" V_END);
00621 ast_moh_start(chan, data, pvt->mohinterpret);
00622 break;
00623 case AST_CONTROL_UNHOLD:
00624 ast_verb(1, V_BEGIN "Console Has Been Retrieved from Hold" V_END);
00625 ast_moh_stop(chan);
00626 break;
00627 default:
00628 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n",
00629 cond, chan->name);
00630
00631 res = -1;
00632 }
00633
00634 return res;
00635 }
00636
00637 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00638 {
00639 struct console_pvt *pvt = newchan->tech_pvt;
00640
00641 pvt->owner = newchan;
00642
00643 return 0;
00644 }
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
00658 {
00659 if (ext == NULL || ctx == NULL)
00660 return NULL;
00661
00662 *ext = *ctx = NULL;
00663
00664 if (src && *src != '\0')
00665 *ext = ast_strdup(src);
00666
00667 if (*ext == NULL)
00668 return NULL;
00669
00670 if (!pvt->overridecontext) {
00671
00672 *ctx = strrchr(*ext, '@');
00673 if (*ctx)
00674 *(*ctx)++ = '\0';
00675 }
00676
00677 return *ext;
00678 }
00679
00680 static struct console_pvt *get_active_pvt(void)
00681 {
00682 struct console_pvt *pvt;
00683
00684 ast_rwlock_rdlock(&active_lock);
00685 pvt = ref_pvt(active_pvt);
00686 ast_rwlock_unlock(&active_lock);
00687
00688 return pvt;
00689 }
00690
00691 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
00692 struct ast_cli_args *a)
00693 {
00694 struct console_pvt *pvt = get_active_pvt();
00695 char *res = CLI_SUCCESS;
00696
00697 switch (cmd) {
00698 case CLI_INIT:
00699 e->command = "console {set|show} autoanswer [on|off]";
00700 e->usage =
00701 "Usage: console {set|show} autoanswer [on|off]\n"
00702 " Enables or disables autoanswer feature. If used without\n"
00703 " argument, displays the current on/off status of autoanswer.\n"
00704 " The default value of autoanswer is in 'oss.conf'.\n";
00705 return NULL;
00706
00707 case CLI_GENERATE:
00708 return NULL;
00709 }
00710
00711 if (!pvt) {
00712 ast_cli(a->fd, "No console device is set as active.\n");
00713 return CLI_FAILURE;
00714 }
00715
00716 if (a->argc == e->args - 1) {
00717 ast_cli(a->fd, "Auto answer is %s.\n", pvt->autoanswer ? "on" : "off");
00718 unref_pvt(pvt);
00719 return CLI_SUCCESS;
00720 }
00721
00722 if (a->argc != e->args) {
00723 unref_pvt(pvt);
00724 return CLI_SHOWUSAGE;
00725 }
00726
00727 if (!strcasecmp(a->argv[e->args-1], "on"))
00728 pvt->autoanswer = 1;
00729 else if (!strcasecmp(a->argv[e->args - 1], "off"))
00730 pvt->autoanswer = 0;
00731 else
00732 res = CLI_SHOWUSAGE;
00733
00734 unref_pvt(pvt);
00735
00736 return CLI_SUCCESS;
00737 }
00738
00739 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00740 {
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_control(pvt->owner, AST_CONTROL_FLASH);
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 };
00801 const char *s;
00802
00803 if (a->argc == e->args) {
00804 ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
00805 unref_pvt(pvt);
00806 return CLI_FAILURE;
00807 }
00808 s = a->argv[e->args];
00809
00810 for (i = 0; i < strlen(s); i++) {
00811 f.subclass.integer = s[i];
00812 ast_queue_frame(pvt->owner, &f);
00813 }
00814 unref_pvt(pvt);
00815 return CLI_SUCCESS;
00816 }
00817
00818
00819 if (a->argc == e->args + 1) {
00820 char *ext = NULL, *con = NULL;
00821 s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
00822 ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
00823 a->argv[e->args], mye, myc);
00824 mye = ext;
00825 myc = con;
00826 }
00827
00828
00829 if (ast_strlen_zero(mye))
00830 mye = pvt->exten;
00831 if (ast_strlen_zero(myc))
00832 myc = pvt->context;
00833
00834 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00835 console_pvt_lock(pvt);
00836 pvt->hookstate = 1;
00837 console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
00838 console_pvt_unlock(pvt);
00839 } else
00840 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00841
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 const 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 console_pvt *pvt = get_active_pvt();
01036
01037 switch (cmd) {
01038 case CLI_INIT:
01039 e->command = "console answer";
01040 e->usage =
01041 "Usage: console answer\n"
01042 " Answers an incoming call on the console channel.\n";
01043 return NULL;
01044
01045 case CLI_GENERATE:
01046 return NULL;
01047 }
01048
01049 if (!pvt) {
01050 ast_cli(a->fd, "No console device is set as active\n");
01051 return CLI_FAILURE;
01052 }
01053
01054 if (a->argc != e->args) {
01055 unref_pvt(pvt);
01056 return CLI_SHOWUSAGE;
01057 }
01058
01059 if (!pvt->owner) {
01060 ast_cli(a->fd, "No one is calling us\n");
01061 unref_pvt(pvt);
01062 return CLI_FAILURE;
01063 }
01064
01065 pvt->hookstate = 1;
01066
01067 ast_indicate(pvt->owner, -1);
01068
01069 ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
01070
01071 unref_pvt(pvt);
01072
01073 return CLI_SUCCESS;
01074 }
01075
01076
01077
01078
01079
01080
01081
01082 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01083 {
01084 char buf[TEXT_SIZE];
01085 struct console_pvt *pvt = get_active_pvt();
01086 struct ast_frame f = {
01087 .frametype = AST_FRAME_TEXT,
01088 .data.ptr = buf,
01089 .src = "console_send_text",
01090 };
01091 int len;
01092
01093 if (cmd == CLI_INIT) {
01094 e->command = "console send text";
01095 e->usage =
01096 "Usage: console send text <message>\n"
01097 " Sends a text message for display on the remote terminal.\n";
01098 return NULL;
01099 } else if (cmd == CLI_GENERATE)
01100 return NULL;
01101
01102 if (!pvt) {
01103 ast_cli(a->fd, "No console device is set as active\n");
01104 return CLI_FAILURE;
01105 }
01106
01107 if (a->argc < e->args + 1) {
01108 unref_pvt(pvt);
01109 return CLI_SHOWUSAGE;
01110 }
01111
01112 if (!pvt->owner) {
01113 ast_cli(a->fd, "Not in a call\n");
01114 unref_pvt(pvt);
01115 return CLI_FAILURE;
01116 }
01117
01118 ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01119 if (ast_strlen_zero(buf)) {
01120 unref_pvt(pvt);
01121 return CLI_SHOWUSAGE;
01122 }
01123
01124 len = strlen(buf);
01125 buf[len] = '\n';
01126 f.datalen = len + 1;
01127
01128 ast_queue_frame(pvt->owner, &f);
01129
01130 unref_pvt(pvt);
01131
01132 return CLI_SUCCESS;
01133 }
01134
01135 static void set_active(struct console_pvt *pvt, const char *value)
01136 {
01137 if (pvt == &globals) {
01138 ast_log(LOG_ERROR, "active is only valid as a per-device setting\n");
01139 return;
01140 }
01141
01142 if (!ast_true(value))
01143 return;
01144
01145 ast_rwlock_wrlock(&active_lock);
01146 if (active_pvt)
01147 unref_pvt(active_pvt);
01148 active_pvt = ref_pvt(pvt);
01149 ast_rwlock_unlock(&active_lock);
01150 }
01151
01152 static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01153 {
01154 struct console_pvt *pvt;
01155
01156 switch (cmd) {
01157 case CLI_INIT:
01158 e->command = "console {set|show} active";
01159 e->usage =
01160 "Usage: console {set|show} active [<device>]\n"
01161 " Set or show the active console device for the Asterisk CLI.\n";
01162 return NULL;
01163 case CLI_GENERATE:
01164 if (a->pos == e->args) {
01165 struct ao2_iterator i;
01166 int x = 0;
01167 char *res = NULL;
01168 i = ao2_iterator_init(pvts, 0);
01169 while ((pvt = ao2_iterator_next(&i))) {
01170 if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
01171 res = ast_strdup(pvt->name);
01172 unref_pvt(pvt);
01173 if (res) {
01174 ao2_iterator_destroy(&i);
01175 return res;
01176 }
01177 }
01178 ao2_iterator_destroy(&i);
01179 }
01180 return NULL;
01181 }
01182
01183 if (a->argc < e->args)
01184 return CLI_SHOWUSAGE;
01185
01186 if (a->argc == 3) {
01187 pvt = get_active_pvt();
01188
01189 if (!pvt)
01190 ast_cli(a->fd, "No device is currently set as the active console device.\n");
01191 else {
01192 console_pvt_lock(pvt);
01193 ast_cli(a->fd, "The active console device is '%s'.\n", pvt->name);
01194 console_pvt_unlock(pvt);
01195 pvt = unref_pvt(pvt);
01196 }
01197
01198 return CLI_SUCCESS;
01199 }
01200
01201 if (!(pvt = find_pvt(a->argv[e->args - 1]))) {
01202 ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
01203 return CLI_FAILURE;
01204 }
01205
01206 set_active(pvt, "yes");
01207
01208 console_pvt_lock(pvt);
01209 ast_cli(a->fd, "The active console device has been set to '%s'\n", pvt->name);
01210 console_pvt_unlock(pvt);
01211
01212 unref_pvt(pvt);
01213
01214 return CLI_SUCCESS;
01215 }
01216
01217 static struct ast_cli_entry cli_console[] = {
01218 AST_CLI_DEFINE(cli_console_dial, "Dial an extension from the console"),
01219 AST_CLI_DEFINE(cli_console_hangup, "Hangup a call on the console"),
01220 AST_CLI_DEFINE(cli_console_mute, "Disable/Enable mic input"),
01221 AST_CLI_DEFINE(cli_console_answer, "Answer an incoming console call"),
01222 AST_CLI_DEFINE(cli_console_sendtext, "Send text to a connected party"),
01223 AST_CLI_DEFINE(cli_console_flash, "Send a flash to the connected party"),
01224 AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
01225 AST_CLI_DEFINE(cli_list_available, "List available devices"),
01226 AST_CLI_DEFINE(cli_list_devices, "List configured devices"),
01227 AST_CLI_DEFINE(cli_console_active, "View or Set the active console device"),
01228 };
01229
01230
01231
01232
01233
01234
01235 static void set_pvt_defaults(struct console_pvt *pvt)
01236 {
01237 if (pvt == &globals) {
01238 ast_string_field_set(pvt, mohinterpret, "default");
01239 ast_string_field_set(pvt, context, "default");
01240 ast_string_field_set(pvt, exten, "s");
01241 ast_string_field_set(pvt, language, "");
01242 ast_string_field_set(pvt, cid_num, "");
01243 ast_string_field_set(pvt, cid_name, "");
01244 ast_string_field_set(pvt, parkinglot, "");
01245
01246 pvt->overridecontext = 0;
01247 pvt->autoanswer = 0;
01248 } else {
01249 ast_mutex_lock(&globals_lock);
01250
01251 ast_string_field_set(pvt, mohinterpret, globals.mohinterpret);
01252 ast_string_field_set(pvt, context, globals.context);
01253 ast_string_field_set(pvt, exten, globals.exten);
01254 ast_string_field_set(pvt, language, globals.language);
01255 ast_string_field_set(pvt, cid_num, globals.cid_num);
01256 ast_string_field_set(pvt, cid_name, globals.cid_name);
01257 ast_string_field_set(pvt, parkinglot, globals.parkinglot);
01258
01259 pvt->overridecontext = globals.overridecontext;
01260 pvt->autoanswer = globals.autoanswer;
01261
01262 ast_mutex_unlock(&globals_lock);
01263 }
01264 }
01265
01266 static void store_callerid(struct console_pvt *pvt, const char *value)
01267 {
01268 char cid_name[256];
01269 char cid_num[256];
01270
01271 ast_callerid_split(value, cid_name, sizeof(cid_name),
01272 cid_num, sizeof(cid_num));
01273
01274 ast_string_field_set(pvt, cid_name, cid_name);
01275 ast_string_field_set(pvt, cid_num, cid_num);
01276 }
01277
01278
01279
01280
01281
01282
01283 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
01284 {
01285 if (pvt == &globals && !ast_jb_read_conf(&global_jbconf, var, value))
01286 return;
01287
01288 CV_START(var, value);
01289
01290 CV_STRFIELD("context", pvt, context);
01291 CV_STRFIELD("extension", pvt, exten);
01292 CV_STRFIELD("mohinterpret", pvt, mohinterpret);
01293 CV_STRFIELD("language", pvt, language);
01294 CV_F("callerid", store_callerid(pvt, value));
01295 CV_BOOL("overridecontext", pvt->overridecontext);
01296 CV_BOOL("autoanswer", pvt->autoanswer);
01297 CV_STRFIELD("parkinglot", pvt, parkinglot);
01298
01299 if (pvt != &globals) {
01300 CV_F("active", set_active(pvt, value))
01301 CV_STRFIELD("input_device", pvt, input_device);
01302 CV_STRFIELD("output_device", pvt, output_device);
01303 }
01304
01305 ast_log(LOG_WARNING, "Unknown option '%s'\n", var);
01306
01307 CV_END;
01308 }
01309
01310 static void pvt_destructor(void *obj)
01311 {
01312 struct console_pvt *pvt = obj;
01313
01314 ast_string_field_free_memory(pvt);
01315 }
01316
01317 static int init_pvt(struct console_pvt *pvt, const char *name)
01318 {
01319 pvt->thread = AST_PTHREADT_NULL;
01320
01321 if (ast_string_field_init(pvt, 32))
01322 return -1;
01323
01324 ast_string_field_set(pvt, name, S_OR(name, ""));
01325
01326 return 0;
01327 }
01328
01329 static void build_device(struct ast_config *cfg, const char *name)
01330 {
01331 struct ast_variable *v;
01332 struct console_pvt *pvt;
01333 int new = 0;
01334
01335 if ((pvt = find_pvt(name))) {
01336 console_pvt_lock(pvt);
01337 set_pvt_defaults(pvt);
01338 pvt->destroy = 0;
01339 } else {
01340 if (!(pvt = ao2_alloc(sizeof(*pvt), pvt_destructor)))
01341 return;
01342 init_pvt(pvt, name);
01343 set_pvt_defaults(pvt);
01344 new = 1;
01345 }
01346
01347 for (v = ast_variable_browse(cfg, name); v; v = v->next)
01348 store_config_core(pvt, v->name, v->value);
01349
01350 if (new)
01351 ao2_link(pvts, pvt);
01352 else
01353 console_pvt_unlock(pvt);
01354
01355 unref_pvt(pvt);
01356 }
01357
01358 static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
01359 {
01360 struct console_pvt *pvt = obj;
01361 pvt->destroy = 1;
01362 return 0;
01363 }
01364
01365 static void destroy_pvts(void)
01366 {
01367 struct ao2_iterator i;
01368 struct console_pvt *pvt;
01369
01370 i = ao2_iterator_init(pvts, 0);
01371 while ((pvt = ao2_iterator_next(&i))) {
01372 if (pvt->destroy) {
01373 ao2_unlink(pvts, pvt);
01374 ast_rwlock_wrlock(&active_lock);
01375 if (active_pvt == pvt)
01376 active_pvt = unref_pvt(pvt);
01377 ast_rwlock_unlock(&active_lock);
01378 }
01379 unref_pvt(pvt);
01380 }
01381 ao2_iterator_destroy(&i);
01382 }
01383
01384
01385
01386
01387
01388
01389
01390 static int load_config(int reload)
01391 {
01392 struct ast_config *cfg;
01393 struct ast_variable *v;
01394 struct ast_flags config_flags = { 0 };
01395 char *context = NULL;
01396
01397
01398 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
01399 ast_mutex_lock(&globals_lock);
01400 set_pvt_defaults(&globals);
01401 ast_mutex_unlock(&globals_lock);
01402
01403 if (!(cfg = ast_config_load(config_file, config_flags))) {
01404 ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
01405 return -1;
01406 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01407 ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file);
01408 return -1;
01409 }
01410
01411 ao2_callback(pvts, OBJ_NODATA, pvt_mark_destroy_cb, NULL);
01412
01413 ast_mutex_lock(&globals_lock);
01414 for (v = ast_variable_browse(cfg, "general"); v; v = v->next)
01415 store_config_core(&globals, v->name, v->value);
01416 ast_mutex_unlock(&globals_lock);
01417
01418 while ((context = ast_category_browse(cfg, context))) {
01419 if (strcasecmp(context, "general"))
01420 build_device(cfg, context);
01421 }
01422
01423 ast_config_destroy(cfg);
01424
01425 destroy_pvts();
01426
01427 return 0;
01428 }
01429
01430 static int pvt_hash_cb(const void *obj, const int flags)
01431 {
01432 const struct console_pvt *pvt = obj;
01433
01434 return ast_str_case_hash(pvt->name);
01435 }
01436
01437 static int pvt_cmp_cb(void *obj, void *arg, int flags)
01438 {
01439 struct console_pvt *pvt = obj, *pvt2 = arg;
01440
01441 return !strcasecmp(pvt->name, pvt2->name) ? CMP_MATCH | CMP_STOP : 0;
01442 }
01443
01444 static void stop_streams(void)
01445 {
01446 struct console_pvt *pvt;
01447 struct ao2_iterator i;
01448
01449 i = ao2_iterator_init(pvts, 0);
01450 while ((pvt = ao2_iterator_next(&i))) {
01451 if (pvt->hookstate)
01452 stop_stream(pvt);
01453 unref_pvt(pvt);
01454 }
01455 ao2_iterator_destroy(&i);
01456 }
01457
01458 static int unload_module(void)
01459 {
01460 ast_channel_unregister(&console_tech);
01461 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01462
01463 stop_streams();
01464
01465 Pa_Terminate();
01466
01467
01468 ao2_ref(pvts, -1);
01469
01470 pvt_destructor(&globals);
01471
01472 return 0;
01473 }
01474
01475 static int load_module(void)
01476 {
01477 PaError res;
01478
01479 init_pvt(&globals, NULL);
01480
01481 if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
01482 goto return_error;
01483
01484 if (load_config(0))
01485 goto return_error;
01486
01487 res = Pa_Initialize();
01488 if (res != paNoError) {
01489 ast_log(LOG_WARNING, "Failed to initialize audio system - (%d) %s\n",
01490 res, Pa_GetErrorText(res));
01491 goto return_error_pa_init;
01492 }
01493
01494 if (ast_channel_register(&console_tech)) {
01495 ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
01496 goto return_error_chan_reg;
01497 }
01498
01499 if (ast_cli_register_multiple(cli_console, ARRAY_LEN(cli_console)))
01500 goto return_error_cli_reg;
01501
01502 return AST_MODULE_LOAD_SUCCESS;
01503
01504 return_error_cli_reg:
01505 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01506 return_error_chan_reg:
01507 ast_channel_unregister(&console_tech);
01508 return_error_pa_init:
01509 Pa_Terminate();
01510 return_error:
01511 if (pvts)
01512 ao2_ref(pvts, -1);
01513 pvts = NULL;
01514 pvt_destructor(&globals);
01515
01516 return AST_MODULE_LOAD_DECLINE;
01517 }
01518
01519 static int reload(void)
01520 {
01521 return load_config(1);
01522 }
01523
01524 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
01525 .load = load_module,
01526 .unload = unload_module,
01527 .reload = reload,
01528 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01529 );