⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chan_oss.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (*ext == NULL)		return NULL;	if (!o->overridecontext) {		/* parse from the right */		*ctx = strrchr(*ext, '@');		if (*ctx)			*(*ctx)++ = '\0';	}	return *ext;}/* * Returns the number of blocks used in the audio output channel */static int used_blocks(struct chan_oss_pvt *o){	struct audio_buf_info info;	if (ioctl(o->sounddev, SNDCTL_DSP_GETOSPACE, &info)) {		if (!(o->warned & WARN_used_blocks)) {			ast_log(LOG_WARNING, "Error reading output space\n");			o->warned |= WARN_used_blocks;		}		return 1;	}	if (o->total_blocks == 0) {		if (0)					/* debugging */			ast_log(LOG_WARNING, "fragtotal %d size %d avail %d\n", info.fragstotal, info.fragsize, info.fragments);		o->total_blocks = info.fragments;	}	return o->total_blocks - info.fragments;}/* Write an exactly FRAME_SIZE sized frame */static int soundcard_writeframe(struct chan_oss_pvt *o, short *data){	int res;	if (o->sounddev < 0)		setformat(o, O_RDWR);	if (o->sounddev < 0)		return 0;				/* not fatal */	/*	 * Nothing complex to manage the audio device queue.	 * If the buffer is full just drop the extra, otherwise write.	 * XXX in some cases it might be useful to write anyways after	 * a number of failures, to restart the output chain.	 */	res = used_blocks(o);	if (res > o->queuesize) {	/* no room to write a block */		if (o->w_errors++ == 0 && (oss_debug & 0x4))			ast_log(LOG_WARNING, "write: used %d blocks (%d)\n", res, o->w_errors);		return 0;	}	o->w_errors = 0;	return write(o->sounddev, ((void *) data), FRAME_SIZE * 2);}/* * Handler for 'sound writable' events from the sound thread. * Builds a frame from the high level description of the sounds, * and passes it to the audio device. * The actual sound is made of 1 or more sequences of sound samples * (s->datalen, repeated to make s->samplen samples) followed by * s->silencelen samples of silence. The position in the sequence is stored * in o->sampsent, which goes between 0 .. s->samplen+s->silencelen. * In case we fail to write a frame, don't update o->sampsent. */static void send_sound(struct chan_oss_pvt *o){	short myframe[FRAME_SIZE];	int ofs, l, start;	int l_sampsent = o->sampsent;	struct sound *s;	if (o->cursound < 0)		/* no sound to send */		return;	s = &sounds[o->cursound];	for (ofs = 0; ofs < FRAME_SIZE; ofs += l) {		l = s->samplen - l_sampsent;	/* # of available samples */		if (l > 0) {			start = l_sampsent % s->datalen;	/* source offset */			if (l > FRAME_SIZE - ofs)	/* don't overflow the frame */				l = FRAME_SIZE - ofs;			if (l > s->datalen - start)	/* don't overflow the source */				l = s->datalen - start;			bcopy(s->data + start, myframe + ofs, l * 2);			if (0)				ast_log(LOG_WARNING, "send_sound sound %d/%d of %d into %d\n", l_sampsent, l, s->samplen, ofs);			l_sampsent += l;		} else {				/* end of samples, maybe some silence */			static const short silence[FRAME_SIZE] = { 0, };			l += s->silencelen;			if (l > 0) {				if (l > FRAME_SIZE - ofs)					l = FRAME_SIZE - ofs;				bcopy(silence, myframe + ofs, l * 2);				l_sampsent += l;			} else {			/* silence is over, restart sound if loop */				if (s->repeat == 0) {	/* last block */					o->cursound = -1;					o->nosound = 0;	/* allow audio data */					if (ofs < FRAME_SIZE)	/* pad with silence */						bcopy(silence, myframe + ofs, (FRAME_SIZE - ofs) * 2);				}				l_sampsent = 0;			}		}	}	l = soundcard_writeframe(o, myframe);	if (l > 0)		o->sampsent = l_sampsent;	/* update status */}static void *sound_thread(void *arg){	char ign[4096];	struct chan_oss_pvt *o = (struct chan_oss_pvt *) arg;	/*	 * Just in case, kick the driver by trying to read from it.	 * Ignore errors - this read is almost guaranteed to fail.	 */	read(o->sounddev, ign, sizeof(ign));	for (;;) {		fd_set rfds, wfds;		int maxfd, res;		FD_ZERO(&rfds);		FD_ZERO(&wfds);		FD_SET(o->sndcmd[0], &rfds);		maxfd = o->sndcmd[0];	/* pipe from the main process */		if (o->cursound > -1 && o->sounddev < 0)			setformat(o, O_RDWR);	/* need the channel, try to reopen */		else if (o->cursound == -1 && o->owner == NULL)			setformat(o, O_CLOSE);	/* can close */		if (o->sounddev > -1) {			if (!o->owner) {	/* no one owns the audio, so we must drain it */				FD_SET(o->sounddev, &rfds);				maxfd = MAX(o->sounddev, maxfd);			}			if (o->cursound > -1) {				FD_SET(o->sounddev, &wfds);				maxfd = MAX(o->sounddev, maxfd);			}		}		/* ast_select emulates linux behaviour in terms of timeout handling */		res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);		if (res < 1) {			ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));			sleep(1);			continue;		}		if (FD_ISSET(o->sndcmd[0], &rfds)) {			/* read which sound to play from the pipe */			int i, what = -1;			read(o->sndcmd[0], &what, sizeof(what));			for (i = 0; sounds[i].ind != -1; i++) {				if (sounds[i].ind == what) {					o->cursound = i;					o->sampsent = 0;					o->nosound = 1;	/* block audio from pbx */					break;				}			}			if (sounds[i].ind == -1)				ast_log(LOG_WARNING, "invalid sound index: %d\n", what);		}		if (o->sounddev > -1) {			if (FD_ISSET(o->sounddev, &rfds))	/* read and ignore errors */				read(o->sounddev, ign, sizeof(ign));			if (FD_ISSET(o->sounddev, &wfds))				send_sound(o);		}	}	return NULL;				/* Never reached */}/* * reset and close the device if opened, * then open and initialize it in the desired mode, * trigger reads and writes so we can start using it. */static int setformat(struct chan_oss_pvt *o, int mode){	int fmt, desired, res, fd;	if (o->sounddev >= 0) {		ioctl(o->sounddev, SNDCTL_DSP_RESET, 0);		close(o->sounddev);		o->duplex = M_UNSET;		o->sounddev = -1;	}	if (mode == O_CLOSE)		/* we are done */		return 0;	if (ast_tvdiff_ms(ast_tvnow(), o->lastopen) < 1000)		return -1;				/* don't open too often */	o->lastopen = ast_tvnow();	fd = o->sounddev = open(o->device, mode | O_NONBLOCK);	if (fd < 0) {		ast_log(LOG_WARNING, "Unable to re-open DSP device %s: %s\n", o->device, strerror(errno));		return -1;	}	if (o->owner)		o->owner->fds[0] = fd;#if __BYTE_ORDER == __LITTLE_ENDIAN	fmt = AFMT_S16_LE;#else	fmt = AFMT_S16_BE;#endif	res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);	if (res < 0) {		ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");		return -1;	}	switch (mode) {		case O_RDWR:			res = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);			/* Check to see if duplex set (FreeBSD Bug) */			res = ioctl(fd, SNDCTL_DSP_GETCAPS, &fmt);			if (res == 0 && (fmt & DSP_CAP_DUPLEX)) {				if (option_verbose > 1)					ast_verbose(VERBOSE_PREFIX_2 "Console is full duplex\n");				o->duplex = M_FULL;			};			break;		case O_WRONLY:			o->duplex = M_WRITE;			break;		case O_RDONLY:			o->duplex = M_READ;			break;	}	fmt = 0;	res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);	if (res < 0) {		ast_log(LOG_WARNING, "Failed to set audio device to mono\n");		return -1;	}	fmt = desired = DEFAULT_SAMPLE_RATE;	/* 8000 Hz desired */	res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);	if (res < 0) {		ast_log(LOG_WARNING, "Failed to set audio device to mono\n");		return -1;	}	if (fmt != desired) {		if (!(o->warned & WARN_speed)) {			ast_log(LOG_WARNING,			    "Requested %d Hz, got %d Hz -- sound may be choppy\n",			    desired, fmt);			o->warned |= WARN_speed;		}	}	/*	 * on Freebsd, SETFRAGMENT does not work very well on some cards.	 * Default to use 256 bytes, let the user override	 */	if (o->frags) {		fmt = o->frags;		res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);		if (res < 0) {			if (!(o->warned & WARN_frag)) {				ast_log(LOG_WARNING,					"Unable to set fragment size -- sound may be choppy\n");				o->warned |= WARN_frag;			}		}	}	/* on some cards, we need SNDCTL_DSP_SETTRIGGER to start outputting */	res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;	res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);	/* it may fail if we are in half duplex, never mind */	return 0;}/* * some of the standard methods supported by channels. */static int oss_digit_begin(struct ast_channel *c, char digit){	return 0;}static int oss_digit_end(struct ast_channel *c, char digit, unsigned int duration){	/* no better use for received digits than print them */	ast_verbose(" << Console Received digit %c of duration %u ms >> \n", 		digit, duration);	return 0;}static int oss_text(struct ast_channel *c, const char *text){	/* print received messages */	ast_verbose(" << Console Received text %s >> \n", text);	return 0;}/* Play ringtone 'x' on device 'o' */static void ring(struct chan_oss_pvt *o, int x){	write(o->sndcmd[1], &x, sizeof(x));}/* * handler for incoming calls. Either autoanswer, or start ringing */static int oss_call(struct ast_channel *c, char *dest, int timeout){	struct chan_oss_pvt *o = c->tech_pvt;	struct ast_frame f = { 0, };	ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n", dest, c->cid.cid_dnid, c->cid.cid_rdnis, c->cid.cid_name, c->cid.cid_num);	if (o->autoanswer) {		ast_verbose(" << Auto-answered >> \n");		f.frametype = AST_FRAME_CONTROL;		f.subclass = AST_CONTROL_ANSWER;		ast_queue_frame(c, &f);	} else {		ast_verbose("<< Type 'answer' to answer, or use 'autoanswer' for future calls >> \n");		f.frametype = AST_FRAME_CONTROL;		f.subclass = AST_CONTROL_RINGING;		ast_queue_frame(c, &f);		ring(o, AST_CONTROL_RING);	}	return 0;}/* * remote side answered the phone */static int oss_answer(struct ast_channel *c){	struct chan_oss_pvt *o = c->tech_pvt;	ast_verbose(" << Console call has been answered >> \n");#if 0	/* play an answer tone (XXX do we really need it ?) */	ring(o, AST_CONTROL_ANSWER);#endif	ast_setstate(c, AST_STATE_UP);	o->cursound = -1;	o->nosound = 0;	return 0;}static int oss_hangup(struct ast_channel *c){	struct chan_oss_pvt *o = c->tech_pvt;	o->cursound = -1;	o->nosound = 0;	c->tech_pvt = NULL;	o->owner = NULL;	ast_verbose(" << Hangup on console >> \n");	ast_module_unref(ast_module_info->self);	if (o->hookstate) {		if (o->autoanswer || o->autohangup) {			/* Assume auto-hangup too */			o->hookstate = 0;			setformat(o, O_CLOSE);		} else {			/* Make congestion noise */			ring(o, AST_CONTROL_CONGESTION);		}	}	return 0;}/* used for data coming from the network */static int oss_write(struct ast_channel *c, struct ast_frame *f){	int src;	struct chan_oss_pvt *o = c->tech_pvt;	/* Immediately return if no sound is enabled */	if (o->nosound)		return 0;	/* Stop any currently playing sound */	o->cursound = -1;	/*	 * we could receive a block which is not a multiple of our	 * FRAME_SIZE, so buffer it locally and write to the device	 * in FRAME_SIZE chunks.	 * Keep the residue stored for future use.	 */	src = 0;					/* read position into f->data */	while (src < f->datalen) {		/* Compute spare room in the buffer */		int l = sizeof(o->oss_write_buf) - o->oss_write_dst;		if (f->datalen - src >= l) {	/* enough to fill a frame */			memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);			soundcard_writeframe(o, (short *) o->oss_write_buf);			src += l;			o->oss_write_dst = 0;		} else {				/* copy residue */			l = f->datalen - src;			memcpy(o->oss_write_buf + o->oss_write_dst, f->data + src, l);			src += l;			/* but really, we are done */			o->oss_write_dst += l;		}	}	return 0;}static struct ast_frame *oss_read(struct ast_channel *c){	int res;	struct chan_oss_pvt *o = c->tech_pvt;	struct ast_frame *f = &o->read_f;	/* XXX can be simplified returning &ast_null_frame */	/* prepare a NULL frame in case we don't have enough data to return */	bzero(f, sizeof(struct ast_frame));	f->frametype = AST_FRAME_NULL;	f->src = oss_tech.type;	res = read(o->sounddev, o->oss_read_buf + o->readpos, sizeof(o->oss_read_buf) - o->readpos);	if (res < 0)				/* audio data not ready, return a NULL frame */		return f;	o->readpos += res;	if (o->readpos < sizeof(o->oss_read_buf))	/* not enough samples */		return f;	if (o->mute)		return f;	o->readpos = AST_FRIENDLY_OFFSET;	/* reset read pointer for next frame */	if (c->_state != AST_STATE_UP)	/* drop data if frame is not up */		return f;	/* ok we can build and deliver the frame to the caller */	f->frametype = AST_FRAME_VOICE;	f->subclass = AST_FORMAT_SLINEAR;	f->samples = FRAME_SIZE;	f->datalen = FRAME_SIZE * 2;	f->data = o->oss_read_buf + AST_FRIENDLY_OFFSET;	if (o->boost != BOOST_SCALE) {	/* scale and clip values */		int i, x;		int16_t *p = (int16_t *) f->data;		for (i = 0; i < f->samples; i++) {			x = (p[i] * o->boost) / BOOST_SCALE;			if (x > 32767)				x = 32767;			else if (x < -32768)				x = -32768;			p[i] = x;		}	}	f->offset = AST_FRIENDLY_OFFSET;	return f;}static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){	struct chan_oss_pvt *o = newchan->tech_pvt;	o->owner = newchan;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -