📄 chan_alsa.c
字号:
if (err <= 0) ast_log(LOG_ERROR, "Unable to get a poll descriptors count, error is %s\n", snd_strerror(err)); if (err != 1) ast_log(LOG_DEBUG, "Can't handle more than one device\n"); snd_pcm_poll_descriptors(handle, &pfd, err); ast_log(LOG_DEBUG, "Acquired fd %d from the poll descriptor\n", pfd.fd); if (stream == SND_PCM_STREAM_CAPTURE) readdev = pfd.fd; else writedev = pfd.fd; return handle;}static int soundcard_init(void){ alsa.icard = alsa_card_init(indevname, SND_PCM_STREAM_CAPTURE); alsa.ocard = alsa_card_init(outdevname, SND_PCM_STREAM_PLAYBACK); if (!alsa.icard || !alsa.ocard) { ast_log(LOG_ERROR, "Problem opening alsa I/O devices\n"); return -1; } return readdev;}static int alsa_digit(struct ast_channel *c, char digit, unsigned int duration){ ast_mutex_lock(&alsalock); ast_verbose(" << Console Received digit %c of duration %u ms >> \n", digit, duration); ast_mutex_unlock(&alsalock); return 0;}static int alsa_text(struct ast_channel *c, const char *text){ ast_mutex_lock(&alsalock); ast_verbose(" << Console Received text %s >> \n", text); ast_mutex_unlock(&alsalock); return 0;}static void grab_owner(void){ while (alsa.owner && ast_mutex_trylock(&alsa.owner->lock)) { DEADLOCK_AVOIDANCE(&alsalock); }}static int alsa_call(struct ast_channel *c, char *dest, int timeout){ int res = 3; struct ast_frame f = { AST_FRAME_CONTROL }; ast_mutex_lock(&alsalock); ast_verbose(" << Call placed to '%s' on console >> \n", dest); if (autoanswer) { ast_verbose(" << Auto-answered >> \n"); grab_owner(); if (alsa.owner) { f.subclass = AST_CONTROL_ANSWER; ast_queue_frame(alsa.owner, &f); ast_mutex_unlock(&alsa.owner->lock); } } else { ast_verbose(" << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n"); grab_owner(); if (alsa.owner) { f.subclass = AST_CONTROL_RINGING; ast_queue_frame(alsa.owner, &f); ast_mutex_unlock(&alsa.owner->lock); } write(sndcmd[1], &res, sizeof(res)); } snd_pcm_prepare(alsa.icard); snd_pcm_start(alsa.icard); ast_mutex_unlock(&alsalock); return 0;}static void answer_sound(void){ int res; nosound = 1; res = 4; write(sndcmd[1], &res, sizeof(res));}static int alsa_answer(struct ast_channel *c){ ast_mutex_lock(&alsalock); ast_verbose(" << Console call has been answered >> \n"); answer_sound(); ast_setstate(c, AST_STATE_UP); cursound = -1; snd_pcm_prepare(alsa.icard); snd_pcm_start(alsa.icard); ast_mutex_unlock(&alsalock); return 0;}static int alsa_hangup(struct ast_channel *c){ int res; ast_mutex_lock(&alsalock); cursound = -1; c->tech_pvt = NULL; alsa.owner = NULL; ast_verbose(" << Hangup on console >> \n"); ast_module_unref(ast_module_info->self); if (hookstate) { hookstate = 0; if (!autoanswer) { /* Congestion noise */ res = 2; write(sndcmd[1], &res, sizeof(res)); } } snd_pcm_drop(alsa.icard); ast_mutex_unlock(&alsalock); return 0;}static int alsa_write(struct ast_channel *chan, struct ast_frame *f){ static char sizbuf[8000]; static int sizpos = 0; int len = sizpos; int pos; int res = 0; /* size_t frames = 0; */ snd_pcm_state_t state; /* Immediately return if no sound is enabled */ if (nosound) return 0; ast_mutex_lock(&alsalock); /* Stop any currently playing sound */ if (cursound != -1) { snd_pcm_drop(alsa.ocard); snd_pcm_prepare(alsa.ocard); cursound = -1; } /* We have to digest the frame in 160-byte portions */ if (f->datalen > sizeof(sizbuf) - sizpos) { ast_log(LOG_WARNING, "Frame too large\n"); res = -1; } else { memcpy(sizbuf + sizpos, f->data, f->datalen); len += f->datalen; pos = 0;#ifdef ALSA_MONITOR alsa_monitor_write(sizbuf, len);#endif state = snd_pcm_state(alsa.ocard); if (state == SND_PCM_STATE_XRUN) snd_pcm_prepare(alsa.ocard); res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2); if (res == -EPIPE) {#if DEBUG ast_log(LOG_DEBUG, "XRUN write\n");#endif snd_pcm_prepare(alsa.ocard); res = snd_pcm_writei(alsa.ocard, sizbuf, len / 2); if (res != len / 2) { ast_log(LOG_ERROR, "Write error: %s\n", snd_strerror(res)); res = -1; } else if (res < 0) { ast_log(LOG_ERROR, "Write error %s\n", snd_strerror(res)); res = -1; } } else { if (res == -ESTRPIPE) ast_log(LOG_ERROR, "You've got some big problems\n"); else if (res < 0) ast_log(LOG_NOTICE, "Error %d on write\n", res); } } ast_mutex_unlock(&alsalock); if (res > 0) res = 0; return res;}static struct ast_frame *alsa_read(struct ast_channel *chan){ static struct ast_frame f; static short __buf[FRAME_SIZE + AST_FRIENDLY_OFFSET / 2]; short *buf; static int readpos = 0; static int left = FRAME_SIZE; snd_pcm_state_t state; int r = 0; int off = 0; ast_mutex_lock(&alsalock); /* Acknowledge any pending cmd */ f.frametype = AST_FRAME_NULL; f.subclass = 0; f.samples = 0; f.datalen = 0; f.data = NULL; f.offset = 0; f.src = "Console"; f.mallocd = 0; f.delivery.tv_sec = 0; f.delivery.tv_usec = 0; state = snd_pcm_state(alsa.icard); if ((state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING)) { snd_pcm_prepare(alsa.icard); } buf = __buf + AST_FRIENDLY_OFFSET / 2; r = snd_pcm_readi(alsa.icard, buf + readpos, left); if (r == -EPIPE) {#if DEBUG ast_log(LOG_ERROR, "XRUN read\n");#endif snd_pcm_prepare(alsa.icard); } else if (r == -ESTRPIPE) { ast_log(LOG_ERROR, "-ESTRPIPE\n"); snd_pcm_prepare(alsa.icard); } else if (r < 0) { ast_log(LOG_ERROR, "Read error: %s\n", snd_strerror(r)); } else if (r >= 0) { off -= r; } /* Update positions */ readpos += r; left -= r; if (readpos >= FRAME_SIZE) { /* A real frame */ readpos = 0; left = FRAME_SIZE; if (chan->_state != AST_STATE_UP) { /* Don't transmit unless it's up */ ast_mutex_unlock(&alsalock); return &f; } f.frametype = AST_FRAME_VOICE; f.subclass = AST_FORMAT_SLINEAR; f.samples = FRAME_SIZE; f.datalen = FRAME_SIZE * 2; f.data = buf; f.offset = AST_FRIENDLY_OFFSET; f.src = "Console"; f.mallocd = 0;#ifdef ALSA_MONITOR alsa_monitor_read((char *) buf, FRAME_SIZE * 2);#endif } ast_mutex_unlock(&alsalock); return &f;}static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){ struct chan_alsa_pvt *p = newchan->tech_pvt; ast_mutex_lock(&alsalock); p->owner = newchan; ast_mutex_unlock(&alsalock); return 0;}static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen){ int res = 0; ast_mutex_lock(&alsalock); switch (cond) { case AST_CONTROL_BUSY: res = 1; break; case AST_CONTROL_CONGESTION: res = 2; break; case AST_CONTROL_RINGING: case AST_CONTROL_PROGRESS: break; case -1: res = -1; break; case AST_CONTROL_VIDUPDATE: res = -1; break; case AST_CONTROL_HOLD: ast_verbose(" << Console Has Been Placed on Hold >> \n"); ast_moh_start(chan, data, mohinterpret); break; case AST_CONTROL_UNHOLD: ast_verbose(" << Console Has Been Retrieved from Hold >> \n"); ast_moh_stop(chan); break; case AST_CONTROL_SRCUPDATE: break; default: ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name); res = -1; } if (res > -1) write(sndcmd[1], &res, sizeof(res)); ast_mutex_unlock(&alsalock); return res;}static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state){ struct ast_channel *tmp = NULL; if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "ALSA/%s", indevname))) return NULL; tmp->tech = &alsa_tech; tmp->fds[0] = readdev; tmp->nativeformats = AST_FORMAT_SLINEAR; tmp->readformat = AST_FORMAT_SLINEAR; tmp->writeformat = AST_FORMAT_SLINEAR; tmp->tech_pvt = p; if (!ast_strlen_zero(p->context)) ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); if (!ast_strlen_zero(p->exten)) ast_copy_string(tmp->exten, p->exten, sizeof(tmp->exten)); if (!ast_strlen_zero(language)) ast_string_field_set(tmp, language, language); p->owner = tmp; ast_module_ref(ast_module_info->self); ast_jb_configure(tmp, &global_jbconf); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); tmp = NULL; } } return tmp;}static struct ast_channel *alsa_request(const char *type, int format, void *data, int *cause){ int oldformat = format; struct ast_channel *tmp = NULL; format &= AST_FORMAT_SLINEAR; if (!format) { ast_log(LOG_NOTICE, "Asked to get a channel of format '%d'\n", oldformat); return NULL; } ast_mutex_lock(&alsalock); if (alsa.owner) { ast_log(LOG_NOTICE, "Already have a call on the ALSA channel\n"); *cause = AST_CAUSE_BUSY; } else if (!(tmp = alsa_new(&alsa, AST_STATE_DOWN))) ast_log(LOG_WARNING, "Unable to create new ALSA channel\n"); ast_mutex_unlock(&alsalock); return tmp;}static int console_autoanswer_deprecated(int fd, int argc, char *argv[]){ int res = RESULT_SUCCESS; if ((argc != 1) && (argc != 2)) return RESULT_SHOWUSAGE; ast_mutex_lock(&alsalock); if (argc == 1) { ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off"); } else { if (!strcasecmp(argv[1], "on")) autoanswer = -1; else if (!strcasecmp(argv[1], "off")) autoanswer = 0; else res = RESULT_SHOWUSAGE; } ast_mutex_unlock(&alsalock); return res;}static int console_autoanswer(int fd, int argc, char *argv[]){ int res = RESULT_SUCCESS;; if ((argc != 2) && (argc != 3)) return RESULT_SHOWUSAGE; ast_mutex_lock(&alsalock); if (argc == 2) { ast_cli(fd, "Auto answer is %s.\n", autoanswer ? "on" : "off"); } else { if (!strcasecmp(argv[2], "on")) autoanswer = -1; else if (!strcasecmp(argv[2], "off")) autoanswer = 0; else res = RESULT_SHOWUSAGE; } ast_mutex_unlock(&alsalock); return res;}static char *autoanswer_complete(const char *line, const char *word, int pos, int state){#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif switch (state) { case 0: if (!ast_strlen_zero(word) && !strncasecmp(word, "on", MIN(strlen(word), 2))) return ast_strdup("on"); case 1: if (!ast_strlen_zero(word) && !strncasecmp(word, "off", MIN(strlen(word), 3))) return ast_strdup("off"); default: return NULL; } return NULL;}static const char autoanswer_usage[] = "Usage: console autoanswer [on|off]\n" " Enables or disables autoanswer feature. If used without\n" " argument, displays the current on/off status of autoanswer.\n" " The default value of autoanswer is in 'alsa.conf'.\n";static int console_answer_deprecated(int fd, int argc, char *argv[]){ int res = RESULT_SUCCESS; if (argc != 1) return RESULT_SHOWUSAGE; ast_mutex_lock(&alsalock); if (!alsa.owner) { ast_cli(fd, "No one is calling us\n"); res = RESULT_FAILURE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -