![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_alsa.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * By Matthew Fredrickson <creslin@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * \brief ALSA sound card channel driver 00021 * 00022 * \author Matthew Fredrickson <creslin@digium.com> 00023 * 00024 * \par See also 00025 * \arg Config_alsa 00026 * 00027 * \ingroup channel_drivers 00028 */ 00029 00030 /*** MODULEINFO 00031 <depend>asound</depend> 00032 ***/ 00033 00034 #include "asterisk.h" 00035 00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51806 $") 00037 00038 #include <unistd.h> 00039 #include <fcntl.h> 00040 #include <errno.h> 00041 #include <sys/ioctl.h> 00042 #include <sys/time.h> 00043 #include <string.h> 00044 #include <stdlib.h> 00045 #include <stdio.h> 00046 00047 #define ALSA_PCM_NEW_HW_PARAMS_API 00048 #define ALSA_PCM_NEW_SW_PARAMS_API 00049 #include <alsa/asoundlib.h> 00050 00051 #include "asterisk/frame.h" 00052 #include "asterisk/logger.h" 00053 #include "asterisk/channel.h" 00054 #include "asterisk/module.h" 00055 #include "asterisk/options.h" 00056 #include "asterisk/pbx.h" 00057 #include "asterisk/config.h" 00058 #include "asterisk/cli.h" 00059 #include "asterisk/utils.h" 00060 #include "asterisk/causes.h" 00061 #include "asterisk/endian.h" 00062 #include "asterisk/stringfields.h" 00063 #include "asterisk/abstract_jb.h" 00064 #include "asterisk/musiconhold.h" 00065 00066 #include "busy.h" 00067 #include "ringtone.h" 00068 #include "ring10.h" 00069 #include "answer.h" 00070 00071 #ifdef ALSA_MONITOR 00072 #include "alsa-monitor.h" 00073 #endif 00074 00075 /*! Global jitterbuffer configuration - by default, jb is disabled */ 00076 static struct ast_jb_conf default_jbconf = { 00077 .flags = 0, 00078 .max_size = -1, 00079 .resync_threshold = -1, 00080 .impl = "" 00081 }; 00082 static struct ast_jb_conf global_jbconf; 00083 00084 #define DEBUG 0 00085 /* Which device to use */ 00086 #define ALSA_INDEV "hw:0,0" 00087 #define ALSA_OUTDEV "hw:0,0" 00088 #define DESIRED_RATE 8000 00089 00090 /* Lets use 160 sample frames, just like GSM. */ 00091 #define FRAME_SIZE 160 00092 #define PERIOD_FRAMES 80 /* 80 Frames, at 2 bytes each */ 00093 00094 /* When you set the frame size, you have to come up with 00095 the right buffer format as well. */ 00096 /* 5 64-byte frames = one frame */ 00097 #define BUFFER_FMT ((buffersize * 10) << 16) | (0x0006); 00098 00099 /* Don't switch between read/write modes faster than every 300 ms */ 00100 #define MIN_SWITCH_TIME 600 00101 00102 #if __BYTE_ORDER == __LITTLE_ENDIAN 00103 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 00104 #else 00105 static snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE; 00106 #endif 00107 00108 /* static int block = O_NONBLOCK; */ 00109 static char indevname[50] = ALSA_INDEV; 00110 static char outdevname[50] = ALSA_OUTDEV; 00111 00112 #if 0 00113 static struct timeval lasttime; 00114 #endif 00115 00116 static int silencesuppression = 0; 00117 static int silencethreshold = 1000; 00118 00119 AST_MUTEX_DEFINE_STATIC(alsalock); 00120 00121 static const char tdesc[] = "ALSA Console Channel Driver"; 00122 static const char config[] = "alsa.conf"; 00123 00124 static char context[AST_MAX_CONTEXT] = "default"; 00125 static char language[MAX_LANGUAGE] = ""; 00126 static char exten[AST_MAX_EXTENSION] = "s"; 00127 static char mohinterpret[MAX_MUSICCLASS]; 00128 00129 static int hookstate = 0; 00130 00131 static short silence[FRAME_SIZE] = { 0, }; 00132 00133 struct sound { 00134 int ind; 00135 short *data; 00136 int datalen; 00137 int samplen; 00138 int silencelen; 00139 int repeat; 00140 }; 00141 00142 static struct sound sounds[] = { 00143 {AST_CONTROL_RINGING, ringtone, sizeof(ringtone) / 2, 16000, 32000, 1}, 00144 {AST_CONTROL_BUSY, busy, sizeof(busy) / 2, 4000, 4000, 1}, 00145 {AST_CONTROL_CONGESTION, busy, sizeof(busy) / 2, 2000, 2000, 1}, 00146 {AST_CONTROL_RING, ring10, sizeof(ring10) / 2, 16000, 32000, 1}, 00147 {AST_CONTROL_ANSWER, answer, sizeof(answer) / 2, 2200, 0, 0}, 00148 }; 00149 00150 /* Sound command pipe */ 00151 static int sndcmd[2]; 00152 00153 static struct chan_alsa_pvt { 00154 /* We only have one ALSA structure -- near sighted perhaps, but it 00155 keeps this driver as simple as possible -- as it should be. */ 00156 struct ast_channel *owner; 00157 char exten[AST_MAX_EXTENSION]; 00158 char context[AST_MAX_CONTEXT]; 00159 #if 0 00160 snd_pcm_t *card; 00161 #endif 00162 snd_pcm_t *icard, *ocard; 00163 00164 } alsa; 00165 00166 /* Number of buffers... Each is FRAMESIZE/8 ms long. For example 00167 with 160 sample frames, and a buffer size of 3, we have a 60ms buffer, 00168 usually plenty. */ 00169 00170 pthread_t sthread; 00171 00172 #define MAX_BUFFER_SIZE 100 00173 00174 /* File descriptors for sound device */ 00175 static int readdev = -1; 00176 static int writedev = -1; 00177 00178 static int autoanswer = 1; 00179 00180 static int cursound = -1; 00181 static int sampsent = 0; 00182 static int silencelen = 0; 00183 static int offset = 0; 00184 static int nosound = 0; 00185 00186 /* ZZ */ 00187 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause); 00188 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration); 00189 static int alsa_text(struct ast_channel *c, const char *text); 00190 static int alsa_hangup(struct ast_channel *c); 00191 static int alsa_answer(struct ast_channel *c); 00192 static struct ast_frame *alsa_read(struct ast_channel *chan); 00193 static int alsa_call(struct ast_channel *c, char *dest, int timeout); 00194 static int alsa_write(struct ast_channel *chan, struct ast_frame *f); 00195 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen); 00196 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 00197 00198 static const struct ast_channel_tech alsa_tech = { 00199 .type = "Console", 00200 .description = tdesc, 00201 .capabilities = AST_FORMAT_SLINEAR, 00202 .requester = alsa_request, 00203 .send_digit_end = alsa_digit, 00204 .send_text = alsa_text, 00205 .hangup = alsa_hangup, 00206 .answer = alsa_answer, 00207 .read = alsa_read, 00208 .call = alsa_call, 00209 .write = alsa_write, 00210 .indicate = alsa_indicate, 00211 .fixup = alsa_fixup, 00212 }; 00213 00214 static int send_sound(void) 00215 { 00216 short myframe[FRAME_SIZE]; 00217 int total = FRAME_SIZE; 00218 short *frame = NULL; 00219 int amt = 0, res, myoff; 00220 snd_pcm_state_t state; 00221 00222 if (cursound == -1) 00223 return 0; 00224 00225 res = total; 00226 if (sampsent < sounds[cursound].samplen) { 00227 myoff = 0; 00228 while (total) { 00229 amt = total; 00230 if (amt > (sounds[cursound].datalen - offset)) 00231 amt = sounds[cursound].datalen - offset; 00232 memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2); 00233 total -= amt; 00234 offset += amt; 00235 sampsent += amt; 00236 myoff += amt; 00237 if (offset >= sounds[cursound].datalen) 00238 offset = 0; 00239 } 00240 /* Set it up for silence */ 00241 if (sampsent >= sounds[cursound].samplen) 00242 silencelen = sounds[cursound].silencelen; 00243 frame = myframe; 00244 } else { 00245 if (silencelen > 0) { 00246 frame = silence; 00247 silencelen -= res; 00248 } else { 00249 if (sounds[cursound].repeat) { 00250 /* Start over */ 00251 sampsent = 0; 00252 offset = 0; 00253 } else { 00254 cursound = -1; 00255 nosound = 0; 00256 } 00257 return 0; 00258 } 00259 } 00260 00261 if (res == 0 || !frame) 00262 return 0; 00263 00264 #ifdef ALSA_MONITOR 00265 alsa_monitor_write((char *) frame, res * 2); 00266 #endif 00267 state = snd_pcm_state(alsa.ocard); 00268 if (state == SND_PCM_STATE_XRUN) 00269 snd_pcm_prepare(alsa.ocard); 00270 res = snd_pcm_writei(alsa.ocard, frame, res); 00271 if (res > 0) 00272 return 0; 00273 return 0; 00274 } 00275 00276 static void *sound_thread(void *unused) 00277 { 00278 fd_set rfds; 00279 fd_set wfds; 00280 int max, res; 00281 00282 for (;;) { 00283 FD_ZERO(&rfds); 00284 FD_ZERO(&wfds); 00285 max = sndcmd[0]; 00286 FD_SET(sndcmd[0], &rfds); 00287 if (cursound > -1) { 00288 FD_SET(writedev, &wfds); 00289 if (writedev > max) 00290 max = writedev; 00291 } 00292 #ifdef ALSA_MONITOR 00293 if (!alsa.owner) { 00294 FD_SET(readdev, &rfds); 00295 if (readdev > max) 00296 max = readdev; 00297 } 00298 #endif 00299 res = ast_select(max + 1, &rfds, &wfds, NULL, NULL); 00300 if (res < 1) { 00301 ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno)); 00302 continue; 00303 } 00304 #ifdef ALSA_MONITOR 00305 if (FD_ISSET(readdev, &rfds)) { 00306 /* Keep the pipe going with read audio */ 00307 snd_pcm_state_t state; 00308 short buf[FRAME_SIZE]; 00309 int r; 00310 00311 state = snd_pcm_state(alsa.ocard); 00312 if (state == SND_PCM_STATE_XRUN) { 00313 snd_pcm_prepare(alsa.ocard); 00314 } 00315 r = snd_pcm_readi(alsa.icard, buf, FRAME_SIZE); 00316 if (r == -EPIPE) { 00317 #if DEBUG 00318 ast_log(LOG_ERROR, "XRUN read\n"); 00319 #endif 00320 snd_pcm_prepare(alsa.icard); 00321 } else if (r == -ESTRPIPE) { 00322 ast_log(LOG_ERROR, "-ESTRPIPE\n"); 00323 snd_pcm_prepare(alsa.icard); 00324 } else if (r < 0) { 00325 ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r)); 00326 } else 00327 alsa_monitor_read((char *) buf, r * 2); 00328 } 00329 #endif 00330 if (FD_ISSET(sndcmd[0], &rfds)) { 00331 read(sndcmd[0], &cursound, sizeof(cursound)); 00332 silencelen = 0; 00333 offset = 0; 00334 sampsent = 0; 00335 } 00336 if (FD_ISSET(writedev, &wfds)) 00337 if (send_sound()) 00338 ast_log(LOG_WARNING, "Failed to write sound\n"); 00339 } 00340 /* Never reached */ 00341 return NULL; 00342 } 00343 00344 static snd_pcm_t *alsa_card_init(char *dev, snd_pcm_stream_t stream) 00345 { 00346 int err; 00347 int direction; 00348 snd_pcm_t *handle = NULL; 00349 snd_pcm_hw_params_t *hwparams = NULL; 00350 snd_pcm_sw_params_t *swparams = NULL; 00351 struct pollfd pfd; 00352 snd_pcm_uframes_t period_size = PERIOD_FRAMES * 4; 00353 /* int period_bytes = 0; */ 00354 snd_pcm_uframes_t buffer_size = 0; 00355 00356 unsigned int rate = DESIRED_RATE; 00357 #if 0 00358 unsigned int per_min = 1; 00359 #endif 00360 /* unsigned int per_max = 8; */ 00361 snd_pcm_uframes_t start_threshold, stop_threshold; 00362 00363 err = snd_pcm_open(&handle, dev, stream, O_NONBLOCK); 00364 if (err < 0) { 00365 ast_log(LOG_ERROR, "snd_pcm_open failed: %s\n", snd_strerror(err)); 00366 return NULL; 00367 } else { 00368 if (option_debug) 00369 ast_log(LOG_DEBUG, "Opening device %s in %s mode\n", dev, (stream == SND_PCM_STREAM_CAPTURE) ? "read" : "write"); 00370 } 00371 00372 snd_pcm_hw_params_alloca(&hwparams); 00373 snd_pcm_hw_params_any(handle, hwparams); 00374 00375 err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); 00376 if (err < 0) 00377 ast_log(LOG_ERROR, "set_access failed: %s\n", snd_strerror(err)); 00378 00379 err = snd_pcm_hw_params_set_format(handle, hwparams, format); 00380 if (err < 0) 00381 ast_log(LOG_ERROR, "set_format failed: %s\n", snd_strerror(err)); 00382 00383 err = snd_pcm_hw_params_set_channels(handle, hwparams, 1); 00384 if (err < 0) 00385 ast_log(LOG_ERROR, "set_channels failed: %s\n", snd_strerror(err)); 00386 00387 direction = 0; 00388 err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &direction); 00389 if (rate != DESIRED_RATE) 00390 ast_log(LOG_WARNING, "Rate not correct, requested %d, got %d\n", DESIRED_RATE, rate); 00391 00392 direction = 0; 00393 err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &direction); 00394 if (err < 0) 00395 ast_log(LOG_ERROR, "period_size(%ld frames) is bad: %s\n", period_size, snd_strerror(err)); 00396 else { 00397 if (option_debug) 00398 ast_log(LOG_DEBUG, "Period size is %d\n", err); 00399 } 00400 00401 buffer_size = 4096 * 2; /* period_size * 16; */ 00402 err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size); 00403 if (err < 0) 00404 ast_log(LOG_WARNING, "Problem setting buffer size of %ld: %s\n", buffer_size, snd_strerror(err)); 00405 else { 00406 if (option_debug) 00407 ast_log(LOG_DEBUG, "Buffer size is set to %d frames\n", err); 00408 } 00409 00410 #if 0 00411 direction = 0; 00412 err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &per_min, &direction); 00413 if (err < 0) 00414 ast_log(LOG_ERROR, "periods_min: %s\n", snd_strerror(err)); 00415 00416 err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &per_max, 0); 00417 if (err < 0) 00418 ast_log(LOG_ERROR, "periods_max: %s\n", snd_strerror(err)); 00419 #endif 00420 00421 err = snd_pcm_hw_params(handle, hwparams); 00422 if (err < 0) 00423 ast_log(LOG_ERROR, "Couldn't set the new hw params: %s\n", snd_strerror(err)); 00424 00425 snd_pcm_sw_params_alloca(&swparams); 00426 snd_pcm_sw_params_current(handle, swparams); 00427 00428 #if 1 00429 if (stream == SND_PCM_STREAM_PLAYBACK) 00430 start_threshold = period_size; 00431 else 00432 start_threshold = 1; 00433 00434 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); 00435 if (err < 0) 00436 ast_log(LOG_ERROR, "start threshold: %s\n", snd_strerror(err)); 00437 #endif 00438 00439 #if 1 00440 if (stream == SND_PCM_STREAM_PLAYBACK) 00441 stop_threshold = buffer_size; 00442 else 00443 stop_threshold = buffer_size; 00444 00445 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); 00446 if (err < 0) 00447 ast_log(LOG_ERROR, "stop threshold: %s\n", snd_strerror(err)); 00448 #endif 00449 #if 0 00450 err = snd_pcm_sw_params_set_xfer_align(handle, swparams, PERIOD_FRAMES); 00451 if (err < 0) 00452 ast_log(LOG_ERROR, "Unable to set xfer alignment: %s\n", snd_strerror(err)); 00453 #endif 00454 00455 #if 0 00456 err = snd_pcm_sw_params_set_silence_threshold(handle, swparams, silencethreshold); 00457 if (err < 0) 00458 ast_log(LOG_ERROR, "Unable to set silence threshold: %s\n", snd_strerror(err)); 00459 #endif 00460 err = snd_pcm_sw_params(handle, swparams); 00461 if (err < 0) 00462 ast_log(LOG_ERROR, "sw_params: %s\n", snd_strerror(err)); 00463 00464 err = snd_pcm_poll_descriptors_count(handle); 00465 if (err <= 0) 00466 ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err)); 00467 if (err != 1) { 00468 if (option_debug) 00469 ast_log(LOG_DEBUG, "Can't handle more than one device\n"); 00470 } 00471 00472 snd_pcm_poll_descriptors(handle, &pfd, err); 00473 if (option_debug) 00474 ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd); 00475 00476 if (stream == SND_PCM_STREAM_CAPTURE) 00477 readdev = pfd.fd; 00478 else 00479 writedev = pfd.fd; 00480 00481 return handle; 00482 } 00483 00484 static int soundcard_init(void) 00485 { 00486 alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE); 00487 alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK); 00488 00489 if (!alsa.icard || !alsa.ocard) { 00490 ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n"); 00491 return -1; 00492 } 00493 00494 return readdev; 00495 } 00496 00497 static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration) 00498 { 00499 ast_mutex_lock(&alsalock); 00500 ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 00501 digit, duration); 00502 ast_mutex_unlock(&alsalock); 00503 return 0; 00504 } 00505 00506 static int alsa_text(struct ast_channel *c, const char *text) 00507 { 00508 ast_mutex_lock(&alsalock); 00509 ast_verbose(" << Console Received text %s >> \n", text); 00510 ast_mutex_unlock(&alsalock); 00511 return 0; 00512 } 00513 00514 static void grab_owner(void) 00515 { 00516 while (alsa.owner && ast_mutex_trylock(&alsa.owner->lock)) { 00517 ast_mutex_unlock(&alsalock); 00518 usleep(1); 00519 ast_mutex_lock(&alsalock); 00520 } 00521 } 00522 00523 static int alsa_call(struct ast_channel *c, char *dest, int timeout) 00524 { 00525 int res = 3; 00526 struct ast_frame f = { AST_FRAME_CONTROL }; 00527 ast_mutex_lock(&alsalock); 00528 ast_verbose(" << Call placed to '%s' on console >> \n", dest); 00529 if (autoanswer) { 00530 ast_verbose(" << Auto-answered >> \n"); 00531 grab_owner(); 00532 if (alsa.owner) { 00533 f.subclass = AST_CONTROL_ANSWER; 00534 ast_queue_frame(alsa.owner, &f); 00535 ast_mutex_unlock(&alsa.owner->lock); 00536 } 00537 } else { 00538 ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n"); 00539 grab_owner(); 00540 if (alsa.owner) { 00541 f.subclass = AST_CONTROL_RINGING; 00542 ast_queue_frame(alsa.owner, &f); 00543 ast_mutex_unlock(&alsa.owner->lock); 00544 } 00545 write(sndcmd[1], &res, sizeof(res)); 00546 } 00547 snd_pcm_prepare(alsa.icard); 00548 snd_pcm_start(alsa.icard); 00549 ast_mutex_unlock(&alsalock); 00550 return 0; 00551 } 00552 00553 static void answer_sound(void) 00554 { 00555 int res; 00556 nosound = 1; 00557 res = 4; 00558 write(sndcmd[1], &res, sizeof(res)); 00559 00560 } 00561 00562 static int alsa_answer(struct ast_channel *c) 00563 { 00564 ast_mutex_lock(&alsalock); 00565 ast_verbose(" << Console call has been answered >> \n"); 00566 answer_sound(); 00567 ast_setstate(c, AST_STATE_UP); 00568 cursound = -1; 00569 snd_pcm_prepare(alsa.icard); 00570 snd_pcm_start(alsa.icard); 00571 ast_mutex_unlock(&alsalock); 00572 return 0; 00573 } 00574 00575 static int alsa_hangup(struct ast_channel *c) 00576 { 00577 int res; 00578 ast_mutex_lock(&alsalock); 00579 cursound = -1; 00580 c->tech_pvt = NULL; 00581 alsa.owner = NULL; 00582 ast_verbose(" << Hangup on console >> \n"); 00583 ast_module_unref(ast_module_info->self); 00584 if (hookstate) { 00585 hookstate = 0; 00586 if (!autoanswer) { 00587 /* Congestion noise */ 00588 res = 2; 00589 write(sndcmd[1], &res, sizeof(res)); 00590 } 00591 } 00592 snd_pcm_drop(alsa.icard); 00593 ast_mutex_unlock(&alsalock); 00594 return 0; 00595 } 00596 00597 static int alsa_write(struct ast_channel *chan, struct ast_frame *f) 00598 { 00599 static char sizbuf[8000]; 00600 static int sizpos = 0; 00601 int len = sizpos; 00602 int pos; 00603 int res = 0; 00604 /* size_t frames = 0; */ 00605 snd_pcm_state_t state; 00606 00607 /* Immediately return if no sound is enabled */ 00608 if (nosound) 00609 return 0; 00610 00611 ast_mutex_lock(&alsalock); 00612 /* Stop any currently playing sound */ 00613 if (cursound != -1) { 00614 snd_pcm_drop(alsa.ocard); 00615 snd_pcm_prepare(alsa.ocard); 00616 cursound = -1; 00617 } 00618 00619 00620 /* We have to digest the frame in 160-byte portions */ 00621 if (f->datalen > sizeof(sizbuf) - sizpos) { 00622 ast_log(LOG_WARNING, "Frame too large\n"); 00623 res = -1; 00624 } else { 00625 memcpy(sizbuf + sizpos, f->data, f->datalen); 00626 len += f->datalen; 00627 pos = 0; 00628 #ifdef ALSA_MONITOR 00629 alsa_monitor_write(sizbuf, len); 00630 #endif 00631 state = snd_pcm_state(alsa.ocard); 00632 if (state == SND_PCM_STATE_XRUN) 00633 snd_pcm_prepare(alsa.ocard); 00634 res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2); 00635 if (res == -EPIPE) { 00636 #if DEBUG 00637 if (option_debug) 00638 ast_log(LOG_DEBUG, "XRUN write\n"); 00639 #endif 00640 snd_pcm_prepare(alsa.ocard); 00641 res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2); 00642 if (res != len / 2) { 00643 ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res)); 00644 res = -1; 00645 } else if (res < 0) { 00646 ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res)); 00647 res = -1; 00648 } 00649 } else { 00650 if (res == -ESTRPIPE) 00651 ast_log(LOG_ERROR, "You've got some big problems\n"); 00652 else if (res < 0) 00653 ast_log(LOG_NOTICE, "Error %d on write\n", res); 00654 } 00655 } 00656 ast_mutex_unlock(&alsalock); 00657 if (res > 0) 00658 res = 0; 00659 return res; 00660 } 00661 00662 00663 static struct ast_frame *alsa_read(struct ast_channel *chan) 00664 { 00665 static struct ast_frame f; 00666 static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2]; 00667 short *buf; 00668 static int readpos = 0; 00669 static int left = FRAME_SIZE; 00670 snd_pcm_state_t state; 00671 int r = 0; 00672 int off = 0; 00673 00674 ast_mutex_lock(&alsalock); 00675 /* Acknowledge any pending cmd */ 00676 f.frametype = AST_FRAME_NULL; 00677 f.subclass = 0; 00678 f.samples = 0; 00679 f.datalen = 0; 00680 f.data = NULL; 00681 f.offset = 0; 00682 f.src = "Console"; 00683 f.mallocd = 0; 00684 f.delivery.tv_sec = 0; 00685 f.delivery.tv_usec = 0; 00686 00687 state = snd_pcm_state(alsa.icard); 00688 if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) { 00689 snd_pcm_prepare(alsa.icard); 00690 } 00691 00692 buf = __buf + AST_FRIENDLY_OFFSET / 2; 00693 00694 r = snd_pcm_readi(alsa.icard, buf + readpos, left); 00695 if (r == -EPIPE) { 00696 #if DEBUG 00697 ast_log(LOG_ERROR, "XRUN read\n"); 00698 #endif 00699 snd_pcm_prepare(alsa.icard); 00700 } else if (r == -ESTRPIPE) { 00701 ast_log(LOG_ERROR, "-ESTRPIPE\n"); 00702 snd_pcm_prepare(alsa.icard); 00703 } else if (r < 0) { 00704 ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r)); 00705 } else if (r >= 0) { 00706 off -= r; 00707 } 00708 /* Update positions */ 00709 readpos += r; 00710 left -= r; 00711 00712 if (readpos >= FRAME_SIZE) { 00713 /* A real frame */ 00714 readpos = 0; 00715 left = FRAME_SIZE; 00716 if (chan->_state != AST_STATE_UP) { 00717 /* Don't transmit unless it's up */ 00718 ast_mutex_unlock(&alsalock); 00719 return &f; 00720 } 00721 f.frametype = AST_FRAME_VOICE; 00722 f.subclass = AST_FORMAT_SLINEAR; 00723 f.samples = FRAME_SIZE; 00724 f.datalen = FRAME_SIZE * 2; 00725 f.data = buf; 00726 f.offset = AST_FRIENDLY_OFFSET; 00727 f.src = "Console"; 00728 f.mallocd = 0; 00729 #ifdef ALSA_MONITOR 00730 alsa_monitor_read((char *) buf, FRAME_SIZE * 2); 00731 #endif 00732 00733 } 00734 ast_mutex_unlock(&alsalock); 00735 return &f; 00736 } 00737 00738 static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 00739 { 00740 struct chan_alsa_pvt *p = newchan->tech_pvt; 00741 ast_mutex_lock(&alsalock); 00742 p->owner = newchan; 00743 ast_mutex_unlock(&alsalock); 00744 return 0; 00745 } 00746 00747 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen) 00748 { 00749 int res = 0; 00750 00751 ast_mutex_lock(&alsalock); 00752 00753 switch (cond) { 00754 case AST_CONTROL_BUSY: 00755 res = 1; 00756 break; 00757 case AST_CONTROL_CONGESTION: 00758 res = 2; 00759 break; 00760 case AST_CONTROL_RINGING: 00761 break; 00762 case -1: 00763 res = -1; 00764 break; 00765 case AST_CONTROL_VIDUPDATE: 00766 res = -1; 00767 break; 00768 case AST_CONTROL_HOLD: 00769 ast_verbose(" << Console Has Been Placed on Hold >> \n"); 00770 ast_moh_start(chan, data, mohinterpret); 00771 break; 00772 case AST_CONTROL_UNHOLD: 00773 ast_verbose(" << Console Has Been Retrieved from Hold >> \n"); 00774 ast_moh_stop(chan); 00775 break; 00776 default: 00777 ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name); 00778 res = -1; 00779 } 00780 00781 if (res > -1) 00782 write(sndcmd[1], &res, sizeof(res)); 00783 00784 ast_mutex_unlock(&alsalock); 00785 00786 return res; 00787 } 00788 00789 static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state) 00790 { 00791 struct ast_channel *tmp = NULL; 00792 00793 if (!(tmp = ast_channel_alloc(1, state, 0, 0, "ALSA/%s", indevname))) 00794 return NULL; 00795 00796 tmp->tech = &alsa_tech; 00797 tmp->fds[0] = readdev; 00798 tmp->nativeformats = AST_FORMAT_SLINEAR; 00799 tmp->readformat = AST_FORMAT_SLINEAR; 00800 tmp->writeformat = AST_FORMAT_SLINEAR; 00801 tmp->tech_pvt = p; 00802 if (!ast_strlen_zero(p->context)) 00803 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00804 if (!ast_strlen_zero(p->exten)) 00805 ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten)); 00806 if (!ast_strlen_zero(language)) 00807 ast_string_field_set(tmp, language, language); 00808 p->owner = tmp; 00809 ast_module_ref(ast_module_info->self); 00810 ast_jb_configure(tmp, &global_jbconf); 00811 if (state != AST_STATE_DOWN) { 00812 if (ast_pbx_start(tmp)) { 00813 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); 00814 ast_hangup(tmp); 00815 tmp = NULL; 00816 } 00817 } 00818 00819 return tmp; 00820 } 00821 00822 static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause) 00823 { 00824 int oldformat = format; 00825 struct ast_channel *tmp = NULL; 00826 00827 format &= AST_FORMAT_SLINEAR; 00828 if (!format) { 00829 ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat); 00830 return NULL; 00831 } 00832 00833 ast_mutex_lock(&alsalock); 00834 00835 if (alsa.owner) { 00836 ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n"); 00837 *cause = AST_CAUSE_BUSY; 00838 } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN))) 00839 ast_log(LOG_WARNING, "Unable to create new ALSA channel\n"); 00840 00841 ast_mutex_unlock(&alsalock); 00842 00843 return tmp; 00844 } 00845 00846 static int console_autoanswer(int fd, int argc, char *argv[]) 00847 { 00848 int res = RESULT_SUCCESS;; 00849 if ((argc != 2) && (argc != 3)) 00850 return RESULT_SHOWUSAGE; 00851 ast_mutex_lock(&alsalock); 00852 if (argc == 2) { 00853 ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off"); 00854 } else { 00855 if (!strcasecmp(argv[2], "on")) 00856 autoanswer = -1; 00857 else if (!strcasecmp(argv[2], "off")) 00858 autoanswer = 0; 00859 else 00860 res = RESULT_SHOWUSAGE; 00861 } 00862 ast_mutex_unlock(&alsalock); 00863 return res; 00864 } 00865 00866 static char *autoanswer_complete(const char *line, const char *word, int pos, int state) 00867 { 00868 #ifndef MIN 00869 #define MIN(a,b) ((a) < (b) ? (a) : (b)) 00870 #endif 00871 switch (state) { 00872 case 0: 00873 if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2))) 00874 return ast_strdup("on"); 00875 case 1: 00876 if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3))) 00877 return ast_strdup("off"); 00878 default: 00879 return NULL; 00880 } 00881 return NULL; 00882 } 00883 00884 static const char autoanswer_usage[] = 00885 "Usage: console autoanswer [on|off]\n" 00886 " Enables or disables autoanswer feature. If used without\n" 00887 " argument, displays the current on/off status of autoanswer.\n" 00888 " The default value of autoanswer is in 'alsa.conf'.\n"; 00889 00890 static int console_answer(int fd, int argc, char *argv[]) 00891 { 00892 int res = RESULT_SUCCESS; 00893 00894 if (argc != 2) 00895 return RESULT_SHOWUSAGE; 00896 00897 ast_mutex_lock(&alsalock); 00898 00899 if (!alsa.owner) { 00900 ast_cli(fd, "No one is calling us\n"); 00901 res = RESULT_FAILURE; 00902 } else { 00903 hookstate = 1; 00904 cursound = -1; 00905 grab_owner(); 00906 if (alsa.owner) { 00907 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00908 ast_queue_frame(alsa.owner, &f); 00909 ast_mutex_unlock(&alsa.owner->lock); 00910 } 00911 answer_sound(); 00912 } 00913 00914 snd_pcm_prepare(alsa.icard); 00915 snd_pcm_start(alsa.icard); 00916 00917 ast_mutex_unlock(&alsalock); 00918 00919 return RESULT_SUCCESS; 00920 } 00921 00922 static const char sendtext_usage[] = 00923 "Usage: console send text <message>\n" 00924 " Sends a text message for display on the remote terminal.\n"; 00925 00926 static int console_sendtext(int fd, int argc, char *argv[]) 00927 { 00928 int tmparg = 3; 00929 int res = RESULT_SUCCESS; 00930 00931 if (argc < 3) 00932 return RESULT_SHOWUSAGE; 00933 00934 ast_mutex_lock(&alsalock); 00935 00936 if (!alsa.owner) { 00937 ast_cli(fd, "No one is calling us\n"); 00938 res = RESULT_FAILURE; 00939 } else { 00940 struct ast_frame f = { AST_FRAME_TEXT, 0 }; 00941 char text2send[256] = ""; 00942 text2send[0] = '\0'; 00943 while (tmparg < argc) { 00944 strncat(text2send, argv[tmparg++], sizeof(text2send) - strlen(text2send) - 1); 00945 strncat(text2send, " ", sizeof(text2send) - strlen(text2send) - 1); 00946 } 00947 text2send[strlen(text2send) - 1] = '\n'; 00948 f.data = text2send; 00949 f.datalen = strlen(text2send) + 1; 00950 grab_owner(); 00951 if (alsa.owner) { 00952 ast_queue_frame(alsa.owner, &f); 00953 f.frametype = AST_FRAME_CONTROL; 00954 f.subclass = AST_CONTROL_ANSWER; 00955 f.data = NULL; 00956 f.datalen = 0; 00957 ast_queue_frame(alsa.owner, &f); 00958 ast_mutex_unlock(&alsa.owner->lock); 00959 } 00960 } 00961 00962 ast_mutex_unlock(&alsalock); 00963 00964 return res; 00965 } 00966 00967 static const char answer_usage[] = 00968 "Usage: console answer\n" 00969 " Answers an incoming call on the console (ALSA) channel.\n"; 00970 00971 static int console_hangup(int fd, int argc, char *argv[]) <