| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2005, Anthony Minessale II. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Anthony Minessale <anthmct@yahoo.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief A machine to gather up arbitrary frames and convert them | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * to raw slinear on demand. | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Anthony Minessale <anthmct@yahoo.com> | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:05 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | #include "asterisk/frame.h"
 | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | #include "asterisk/slinfactory.h"
 | 
					
						
							|  |  |  | #include "asterisk/translate.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_slinfactory_init(struct ast_slinfactory *sf)  | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 	memset(sf, 0, sizeof(*sf)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 	sf->offset = sf->hold; | 
					
						
							| 
									
										
										
										
											2009-02-10 19:38:26 +00:00
										 |  |  | 	sf->output_format = AST_FORMAT_SLINEAR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memset(sf, 0, sizeof(*sf)); | 
					
						
							|  |  |  | 	sf->offset = sf->hold; | 
					
						
							|  |  |  | 	switch (sample_rate) { | 
					
						
							|  |  |  | 	case 8000: | 
					
						
							|  |  |  | 		sf->output_format = AST_FORMAT_SLINEAR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 16000: | 
					
						
							|  |  |  | 		sf->output_format = AST_FORMAT_SLINEAR16; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_slinfactory_destroy(struct ast_slinfactory *sf)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sf->trans) { | 
					
						
							|  |  |  | 		ast_translator_free_path(sf->trans); | 
					
						
							|  |  |  | 		sf->trans = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-29 20:50:36 +00:00
										 |  |  | 	while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 		ast_frfree(f); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-03-05 04:21:28 +00:00
										 |  |  | 	struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr; | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 	unsigned int x = 0; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-27 20:11:30 +00:00
										 |  |  | 	/* In some cases, we can be passed a frame which has no data in it, but
 | 
					
						
							|  |  |  | 	 * which has a positive number of samples defined. Once such situation is | 
					
						
							|  |  |  | 	 * when a jitter buffer is in use and the jitter buffer interpolates a frame. | 
					
						
							|  |  |  | 	 * The frame it produces has data set to NULL, datalen set to 0, and samples | 
					
						
							|  |  |  | 	 * set to either 160 or 240. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!f->data.ptr) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	if (f->subclass.codec != sf->output_format) { | 
					
						
							|  |  |  | 		if (sf->trans && f->subclass.codec != sf->format) { | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 			ast_translator_free_path(sf->trans); | 
					
						
							|  |  |  | 			sf->trans = NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-01-19 10:06:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 		if (!sf->trans) { | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 			if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass.codec))) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(f->subclass.codec), | 
					
						
							| 
									
										
										
										
											2009-02-10 19:38:26 +00:00
										 |  |  | 					ast_getformatname(sf->output_format)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				return 0; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 			sf->format = f->subclass.codec; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-01-19 10:06:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 		if (!(begin_frame = ast_translate(sf->trans, f, 0))) { | 
					
						
							| 
									
										
										
										
											2008-01-19 10:06:02 +00:00
										 |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-01-19 10:06:02 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 		if (!(duped_frame = ast_frisolate(begin_frame))) { | 
					
						
							| 
									
										
										
										
											2007-05-25 01:37:50 +00:00
										 |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (duped_frame != begin_frame) { | 
					
						
							|  |  |  | 			ast_frfree(begin_frame); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-05-25 01:37:50 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-05-25 13:26:52 +00:00
										 |  |  | 		if (sf->trans) { | 
					
						
							|  |  |  | 			ast_translator_free_path(sf->trans); | 
					
						
							|  |  |  | 			sf->trans = NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-05-25 01:37:50 +00:00
										 |  |  | 		if (!(duped_frame = ast_frdup(f))) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-10 19:38:26 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) { | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 		x++; | 
					
						
							| 
									
										
										
										
											2009-02-10 19:38:26 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-16 18:54:30 +00:00
										 |  |  | 	/* if the frame was translated, the translator may have returned multiple
 | 
					
						
							|  |  |  | 	   frames, so process each of them | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	for (begin_frame = duped_frame; begin_frame; begin_frame = AST_LIST_NEXT(begin_frame, frame_list)) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_TAIL(&sf->queue, begin_frame, frame_list); | 
					
						
							|  |  |  | 		sf->size += begin_frame->samples; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return x; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)  | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *frame_ptr; | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 	unsigned int sofar = 0, ineed, remain; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 	short *frame_data, *offset = buf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 	while (sofar < samples) { | 
					
						
							|  |  |  | 		ineed = samples - sofar; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (sf->holdlen) { | 
					
						
							| 
									
										
										
										
											2008-01-30 15:42:29 +00:00
										 |  |  | 			if (sf->holdlen <= ineed) { | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				memcpy(offset, sf->hold, sf->holdlen * sizeof(*offset)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sofar += sf->holdlen; | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				offset += sf->holdlen; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sf->holdlen = 0; | 
					
						
							|  |  |  | 				sf->offset = sf->hold; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				remain = sf->holdlen - ineed; | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				memcpy(offset, sf->offset, ineed * sizeof(*offset)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sofar += ineed; | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				sf->offset += ineed; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sf->holdlen = remain; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2006-08-29 20:50:36 +00:00
										 |  |  | 		if ((frame_ptr = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) { | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 			frame_data = frame_ptr->data.ptr; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2008-01-30 15:42:29 +00:00
										 |  |  | 			if (frame_ptr->samples <= ineed) { | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				memcpy(offset, frame_data, frame_ptr->samples * sizeof(*offset)); | 
					
						
							|  |  |  | 				sofar += frame_ptr->samples; | 
					
						
							|  |  |  | 				offset += frame_ptr->samples; | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				remain = frame_ptr->samples - ineed; | 
					
						
							|  |  |  | 				memcpy(offset, frame_data, ineed * sizeof(*offset)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sofar += ineed; | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				frame_data += ineed; | 
					
						
							| 
									
										
										
										
											2008-04-07 14:54:42 +00:00
										 |  |  | 				if (remain > (AST_SLINFACTORY_MAX_HOLD - sf->holdlen)) { | 
					
						
							|  |  |  | 					remain = AST_SLINFACTORY_MAX_HOLD - sf->holdlen; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 				memcpy(sf->hold, frame_data, remain * sizeof(*offset)); | 
					
						
							| 
									
										
										
										
											2005-07-20 00:53:21 +00:00
										 |  |  | 				sf->holdlen = remain; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ast_frfree(frame_ptr); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sf->size -= sofar; | 
					
						
							|  |  |  | 	return sofar; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-28 18:03:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sf->size; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:30:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void ast_slinfactory_flush(struct ast_slinfactory *sf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *fr = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sf->trans) { | 
					
						
							|  |  |  | 		ast_translator_free_path(sf->trans); | 
					
						
							|  |  |  | 		sf->trans = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((fr = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) | 
					
						
							|  |  |  | 		ast_frfree(fr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sf->size = sf->holdlen = 0; | 
					
						
							|  |  |  | 	sf->offset = sf->hold; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } |