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 #include "asterisk.h"
00042
00043 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374166 $")
00044
00045 #include <fcntl.h>
00046 #include <sys/ioctl.h>
00047 #include <sys/time.h>
00048
00049 #define ALSA_PCM_NEW_HW_PARAMS_API
00050 #define ALSA_PCM_NEW_SW_PARAMS_API
00051 #include <alsa/asoundlib.h>
00052
00053 #include "asterisk/frame.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/module.h"
00056 #include "asterisk/pbx.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/cli.h"
00059 #include "asterisk/utils.h"
00060 #include "asterisk/causes.h"
00061 #include "asterisk/endian.h"
00062 #include "asterisk/stringfields.h"
00063 #include "asterisk/abstract_jb.h"
00064 #include "asterisk/musiconhold.h"
00065 #include "asterisk/poll-compat.h"
00066
00067
00068
00069 static struct ast_jb_conf default_jbconf = {
00070 .flags = 0,
00071 .max_size = 200,
00072 .resync_threshold = 1000,
00073 .impl = "fixed",
00074 .target_extra = 40,
00075 };
00076 static struct ast_jb_conf global_jbconf;
00077
00078 #define DEBUG 0
00079
00080 #define ALSA_INDEV "default"
00081 #define ALSA_OUTDEV "default"
00082 #define DESIRED_RATE 8000
00083
00084
00085 #define FRAME_SIZE 160
00086 #define PERIOD_FRAMES 80
00087
00088
00089
00090
00091 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
00092
00093
00094 #define MIN_SWITCH_TIME 600
00095
00096 #if __BYTE_ORDER == __LITTLE_ENDIAN
00097 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
00098 #else
00099 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
00100 #endif
00101
00102 static char indevname[50] = ALSA_INDEV;
00103 static char outdevname[50] = ALSA_OUTDEV;
00104
00105 static int silencesuppression = 0;
00106 static int silencethreshold = 1000;
00107
00108 AST_MUTEX_DEFINE_STATIC(alsalock);
00109
00110 static const char tdesc[] = "ALSA Console Channel Driver";
00111 static const char config[] = "alsa.conf";
00112
00113 static char context[AST_MAX_CONTEXT] = "default";
00114 static char language[MAX_LANGUAGE] = "";
00115 static char exten[AST_MAX_EXTENSION] = "s";
00116 static char mohinterpret[MAX_MUSICCLASS];
00117
00118 static int hookstate = 0;
00119
00120 static struct chan_alsa_pvt {
00121
00122
00123 struct ast_channel *owner;
00124 char exten[AST_MAX_EXTENSION];
00125 char context[AST_MAX_CONTEXT];
00126 snd_pcm_t *icard, *ocard;
00127
00128 } alsa;
00129
00130
00131
00132
00133
00134 #define MAX_BUFFER_SIZE 100
00135
00136
00137 static int readdev = -1;
00138 static int writedev = -1;
00139
00140 static int autoanswer = 1;
00141 static int mute = 0;
00142 static int noaudiocapture = 0;
00143
00144 static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00145 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
00146 static int alsa_text(struct ast_channel *c, const char *text);
00147 static int alsa_hangup(struct ast_channel *c);
00148 static int alsa_answer(struct ast_channel *c);
00149 static struct ast_frame *alsa_read(struct ast_channel *chan);
00150 static int alsa_call(struct ast_channel *c, const char *dest, int timeout);
00151 static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
00152 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00153 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00154
00155 static struct ast_channel_tech alsa_tech = {
00156 .type = "Console",
00157 .description = tdesc,
00158 .requester = alsa_request,
00159 .send_digit_end = alsa_digit,
00160 .send_text = alsa_text,
00161 .hangup = alsa_hangup,
00162 .answer = alsa_answer,
00163 .read = alsa_read,
00164 .call = alsa_call,
00165 .write = alsa_write,
00166 .indicate = alsa_indicate,
00167 .fixup = alsa_fixup,
00168 };
00169
00170 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
00171 {
00172 int err;
00173 int direction;
00174 snd_pcm_t *handle = NULL;
00175 snd_pcm_hw_params_t *hwparams = NULL;
00176 snd_pcm_sw_params_t *swparams = NULL;
00177 struct pollfd pfd;
00178 snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
00179 snd_pcm_uframes_t buffer_size = 0;
00180 unsigned int rate = DESIRED_RATE;
00181 snd_pcm_uframes_t start_threshold, stop_threshold;
00182
00183 err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
00184 if (err < 0) {
00185 ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
00186 return NULL;
00187 } else {
00188 ast_debug(1, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
00189 }
00190
00191 hwparams = ast_alloca(snd_pcm_hw_params_sizeof());
00192 memset(hwparams, 0, snd_pcm_hw_params_sizeof());
00193 snd_pcm_hw_params_any(handle, hwparams);
00194
00195 err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
00196 if (err < 0)
00197 ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
00198
00199 err = snd_pcm_hw_params_set_format(handle, hwparams, format);
00200 if (err < 0)
00201 ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
00202
00203 err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
00204 if (err < 0)
00205 ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
00206
00207 direction = 0;
00208 err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
00209 if (rate != DESIRED_RATE)
00210 ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
00211
00212 direction = 0;
00213 err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
00214 if (err < 0)
00215 ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
00216 else {
00217 ast_debug(1, "Period size is %d\n", err);
00218 }
00219
00220 buffer_size = 4096 * 2;
00221 err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
00222 if (err < 0)
00223 ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
00224 else {
00225 ast_debug(1, "Buffer size is set to %d frames\n", err);
00226 }
00227
00228 err = snd_pcm_hw_params(handle, hwparams);
00229 if (err < 0)
00230 ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
00231
00232 swparams = ast_alloca(snd_pcm_sw_params_sizeof());
00233 memset(swparams, 0, snd_pcm_sw_params_sizeof());
00234 snd_pcm_sw_params_current(handle, swparams);
00235
00236 if (stream == SND_PCM_STREAM_PLAYBACK)
00237 start_threshold = period_size;
00238 else
00239 start_threshold = 1;
00240
00241 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00242 if (err < 0)
00243 ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
00244
00245 if (stream == SND_PCM_STREAM_PLAYBACK)
00246 stop_threshold = buffer_size;
00247 else
00248 stop_threshold = buffer_size;
00249
00250 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00251 if (err < 0)
00252 ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
00253
00254 err = snd_pcm_sw_params(handle, swparams);
00255 if (err < 0)
00256 ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
00257
00258 err = snd_pcm_poll_descriptors_count(handle);
00259 if (err <= 0)
00260 ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
00261 if (err != 1) {
00262 ast_debug(1, "Can't handle more than one device\n");
00263 }
00264
00265 snd_pcm_poll_descriptors(handle, &pfd, err);
00266 ast_debug(1, "Acquired fd %d from the poll descriptor\n", pfd.fd);
00267
00268 if (stream == SND_PCM_STREAM_CAPTURE)
00269 readdev = pfd.fd;
00270 else
00271 writedev = pfd.fd;
00272
00273 return handle;
00274 }
00275
00276 static int soundcard_init(void)
00277 {
00278 if (!noaudiocapture) {
00279 alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
00280 if (!alsa.icard) {
00281 ast_log(LOG_ERROR, "Problem opening alsa capture device\n");
00282 return -1;
00283 }
00284 }
00285
00286 alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
00287
00288 if (!alsa.ocard) {
00289 ast_log(LOG_ERROR, "Problem opening ALSA playback device\n");
00290 return -1;
00291 }
00292
00293 return writedev;
00294 }
00295
00296 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
00297 {
00298 ast_mutex_lock(&alsalock);
00299 ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
00300 digit, duration);
00301 ast_mutex_unlock(&alsalock);
00302
00303 return 0;
00304 }
00305
00306 static int alsa_text(struct ast_channel *c, const char *text)
00307 {
00308 ast_mutex_lock(&alsalock);
00309 ast_verbose(" << Console Received text %s >> \n", text);
00310 ast_mutex_unlock(&alsalock);
00311
00312 return 0;
00313 }
00314
00315 static void grab_owner(void)
00316 {
00317 while (alsa.owner && ast_channel_trylock(alsa.owner)) {
00318 DEADLOCK_AVOIDANCE(&alsalock);
00319 }
00320 }
00321
00322 static int alsa_call(struct ast_channel *c, const char *dest, int timeout)
00323 {
00324 struct ast_frame f = { AST_FRAME_CONTROL };
00325
00326 ast_mutex_lock(&alsalock);
00327 ast_verbose(" << Call placed to '%s' on console >> \n", dest);
00328 if (autoanswer) {
00329 ast_verbose(" << Auto-answered >> \n");
00330 if (mute) {
00331 ast_verbose( " << Muted >> \n" );
00332 }
00333 grab_owner();
00334 if (alsa.owner) {
00335 f.subclass.integer = AST_CONTROL_ANSWER;
00336 ast_queue_frame(alsa.owner, &f);
00337 ast_channel_unlock(alsa.owner);
00338 }
00339 } else {
00340 ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00341 grab_owner();
00342 if (alsa.owner) {
00343 f.subclass.integer = AST_CONTROL_RINGING;
00344 ast_queue_frame(alsa.owner, &f);
00345 ast_channel_unlock(alsa.owner);
00346 ast_indicate(alsa.owner, AST_CONTROL_RINGING);
00347 }
00348 }
00349 if (!noaudiocapture) {
00350 snd_pcm_prepare(alsa.icard);
00351 snd_pcm_start(alsa.icard);
00352 }
00353 ast_mutex_unlock(&alsalock);
00354
00355 return 0;
00356 }
00357
00358 static int alsa_answer(struct ast_channel *c)
00359 {
00360 ast_mutex_lock(&alsalock);
00361 ast_verbose(" << Console call has been answered >> \n");
00362 ast_setstate(c, AST_STATE_UP);
00363 if (!noaudiocapture) {
00364 snd_pcm_prepare(alsa.icard);
00365 snd_pcm_start(alsa.icard);
00366 }
00367 ast_mutex_unlock(&alsalock);
00368
00369 return 0;
00370 }
00371
00372 static int alsa_hangup(struct ast_channel *c)
00373 {
00374 ast_mutex_lock(&alsalock);
00375 ast_channel_tech_pvt_set(c, NULL);
00376 alsa.owner = NULL;
00377 ast_verbose(" << Hangup on console >> \n");
00378 ast_module_unref(ast_module_info->self);
00379 hookstate = 0;
00380 if (!noaudiocapture) {
00381 snd_pcm_drop(alsa.icard);
00382 }
00383 ast_mutex_unlock(&alsalock);
00384
00385 return 0;
00386 }
00387
00388 static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
00389 {
00390 static char sizbuf[8000];
00391 static int sizpos = 0;
00392 int len = sizpos;
00393 int res = 0;
00394
00395 snd_pcm_state_t state;
00396
00397 ast_mutex_lock(&alsalock);
00398
00399
00400 if (f->datalen > sizeof(sizbuf) - sizpos) {
00401 ast_log(LOG_WARNING, "Frame too large\n");
00402 res = -1;
00403 } else {
00404 memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
00405 len += f->datalen;
00406 state = snd_pcm_state(alsa.ocard);
00407 if (state == SND_PCM_STATE_XRUN)
00408 snd_pcm_prepare(alsa.ocard);
00409 while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00410 usleep(1);
00411 }
00412 if (res == -EPIPE) {
00413 #if DEBUG
00414 ast_debug(1, "XRUN write\n");
00415 #endif
00416 snd_pcm_prepare(alsa.ocard);
00417 while ((res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2)) == -EAGAIN) {
00418 usleep(1);
00419 }
00420 if (res != len / 2) {
00421 ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res));
00422 res = -1;
00423 } else if (res < 0) {
00424 ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res));
00425 res = -1;
00426 }
00427 } else {
00428 if (res == -ESTRPIPE)
00429 ast_log(LOG_ERROR, "You've got some big problems\n");
00430 else if (res < 0)
00431 ast_log(LOG_NOTICE, "Error %d on write\n", res);
00432 }
00433 }
00434 ast_mutex_unlock(&alsalock);
00435
00436 return res >= 0 ? 0 : res;
00437 }
00438
00439
00440 static struct ast_frame *alsa_read(struct ast_channel *chan)
00441 {
00442 static struct ast_frame f;
00443 static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
00444 short *buf;
00445 static int readpos = 0;
00446 static int left = FRAME_SIZE;
00447 snd_pcm_state_t state;
00448 int r = 0;
00449
00450 ast_mutex_lock(&alsalock);
00451 f.frametype = AST_FRAME_NULL;
00452 f.subclass.integer = 0;
00453 f.samples = 0;
00454 f.datalen = 0;
00455 f.data.ptr = NULL;
00456 f.offset = 0;
00457 f.src = "Console";
00458 f.mallocd = 0;
00459 f.delivery.tv_sec = 0;
00460 f.delivery.tv_usec = 0;
00461
00462 if (noaudiocapture) {
00463
00464 ast_mutex_unlock(&alsalock);
00465 return &f;
00466 }
00467
00468 state = snd_pcm_state(alsa.icard);
00469 if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) {
00470 snd_pcm_prepare(alsa.icard);
00471 }
00472
00473 buf = __buf + AST_FRIENDLY_OFFSET / 2;
00474
00475 r = snd_pcm_readi(alsa.icard, buf + readpos, left);
00476 if (r == -EPIPE) {
00477 #if DEBUG
00478 ast_log(LOG_ERROR, "XRUN read\n");
00479 #endif
00480 snd_pcm_prepare(alsa.icard);
00481 } else if (r == -ESTRPIPE) {
00482 ast_log(LOG_ERROR, "-ESTRPIPE\n");
00483 snd_pcm_prepare(alsa.icard);
00484 } else if (r < 0) {
00485 ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r));
00486 }
00487
00488 readpos += r;
00489 left -= r;
00490
00491 if (readpos >= FRAME_SIZE) {
00492
00493 readpos = 0;
00494 left = FRAME_SIZE;
00495 if (ast_channel_state(chan) != AST_STATE_UP) {
00496
00497 ast_mutex_unlock(&alsalock);
00498 return &f;
00499 }
00500 if (mute) {
00501
00502 ast_mutex_unlock(&alsalock);
00503 return &f;
00504 }
00505
00506 f.frametype = AST_FRAME_VOICE;
00507 ast_format_set(&f.subclass.format, AST_FORMAT_SLINEAR, 0);
00508 f.samples = FRAME_SIZE;
00509 f.datalen = FRAME_SIZE * 2;
00510 f.data.ptr = buf;
00511 f.offset = AST_FRIENDLY_OFFSET;
00512 f.src = "Console";
00513 f.mallocd = 0;
00514
00515 }
00516 ast_mutex_unlock(&alsalock);
00517
00518 return &f;
00519 }
00520
00521 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00522 {
00523 struct chan_alsa_pvt *p = ast_channel_tech_pvt(newchan);
00524
00525 ast_mutex_lock(&alsalock);
00526 p->owner = newchan;
00527 ast_mutex_unlock(&alsalock);
00528
00529 return 0;
00530 }
00531
00532 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
00533 {
00534 int res = 0;
00535
00536 ast_mutex_lock(&alsalock);
00537
00538 switch (cond) {
00539 case AST_CONTROL_BUSY:
00540 case AST_CONTROL_CONGESTION:
00541 case AST_CONTROL_RINGING:
00542 case AST_CONTROL_INCOMPLETE:
00543 case AST_CONTROL_PVT_CAUSE_CODE:
00544 case -1:
00545 res = -1;
00546 break;
00547 case AST_CONTROL_PROGRESS:
00548 case AST_CONTROL_PROCEEDING:
00549 case AST_CONTROL_VIDUPDATE:
00550 case AST_CONTROL_SRCUPDATE:
00551 break;
00552 case AST_CONTROL_HOLD:
00553 ast_verbose(" << Console Has Been Placed on Hold >> \n");
00554 ast_moh_start(chan, data, mohinterpret);
00555 break;
00556 case AST_CONTROL_UNHOLD:
00557 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00558 ast_moh_stop(chan);
00559 break;
00560 default:
00561 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, ast_channel_name(chan));
00562 res = -1;
00563 }
00564
00565 ast_mutex_unlock(&alsalock);
00566
00567 return res;
00568 }
00569
00570 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const char *linkedid)
00571 {
00572 struct ast_channel *tmp = NULL;
00573
00574 if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, linkedid, 0, "ALSA/%s", indevname)))
00575 return NULL;
00576
00577 ast_channel_tech_set(tmp, &alsa_tech);
00578 ast_channel_set_fd(tmp, 0, readdev);
00579 ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
00580 ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
00581 ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
00582
00583 ast_channel_tech_pvt_set(tmp, p);
00584 if (!ast_strlen_zero(p->context))
00585 ast_channel_context_set(tmp, p->context);
00586 if (!ast_strlen_zero(p->exten))
00587 ast_channel_exten_set(tmp, p->exten);
00588 if (!ast_strlen_zero(language))
00589 ast_channel_language_set(tmp, language);
00590 p->owner = tmp;
00591 ast_module_ref(ast_module_info->self);
00592 ast_jb_configure(tmp, &global_jbconf);
00593 if (state != AST_STATE_DOWN) {
00594 if (ast_pbx_start(tmp)) {
00595 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
00596 ast_hangup(tmp);
00597 tmp = NULL;
00598 }
00599 }
00600
00601 return tmp;
00602 }
00603
00604 static struct ast_channel *alsa_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
00605 {
00606 struct ast_format tmpfmt;
00607 char buf[256];
00608 struct ast_channel *tmp = NULL;
00609
00610 ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);
00611
00612 if (!(ast_format_cap_iscompatible(cap, &tmpfmt))) {
00613 ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
00614 return NULL;
00615 }
00616
00617 ast_mutex_lock(&alsalock);
00618
00619 if (alsa.owner) {
00620 ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
00621 *cause = AST_CAUSE_BUSY;
00622 } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL))) {
00623 ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
00624 }
00625
00626 ast_mutex_unlock(&alsalock);
00627
00628 return tmp;
00629 }
00630
00631 static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
00632 {
00633 switch (state) {
00634 case 0:
00635 if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
00636 return ast_strdup("on");
00637 case 1:
00638 if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
00639 return ast_strdup("off");
00640 default:
00641 return NULL;
00642 }
00643
00644 return NULL;
00645 }
00646
00647 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00648 {
00649 char *res = CLI_SUCCESS;
00650
00651 switch (cmd) {
00652 case CLI_INIT:
00653 e->command = "console autoanswer";
00654 e->usage =
00655 "Usage: console autoanswer [on|off]\n"
00656 " Enables or disables autoanswer feature. If used without\n"
00657 " argument, displays the current on/off status of autoanswer.\n"
00658 " The default value of autoanswer is in 'alsa.conf'.\n";
00659 return NULL;
00660 case CLI_GENERATE:
00661 return autoanswer_complete(a->line, a->word, a->pos, a->n);
00662 }
00663
00664 if ((a->argc != 2) && (a->argc != 3))
00665 return CLI_SHOWUSAGE;
00666
00667 ast_mutex_lock(&alsalock);
00668 if (a->argc == 2) {
00669 ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00670 } else {
00671 if (!strcasecmp(a->argv[2], "on"))
00672 autoanswer = -1;
00673 else if (!strcasecmp(a->argv[2], "off"))
00674 autoanswer = 0;
00675 else
00676 res = CLI_SHOWUSAGE;
00677 }
00678 ast_mutex_unlock(&alsalock);
00679
00680 return res;
00681 }
00682
00683 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00684 {
00685 char *res = CLI_SUCCESS;
00686
00687 switch (cmd) {
00688 case CLI_INIT:
00689 e->command = "console answer";
00690 e->usage =
00691 "Usage: console answer\n"
00692 " Answers an incoming call on the console (ALSA) channel.\n";
00693
00694 return NULL;
00695 case CLI_GENERATE:
00696 return NULL;
00697 }
00698
00699 if (a->argc != 2)
00700 return CLI_SHOWUSAGE;
00701
00702 ast_mutex_lock(&alsalock);
00703
00704 if (!alsa.owner) {
00705 ast_cli(a->fd, "No one is calling us\n");
00706 res = CLI_FAILURE;
00707 } else {
00708 if (mute) {
00709 ast_verbose( " << Muted >> \n" );
00710 }
00711 hookstate = 1;
00712 grab_owner();
00713 if (alsa.owner) {
00714 ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
00715 ast_channel_unlock(alsa.owner);
00716 }
00717 }
00718
00719 if (!noaudiocapture) {
00720 snd_pcm_prepare(alsa.icard);
00721 snd_pcm_start(alsa.icard);
00722 }
00723
00724 ast_mutex_unlock(&alsalock);
00725
00726 return res;
00727 }
00728
00729 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00730 {
00731 int tmparg = 3;
00732 char *res = CLI_SUCCESS;
00733
00734 switch (cmd) {
00735 case CLI_INIT:
00736 e->command = "console send text";
00737 e->usage =
00738 "Usage: console send text <message>\n"
00739 " Sends a text message for display on the remote terminal.\n";
00740 return NULL;
00741 case CLI_GENERATE:
00742 return NULL;
00743 }
00744
00745 if (a->argc < 3)
00746 return CLI_SHOWUSAGE;
00747
00748 ast_mutex_lock(&alsalock);
00749
00750 if (!alsa.owner) {
00751 ast_cli(a->fd, "No channel active\n");
00752 res = CLI_FAILURE;
00753 } else {
00754 struct ast_frame f = { AST_FRAME_TEXT };
00755 char text2send[256] = "";
00756
00757 while (tmparg < a->argc) {
00758 strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
00759 strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
00760 }
00761
00762 text2send[strlen(text2send) - 1] = '\n';
00763 f.data.ptr = text2send;
00764 f.datalen = strlen(text2send) + 1;
00765 grab_owner();
00766 if (alsa.owner) {
00767 ast_queue_frame(alsa.owner, &f);
00768 ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
00769 ast_channel_unlock(alsa.owner);
00770 }
00771 }
00772
00773 ast_mutex_unlock(&alsalock);
00774
00775 return res;
00776 }
00777
00778 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00779 {
00780 char *res = CLI_SUCCESS;
00781
00782 switch (cmd) {
00783 case CLI_INIT:
00784 e->command = "console hangup";
00785 e->usage =
00786 "Usage: console hangup\n"
00787 " Hangs up any call currently placed on the console.\n";
00788 return NULL;
00789 case CLI_GENERATE:
00790 return NULL;
00791 }
00792
00793
00794 if (a->argc != 2)
00795 return CLI_SHOWUSAGE;
00796
00797 ast_mutex_lock(&alsalock);
00798
00799 if (!alsa.owner && !hookstate) {
00800 ast_cli(a->fd, "No call to hangup\n");
00801 res = CLI_FAILURE;
00802 } else {
00803 hookstate = 0;
00804 grab_owner();
00805 if (alsa.owner) {
00806 ast_queue_hangup_with_cause(alsa.owner, AST_CAUSE_NORMAL_CLEARING);
00807 ast_channel_unlock(alsa.owner);
00808 }
00809 }
00810
00811 ast_mutex_unlock(&alsalock);
00812
00813 return res;
00814 }
00815
00816 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00817 {
00818 char tmp[256], *tmp2;
00819 char *mye, *myc;
00820 const char *d;
00821 char *res = CLI_SUCCESS;
00822
00823 switch (cmd) {
00824 case CLI_INIT:
00825 e->command = "console dial";
00826 e->usage =
00827 "Usage: console dial [extension[@context]]\n"
00828 " Dials a given extension (and context if specified)\n";
00829 return NULL;
00830 case CLI_GENERATE:
00831 return NULL;
00832 }
00833
00834 if ((a->argc != 2) && (a->argc != 3))
00835 return CLI_SHOWUSAGE;
00836
00837 ast_mutex_lock(&alsalock);
00838
00839 if (alsa.owner) {
00840 if (a->argc == 3) {
00841 if (alsa.owner) {
00842 for (d = a->argv[2]; *d; d++) {
00843 struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = *d };
00844
00845 ast_queue_frame(alsa.owner, &f);
00846 }
00847 }
00848 } else {
00849 ast_cli(a->fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
00850 res = CLI_FAILURE;
00851 }
00852 } else {
00853 mye = exten;
00854 myc = context;
00855 if (a->argc == 3) {
00856 char *stringp = NULL;
00857
00858 ast_copy_string(tmp, a->argv[2], sizeof(tmp));
00859 stringp = tmp;
00860 strsep(&stringp, "@");
00861 tmp2 = strsep(&stringp, "@");
00862 if (!ast_strlen_zero(tmp))
00863 mye = tmp;
00864 if (!ast_strlen_zero(tmp2))
00865 myc = tmp2;
00866 }
00867 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00868 ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
00869 ast_copy_string(alsa.context, myc, sizeof(alsa.context));
00870 hookstate = 1;
00871 alsa_new(&alsa, AST_STATE_RINGING, NULL);
00872 } else
00873 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00874 }
00875
00876 ast_mutex_unlock(&alsalock);
00877
00878 return res;
00879 }
00880
00881 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00882 {
00883 int toggle = 0;
00884 char *res = CLI_SUCCESS;
00885
00886 switch (cmd) {
00887 case CLI_INIT:
00888 e->command = "console {mute|unmute} [toggle]";
00889 e->usage =
00890 "Usage: console {mute|unmute} [toggle]\n"
00891 " Mute/unmute the microphone.\n";
00892 return NULL;
00893 case CLI_GENERATE:
00894 return NULL;
00895 }
00896
00897
00898 if (a->argc > 3) {
00899 return CLI_SHOWUSAGE;
00900 }
00901
00902 if (a->argc == 3) {
00903 if (strcasecmp(a->argv[2], "toggle"))
00904 return CLI_SHOWUSAGE;
00905 toggle = 1;
00906 }
00907
00908 if (a->argc < 2) {
00909 return CLI_SHOWUSAGE;
00910 }
00911
00912 if (!strcasecmp(a->argv[1], "mute")) {
00913 mute = toggle ? !mute : 1;
00914 } else if (!strcasecmp(a->argv[1], "unmute")) {
00915 mute = toggle ? !mute : 0;
00916 } else {
00917 return CLI_SHOWUSAGE;
00918 }
00919
00920 ast_cli(a->fd, "Console mic is %s\n", mute ? "off" : "on");
00921
00922 return res;
00923 }
00924
00925 static struct ast_cli_entry cli_alsa[] = {
00926 AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
00927 AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
00928 AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
00929 AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
00930 AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
00931 AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
00932 };
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944 static int load_module(void)
00945 {
00946 struct ast_config *cfg;
00947 struct ast_variable *v;
00948 struct ast_flags config_flags = { 0 };
00949 struct ast_format tmpfmt;
00950
00951 if (!(alsa_tech.capabilities = ast_format_cap_alloc())) {
00952 return AST_MODULE_LOAD_DECLINE;
00953 }
00954 ast_format_cap_add(alsa_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
00955
00956
00957 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
00958
00959 strcpy(mohinterpret, "default");
00960
00961 if (!(cfg = ast_config_load(config, config_flags))) {
00962 ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s. Aborting.\n", config);
00963 return AST_MODULE_LOAD_DECLINE;
00964 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00965 ast_log(LOG_ERROR, "%s is in an invalid format. Aborting.\n", config);
00966 return AST_MODULE_LOAD_DECLINE;
00967 }
00968
00969 v = ast_variable_browse(cfg, "general");
00970 for (; v; v = v->next) {
00971
00972 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
00973 continue;
00974 }
00975
00976 if (!strcasecmp(v->name, "autoanswer")) {
00977 autoanswer = ast_true(v->value);
00978 } else if (!strcasecmp(v->name, "mute")) {
00979 mute = ast_true(v->value);
00980 } else if (!strcasecmp(v->name, "noaudiocapture")) {
00981 noaudiocapture = ast_true(v->value);
00982 } else if (!strcasecmp(v->name, "silencesuppression")) {
00983 silencesuppression = ast_true(v->value);
00984 } else if (!strcasecmp(v->name, "silencethreshold")) {
00985 silencethreshold = atoi(v->value);
00986 } else if (!strcasecmp(v->name, "context")) {
00987 ast_copy_string(context, v->value, sizeof(context));
00988 } else if (!strcasecmp(v->name, "language")) {
00989 ast_copy_string(language, v->value, sizeof(language));
00990 } else if (!strcasecmp(v->name, "extension")) {
00991 ast_copy_string(exten, v->value, sizeof(exten));
00992 } else if (!strcasecmp(v->name, "input_device")) {
00993 ast_copy_string(indevname, v->value, sizeof(indevname));
00994 } else if (!strcasecmp(v->name, "output_device")) {
00995 ast_copy_string(outdevname, v->value, sizeof(outdevname));
00996 } else if (!strcasecmp(v->name, "mohinterpret")) {
00997 ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
00998 }
00999 }
01000 ast_config_destroy(cfg);
01001
01002 if (soundcard_init() < 0) {
01003 ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
01004 ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
01005 return AST_MODULE_LOAD_DECLINE;
01006 }
01007
01008 if (ast_channel_register(&alsa_tech)) {
01009 ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
01010 return AST_MODULE_LOAD_FAILURE;
01011 }
01012
01013 ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
01014
01015 return AST_MODULE_LOAD_SUCCESS;
01016 }
01017
01018 static int unload_module(void)
01019 {
01020 ast_channel_unregister(&alsa_tech);
01021 ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
01022
01023 if (alsa.icard)
01024 snd_pcm_close(alsa.icard);
01025 if (alsa.ocard)
01026 snd_pcm_close(alsa.ocard);
01027 if (alsa.owner)
01028 ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
01029 if (alsa.owner)
01030 return -1;
01031
01032 alsa_tech.capabilities = ast_format_cap_destroy(alsa_tech.capabilities);
01033 return 0;
01034 }
01035
01036 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver",
01037 .load = load_module,
01038 .unload = unload_module,
01039 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01040 );