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 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 278132 $")
00037
00038 #include <fcntl.h>
00039 #include <sys/ioctl.h>
00040 #include <sys/time.h>
00041
00042 #define ALSA_PCM_NEW_HW_PARAMS_API
00043 #define ALSA_PCM_NEW_SW_PARAMS_API
00044 #include <alsa/asoundlib.h>
00045
00046 #include "asterisk/frame.h"
00047 #include "asterisk/channel.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/utils.h"
00053 #include "asterisk/causes.h"
00054 #include "asterisk/endian.h"
00055 #include "asterisk/stringfields.h"
00056 #include "asterisk/abstract_jb.h"
00057 #include "asterisk/musiconhold.h"
00058 #include "asterisk/poll-compat.h"
00059
00060
00061 static struct ast_jb_conf default_jbconf = {
00062 .flags = 0,
00063 .max_size = -1,
00064 .resync_threshold = -1,
00065 .impl = "",
00066 .target_extra = -1,
00067 };
00068 static struct ast_jb_conf global_jbconf;
00069
00070 #define DEBUG 0
00071
00072 #define ALSA_INDEV "default"
00073 #define ALSA_OUTDEV "default"
00074 #define DESIRED_RATE 8000
00075
00076
00077 #define FRAME_SIZE 160
00078 #define PERIOD_FRAMES 80
00079
00080
00081
00082
00083 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006);
00084
00085
00086 #define MIN_SWITCH_TIME 600
00087
00088 #if __BYTE_ORDER == __LITTLE_ENDIAN
00089 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
00090 #else
00091 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
00092 #endif
00093
00094 static char indevname[50] = ALSA_INDEV;
00095 static char outdevname[50] = ALSA_OUTDEV;
00096
00097 static int silencesuppression = 0;
00098 static int silencethreshold = 1000;
00099
00100 AST_MUTEX_DEFINE_STATIC(alsalock);
00101
00102 static const char tdesc[] = "ALSA Console Channel Driver";
00103 static const char config[] = "alsa.conf";
00104
00105 static char context[AST_MAX_CONTEXT] = "default";
00106 static char language[MAX_LANGUAGE] = "";
00107 static char exten[AST_MAX_EXTENSION] = "s";
00108 static char mohinterpret[MAX_MUSICCLASS];
00109
00110 static int hookstate = 0;
00111
00112 static struct chan_alsa_pvt {
00113
00114
00115 struct ast_channel *owner;
00116 char exten[AST_MAX_EXTENSION];
00117 char context[AST_MAX_CONTEXT];
00118 snd_pcm_t *icard, *ocard;
00119
00120 } alsa;
00121
00122
00123
00124
00125
00126 #define MAX_BUFFER_SIZE 100
00127
00128
00129 static int readdev = -1;
00130 static int writedev = -1;
00131
00132 static int autoanswer = 1;
00133 static int mute = 0;
00134 static int noaudiocapture = 0;
00135
00136 static struct ast_channel *alsa_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
00137 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration);
00138 static int alsa_text(struct ast_channel *c, const char *text);
00139 static int alsa_hangup(struct ast_channel *c);
00140 static int alsa_answer(struct ast_channel *c);
00141 static struct ast_frame *alsa_read(struct ast_channel *chan);
00142 static int alsa_call(struct ast_channel *c, char *dest, int timeout);
00143 static int alsa_write(struct ast_channel *chan, struct ast_frame *f);
00144 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen);
00145 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00146
00147 static const struct ast_channel_tech alsa_tech = {
00148 .type = "Console",
00149 .description = tdesc,
00150 .capabilities = AST_FORMAT_SLINEAR,
00151 .requester = alsa_request,
00152 .send_digit_end = alsa_digit,
00153 .send_text = alsa_text,
00154 .hangup = alsa_hangup,
00155 .answer = alsa_answer,
00156 .read = alsa_read,
00157 .call = alsa_call,
00158 .write = alsa_write,
00159 .indicate = alsa_indicate,
00160 .fixup = alsa_fixup,
00161 };
00162
00163 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream)
00164 {
00165 int err;
00166 int direction;
00167 snd_pcm_t *handle = NULL;
00168 snd_pcm_hw_params_t *hwparams = NULL;
00169 snd_pcm_sw_params_t *swparams = NULL;
00170 struct pollfd pfd;
00171 snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4;
00172 snd_pcm_uframes_t buffer_size = 0;
00173 unsigned int rate = DESIRED_RATE;
00174 snd_pcm_uframes_t start_threshold, stop_threshold;
00175
00176 err = snd_pcm_open(&handle, dev, stream, SND_PCM_NONBLOCK);
00177 if (err < 0) {
00178 ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err));
00179 return NULL;
00180 } else {
00181 ast_debug(1, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write");
00182 }
00183
00184 hwparams = alloca(snd_pcm_hw_params_sizeof());
00185 memset(hwparams, 0, snd_pcm_hw_params_sizeof());
00186 snd_pcm_hw_params_any(handle, hwparams);
00187
00188 err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
00189 if (err < 0)
00190 ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err));
00191
00192 err = snd_pcm_hw_params_set_format(handle, hwparams, format);
00193 if (err < 0)
00194 ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err));
00195
00196 err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
00197 if (err < 0)
00198 ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err));
00199
00200 direction = 0;
00201 err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction);
00202 if (rate != DESIRED_RATE)
00203 ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate);
00204
00205 direction = 0;
00206 err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction);
00207 if (err < 0)
00208 ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err));
00209 else {
00210 ast_debug(1, "Period size is %d\n", err);
00211 }
00212
00213 buffer_size = 4096 * 2;
00214 err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
00215 if (err < 0)
00216 ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err));
00217 else {
00218 ast_debug(1, "Buffer size is set to %d frames\n", err);
00219 }
00220
00221 err = snd_pcm_hw_params(handle, hwparams);
00222 if (err < 0)
00223 ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err));
00224
00225 swparams = alloca(snd_pcm_sw_params_sizeof());
00226 memset(swparams, 0, snd_pcm_sw_params_sizeof());
00227 snd_pcm_sw_params_current(handle, swparams);
00228
00229 if (stream == SND_PCM_STREAM_PLAYBACK)
00230 start_threshold = period_size;
00231 else
00232 start_threshold = 1;
00233
00234 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00235 if (err < 0)
00236 ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err));
00237
00238 if (stream == SND_PCM_STREAM_PLAYBACK)
00239 stop_threshold = buffer_size;
00240 else
00241 stop_threshold = buffer_size;
00242
00243 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00244 if (err < 0)
00245 ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err));
00246
00247 err = snd_pcm_sw_params(handle, swparams);
00248 if (err < 0)
00249 ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err));
00250
00251 err = snd_pcm_poll_descriptors_count(handle);
00252 if (err <= 0)
00253 ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err));
00254 if (err != 1) {
00255 ast_debug(1, "Can't handle more than one device\n");
00256 }
00257
00258 snd_pcm_poll_descriptors(handle, &pfd, err);
00259 ast_debug(1, "Acquired fd %d from the poll descriptor\n", pfd.fd);
00260
00261 if (stream == SND_PCM_STREAM_CAPTURE)
00262 readdev = pfd.fd;
00263 else
00264 writedev = pfd.fd;
00265
00266 return handle;
00267 }
00268
00269 static int soundcard_init(void)
00270 {
00271 if (!noaudiocapture) {
00272 alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE);
00273 if (!alsa.icard) {
00274 ast_log(LOG_ERROR, "Problem opening alsa capture device\n");
00275 return -1;
00276 }
00277 }
00278
00279 alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK);
00280
00281 if (!alsa.ocard) {
00282 ast_log(LOG_ERROR, "Problem opening ALSA playback device\n");
00283 return -1;
00284 }
00285
00286 return writedev;
00287 }
00288
00289 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration)
00290 {
00291 ast_mutex_lock(&alsalock);
00292 ast_verbose(" << Console Received digit %c of duration %u ms >> \n",
00293 digit, duration);
00294 ast_mutex_unlock(&alsalock);
00295
00296 return 0;
00297 }
00298
00299 static int alsa_text(struct ast_channel *c, const char *text)
00300 {
00301 ast_mutex_lock(&alsalock);
00302 ast_verbose(" << Console Received text %s >> \n", text);
00303 ast_mutex_unlock(&alsalock);
00304
00305 return 0;
00306 }
00307
00308 static void grab_owner(void)
00309 {
00310 while (alsa.owner && ast_channel_trylock(alsa.owner)) {
00311 DEADLOCK_AVOIDANCE(&alsalock);
00312 }
00313 }
00314
00315 static int alsa_call(struct ast_channel *c, char *dest, int timeout)
00316 {
00317 struct ast_frame f = { AST_FRAME_CONTROL };
00318
00319 ast_mutex_lock(&alsalock);
00320 ast_verbose(" << Call placed to '%s' on console >> \n", dest);
00321 if (autoanswer) {
00322 ast_verbose(" << Auto-answered >> \n");
00323 if (mute) {
00324 ast_verbose( " << Muted >> \n" );
00325 }
00326 grab_owner();
00327 if (alsa.owner) {
00328 f.subclass.integer = AST_CONTROL_ANSWER;
00329 ast_queue_frame(alsa.owner, &f);
00330 ast_channel_unlock(alsa.owner);
00331 }
00332 } else {
00333 ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");
00334 grab_owner();
00335 if (alsa.owner) {
00336 f.subclass.integer = AST_CONTROL_RINGING;
00337 ast_queue_frame(alsa.owner, &f);
00338 ast_channel_unlock(alsa.owner);
00339 ast_indicate(alsa.owner, AST_CONTROL_RINGING);
00340 }
00341 }
00342 if (!noaudiocapture) {
00343 snd_pcm_prepare(alsa.icard);
00344 snd_pcm_start(alsa.icard);
00345 }
00346 ast_mutex_unlock(&alsalock);
00347
00348 return 0;
00349 }
00350
00351 static int alsa_answer(struct ast_channel *c)
00352 {
00353 ast_mutex_lock(&alsalock);
00354 ast_verbose(" << Console call has been answered >> \n");
00355 ast_setstate(c, AST_STATE_UP);
00356 if (!noaudiocapture) {
00357 snd_pcm_prepare(alsa.icard);
00358 snd_pcm_start(alsa.icard);
00359 }
00360 ast_mutex_unlock(&alsalock);
00361
00362 return 0;
00363 }
00364
00365 static int alsa_hangup(struct ast_channel *c)
00366 {
00367 ast_mutex_lock(&alsalock);
00368 c->tech_pvt = NULL;
00369 alsa.owner = NULL;
00370 ast_verbose(" << Hangup on console >> \n");
00371 ast_module_unref(ast_module_info->self);
00372 hookstate = 0;
00373 if (!noaudiocapture) {
00374 snd_pcm_drop(alsa.icard);
00375 }
00376 ast_mutex_unlock(&alsalock);
00377
00378 return 0;
00379 }
00380
00381 static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
00382 {
00383 static char sizbuf[8000];
00384 static int sizpos = 0;
00385 int len = sizpos;
00386 int pos;
00387 int res = 0;
00388
00389 snd_pcm_state_t state;
00390
00391 ast_mutex_lock(&alsalock);
00392
00393
00394 if (f->datalen > sizeof(sizbuf) - sizpos) {
00395 ast_log(LOG_WARNING, "Frame too large\n");
00396 res = -1;
00397 } else {
00398 memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
00399 len += f->datalen;
00400 pos = 0;
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 );