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