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