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: 196989 $")
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, 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 = 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 = 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 format, void *data, int *cause)
00569 {
00570 int oldformat = format;
00571 struct ast_channel *tmp = NULL;
00572
00573 if (!(format &= 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 #ifndef MIN
00595 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00596 #endif
00597 switch (state) {
00598 case 0:
00599 if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2)))
00600 return ast_strdup("on");
00601 case 1:
00602 if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3)))
00603 return ast_strdup("off");
00604 default:
00605 return NULL;
00606 }
00607
00608 return NULL;
00609 }
00610
00611 static char *console_autoanswer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00612 {
00613 char *res = CLI_SUCCESS;
00614
00615 switch (cmd) {
00616 case CLI_INIT:
00617 e->command = "console autoanswer";
00618 e->usage =
00619 "Usage: console autoanswer [on|off]\n"
00620 " Enables or disables autoanswer feature. If used without\n"
00621 " argument, displays the current on/off status of autoanswer.\n"
00622 " The default value of autoanswer is in 'alsa.conf'.\n";
00623 return NULL;
00624 case CLI_GENERATE:
00625 return autoanswer_complete(a->line, a->word, a->pos, a->n);
00626 }
00627
00628 if ((a->argc != 2) && (a->argc != 3))
00629 return CLI_SHOWUSAGE;
00630
00631 ast_mutex_lock(&alsalock);
00632 if (a->argc == 2) {
00633 ast_cli(a->fd, "Auto answer is %s.\n", autoanswer ? "on" : "off");
00634 } else {
00635 if (!strcasecmp(a->argv[2], "on"))
00636 autoanswer = -1;
00637 else if (!strcasecmp(a->argv[2], "off"))
00638 autoanswer = 0;
00639 else
00640 res = CLI_SHOWUSAGE;
00641 }
00642 ast_mutex_unlock(&alsalock);
00643
00644 return res;
00645 }
00646
00647 static char *console_answer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00648 {
00649 char *res = CLI_SUCCESS;
00650
00651 switch (cmd) {
00652 case CLI_INIT:
00653 e->command = "console answer";
00654 e->usage =
00655 "Usage: console answer\n"
00656 " Answers an incoming call on the console (ALSA) channel.\n";
00657
00658 return NULL;
00659 case CLI_GENERATE:
00660 return NULL;
00661 }
00662
00663 if (a->argc != 2)
00664 return CLI_SHOWUSAGE;
00665
00666 ast_mutex_lock(&alsalock);
00667
00668 if (!alsa.owner) {
00669 ast_cli(a->fd, "No one is calling us\n");
00670 res = CLI_FAILURE;
00671 } else {
00672 hookstate = 1;
00673 grab_owner();
00674 if (alsa.owner) {
00675 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00676
00677 ast_queue_frame(alsa.owner, &f);
00678 ast_channel_unlock(alsa.owner);
00679 }
00680 }
00681
00682 snd_pcm_prepare(alsa.icard);
00683 snd_pcm_start(alsa.icard);
00684
00685 ast_mutex_unlock(&alsalock);
00686
00687 return res;
00688 }
00689
00690 static char *console_sendtext(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00691 {
00692 int tmparg = 3;
00693 char *res = CLI_SUCCESS;
00694
00695 switch (cmd) {
00696 case CLI_INIT:
00697 e->command = "console send text";
00698 e->usage =
00699 "Usage: console send text <message>\n"
00700 " Sends a text message for display on the remote terminal.\n";
00701 return NULL;
00702 case CLI_GENERATE:
00703 return NULL;
00704 }
00705
00706 if (a->argc < 3)
00707 return CLI_SHOWUSAGE;
00708
00709 ast_mutex_lock(&alsalock);
00710
00711 if (!alsa.owner) {
00712 ast_cli(a->fd, "No channel active\n");
00713 res = CLI_FAILURE;
00714 } else {
00715 struct ast_frame f = { AST_FRAME_TEXT, 0 };
00716 char text2send[256] = "";
00717
00718 while (tmparg < a->argc) {
00719 strncat(text2send, a->argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1);
00720 strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1);
00721 }
00722
00723 text2send[strlen(text2send) - 1] = '\n';
00724 f.data = text2send;
00725 f.datalen = strlen(text2send) + 1;
00726 grab_owner();
00727 if (alsa.owner) {
00728 ast_queue_frame(alsa.owner, &f);
00729 f.frametype = AST_FRAME_CONTROL;
00730 f.subclass = AST_CONTROL_ANSWER;
00731 f.data = NULL;
00732 f.datalen = 0;
00733 ast_queue_frame(alsa.owner, &f);
00734 ast_channel_unlock(alsa.owner);
00735 }
00736 }
00737
00738 ast_mutex_unlock(&alsalock);
00739
00740 return res;
00741 }
00742
00743 static char *console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00744 {
00745 char *res = CLI_SUCCESS;
00746
00747 switch (cmd) {
00748 case CLI_INIT:
00749 e->command = "console hangup";
00750 e->usage =
00751 "Usage: console hangup\n"
00752 " Hangs up any call currently placed on the console.\n";
00753 return NULL;
00754 case CLI_GENERATE:
00755 return NULL;
00756 }
00757
00758
00759 if (a->argc != 2)
00760 return CLI_SHOWUSAGE;
00761
00762 ast_mutex_lock(&alsalock);
00763
00764 if (!alsa.owner && !hookstate) {
00765 ast_cli(a->fd, "No call to hangup\n");
00766 res = CLI_FAILURE;
00767 } else {
00768 hookstate = 0;
00769 grab_owner();
00770 if (alsa.owner) {
00771 ast_queue_hangup(alsa.owner);
00772 ast_channel_unlock(alsa.owner);
00773 }
00774 }
00775
00776 ast_mutex_unlock(&alsalock);
00777
00778 return res;
00779 }
00780
00781 static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00782 {
00783 char tmp[256], *tmp2;
00784 char *mye, *myc;
00785 char *d;
00786 char *res = CLI_SUCCESS;
00787
00788 switch (cmd) {
00789 case CLI_INIT:
00790 e->command = "console dial";
00791 e->usage =
00792 "Usage: console dial [extension[@context]]\n"
00793 " Dials a given extension (and context if specified)\n";
00794 return NULL;
00795 case CLI_GENERATE:
00796 return NULL;
00797 }
00798
00799 if ((a->argc != 2) && (a->argc != 3))
00800 return CLI_SHOWUSAGE;
00801
00802 ast_mutex_lock(&alsalock);
00803
00804 if (alsa.owner) {
00805 if (a->argc == 3) {
00806 if (alsa.owner) {
00807 for (d = a->argv[2]; *d; d++) {
00808 struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass = *d };
00809
00810 ast_queue_frame(alsa.owner, &f);
00811 }
00812 }
00813 } else {
00814 ast_cli(a->fd, "You're already in a call. You can use this only to dial digits until you hangup\n");
00815 res = CLI_FAILURE;
00816 }
00817 } else {
00818 mye = exten;
00819 myc = context;
00820 if (a->argc == 3) {
00821 char *stringp = NULL;
00822
00823 ast_copy_string(tmp, a->argv[2], sizeof(tmp));
00824 stringp = tmp;
00825 strsep(&stringp, "@");
00826 tmp2 = strsep(&stringp, "@");
00827 if (!ast_strlen_zero(tmp))
00828 mye = tmp;
00829 if (!ast_strlen_zero(tmp2))
00830 myc = tmp2;
00831 }
00832 if (ast_exists_extension(NULL, myc, mye, 1, NULL)) {
00833 ast_copy_string(alsa.exten, mye, sizeof(alsa.exten));
00834 ast_copy_string(alsa.context, myc, sizeof(alsa.context));
00835 hookstate = 1;
00836 alsa_new(&alsa, AST_STATE_RINGING);
00837 } else
00838 ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
00839 }
00840
00841 ast_mutex_unlock(&alsalock);
00842
00843 return res;
00844 }
00845
00846 static struct ast_cli_entry cli_alsa[] = {
00847 AST_CLI_DEFINE(console_answer, "Answer an incoming console call"),
00848 AST_CLI_DEFINE(console_hangup, "Hangup a call on the console"),
00849 AST_CLI_DEFINE(console_dial, "Dial an extension on the console"),
00850 AST_CLI_DEFINE(console_sendtext, "Send text to the remote device"),
00851 AST_CLI_DEFINE(console_autoanswer, "Sets/displays autoanswer"),
00852 };
00853
00854 static int load_module(void)
00855 {
00856 struct ast_config *cfg;
00857 struct ast_variable *v;
00858 struct ast_flags config_flags = { 0 };
00859
00860
00861 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
00862
00863 strcpy(mohinterpret, "default");
00864
00865 if (!(cfg = ast_config_load(config, config_flags))) {
00866 ast_log(LOG_ERROR, "Unable to read ALSA configuration file %s. Aborting.\n", config);
00867 return AST_MODULE_LOAD_DECLINE;
00868 }
00869
00870 v = ast_variable_browse(cfg, "general");
00871 for (; v; v = v->next) {
00872
00873 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
00874 continue;
00875
00876 if (!strcasecmp(v->name, "autoanswer"))
00877 autoanswer = ast_true(v->value);
00878 else if (!strcasecmp(v->name, "silencesuppression"))
00879 silencesuppression = ast_true(v->value);
00880 else if (!strcasecmp(v->name, "silencethreshold"))
00881 silencethreshold = atoi(v->value);
00882 else if (!strcasecmp(v->name, "context"))
00883 ast_copy_string(context, v->value, sizeof(context));
00884 else if (!strcasecmp(v->name, "language"))
00885 ast_copy_string(language, v->value, sizeof(language));
00886 else if (!strcasecmp(v->name, "extension"))
00887 ast_copy_string(exten, v->value, sizeof(exten));
00888 else if (!strcasecmp(v->name, "input_device"))
00889 ast_copy_string(indevname, v->value, sizeof(indevname));
00890 else if (!strcasecmp(v->name, "output_device"))
00891 ast_copy_string(outdevname, v->value, sizeof(outdevname));
00892 else if (!strcasecmp(v->name, "mohinterpret"))
00893 ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
00894 }
00895 ast_config_destroy(cfg);
00896
00897 if (soundcard_init() < 0) {
00898 ast_verb(2, "No sound card detected -- console channel will be unavailable\n");
00899 ast_verb(2, "Turn off ALSA support by adding 'noload=chan_alsa.so' in /etc/asterisk/modules.conf\n");
00900 return AST_MODULE_LOAD_DECLINE;
00901 }
00902
00903 if (ast_channel_register(&alsa_tech)) {
00904 ast_log(LOG_ERROR, "Unable to register channel class 'Console'\n");
00905 return AST_MODULE_LOAD_FAILURE;
00906 }
00907
00908 ast_cli_register_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
00909
00910 return AST_MODULE_LOAD_SUCCESS;
00911 }
00912
00913 static int unload_module(void)
00914 {
00915 ast_channel_unregister(&alsa_tech);
00916 ast_cli_unregister_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry));
00917
00918 if (alsa.icard)
00919 snd_pcm_close(alsa.icard);
00920 if (alsa.ocard)
00921 snd_pcm_close(alsa.ocard);
00922 if (alsa.owner)
00923 ast_softhangup(alsa.owner, AST_SOFTHANGUP_APPUNLOAD);
00924 if (alsa.owner)
00925 return -1;
00926
00927 return 0;
00928 }
00929
00930 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ALSA Console Channel Driver");