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