Let ExtensionState resolve dynamic hints.
[asterisk/asterisk.git] / main / slinfactory.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005, Anthony Minessale II.
5  *
6  * Anthony Minessale <anthmct@yahoo.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief A machine to gather up arbitrary frames and convert them
22  * to raw slinear on demand.
23  *
24  * \author Anthony Minessale <anthmct@yahoo.com>
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/frame.h"
32 #include "asterisk/slinfactory.h"
33 #include "asterisk/translate.h"
34
35 void ast_slinfactory_init(struct ast_slinfactory *sf) 
36 {
37         memset(sf, 0, sizeof(*sf));
38         sf->offset = sf->hold;
39         sf->output_format = AST_FORMAT_SLINEAR;
40 }
41
42 int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate) 
43 {
44         memset(sf, 0, sizeof(*sf));
45         sf->offset = sf->hold;
46         switch (sample_rate) {
47         case 8000:
48                 sf->output_format = AST_FORMAT_SLINEAR;
49                 break;
50         case 16000:
51                 sf->output_format = AST_FORMAT_SLINEAR16;
52                 break;
53         default:
54                 return -1;
55         }
56
57         return 0;
58 }
59
60 void ast_slinfactory_destroy(struct ast_slinfactory *sf) 
61 {
62         struct ast_frame *f;
63
64         if (sf->trans) {
65                 ast_translator_free_path(sf->trans);
66                 sf->trans = NULL;
67         }
68
69         while ((f = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list)))
70                 ast_frfree(f);
71 }
72
73 int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
74 {
75         struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr;
76         unsigned int x = 0;
77
78         /* In some cases, we can be passed a frame which has no data in it, but
79          * which has a positive number of samples defined. Once such situation is
80          * when a jitter buffer is in use and the jitter buffer interpolates a frame.
81          * The frame it produces has data set to NULL, datalen set to 0, and samples
82          * set to either 160 or 240.
83          */
84         if (!f->data.ptr) {
85                 return 0;
86         }
87
88         if (f->subclass.codec != sf->output_format) {
89                 if (sf->trans && f->subclass.codec != sf->format) {
90                         ast_translator_free_path(sf->trans);
91                         sf->trans = NULL;
92                 }
93
94                 if (!sf->trans) {
95                         if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass.codec))) {
96                                 ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(f->subclass.codec),
97                                         ast_getformatname(sf->output_format));
98                                 return 0;
99                         }
100                         sf->format = f->subclass.codec;
101                 }
102
103                 if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
104                         return 0;
105                 }
106                 
107                 if (!(duped_frame = ast_frisolate(begin_frame))) {
108                         return 0;
109                 }
110
111                 if (duped_frame != begin_frame) {
112                         ast_frfree(begin_frame);
113                 }
114         } else {
115                 if (sf->trans) {
116                         ast_translator_free_path(sf->trans);
117                         sf->trans = NULL;
118                 }
119                 if (!(duped_frame = ast_frdup(f)))
120                         return 0;
121         }
122
123         AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) {
124                 x++;
125         }
126
127         /* if the frame was translated, the translator may have returned multiple
128            frames, so process each of them
129         */
130         for (begin_frame = duped_frame; begin_frame; begin_frame = AST_LIST_NEXT(begin_frame, frame_list)) {
131                 AST_LIST_INSERT_TAIL(&sf->queue, begin_frame, frame_list);
132                 sf->size += begin_frame->samples;
133         }
134
135         return x;
136 }
137
138 int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples) 
139 {
140         struct ast_frame *frame_ptr;
141         unsigned int sofar = 0, ineed, remain;
142         short *frame_data, *offset = buf;
143
144         while (sofar < samples) {
145                 ineed = samples - sofar;
146
147                 if (sf->holdlen) {
148                         if (sf->holdlen <= ineed) {
149                                 memcpy(offset, sf->hold, sf->holdlen * sizeof(*offset));
150                                 sofar += sf->holdlen;
151                                 offset += sf->holdlen;
152                                 sf->holdlen = 0;
153                                 sf->offset = sf->hold;
154                         } else {
155                                 remain = sf->holdlen - ineed;
156                                 memcpy(offset, sf->offset, ineed * sizeof(*offset));
157                                 sofar += ineed;
158                                 sf->offset += ineed;
159                                 sf->holdlen = remain;
160                         }
161                         continue;
162                 }
163                 
164                 if ((frame_ptr = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list))) {
165                         frame_data = frame_ptr->data.ptr;
166                         
167                         if (frame_ptr->samples <= ineed) {
168                                 memcpy(offset, frame_data, frame_ptr->samples * sizeof(*offset));
169                                 sofar += frame_ptr->samples;
170                                 offset += frame_ptr->samples;
171                         } else {
172                                 remain = frame_ptr->samples - ineed;
173                                 memcpy(offset, frame_data, ineed * sizeof(*offset));
174                                 sofar += ineed;
175                                 frame_data += ineed;
176                                 if (remain > (AST_SLINFACTORY_MAX_HOLD - sf->holdlen)) {
177                                         remain = AST_SLINFACTORY_MAX_HOLD - sf->holdlen;
178                                 }
179                                 memcpy(sf->hold, frame_data, remain * sizeof(*offset));
180                                 sf->holdlen = remain;
181                         }
182                         ast_frfree(frame_ptr);
183                 } else {
184                         break;
185                 }
186         }
187
188         sf->size -= sofar;
189         return sofar;
190 }
191
192 unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
193 {
194         return sf->size;
195 }
196
197 void ast_slinfactory_flush(struct ast_slinfactory *sf)
198 {
199         struct ast_frame *fr = NULL;
200
201         if (sf->trans) {
202                 ast_translator_free_path(sf->trans);
203                 sf->trans = NULL;
204         }
205
206         while ((fr = AST_LIST_REMOVE_HEAD(&sf->queue, frame_list)))
207                 ast_frfree(fr);
208
209         sf->size = sf->holdlen = 0;
210         sf->offset = sf->hold;
211
212         return;
213 }