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