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