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: 370642 $")
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 = ast_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 = ast_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 AST_CONTROL_INCOMPLETE:
00541 case -1:
00542 res = -1;
00543 break;
00544 case AST_CONTROL_PROGRESS:
00545 case AST_CONTROL_PROCEEDING:
00546 case AST_CONTROL_VIDUPDATE:
00547 case AST_CONTROL_SRCUPDATE:
00548 break;
00549 case AST_CONTROL_HOLD:
00550 ast_verbose(" << Console Has Been Placed on Hold >> \n");
00551 ast_moh_start(chan, data, mohinterpret);
00552 break;
00553 case AST_CONTROL_UNHOLD:
00554 ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
00555 ast_moh_stop(chan);
00556 break;
00557 default:
00558 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
00559 res = -1;
00560 }
00561
00562 ast_mutex_unlock(&alsalock);
00563
00564 return res;
00565 }
00566
00567 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const char *linkedid)
00568 {
00569 struct ast_channel *tmp = NULL;
00570
00571 if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, linkedid, 0, "ALSA/%s", indevname)))
00572 return NULL;
00573
00574 tmp->tech = &alsa_tech;
00575 ast_channel_set_fd(tmp, 0, readdev);
00576 tmp->nativeformats = AST_FORMAT_SLINEAR;
00577 tmp->readformat = AST_FORMAT_SLINEAR;
00578 tmp->writeformat = AST_FORMAT_SLINEAR;
00579 tmp->tech_pvt = p;
00580 if (!ast_strlen_zero(p->context))
00581 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00582 if (!ast_strlen_zero(p->exten))
00583 ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten));
00584 if (!ast_strlen_zero(language))
00585 ast_string_field_set(tmp, language, language);
00586 p->owner = tmp;
00587 ast_module_ref(ast_module_info->self);
00588 ast_jb_configure(tmp, &global_jbconf);
00589 if (state != AST_STATE_DOWN) {
00590 if (ast_pbx_start(tmp)) {
00591 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00592 ast_hangup(tmp);
00593 tmp = NULL;
00594 }
00595 }
00596
00597 return tmp;
00598 }
00599
00600 static struct ast_channel *alsa_request(const char *type, format_t fmt, const struct ast_channel *requestor, void *data, int *cause)
00601 {
00602 format_t oldformat = fmt;
00603 char buf[256];
00604 struct ast_channel *tmp = NULL;
00605
00606 if (!(fmt &= AST_FORMAT_SLINEAR)) {
00607 ast_log(LOG_NOTICE, "Asked to get a channel of format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), oldformat));
00608 return NULL;
00609 }
00610
00611 ast_mutex_lock(&alsalock);
00612
00613 if (alsa.owner) {
00614 ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n");
00615 *cause = AST_CAUSE_BUSY;
00616 } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
00617 ast_log(LOG_WARNING, "Unable to create new ALSA channel\n");
00618 }
00619
00620 ast_mutex_unlock(&alsalock);
00621
00622 return tmp;
00623 }
00624
00625 static char *autoanswer_complete(const char *line, const char *word, int pos, int state)
00626 {
00627 switch (state) {
00628 case 0:
00629 if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
00630 return ast_strdup("on");
00631 case 1:
00632 if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
00633 return ast_strdup("off");
00634 default:
00635 return NULL;
00636 }
00637
00638 return NULL;
00639 }
00640
00641 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00642 {
00643 char *res = CLI_SUCCESS;
00644
00645 switch (cmd) {
00646 case CLI_INIT:
00647 e->command = "console autoanswer";
00648 e->usage =
00649 "Usage: console autoanswer [on|off]\n"
00650 " Enables or disables autoanswer feature. If used without\n"
00651 " argument, displays the current on/off status of autoanswer.\n"
00652 " The default value of autoanswer is in 'alsa.conf'.\n";
00653 return NULL;
00654 case CLI_GENERATE:
00655 return autoanswer_complete(a->line, a->word, a->pos, a->n);
00656 }
00657
00658 if ((a->argc != 2) && (a->argc != 3))
00659 return CLI_SHOWUSAGE;
00660
00661 ast_mutex_lock(&alsalock);
00662 if (a->argc == 2) {
00663 ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00664 } else {
00665 if (!strcasecmp(a->argv[2], "on"))
00666 autoanswer = -1;
00667 else if (!strcasecmp(a->argv[2], "off"))
00668 autoanswer = 0;
00669 else
00670 res = CLI_SHOWUSAGE;
00671 }
00672 ast_mutex_unlock(&alsalock);
00673
00674 return res;
00675 }
00676
00677 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00678 {
00679 char *res = CLI_SUCCESS;
00680
00681 switch (cmd) {
00682 case CLI_INIT:
00683 e->command = "console answer";
00684 e->usage =
00685 "Usage: console answer\n"
00686 " Answers an incoming call on the console (ALSA) channel.\n";
00687
00688 return NULL;
00689 case CLI_GENERATE:
00690 return NULL;
00691 }
00692
00693 if (a->argc != 2)
00694 return CLI_SHOWUSAGE;
00695
00696 ast_mutex_lock(&alsalock);
00697
00698 if (!alsa.owner) {
00699 ast_cli(a->fd, "No one is calling us\n");
00700 res = CLI_FAILURE;
00701 } else {
00702 if (mute) {
00703 ast_verbose( " << Muted >> \n" );
00704 }
00705 hookstate = 1;
00706 grab_owner();
00707 if (alsa.owner) {
00708 ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
00709 ast_channel_unlock(alsa.owner);
00710 }
00711 }
00712
00713 if (!noaudiocapture) {
00714 snd_pcm_prepare(alsa.icard);
00715 snd_pcm_start(alsa.icard);
00716 }
00717
00718 ast_mutex_unlock(&alsalock);
00719
00720 return res;
00721 }
00722
00723 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00724 {
00725 int tmparg = 3;
00726 char *res = CLI_SUCCESS;
00727
00728 switch (cmd) {
00729 case CLI_INIT:
00730 e->command = "console send text";
00731 e->usage =
00732 "Usage: console send text <message>\n"
00733 " Sends a text message for display on the remote terminal.\n";
00734 return NULL;
00735 case CLI_GENERATE:
00736 return NULL;
00737 }
00738
00739 if (a->argc < 3)
00740 return CLI_SHOWUSAGE;
00741
00742 ast_mutex_lock(&alsalock);
00743
00744 if (!alsa.owner) {
00745 ast_cli(a->fd, "No channel active\n");
00746 res = CLI_FAILURE;
00747 } else {
00748 struct ast_frame f = { AST_FRAME_TEXT };
00749 char text2send[256] = "";
00750
00751 while (tmparg < a->argc) {
00752 strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
00753 strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
00754 }
00755
00756 text2send[strlen(text2send) - 1] = '\n';
00757 f.data.ptr = text2send;
00758 f.datalen = strlen(text2send) + 1;
00759 grab_owner();
00760 if (alsa.owner) {
00761 ast_queue_frame(alsa.owner, &f);
00762 ast_queue_control(alsa.owner, AST_CONTROL_ANSWER);
00763 ast_channel_unlock(alsa.owner);
00764 }
00765 }
00766
00767 ast_mutex_unlock(&alsalock);
00768
00769 return res;
00770 }
00771
00772 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00773 {
00774 char *res = CLI_SUCCESS;
00775
00776 switch (cmd) {
00777 case CLI_INIT:
00778 e->command = "console hangup";
00779 e->usage =
00780 "Usage: console hangup\n"
00781 " Hangs up any call currently placed on the console.\n";
00782 return NULL;
00783 case CLI_GENERATE:
00784 return NULL;
00785 }
00786
00787
00788 if (a->argc != 2)
00789 return CLI_SHOWUSAGE;
00790
00791 ast_mutex_lock(&alsalock);
00792
00793 if (!alsa.owner && !hookstate) {
00794 ast_cli(a->fd, "No call to hangup\n");
00795 res = CLI_FAILURE;
00796 } else {
00797 hookstate = 0;
00798 grab_owner();
00799 if (alsa.owner) {
00800 ast_queue_hangup_with_cause(alsa.owner, AST_CAUSE_NORMAL_CLEARING);
00801 ast_channel_unlock(alsa.owner);
00802 }
00803 }
00804
00805 ast_mutex_unlock(&alsalock);
00806
00807 return res;
00808 }
00809
00810 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00811 {
00812 char tmp[256], *tmp2;
00813 char *mye, *myc;
00814 const char *d;
00815 char *res = CLI_SUCCESS;
00816
00817 switch (cmd) {
00818 case CLI_INIT:
00819 e->command = "console dial";
00820 e->usage =
00821 "Usage: console dial [extension[@context]]\n"
00822 " Dials a given extension (and context if specified)\n";
00823 return NULL;
00824 case CLI_GENERATE:
00825 return NULL;
00826 }
00827
00828 if ((a->argc != 2) && (a->argc != 3))
00829 return CLI_SHOWUSAGE;
00830
00831 ast_mutex_lock(&alsalock);
00832
00833 if (alsa.owner) {
00834 if (a->argc == 3) {
00835 if (alsa.owner) {
00836 for (d = a->argv[2]; *d; d++) {
00837 struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = *d };
00838
00839 ast_queue_frame(alsa.owner, &f);
00840 }
00841 }
00842 } else {
00843 ast_cli(a->fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
00844 res = CLI_FAILURE;
00845 }
00846 } else {
00847 mye = exten;
00848 myc = context;
00849 if (a->argc == 3) {
00850 char *stringp = NULL;
00851
00852 ast_copy_string(tmp, a->argv[2], sizeof(tmp));
00853 stringp = tmp;
00854 strsep(&stringp, "@");
00855 tmp2 = strsep(&stringp, "@");
00856 if (!ast_strlen_zero(tmp))
00857 mye = tmp;
00858 if (!ast_strlen_zero(tmp2))
00859 myc = tmp2;
00860 }
00861 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00862 ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
00863 ast_copy_string(alsa.context, myc, sizeof(alsa.context));
00864 hookstate = 1;
00865 alsa_new(&alsa, AST_STATE_RINGING, NULL);
00866 } else
00867 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00868 }
00869
00870 ast_mutex_unlock(&alsalock);
00871
00872 return res;
00873 }
00874
00875 static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00876 {
00877 int toggle = 0;
00878 char *res = CLI_SUCCESS;
00879
00880 switch (cmd) {
00881 case CLI_INIT:
00882 e->command = "console {mute|unmute} [toggle]";
00883 e->usage =
00884 "Usage: console {mute|unmute} [toggle]\n"
00885 " Mute/unmute the microphone.\n";
00886 return NULL;
00887 case CLI_GENERATE:
00888 return NULL;
00889 }
00890
00891
00892 if (a->argc > 3) {
00893 return CLI_SHOWUSAGE;
00894 }
00895
00896 if (a->argc == 3) {
00897 if (strcasecmp(a->argv[2], "toggle"))
00898 return CLI_SHOWUSAGE;
00899 toggle = 1;
00900 }
00901
00902 if (a->argc < 2) {
00903 return CLI_SHOWUSAGE;
00904 }
00905
00906 if (!strcasecmp(a->argv[1], "mute")) {
00907 mute = toggle ? !mute : 1;
00908 } else if (!strcasecmp(a->argv[1], "unmute")) {
00909 mute = toggle ? !mute : 0;
00910 } else {
00911 return CLI_SHOWUSAGE;
00912 }
00913
00914 ast_cli(a->fd, "Console mic is %s\n", mute ? "off" : "on");
00915
00916 return res;
00917 }
00918
00919 static struct ast_cli_entry cli_alsa[] = {
00920 AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
00921 AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
00922 AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
00923 AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
00924 AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
00925 AST_CLI_DEFINE(console_mute, "Disable/Enable mic input"),
00926 };
00927
00928 static int load_module(void)
00929 {
00930 struct ast_config *cfg;
00931 struct ast_variable *v;
00932 struct ast_flags config_flags = { 0 };
00933
00934
00935 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
00936
00937 strcpy(mohinterpret, "default");
00938
00939 if (!(cfg = ast_config_load(config, config_flags))) {
00940 ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s. Aborting.\n", config);
00941 return AST_MODULE_LOAD_DECLINE;
00942 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00943 ast_log(LOG_ERROR, "%s is in an invalid format. Aborting.\n", config);
00944 return AST_MODULE_LOAD_DECLINE;
00945 }
00946
00947 v = ast_variable_browse(cfg, "general");
00948 for (; v; v = v->next) {
00949
00950 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
00951 continue;
00952 }
00953
00954 if (!strcasecmp(v->name, "autoanswer")) {
00955 autoanswer = ast_true(v->value);
00956 } else if (!strcasecmp(v->name, "mute")) {
00957 mute = ast_true(v->value);
00958 } else if (!strcasecmp(v->name, "noaudiocapture")) {
00959 noaudiocapture = ast_true(v->value);
00960 } else if (!strcasecmp(v->name, "silencesuppression")) {
00961 silencesuppression = ast_true(v->value);
00962 } else if (!strcasecmp(v->name, "silencethreshold")) {
00963 silencethreshold = atoi(v->value);
00964 } else if (!strcasecmp(v->name, "context")) {
00965 ast_copy_string(context, v->value, sizeof(context));
00966 } else if (!strcasecmp(v->name, "language")) {
00967 ast_copy_string(language, v->value, sizeof(language));
00968 } else if (!strcasecmp(v->name, "extension")) {
00969 ast_copy_string(exten, v->value, sizeof(exten));
00970 } else if (!strcasecmp(v->name, "input_device")) {
00971 ast_copy_string(indevname, v->value, sizeof(indevname));
00972 } else if (!strcasecmp(v->name, "output_device")) {
00973 ast_copy_string(outdevname, v->value, sizeof(outdevname));
00974 } else if (!strcasecmp(v->name, "mohinterpret")) {
00975 ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
00976 }
00977 }
00978 ast_config_destroy(cfg);
00979
00980 if (soundcard_init() < 0) {
00981 ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
00982 ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
00983 return AST_MODULE_LOAD_DECLINE;
00984 }
00985
00986 if (ast_channel_register(&alsa_tech)) {
00987 ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
00988 return AST_MODULE_LOAD_FAILURE;
00989 }
00990
00991 ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
00992
00993 return AST_MODULE_LOAD_SUCCESS;
00994 }
00995
00996 static int unload_module(void)
00997 {
00998 ast_channel_unregister(&alsa_tech);
00999 ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa));
01000
01001 if (alsa.icard)
01002 snd_pcm_close(alsa.icard);
01003 if (alsa.ocard)
01004 snd_pcm_close(alsa.ocard);
01005 if (alsa.owner)
01006 ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
01007 if (alsa.owner)
01008 return -1;
01009
01010 return 0;
01011 }
01012
01013 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ALSA Console Channel Driver",
01014 .load = load_module,
01015 .unload = unload_module,
01016 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01017 );