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: 335064 $")
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 AST_CONTROL_INCOMPLETE:
00614 case -1:
00615 res = -1;
00616 break;
00617 case AST_CONTROL_PROGRESS:
00618 case AST_CONTROL_PROCEEDING:
00619 case AST_CONTROL_VIDUPDATE:
00620 case AST_CONTROL_SRCUPDATE:
00621 break;
00622 case AST_CONTROL_HOLD:
00623 ast_verb(1, V_BEGIN "Console Has Been Placed on Hold" V_END);
00624 ast_moh_start(chan, data, pvt->mohinterpret);
00625 break;
00626 case AST_CONTROL_UNHOLD:
00627 ast_verb(1, V_BEGIN "Console Has Been Retrieved from Hold" V_END);
00628 ast_moh_stop(chan);
00629 break;
00630 default:
00631 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n",
00632 cond, chan->name);
00633
00634 res = -1;
00635 }
00636
00637 return res;
00638 }
00639
00640 static int console_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00641 {
00642 struct console_pvt *pvt = newchan->tech_pvt;
00643
00644 pvt->owner = newchan;
00645
00646 return 0;
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 static char *ast_ext_ctx(struct console_pvt *pvt, const char *src, char **ext, char **ctx)
00661 {
00662 if (ext == NULL || ctx == NULL)
00663 return NULL;
00664
00665 *ext = *ctx = NULL;
00666
00667 if (src && *src != '\0')
00668 *ext = ast_strdup(src);
00669
00670 if (*ext == NULL)
00671 return NULL;
00672
00673 if (!pvt->overridecontext) {
00674
00675 *ctx = strrchr(*ext, '@');
00676 if (*ctx)
00677 *(*ctx)++ = '\0';
00678 }
00679
00680 return *ext;
00681 }
00682
00683 static struct console_pvt *get_active_pvt(void)
00684 {
00685 struct console_pvt *pvt;
00686
00687 ast_rwlock_rdlock(&active_lock);
00688 pvt = ref_pvt(active_pvt);
00689 ast_rwlock_unlock(&active_lock);
00690
00691 return pvt;
00692 }
00693
00694 static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
00695 struct ast_cli_args *a)
00696 {
00697 struct console_pvt *pvt = get_active_pvt();
00698 char *res = CLI_SUCCESS;
00699
00700 switch (cmd) {
00701 case CLI_INIT:
00702 e->command = "console {set|show} autoanswer [on|off]";
00703 e->usage =
00704 "Usage: console {set|show} autoanswer [on|off]\n"
00705 " Enables or disables autoanswer feature. If used without\n"
00706 " argument, displays the current on/off status of autoanswer.\n"
00707 " The default value of autoanswer is in 'oss.conf'.\n";
00708 return NULL;
00709
00710 case CLI_GENERATE:
00711 return NULL;
00712 }
00713
00714 if (!pvt) {
00715 ast_cli(a->fd, "No console device is set as active.\n");
00716 return CLI_FAILURE;
00717 }
00718
00719 if (a->argc == e->args - 1) {
00720 ast_cli(a->fd, "Auto answer is %s.\n", pvt->autoanswer ? "on" : "off");
00721 unref_pvt(pvt);
00722 return CLI_SUCCESS;
00723 }
00724
00725 if (a->argc != e->args) {
00726 unref_pvt(pvt);
00727 return CLI_SHOWUSAGE;
00728 }
00729
00730 if (!strcasecmp(a->argv[e->args-1], "on"))
00731 pvt->autoanswer = 1;
00732 else if (!strcasecmp(a->argv[e->args - 1], "off"))
00733 pvt->autoanswer = 0;
00734 else
00735 res = CLI_SHOWUSAGE;
00736
00737 unref_pvt(pvt);
00738
00739 return res;
00740 }
00741
00742 static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00743 {
00744 struct console_pvt *pvt = get_active_pvt();
00745
00746 if (cmd == CLI_INIT) {
00747 e->command = "console flash";
00748 e->usage =
00749 "Usage: console flash\n"
00750 " Flashes the call currently placed on the console.\n";
00751 return NULL;
00752 } else if (cmd == CLI_GENERATE)
00753 return NULL;
00754
00755 if (!pvt) {
00756 ast_cli(a->fd, "No console device is set as active\n");
00757 return CLI_FAILURE;
00758 }
00759
00760 if (a->argc != e->args)
00761 return CLI_SHOWUSAGE;
00762
00763 if (!pvt->owner) {
00764 ast_cli(a->fd, "No call to flash\n");
00765 unref_pvt(pvt);
00766 return CLI_FAILURE;
00767 }
00768
00769 pvt->hookstate = 0;
00770
00771 ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
00772
00773 unref_pvt(pvt);
00774
00775 return CLI_SUCCESS;
00776 }
00777
00778 static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00779 {
00780 char *s = NULL;
00781 const char *mye = NULL, *myc = NULL;
00782 struct console_pvt *pvt = get_active_pvt();
00783
00784 if (cmd == CLI_INIT) {
00785 e->command = "console dial";
00786 e->usage =
00787 "Usage: console dial [extension[@context]]\n"
00788 " Dials a given extension (and context if specified)\n";
00789 return NULL;
00790 } else if (cmd == CLI_GENERATE)
00791 return NULL;
00792
00793 if (!pvt) {
00794 ast_cli(a->fd, "No console device is currently set as active\n");
00795 return CLI_FAILURE;
00796 }
00797
00798 if (a->argc > e->args + 1)
00799 return CLI_SHOWUSAGE;
00800
00801 if (pvt->owner) {
00802 int i;
00803 struct ast_frame f = { AST_FRAME_DTMF };
00804 const char *s;
00805
00806 if (a->argc == e->args) {
00807 ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
00808 unref_pvt(pvt);
00809 return CLI_FAILURE;
00810 }
00811 s = a->argv[e->args];
00812
00813 for (i = 0; i < strlen(s); i++) {
00814 f.subclass.integer = s[i];
00815 ast_queue_frame(pvt->owner, &f);
00816 }
00817 unref_pvt(pvt);
00818 return CLI_SUCCESS;
00819 }
00820
00821
00822 if (a->argc == e->args + 1) {
00823 char *ext = NULL, *con = NULL;
00824 s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
00825 ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
00826 a->argv[e->args], mye, myc);
00827 mye = ext;
00828 myc = con;
00829 }
00830
00831
00832 if (ast_strlen_zero(mye))
00833 mye = pvt->exten;
00834 if (ast_strlen_zero(myc))
00835 myc = pvt->context;
00836
00837 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00838 console_pvt_lock(pvt);
00839 pvt->hookstate = 1;
00840 console_new(pvt, mye, myc, AST_STATE_RINGING, NULL);
00841 console_pvt_unlock(pvt);
00842 } else
00843 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00844
00845 free(s);
00846
00847 unref_pvt(pvt);
00848
00849 return CLI_SUCCESS;
00850 }
00851
00852 static char *cli_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00853 {
00854 struct console_pvt *pvt = get_active_pvt();
00855
00856 if (cmd == CLI_INIT) {
00857 e->command = "console hangup";
00858 e->usage =
00859 "Usage: console hangup\n"
00860 " Hangs up any call currently placed on the console.\n";
00861 return NULL;
00862 } else if (cmd == CLI_GENERATE)
00863 return NULL;
00864
00865 if (!pvt) {
00866 ast_cli(a->fd, "No console device is set as active\n");
00867 return CLI_FAILURE;
00868 }
00869
00870 if (a->argc != e->args)
00871 return CLI_SHOWUSAGE;
00872
00873 if (!pvt->owner && !pvt->hookstate) {
00874 ast_cli(a->fd, "No call to hang up\n");
00875 unref_pvt(pvt);
00876 return CLI_FAILURE;
00877 }
00878
00879 pvt->hookstate = 0;
00880 if (pvt->owner)
00881 ast_queue_hangup(pvt->owner);
00882
00883 unref_pvt(pvt);
00884
00885 return CLI_SUCCESS;
00886 }
00887
00888 static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00889 {
00890 const char *s;
00891 struct console_pvt *pvt = get_active_pvt();
00892 char *res = CLI_SUCCESS;
00893
00894 if (cmd == CLI_INIT) {
00895 e->command = "console {mute|unmute}";
00896 e->usage =
00897 "Usage: console {mute|unmute}\n"
00898 " Mute/unmute the microphone.\n";
00899 return NULL;
00900 } else if (cmd == CLI_GENERATE)
00901 return NULL;
00902
00903 if (!pvt) {
00904 ast_cli(a->fd, "No console device is set as active\n");
00905 return CLI_FAILURE;
00906 }
00907
00908 if (a->argc != e->args)
00909 return CLI_SHOWUSAGE;
00910
00911 s = a->argv[e->args-1];
00912 if (!strcasecmp(s, "mute"))
00913 pvt->muted = 1;
00914 else if (!strcasecmp(s, "unmute"))
00915 pvt->muted = 0;
00916 else
00917 res = CLI_SHOWUSAGE;
00918
00919 ast_verb(1, V_BEGIN "The Console is now %s" V_END,
00920 pvt->muted ? "Muted" : "Unmuted");
00921
00922 unref_pvt(pvt);
00923
00924 return res;
00925 }
00926
00927 static char *cli_list_available(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00928 {
00929 PaDeviceIndex idx, num, def_input, def_output;
00930
00931 if (cmd == CLI_INIT) {
00932 e->command = "console list available";
00933 e->usage =
00934 "Usage: console list available\n"
00935 " List all available devices.\n";
00936 return NULL;
00937 } else if (cmd == CLI_GENERATE)
00938 return NULL;
00939
00940 if (a->argc != e->args)
00941 return CLI_SHOWUSAGE;
00942
00943 ast_cli(a->fd, "\n"
00944 "=============================================================\n"
00945 "=== Available Devices =======================================\n"
00946 "=============================================================\n"
00947 "===\n");
00948
00949 num = Pa_GetDeviceCount();
00950 if (!num) {
00951 ast_cli(a->fd, "(None)\n");
00952 return CLI_SUCCESS;
00953 }
00954
00955 def_input = Pa_GetDefaultInputDevice();
00956 def_output = Pa_GetDefaultOutputDevice();
00957 for (idx = 0; idx < num; idx++) {
00958 const PaDeviceInfo *dev = Pa_GetDeviceInfo(idx);
00959 if (!dev)
00960 continue;
00961 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
00962 "=== Device Name: %s\n", dev->name);
00963 if (dev->maxInputChannels)
00964 ast_cli(a->fd, "=== ---> %sInput Device\n", (idx == def_input) ? "Default " : "");
00965 if (dev->maxOutputChannels)
00966 ast_cli(a->fd, "=== ---> %sOutput Device\n", (idx == def_output) ? "Default " : "");
00967 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
00968 }
00969
00970 ast_cli(a->fd, "=============================================================\n\n");
00971
00972 return CLI_SUCCESS;
00973 }
00974
00975 static char *cli_list_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00976 {
00977 struct ao2_iterator i;
00978 struct console_pvt *pvt;
00979
00980 if (cmd == CLI_INIT) {
00981 e->command = "console list devices";
00982 e->usage =
00983 "Usage: console list devices\n"
00984 " List all configured devices.\n";
00985 return NULL;
00986 } else if (cmd == CLI_GENERATE)
00987 return NULL;
00988
00989 if (a->argc != e->args)
00990 return CLI_SHOWUSAGE;
00991
00992 ast_cli(a->fd, "\n"
00993 "=============================================================\n"
00994 "=== Configured Devices ======================================\n"
00995 "=============================================================\n"
00996 "===\n");
00997
00998 i = ao2_iterator_init(pvts, 0);
00999 while ((pvt = ao2_iterator_next(&i))) {
01000 console_pvt_lock(pvt);
01001
01002 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01003 "=== Device Name: %s\n"
01004 "=== ---> Active: %s\n"
01005 "=== ---> Input Device: %s\n"
01006 "=== ---> Output Device: %s\n"
01007 "=== ---> Context: %s\n"
01008 "=== ---> Extension: %s\n"
01009 "=== ---> CallerID Num: %s\n"
01010 "=== ---> CallerID Name: %s\n"
01011 "=== ---> MOH Interpret: %s\n"
01012 "=== ---> Language: %s\n"
01013 "=== ---> Parkinglot: %s\n"
01014 "=== ---> Muted: %s\n"
01015 "=== ---> Auto-Answer: %s\n"
01016 "=== ---> Override Context: %s\n"
01017 "=== ---------------------------------------------------------\n===\n",
01018 pvt->name, (pvt == active_pvt) ? "Yes" : "No",
01019 pvt->input_device, pvt->output_device, pvt->context,
01020 pvt->exten, pvt->cid_num, pvt->cid_name, pvt->mohinterpret,
01021 pvt->language, pvt->parkinglot, pvt->muted ? "Yes" : "No", pvt->autoanswer ? "Yes" : "No",
01022 pvt->overridecontext ? "Yes" : "No");
01023
01024 console_pvt_unlock(pvt);
01025 unref_pvt(pvt);
01026 }
01027 ao2_iterator_destroy(&i);
01028
01029 ast_cli(a->fd, "=============================================================\n\n");
01030
01031 return CLI_SUCCESS;
01032 }
01033
01034
01035
01036 static char *cli_console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01037 {
01038 struct console_pvt *pvt = get_active_pvt();
01039
01040 switch (cmd) {
01041 case CLI_INIT:
01042 e->command = "console answer";
01043 e->usage =
01044 "Usage: console answer\n"
01045 " Answers an incoming call on the console channel.\n";
01046 return NULL;
01047
01048 case CLI_GENERATE:
01049 return NULL;
01050 }
01051
01052 if (!pvt) {
01053 ast_cli(a->fd, "No console device is set as active\n");
01054 return CLI_FAILURE;
01055 }
01056
01057 if (a->argc != e->args) {
01058 unref_pvt(pvt);
01059 return CLI_SHOWUSAGE;
01060 }
01061
01062 if (!pvt->owner) {
01063 ast_cli(a->fd, "No one is calling us\n");
01064 unref_pvt(pvt);
01065 return CLI_FAILURE;
01066 }
01067
01068 pvt->hookstate = 1;
01069
01070 ast_indicate(pvt->owner, -1);
01071
01072 ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
01073
01074 unref_pvt(pvt);
01075
01076 return CLI_SUCCESS;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085 static char *cli_console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01086 {
01087 char buf[TEXT_SIZE];
01088 struct console_pvt *pvt = get_active_pvt();
01089 struct ast_frame f = {
01090 .frametype = AST_FRAME_TEXT,
01091 .data.ptr = buf,
01092 .src = "console_send_text",
01093 };
01094 int len;
01095
01096 if (cmd == CLI_INIT) {
01097 e->command = "console send text";
01098 e->usage =
01099 "Usage: console send text <message>\n"
01100 " Sends a text message for display on the remote terminal.\n";
01101 return NULL;
01102 } else if (cmd == CLI_GENERATE)
01103 return NULL;
01104
01105 if (!pvt) {
01106 ast_cli(a->fd, "No console device is set as active\n");
01107 return CLI_FAILURE;
01108 }
01109
01110 if (a->argc < e->args + 1) {
01111 unref_pvt(pvt);
01112 return CLI_SHOWUSAGE;
01113 }
01114
01115 if (!pvt->owner) {
01116 ast_cli(a->fd, "Not in a call\n");
01117 unref_pvt(pvt);
01118 return CLI_FAILURE;
01119 }
01120
01121 ast_join(buf, sizeof(buf) - 1, a->argv + e->args);
01122 if (ast_strlen_zero(buf)) {
01123 unref_pvt(pvt);
01124 return CLI_SHOWUSAGE;
01125 }
01126
01127 len = strlen(buf);
01128 buf[len] = '\n';
01129 f.datalen = len + 1;
01130
01131 ast_queue_frame(pvt->owner, &f);
01132
01133 unref_pvt(pvt);
01134
01135 return CLI_SUCCESS;
01136 }
01137
01138 static void set_active(struct console_pvt *pvt, const char *value)
01139 {
01140 if (pvt == &globals) {
01141 ast_log(LOG_ERROR, "active is only valid as a per-device setting\n");
01142 return;
01143 }
01144
01145 if (!ast_true(value))
01146 return;
01147
01148 ast_rwlock_wrlock(&active_lock);
01149 if (active_pvt)
01150 unref_pvt(active_pvt);
01151 active_pvt = ref_pvt(pvt);
01152 ast_rwlock_unlock(&active_lock);
01153 }
01154
01155 static char *cli_console_active(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01156 {
01157 struct console_pvt *pvt;
01158
01159 switch (cmd) {
01160 case CLI_INIT:
01161 e->command = "console {set|show} active";
01162 e->usage =
01163 "Usage: console {set|show} active [<device>]\n"
01164 " Set or show the active console device for the Asterisk CLI.\n";
01165 return NULL;
01166 case CLI_GENERATE:
01167 if (a->pos == e->args) {
01168 struct ao2_iterator i;
01169 int x = 0;
01170 char *res = NULL;
01171 i = ao2_iterator_init(pvts, 0);
01172 while ((pvt = ao2_iterator_next(&i))) {
01173 if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
01174 res = ast_strdup(pvt->name);
01175 unref_pvt(pvt);
01176 if (res) {
01177 ao2_iterator_destroy(&i);
01178 return res;
01179 }
01180 }
01181 ao2_iterator_destroy(&i);
01182 }
01183 return NULL;
01184 }
01185
01186 if (a->argc < e->args)
01187 return CLI_SHOWUSAGE;
01188
01189 if (a->argc == 3) {
01190 pvt = get_active_pvt();
01191
01192 if (!pvt)
01193 ast_cli(a->fd, "No device is currently set as the active console device.\n");
01194 else {
01195 console_pvt_lock(pvt);
01196 ast_cli(a->fd, "The active console device is '%s'.\n", pvt->name);
01197 console_pvt_unlock(pvt);
01198 pvt = unref_pvt(pvt);
01199 }
01200
01201 return CLI_SUCCESS;
01202 }
01203
01204 if (!(pvt = find_pvt(a->argv[e->args - 1]))) {
01205 ast_cli(a->fd, "Could not find a device called '%s'.\n", a->argv[e->args]);
01206 return CLI_FAILURE;
01207 }
01208
01209 set_active(pvt, "yes");
01210
01211 console_pvt_lock(pvt);
01212 ast_cli(a->fd, "The active console device has been set to '%s'\n", pvt->name);
01213 console_pvt_unlock(pvt);
01214
01215 unref_pvt(pvt);
01216
01217 return CLI_SUCCESS;
01218 }
01219
01220 static struct ast_cli_entry cli_console[] = {
01221 AST_CLI_DEFINE(cli_console_dial, "Dial an extension from the console"),
01222 AST_CLI_DEFINE(cli_console_hangup, "Hangup a call on the console"),
01223 AST_CLI_DEFINE(cli_console_mute, "Disable/Enable mic input"),
01224 AST_CLI_DEFINE(cli_console_answer, "Answer an incoming console call"),
01225 AST_CLI_DEFINE(cli_console_sendtext, "Send text to a connected party"),
01226 AST_CLI_DEFINE(cli_console_flash, "Send a flash to the connected party"),
01227 AST_CLI_DEFINE(cli_console_autoanswer, "Turn autoanswer on or off"),
01228 AST_CLI_DEFINE(cli_list_available, "List available devices"),
01229 AST_CLI_DEFINE(cli_list_devices, "List configured devices"),
01230 AST_CLI_DEFINE(cli_console_active, "View or Set the active console device"),
01231 };
01232
01233
01234
01235
01236
01237
01238 static void set_pvt_defaults(struct console_pvt *pvt)
01239 {
01240 if (pvt == &globals) {
01241 ast_string_field_set(pvt, mohinterpret, "default");
01242 ast_string_field_set(pvt, context, "default");
01243 ast_string_field_set(pvt, exten, "s");
01244 ast_string_field_set(pvt, language, "");
01245 ast_string_field_set(pvt, cid_num, "");
01246 ast_string_field_set(pvt, cid_name, "");
01247 ast_string_field_set(pvt, parkinglot, "");
01248
01249 pvt->overridecontext = 0;
01250 pvt->autoanswer = 0;
01251 } else {
01252 ast_mutex_lock(&globals_lock);
01253
01254 ast_string_field_set(pvt, mohinterpret, globals.mohinterpret);
01255 ast_string_field_set(pvt, context, globals.context);
01256 ast_string_field_set(pvt, exten, globals.exten);
01257 ast_string_field_set(pvt, language, globals.language);
01258 ast_string_field_set(pvt, cid_num, globals.cid_num);
01259 ast_string_field_set(pvt, cid_name, globals.cid_name);
01260 ast_string_field_set(pvt, parkinglot, globals.parkinglot);
01261
01262 pvt->overridecontext = globals.overridecontext;
01263 pvt->autoanswer = globals.autoanswer;
01264
01265 ast_mutex_unlock(&globals_lock);
01266 }
01267 }
01268
01269 static void store_callerid(struct console_pvt *pvt, const char *value)
01270 {
01271 char cid_name[256];
01272 char cid_num[256];
01273
01274 ast_callerid_split(value, cid_name, sizeof(cid_name),
01275 cid_num, sizeof(cid_num));
01276
01277 ast_string_field_set(pvt, cid_name, cid_name);
01278 ast_string_field_set(pvt, cid_num, cid_num);
01279 }
01280
01281
01282
01283
01284
01285
01286 static void store_config_core(struct console_pvt *pvt, const char *var, const char *value)
01287 {
01288 if (pvt == &globals && !ast_jb_read_conf(&global_jbconf, var, value))
01289 return;
01290
01291 CV_START(var, value);
01292
01293 CV_STRFIELD("context", pvt, context);
01294 CV_STRFIELD("extension", pvt, exten);
01295 CV_STRFIELD("mohinterpret", pvt, mohinterpret);
01296 CV_STRFIELD("language", pvt, language);
01297 CV_F("callerid", store_callerid(pvt, value));
01298 CV_BOOL("overridecontext", pvt->overridecontext);
01299 CV_BOOL("autoanswer", pvt->autoanswer);
01300 CV_STRFIELD("parkinglot", pvt, parkinglot);
01301
01302 if (pvt != &globals) {
01303 CV_F("active", set_active(pvt, value))
01304 CV_STRFIELD("input_device", pvt, input_device);
01305 CV_STRFIELD("output_device", pvt, output_device);
01306 }
01307
01308 ast_log(LOG_WARNING, "Unknown option '%s'\n", var);
01309
01310 CV_END;
01311 }
01312
01313 static void pvt_destructor(void *obj)
01314 {
01315 struct console_pvt *pvt = obj;
01316
01317 ast_string_field_free_memory(pvt);
01318 }
01319
01320 static int init_pvt(struct console_pvt *pvt, const char *name)
01321 {
01322 pvt->thread = AST_PTHREADT_NULL;
01323
01324 if (ast_string_field_init(pvt, 32))
01325 return -1;
01326
01327 ast_string_field_set(pvt, name, S_OR(name, ""));
01328
01329 return 0;
01330 }
01331
01332 static void build_device(struct ast_config *cfg, const char *name)
01333 {
01334 struct ast_variable *v;
01335 struct console_pvt *pvt;
01336 int new = 0;
01337
01338 if ((pvt = find_pvt(name))) {
01339 console_pvt_lock(pvt);
01340 set_pvt_defaults(pvt);
01341 pvt->destroy = 0;
01342 } else {
01343 if (!(pvt = ao2_alloc(sizeof(*pvt), pvt_destructor)))
01344 return;
01345 init_pvt(pvt, name);
01346 set_pvt_defaults(pvt);
01347 new = 1;
01348 }
01349
01350 for (v = ast_variable_browse(cfg, name); v; v = v->next)
01351 store_config_core(pvt, v->name, v->value);
01352
01353 if (new)
01354 ao2_link(pvts, pvt);
01355 else
01356 console_pvt_unlock(pvt);
01357
01358 unref_pvt(pvt);
01359 }
01360
01361 static int pvt_mark_destroy_cb(void *obj, void *arg, int flags)
01362 {
01363 struct console_pvt *pvt = obj;
01364 pvt->destroy = 1;
01365 return 0;
01366 }
01367
01368 static void destroy_pvts(void)
01369 {
01370 struct ao2_iterator i;
01371 struct console_pvt *pvt;
01372
01373 i = ao2_iterator_init(pvts, 0);
01374 while ((pvt = ao2_iterator_next(&i))) {
01375 if (pvt->destroy) {
01376 ao2_unlink(pvts, pvt);
01377 ast_rwlock_wrlock(&active_lock);
01378 if (active_pvt == pvt)
01379 active_pvt = unref_pvt(pvt);
01380 ast_rwlock_unlock(&active_lock);
01381 }
01382 unref_pvt(pvt);
01383 }
01384 ao2_iterator_destroy(&i);
01385 }
01386
01387
01388
01389
01390
01391
01392
01393 static int load_config(int reload)
01394 {
01395 struct ast_config *cfg;
01396 struct ast_variable *v;
01397 struct ast_flags config_flags = { 0 };
01398 char *context = NULL;
01399
01400
01401 memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
01402 ast_mutex_lock(&globals_lock);
01403 set_pvt_defaults(&globals);
01404 ast_mutex_unlock(&globals_lock);
01405
01406 if (!(cfg = ast_config_load(config_file, config_flags))) {
01407 ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file);
01408 return -1;
01409 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01410 ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file);
01411 return -1;
01412 }
01413
01414 ao2_callback(pvts, OBJ_NODATA, pvt_mark_destroy_cb, NULL);
01415
01416 ast_mutex_lock(&globals_lock);
01417 for (v = ast_variable_browse(cfg, "general"); v; v = v->next)
01418 store_config_core(&globals, v->name, v->value);
01419 ast_mutex_unlock(&globals_lock);
01420
01421 while ((context = ast_category_browse(cfg, context))) {
01422 if (strcasecmp(context, "general"))
01423 build_device(cfg, context);
01424 }
01425
01426 ast_config_destroy(cfg);
01427
01428 destroy_pvts();
01429
01430 return 0;
01431 }
01432
01433 static int pvt_hash_cb(const void *obj, const int flags)
01434 {
01435 const struct console_pvt *pvt = obj;
01436
01437 return ast_str_case_hash(pvt->name);
01438 }
01439
01440 static int pvt_cmp_cb(void *obj, void *arg, int flags)
01441 {
01442 struct console_pvt *pvt = obj, *pvt2 = arg;
01443
01444 return !strcasecmp(pvt->name, pvt2->name) ? CMP_MATCH | CMP_STOP : 0;
01445 }
01446
01447 static void stop_streams(void)
01448 {
01449 struct console_pvt *pvt;
01450 struct ao2_iterator i;
01451
01452 i = ao2_iterator_init(pvts, 0);
01453 while ((pvt = ao2_iterator_next(&i))) {
01454 if (pvt->hookstate)
01455 stop_stream(pvt);
01456 unref_pvt(pvt);
01457 }
01458 ao2_iterator_destroy(&i);
01459 }
01460
01461 static int unload_module(void)
01462 {
01463 ast_channel_unregister(&console_tech);
01464 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01465
01466 stop_streams();
01467
01468 Pa_Terminate();
01469
01470
01471 ao2_ref(pvts, -1);
01472
01473 pvt_destructor(&globals);
01474
01475 return 0;
01476 }
01477
01478 static int load_module(void)
01479 {
01480 PaError res;
01481
01482 init_pvt(&globals, NULL);
01483
01484 if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
01485 goto return_error;
01486
01487 if (load_config(0))
01488 goto return_error;
01489
01490 res = Pa_Initialize();
01491 if (res != paNoError) {
01492 ast_log(LOG_WARNING, "Failed to initialize audio system - (%d) %s\n",
01493 res, Pa_GetErrorText(res));
01494 goto return_error_pa_init;
01495 }
01496
01497 if (ast_channel_register(&console_tech)) {
01498 ast_log(LOG_ERROR, "Unable to register channel type 'Console'\n");
01499 goto return_error_chan_reg;
01500 }
01501
01502 if (ast_cli_register_multiple(cli_console, ARRAY_LEN(cli_console)))
01503 goto return_error_cli_reg;
01504
01505 return AST_MODULE_LOAD_SUCCESS;
01506
01507 return_error_cli_reg:
01508 ast_cli_unregister_multiple(cli_console, ARRAY_LEN(cli_console));
01509 return_error_chan_reg:
01510 ast_channel_unregister(&console_tech);
01511 return_error_pa_init:
01512 Pa_Terminate();
01513 return_error:
01514 if (pvts)
01515 ao2_ref(pvts, -1);
01516 pvts = NULL;
01517 pvt_destructor(&globals);
01518
01519 return AST_MODULE_LOAD_DECLINE;
01520 }
01521
01522 static int reload(void)
01523 {
01524 return load_config(1);
01525 }
01526
01527 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Console Channel Driver",
01528 .load = load_module,
01529 .unload = unload_module,
01530 .reload = reload,
01531 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01532 );