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

📄 isdn_audio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
 */intisdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,		      unsigned char *out, int len){	int a = s->a;	int d = s->d;	int nbits = s->nbits;	int olen = 0;	while (len) {		int e = isdn_audio_get_bits(s, &in, &len);		int sign;		if (nbits == 4 && e == 0)			d = 4;		sign = (e >> (nbits - 1)) ? -1 : 1;		e &= bitmask[nbits - 1];		a += sign * ((e << 1) + 1) * d >> 1;		if (d & 1)			a++;		if (fmt)			*out++ = isdn_audio_ulaw_to_alaw[					 isdn_audio_linear2ulaw(a << 2)];		else			*out++ = isdn_audio_linear2ulaw(a << 2);		olen++;		d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;		if (d < 5)			d = 5;	}	s->a = a;	s->d = d;	return olen;}intisdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,		      unsigned char *out, int len){	int a = s->a;	int d = s->d;	int nbits = s->nbits;	int olen = 0;	while (len--) {		int e = 0,		 nmax = 1 << (nbits - 1);		int sign,		 delta;		if (fmt)			delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;		else			delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;		if (delta < 0) {			e = nmax;			delta = -delta;		}		while (--nmax && delta > d) {			delta -= d;			e++;		}		if (nbits == 4 && ((e & 0x0f) == 0))			e = 8;		isdn_audio_put_bits(e, nbits, s, &out, &olen);		sign = (e >> (nbits - 1)) ? -1 : 1;		e &= bitmask[nbits - 1];		a += sign * ((e << 1) + 1) * d >> 1;		if (d & 1)			a++;		d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;		if (d < 5)			d = 5;	}	s->a = a;	s->d = d;	return olen;}/* * Goertzel algorithm. * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/ * for more info. * Result is stored into an sk_buff and queued up for later * evaluation. */static voidisdn_audio_goertzel(int *sample, modem_info * info){	int sk,	 sk1,	 sk2;	int k,	 n;	struct sk_buff *skb;	int *result;	skb = dev_alloc_skb(sizeof(int) * NCOEFF);	if (!skb) {		printk(KERN_WARNING		  "isdn_audio: Could not alloc DTMF result for ttyI%d\n",		       info->line);		return;	}	result = (int *) skb_put(skb, sizeof(int) * NCOEFF);	for (k = 0; k < NCOEFF; k++) {		sk = sk1 = sk2 = 0;		for (n = 0; n < DTMF_NPOINTS; n++) {			sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;			sk2 = sk1;			sk1 = sk;		}		/* Avoid overflows */		sk >>= 1;		sk2 >>= 1;		/* compute |X(k)|**2 */		/* report overflows. This should not happen. */		/* Comment this out if desired */		if (sk < -32768 || sk > 32767)			printk(KERN_DEBUG			       "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);		if (sk2 < -32768 || sk2 > 32767)			printk(KERN_DEBUG			       "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);		result[k] =		    ((sk * sk) >> AMP_BITS) -		    ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +		    ((sk2 * sk2) >> AMP_BITS);	}	skb_queue_tail(&info->dtmf_queue, skb);	isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);}voidisdn_audio_eval_dtmf(modem_info * info){	struct sk_buff *skb;	int *result;	dtmf_state *s;	int silence;	int i;	int di;	int ch;	int grp[2];	char what;	char *p;	int thresh;	while ((skb = skb_dequeue(&info->dtmf_queue))) {		result = (int *) skb->data;		s = info->dtmf_state;		grp[LOGRP] = grp[HIGRP] = -1;		silence = 0;		thresh = 0;		for (i = 0; i < NCOEFF; i++) {			if (result[i] > DTMF_TRESH) {				if (result[i] > thresh)					thresh = result[i];			}			else if (result[i] < SILENCE_TRESH)				silence++;		}		if (silence == NCOEFF)			what = ' ';		else {			if (thresh > 0)	{				thresh = thresh >> 4;  /* touchtones must match within 12 dB */				for (i = 0; i < NCOEFF; i++) {					if (result[i] < thresh)						continue;  /* ignore */					/* good level found. This is allowed only one time per group */					if (i < NCOEFF / 2) {						/* lowgroup*/						if (grp[LOGRP] >= 0) {							// Bad. Another tone found. */							grp[LOGRP] = -1;							break;						}						else							grp[LOGRP] = i;					}					else { /* higroup */						if (grp[HIGRP] >= 0) { // Bad. Another tone found. */							grp[HIGRP] = -1;							break;						}						else							grp[HIGRP] = i - NCOEFF/2;					}				}				if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {					what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];					if (s->last != ' ' && s->last != '.')						s->last = what;	/* min. 1 non-DTMF between DTMF */				} else					what = '.';			}			else				what = '.';		}		if ((what != s->last) && (what != ' ') && (what != '.')) {			printk(KERN_DEBUG "dtmf: tt='%c'\n", what);			p = skb->data;			*p++ = 0x10;			*p = what;			skb_trim(skb, 2);			ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;			ISDN_AUDIO_SKB_LOCK(skb) = 0;			di = info->isdn_driver;			ch = info->isdn_channel;			__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);			dev->drv[di]->rcvcount[ch] += 2;			/* Schedule dequeuing */			if ((dev->modempoll) && (info->rcvsched))				isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);			wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);		} else			kfree_skb(skb);		s->last = what;	}}/* * Decode DTMF tones, queue result in separate sk_buf for * later examination. * Parameters: *   s    = pointer to state-struct. *   buf  = input audio data *   len  = size of audio data. *   fmt  = audio data format (0 = ulaw, 1 = alaw) */voidisdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt){	dtmf_state *s = info->dtmf_state;	int i;	int c;	while (len) {		c = DTMF_NPOINTS - s->idx;		if (c > len)			c = len;		if (c <= 0)			break;		for (i = 0; i < c; i++) {			if (fmt)				s->buf[s->idx++] =				    isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);			else				s->buf[s->idx++] =				    isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);		}		if (s->idx == DTMF_NPOINTS) {			isdn_audio_goertzel(s->buf, info);			s->idx = 0;		}		len -= c;	}}silence_state *isdn_audio_silence_init(silence_state * s){	if (!s)		s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);	if (s) {		s->idx = 0;		s->state = 0;	}	return s;}voidisdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt){	silence_state *s = info->silence_state;	int i;	signed char c;	if (!info->emu.vpar[1]) return;	for (i = 0; i < len; i++) {		if (fmt)		    c = isdn_audio_alaw_to_ulaw[*buf++];			else		    c = *buf++;		if (c > 0) c -= 128;		c = abs(c);		if (c > (info->emu.vpar[1] * 4)) { 			s->idx = 0;			s->state = 1; 		} else {			if (s->idx < 210000) s->idx++; 		}	}}voidisdn_audio_put_dle_code(modem_info * info, u_char code){	struct sk_buff *skb;	int di;	int ch;	char *p;	skb = dev_alloc_skb(2);	if (!skb) {		printk(KERN_WARNING		  "isdn_audio: Could not alloc skb for ttyI%d\n",		       info->line);		return;	}	p = (char *) skb_put(skb, 2);	p[0] = 0x10;	p[1] = code;	ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;	ISDN_AUDIO_SKB_LOCK(skb) = 0;	di = info->isdn_driver;	ch = info->isdn_channel;	__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);	dev->drv[di]->rcvcount[ch] += 2;	/* Schedule dequeuing */	if ((dev->modempoll) && (info->rcvsched))		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);	wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);}voidisdn_audio_eval_silence(modem_info * info){	silence_state *s = info->silence_state;	char what;	what = ' ';	if (s->idx > (info->emu.vpar[2] * 800)) { 		s->idx = 0;		if (!s->state) {	/* silence from beginning of rec */ 			what = 's';		} else {			what = 'q';		}	}		if ((what == 's') || (what == 'q')) {			printk(KERN_DEBUG "ttyI%d: %s\n", info->line,				(what=='s') ? "silence":"quiet");			isdn_audio_put_dle_code(info, what);		} }

⌨️ 快捷键说明

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