mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	handle AST_FORMAT_SLINEAR endianness properly on big-endian systems (bug #3865)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5373 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -7337,9 +7337,12 @@ retryowner2: | ||||
| 	f.src = "IAX2"; | ||||
| 	f.mallocd = 0; | ||||
| 	f.offset = 0; | ||||
| 	if (f.datalen && (f.frametype == AST_FRAME_VOICE))  | ||||
| 	if (f.datalen && (f.frametype == AST_FRAME_VOICE)) { | ||||
| 		f.samples = get_samples(&f); | ||||
| 	else | ||||
| 		/* We need to byteswap incoming slinear samples from network byte order */ | ||||
| 		if (f.subclass == AST_FORMAT_SLINEAR) | ||||
| 			ast_frame_byteswap_be(&f); | ||||
| 	} else | ||||
| 		f.samples = 0; | ||||
| 	iax_frame_wrap(&fr, &f); | ||||
|  | ||||
|   | ||||
| @@ -544,10 +544,13 @@ static struct ast_frame  *phone_read(struct ast_channel *ast) | ||||
| 			  : AST_FRAME_VIDEO; | ||||
| 	p->fr.subclass = p->lastinput; | ||||
| 	p->fr.offset = AST_FRIENDLY_OFFSET; | ||||
| 	/* Byteswap from little-endian to native-endian */ | ||||
| 	if (p->fr.subclass == AST_FORMAT_SLINEAR) | ||||
| 		ast_frame_byteswap_le(&p->fr); | ||||
| 	return &p->fr; | ||||
| } | ||||
|  | ||||
| static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen) | ||||
| static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap) | ||||
| { | ||||
| 	int res; | ||||
| 	/* Store as much of the buffer as we can, then write fixed frames */ | ||||
| @@ -555,7 +558,10 @@ static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int fr | ||||
| 	/* Make sure we have enough buffer space to store the frame */ | ||||
| 	if (space < len) | ||||
| 		len = space; | ||||
| 	memcpy(p->obuf + p->obuflen, buf, len); | ||||
| 	if (swap) | ||||
| 		ast_memcpy_byteswap(p->obuf+p->obuflen, buf, len/2); | ||||
| 	else | ||||
| 		memcpy(p->obuf + p->obuflen, buf, len); | ||||
| 	p->obuflen += len; | ||||
| 	while(p->obuflen > frlen) { | ||||
| 		res = write(p->fd, p->obuf, frlen); | ||||
| @@ -581,7 +587,7 @@ static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int fr | ||||
| static int phone_send_text(struct ast_channel *ast, const char *text) | ||||
| { | ||||
|     int length = strlen(text); | ||||
|     return phone_write_buf(ast->tech_pvt, text, length, length) ==  | ||||
|     return phone_write_buf(ast->tech_pvt, text, length, length, 0) ==  | ||||
|            length ? 0 : -1; | ||||
| } | ||||
|  | ||||
| @@ -729,12 +735,17 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) | ||||
| 				memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4); | ||||
| 				memcpy(tmpbuf, frame->data, 4); | ||||
| 				expected = 24; | ||||
| 				res = phone_write_buf(p, tmpbuf, expected, maxfr); | ||||
| 				res = phone_write_buf(p, tmpbuf, expected, maxfr, 0); | ||||
| 			} | ||||
| 			res = 4; | ||||
| 			expected=4; | ||||
| 		} else { | ||||
| 			res = phone_write_buf(p, pos, expected, maxfr); | ||||
| 			int swap = 0; | ||||
| #if __BYTE_ORDER == __BIG_ENDIAN | ||||
| 			if (frame->subclass == AST_FORMAT_SLINEAR) | ||||
| 				swap = 1; /* Swap big-endian samples to little-endian as we copy */ | ||||
| #endif | ||||
| 			res = phone_write_buf(p, pos, expected, maxfr, swap); | ||||
| 		} | ||||
| 		if (res != expected) { | ||||
| 			if ((errno != EAGAIN) && (errno != EINTR)) { | ||||
|   | ||||
| @@ -855,8 +855,15 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f) | ||||
| 	fr->af.delivery.tv_sec = 0; | ||||
| 	fr->af.delivery.tv_usec = 0; | ||||
| 	fr->af.data = fr->afdata; | ||||
| 	if (fr->af.datalen)  | ||||
| 	if (fr->af.datalen) { | ||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||
| 		/* We need to byte-swap slinear samples from network byte order */ | ||||
| 		if (fr->af.subclass == AST_FORMAT_SLINEAR) { | ||||
| 			ast_memcpy_byteswap(fr->af.data, f->data, fr->af.samples); | ||||
| 		} else | ||||
| #endif | ||||
| 		memcpy(fr->af.data, f->data, fr->af.datalen); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| struct iax_frame *iax_frame_new(int direction, int datalen) | ||||
|   | ||||
							
								
								
									
										17
									
								
								frame.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								frame.c
									
									
									
									
									
								
							| @@ -83,7 +83,7 @@ void ast_smoother_set_flags(struct ast_smoother *s, int flags) | ||||
| 	s->flags = flags; | ||||
| } | ||||
|  | ||||
| int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f) | ||||
| int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) | ||||
| { | ||||
| 	if (f->frametype != AST_FRAME_VOICE) { | ||||
| 		ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n"); | ||||
| @@ -129,7 +129,10 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f) | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	memcpy(s->data + s->len, f->data, f->datalen); | ||||
| 	if (swap) | ||||
| 		ast_swapcopy_samples(s->data+s->len, f->data, f->samples); | ||||
| 	else | ||||
| 		memcpy(s->data + s->len, f->data, f->datalen); | ||||
| 	/* If either side is empty, reset the delivery time */ | ||||
| 	if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) || | ||||
| 			(!s->delivery.tv_sec && !s->delivery.tv_usec)) | ||||
| @@ -399,6 +402,16 @@ int ast_fr_fdhangup(int fd) | ||||
| 	return ast_fr_fdwrite(fd, &hangup); | ||||
| } | ||||
|  | ||||
| void ast_swapcopy_samples(void *dst, void *src, int samples) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned short *dst_s = dst; | ||||
| 	unsigned short *src_s = src; | ||||
|  | ||||
| 	for (i=0; i<samples; i++) | ||||
| 		dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8); | ||||
| } | ||||
|  | ||||
| static struct ast_format_list AST_FORMAT_LIST[] = { | ||||
| 	{ 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"}, | ||||
| 	{ 1, AST_FORMAT_GSM, "gsm" , "GSM"}, | ||||
|   | ||||
| @@ -301,6 +301,19 @@ int ast_fr_fdwrite(int fd, struct ast_frame *frame); | ||||
|  */ | ||||
| int ast_fr_fdhangup(int fd); | ||||
|  | ||||
| void ast_swapcopy_samples(void *dst, void *src, int samples); | ||||
|  | ||||
| /* Helpers for byteswapping native samples to/from  | ||||
|    little-endian and big-endian. */ | ||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||
| #define ast_frame_byteswap_le(fr) do { ; } while(0) | ||||
| #define ast_frame_byteswap_be(fr) do { struct ast_frame *__f = (fr); ast_swapcopy_samples(__f->data, __f->data, __f->samples); } while(0) | ||||
| #else | ||||
| #define ast_frame_byteswap_le(fr) do { struct ast_frame *__f = (fr); ast_swapcopy_samples(__f->data, __f->data, __f->samples); } while(0) | ||||
| #define ast_frame_byteswap_be(fr) do { ; } while(0) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /*! Get the name of a format */ | ||||
| /*! | ||||
|  * \param format id of format | ||||
| @@ -347,8 +360,16 @@ extern void ast_smoother_set_flags(struct ast_smoother *smoother, int flags); | ||||
| extern int ast_smoother_get_flags(struct ast_smoother *smoother); | ||||
| extern void ast_smoother_free(struct ast_smoother *s); | ||||
| extern void ast_smoother_reset(struct ast_smoother *s, int bytes); | ||||
| extern int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f); | ||||
| extern int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); | ||||
| extern struct ast_frame *ast_smoother_read(struct ast_smoother *s); | ||||
| #define ast_smoother_feed(s,f) do { __ast_smoother_feed(s, f, 0); } while(0) | ||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||
| #define ast_smoother_feed_be(s,f) do { __ast_smoother_feed(s, f, 1); } while(0) | ||||
| #define ast_smoother_feed_le(s,f) do { __ast_smoother_feed(s, f, 0); } while(0) | ||||
| #else | ||||
| #define ast_smoother_feed_be(s,f) do { __ast_smoother_feed(s, f, 0); } while(0) | ||||
| #define ast_smoother_feed_le(s,f) do { __ast_smoother_feed(s, f, 1); } while(0) | ||||
| #endif | ||||
|  | ||||
| extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix); | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								rtp.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								rtp.c
									
									
									
									
									
								
							| @@ -596,6 +596,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) | ||||
| 			break; | ||||
| 		case AST_FORMAT_SLINEAR: | ||||
| 			rtp->f.samples = rtp->f.datalen / 2; | ||||
| 			ast_frame_byteswap_be(&rtp->f); | ||||
| 			break; | ||||
| 		case AST_FORMAT_GSM: | ||||
| 			rtp->f.samples = 160 * (rtp->f.datalen / 33); | ||||
| @@ -1320,6 +1321,19 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f) | ||||
|  | ||||
|  | ||||
| 	switch(subclass) { | ||||
| 	case AST_FORMAT_SLINEAR: | ||||
| 		if (!rtp->smoother) { | ||||
| 			rtp->smoother = ast_smoother_new(320); | ||||
| 		} | ||||
| 		if (!rtp->smoother) { | ||||
| 			ast_log(LOG_WARNING, "Unable to create smoother :(\n"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		ast_smoother_feed_be(rtp->smoother, _f); | ||||
| 		 | ||||
| 		while((f = ast_smoother_read(rtp->smoother))) | ||||
| 			ast_rtp_raw_write(rtp, f, codec); | ||||
| 		break; | ||||
| 	case AST_FORMAT_ULAW: | ||||
| 	case AST_FORMAT_ALAW: | ||||
| 		if (!rtp->smoother) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user