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