Merged revisions 302417 via svnmerge from
[asterisk/asterisk.git] / codecs / codec_resample.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.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 /*! 
20  * \file
21  *
22  * \brief Resample slinear audio
23  * 
24  * \note To install libresample, check it out of the following repository:
25  * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
26  *
27  * \ingroup codecs
28  */
29
30 /*** MODULEINFO
31         <depend>resample</depend>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 /* These are for SHRT_MAX and FLT_MAX -- { */
39 #if defined(__Darwin__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
40 #include <float.h>
41 #else
42 #include <values.h>
43 #endif
44 #include <limits.h>
45 /* } */
46
47 #include <libresample.h>
48
49 #include "asterisk/module.h"
50 #include "asterisk/translate.h"
51
52 #include "asterisk/slin.h"
53
54 #define RESAMPLER_QUALITY 1
55
56 #define OUTBUF_SIZE   8096
57
58 struct slin16_to_slin8_pvt {
59         void *resampler;
60         float resample_factor;
61 };
62
63 struct slin8_to_slin16_pvt {
64         void *resampler;
65         float resample_factor;
66 };
67
68 static int slin16_to_slin8_new(struct ast_trans_pvt *pvt)
69 {
70         struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
71
72         resamp_pvt->resample_factor = 8000.0 / 16000.0;
73
74         if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
75                 return -1;
76
77         return 0;
78 }
79
80 static int slin8_to_slin16_new(struct ast_trans_pvt *pvt)
81 {
82         struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
83
84         resamp_pvt->resample_factor = 16000.0 / 8000.0;
85
86         if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
87                 return -1;
88
89         return 0;
90 }
91
92 static void slin16_to_slin8_destroy(struct ast_trans_pvt *pvt)
93 {
94         struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
95
96         if (resamp_pvt->resampler)
97                 resample_close(resamp_pvt->resampler);
98 }
99
100 static void slin8_to_slin16_destroy(struct ast_trans_pvt *pvt)
101 {
102         struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
103
104         if (resamp_pvt->resampler)
105                 resample_close(resamp_pvt->resampler);
106 }
107
108 static int resample_frame(struct ast_trans_pvt *pvt,
109         void *resampler, float resample_factor, struct ast_frame *f)
110 {
111         int total_in_buf_used = 0;
112         int total_out_buf_used = 0;
113         int16_t *in_buf = (int16_t *) f->data.ptr;
114         int16_t *out_buf = pvt->outbuf.i16 + pvt->samples;
115         float in_buf_f[f->samples];
116         float out_buf_f[2048];
117         int res = 0;
118         int i;
119
120         for (i = 0; i < f->samples; i++)
121                 in_buf_f[i] = in_buf[i] * (FLT_MAX / SHRT_MAX);
122
123         while (total_in_buf_used < f->samples) {
124                 int in_buf_used, out_buf_used;
125
126                 out_buf_used = resample_process(resampler, resample_factor,
127                         &in_buf_f[total_in_buf_used], f->samples - total_in_buf_used,
128                         0, &in_buf_used,
129                         &out_buf_f[total_out_buf_used], ARRAY_LEN(out_buf_f) - total_out_buf_used);
130
131                 if (out_buf_used < 0)
132                         break;
133
134                 total_out_buf_used += out_buf_used;
135                 total_in_buf_used += in_buf_used;
136
137                 if (total_out_buf_used == ARRAY_LEN(out_buf_f)) {
138                         ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size\n");
139                         res = -1;
140                         break;
141                 }
142         }
143
144         for (i = 0; i < total_out_buf_used; i++)
145                 out_buf[i] = out_buf_f[i] * (SHRT_MAX / FLT_MAX);       
146
147         pvt->samples += total_out_buf_used;
148         pvt->datalen += (total_out_buf_used * sizeof(int16_t));
149
150         return res;
151 }
152
153 static int slin16_to_slin8_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
154 {
155         struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
156         void *resampler = resamp_pvt->resampler;
157         float resample_factor = resamp_pvt->resample_factor;
158
159         return resample_frame(pvt, resampler, resample_factor, f);
160 }
161
162 static int slin8_to_slin16_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
163 {
164         struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
165         void *resampler = resamp_pvt->resampler;
166         float resample_factor = resamp_pvt->resample_factor;
167
168         return resample_frame(pvt, resampler, resample_factor, f);
169 }
170
171 static struct ast_translator slin16_to_slin8 = {
172         .name = "slin16_to_slin8",
173         .srcfmt = AST_FORMAT_SLINEAR16,
174         .dstfmt = AST_FORMAT_SLINEAR,
175         .newpvt = slin16_to_slin8_new,
176         .destroy = slin16_to_slin8_destroy,
177         .framein = slin16_to_slin8_framein,
178         .sample = slin16_sample,
179         .desc_size = sizeof(struct slin16_to_slin8_pvt),
180         .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
181         .buf_size = OUTBUF_SIZE,
182 };
183
184 static struct ast_translator slin8_to_slin16 = {
185         .name = "slin8_to_slin16",
186         .srcfmt = AST_FORMAT_SLINEAR,
187         .dstfmt = AST_FORMAT_SLINEAR16,
188         .newpvt = slin8_to_slin16_new,
189         .destroy = slin8_to_slin16_destroy,
190         .framein = slin8_to_slin16_framein,
191         .sample = slin8_sample,
192         .desc_size = sizeof(struct slin8_to_slin16_pvt),
193         .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
194         .buf_size = OUTBUF_SIZE,
195 };
196
197 static int unload_module(void)
198 {
199         int res = 0;
200
201         res |= ast_unregister_translator(&slin16_to_slin8);
202         res |= ast_unregister_translator(&slin8_to_slin16);
203
204         return res;
205 }
206
207 static int load_module(void)
208 {
209         int res = 0;
210
211         res |= ast_register_translator(&slin16_to_slin8);
212         res |= ast_register_translator(&slin8_to_slin16);
213
214         return AST_MODULE_LOAD_SUCCESS;
215 }
216
217 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SLIN Resampling Codec");