xref: /aosp_15_r20/system/media/audio_utils/resampler.c (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker ** Copyright 2011, The Android Open-Source Project
3*b9df5ad1SAndroid Build Coastguard Worker **
4*b9df5ad1SAndroid Build Coastguard Worker ** Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker ** you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker ** You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker **
8*b9df5ad1SAndroid Build Coastguard Worker **     http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker **
10*b9df5ad1SAndroid Build Coastguard Worker ** Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker ** distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker ** See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker ** limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker 
17*b9df5ad1SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "resampler"
19*b9df5ad1SAndroid Build Coastguard Worker 
20*b9df5ad1SAndroid Build Coastguard Worker #include <errno.h>
21*b9df5ad1SAndroid Build Coastguard Worker #include <stdlib.h>
22*b9df5ad1SAndroid Build Coastguard Worker 
23*b9df5ad1SAndroid Build Coastguard Worker #include <log/log.h>
24*b9df5ad1SAndroid Build Coastguard Worker 
25*b9df5ad1SAndroid Build Coastguard Worker #include <system/audio.h>
26*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/resampler.h>
27*b9df5ad1SAndroid Build Coastguard Worker #include <speex/speex_resampler.h>
28*b9df5ad1SAndroid Build Coastguard Worker 
29*b9df5ad1SAndroid Build Coastguard Worker struct resampler {
30*b9df5ad1SAndroid Build Coastguard Worker     struct resampler_itfe itfe;
31*b9df5ad1SAndroid Build Coastguard Worker     SpeexResamplerState *speex_resampler;       // handle on speex resampler
32*b9df5ad1SAndroid Build Coastguard Worker     struct resampler_buffer_provider *provider; // buffer provider installed by client
33*b9df5ad1SAndroid Build Coastguard Worker     uint32_t in_sample_rate;                    // input sampling rate in Hz
34*b9df5ad1SAndroid Build Coastguard Worker     uint32_t out_sample_rate;                   // output sampling rate in Hz
35*b9df5ad1SAndroid Build Coastguard Worker     uint32_t channel_count;                     // number of channels (interleaved)
36*b9df5ad1SAndroid Build Coastguard Worker     int16_t *in_buf;                            // input buffer
37*b9df5ad1SAndroid Build Coastguard Worker     size_t in_buf_size;                         // input buffer size
38*b9df5ad1SAndroid Build Coastguard Worker     size_t frames_in;                           // number of frames in input buffer
39*b9df5ad1SAndroid Build Coastguard Worker     size_t frames_rq;                           // cached number of output frames
40*b9df5ad1SAndroid Build Coastguard Worker     size_t frames_needed;                       // minimum number of input frames to produce
41*b9df5ad1SAndroid Build Coastguard Worker                                                 // frames_rq output frames
42*b9df5ad1SAndroid Build Coastguard Worker     int32_t speex_delay_ns;                     // delay introduced by speex resampler in ns
43*b9df5ad1SAndroid Build Coastguard Worker };
44*b9df5ad1SAndroid Build Coastguard Worker 
45*b9df5ad1SAndroid Build Coastguard Worker 
46*b9df5ad1SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
47*b9df5ad1SAndroid Build Coastguard Worker // speex based resampler
48*b9df5ad1SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
49*b9df5ad1SAndroid Build Coastguard Worker 
resampler_reset(struct resampler_itfe * resampler)50*b9df5ad1SAndroid Build Coastguard Worker static void resampler_reset(struct resampler_itfe *resampler)
51*b9df5ad1SAndroid Build Coastguard Worker {
52*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp = (struct resampler *)resampler;
53*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp != NULL) {
54*b9df5ad1SAndroid Build Coastguard Worker         rsmp->frames_in = 0;
55*b9df5ad1SAndroid Build Coastguard Worker         rsmp->frames_rq = 0;
56*b9df5ad1SAndroid Build Coastguard Worker         if (rsmp->speex_resampler != NULL) {
57*b9df5ad1SAndroid Build Coastguard Worker             speex_resampler_reset_mem(rsmp->speex_resampler);
58*b9df5ad1SAndroid Build Coastguard Worker         }
59*b9df5ad1SAndroid Build Coastguard Worker     }
60*b9df5ad1SAndroid Build Coastguard Worker }
61*b9df5ad1SAndroid Build Coastguard Worker 
resampler_delay_ns(struct resampler_itfe * resampler)62*b9df5ad1SAndroid Build Coastguard Worker static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
63*b9df5ad1SAndroid Build Coastguard Worker {
64*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp = (struct resampler *)resampler;
65*b9df5ad1SAndroid Build Coastguard Worker 
66*b9df5ad1SAndroid Build Coastguard Worker     int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
67*b9df5ad1SAndroid Build Coastguard Worker     delay += rsmp->speex_delay_ns;
68*b9df5ad1SAndroid Build Coastguard Worker 
69*b9df5ad1SAndroid Build Coastguard Worker     return delay;
70*b9df5ad1SAndroid Build Coastguard Worker }
71*b9df5ad1SAndroid Build Coastguard Worker 
72*b9df5ad1SAndroid Build Coastguard Worker // outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount
73*b9df5ad1SAndroid Build Coastguard Worker // with the actual number of frames produced.
resampler_resample_from_provider(struct resampler_itfe * resampler,int16_t * out,size_t * outFrameCount)74*b9df5ad1SAndroid Build Coastguard Worker int resampler_resample_from_provider(struct resampler_itfe *resampler,
75*b9df5ad1SAndroid Build Coastguard Worker                        int16_t *out,
76*b9df5ad1SAndroid Build Coastguard Worker                        size_t *outFrameCount)
77*b9df5ad1SAndroid Build Coastguard Worker {
78*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp = (struct resampler *)resampler;
79*b9df5ad1SAndroid Build Coastguard Worker 
80*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
81*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
82*b9df5ad1SAndroid Build Coastguard Worker     }
83*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->provider == NULL) {
84*b9df5ad1SAndroid Build Coastguard Worker         *outFrameCount = 0;
85*b9df5ad1SAndroid Build Coastguard Worker         return -ENOSYS;
86*b9df5ad1SAndroid Build Coastguard Worker     }
87*b9df5ad1SAndroid Build Coastguard Worker 
88*b9df5ad1SAndroid Build Coastguard Worker     size_t framesRq = *outFrameCount;
89*b9df5ad1SAndroid Build Coastguard Worker     // update and cache the number of frames needed at the input sampling rate to produce
90*b9df5ad1SAndroid Build Coastguard Worker     // the number of frames requested at the output sampling rate
91*b9df5ad1SAndroid Build Coastguard Worker     if (framesRq != rsmp->frames_rq) {
92*b9df5ad1SAndroid Build Coastguard Worker         rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
93*b9df5ad1SAndroid Build Coastguard Worker         rsmp->frames_rq = framesRq;
94*b9df5ad1SAndroid Build Coastguard Worker     }
95*b9df5ad1SAndroid Build Coastguard Worker 
96*b9df5ad1SAndroid Build Coastguard Worker     size_t framesWr = 0;
97*b9df5ad1SAndroid Build Coastguard Worker     spx_uint32_t inFrames = 0;
98*b9df5ad1SAndroid Build Coastguard Worker     while (framesWr < framesRq) {
99*b9df5ad1SAndroid Build Coastguard Worker         if (rsmp->frames_in < rsmp->frames_needed) {
100*b9df5ad1SAndroid Build Coastguard Worker             // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
101*b9df5ad1SAndroid Build Coastguard Worker             // least the number of frames needed to produce the number of frames requested at
102*b9df5ad1SAndroid Build Coastguard Worker             // the output sampling rate
103*b9df5ad1SAndroid Build Coastguard Worker             if (rsmp->in_buf_size < rsmp->frames_needed) {
104*b9df5ad1SAndroid Build Coastguard Worker                 rsmp->in_buf_size = rsmp->frames_needed;
105*b9df5ad1SAndroid Build Coastguard Worker                 rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
106*b9df5ad1SAndroid Build Coastguard Worker                                         rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
107*b9df5ad1SAndroid Build Coastguard Worker             }
108*b9df5ad1SAndroid Build Coastguard Worker             struct resampler_buffer buf;
109*b9df5ad1SAndroid Build Coastguard Worker             buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
110*b9df5ad1SAndroid Build Coastguard Worker             rsmp->provider->get_next_buffer(rsmp->provider, &buf);
111*b9df5ad1SAndroid Build Coastguard Worker             if (buf.raw == NULL) {
112*b9df5ad1SAndroid Build Coastguard Worker                 break;
113*b9df5ad1SAndroid Build Coastguard Worker             }
114*b9df5ad1SAndroid Build Coastguard Worker             memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
115*b9df5ad1SAndroid Build Coastguard Worker                     buf.raw,
116*b9df5ad1SAndroid Build Coastguard Worker                     buf.frame_count * rsmp->channel_count * sizeof(int16_t));
117*b9df5ad1SAndroid Build Coastguard Worker             rsmp->frames_in += buf.frame_count;
118*b9df5ad1SAndroid Build Coastguard Worker             rsmp->provider->release_buffer(rsmp->provider, &buf);
119*b9df5ad1SAndroid Build Coastguard Worker         }
120*b9df5ad1SAndroid Build Coastguard Worker 
121*b9df5ad1SAndroid Build Coastguard Worker         spx_uint32_t outFrames = framesRq - framesWr;
122*b9df5ad1SAndroid Build Coastguard Worker         inFrames = rsmp->frames_in;
123*b9df5ad1SAndroid Build Coastguard Worker         if (rsmp->channel_count == 1) {
124*b9df5ad1SAndroid Build Coastguard Worker             speex_resampler_process_int(rsmp->speex_resampler,
125*b9df5ad1SAndroid Build Coastguard Worker                                         0,
126*b9df5ad1SAndroid Build Coastguard Worker                                         rsmp->in_buf,
127*b9df5ad1SAndroid Build Coastguard Worker                                         &inFrames,
128*b9df5ad1SAndroid Build Coastguard Worker                                         out + framesWr,
129*b9df5ad1SAndroid Build Coastguard Worker                                         &outFrames);
130*b9df5ad1SAndroid Build Coastguard Worker         } else {
131*b9df5ad1SAndroid Build Coastguard Worker             speex_resampler_process_interleaved_int(rsmp->speex_resampler,
132*b9df5ad1SAndroid Build Coastguard Worker                                         rsmp->in_buf,
133*b9df5ad1SAndroid Build Coastguard Worker                                         &inFrames,
134*b9df5ad1SAndroid Build Coastguard Worker                                         out + framesWr * rsmp->channel_count,
135*b9df5ad1SAndroid Build Coastguard Worker                                         &outFrames);
136*b9df5ad1SAndroid Build Coastguard Worker         }
137*b9df5ad1SAndroid Build Coastguard Worker         framesWr += outFrames;
138*b9df5ad1SAndroid Build Coastguard Worker         rsmp->frames_in -= inFrames;
139*b9df5ad1SAndroid Build Coastguard Worker         ALOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0),
140*b9df5ad1SAndroid Build Coastguard Worker                 "ReSampler::resample() remaining %zu frames in and %zu frames out",
141*b9df5ad1SAndroid Build Coastguard Worker                 rsmp->frames_in, (framesRq - framesWr));
142*b9df5ad1SAndroid Build Coastguard Worker     }
143*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->frames_in) {
144*b9df5ad1SAndroid Build Coastguard Worker         memmove(rsmp->in_buf,
145*b9df5ad1SAndroid Build Coastguard Worker                 rsmp->in_buf + inFrames * rsmp->channel_count,
146*b9df5ad1SAndroid Build Coastguard Worker                 rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
147*b9df5ad1SAndroid Build Coastguard Worker     }
148*b9df5ad1SAndroid Build Coastguard Worker     *outFrameCount = framesWr;
149*b9df5ad1SAndroid Build Coastguard Worker 
150*b9df5ad1SAndroid Build Coastguard Worker     return 0;
151*b9df5ad1SAndroid Build Coastguard Worker }
152*b9df5ad1SAndroid Build Coastguard Worker 
resampler_resample_from_input(struct resampler_itfe * resampler,int16_t * in,size_t * inFrameCount,int16_t * out,size_t * outFrameCount)153*b9df5ad1SAndroid Build Coastguard Worker int resampler_resample_from_input(struct resampler_itfe *resampler,
154*b9df5ad1SAndroid Build Coastguard Worker                                   int16_t *in,
155*b9df5ad1SAndroid Build Coastguard Worker                                   size_t *inFrameCount,
156*b9df5ad1SAndroid Build Coastguard Worker                                   int16_t *out,
157*b9df5ad1SAndroid Build Coastguard Worker                                   size_t *outFrameCount)
158*b9df5ad1SAndroid Build Coastguard Worker {
159*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp = (struct resampler *)resampler;
160*b9df5ad1SAndroid Build Coastguard Worker 
161*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
162*b9df5ad1SAndroid Build Coastguard Worker             out == NULL || outFrameCount == NULL) {
163*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
164*b9df5ad1SAndroid Build Coastguard Worker     }
165*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->provider != NULL) {
166*b9df5ad1SAndroid Build Coastguard Worker         *outFrameCount = 0;
167*b9df5ad1SAndroid Build Coastguard Worker         return -ENOSYS;
168*b9df5ad1SAndroid Build Coastguard Worker     }
169*b9df5ad1SAndroid Build Coastguard Worker 
170*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->channel_count == 1) {
171*b9df5ad1SAndroid Build Coastguard Worker         speex_resampler_process_int(rsmp->speex_resampler,
172*b9df5ad1SAndroid Build Coastguard Worker                                     0,
173*b9df5ad1SAndroid Build Coastguard Worker                                     in,
174*b9df5ad1SAndroid Build Coastguard Worker                                     (spx_uint32_t *)inFrameCount,
175*b9df5ad1SAndroid Build Coastguard Worker                                     out,
176*b9df5ad1SAndroid Build Coastguard Worker                                     (spx_uint32_t *)outFrameCount);
177*b9df5ad1SAndroid Build Coastguard Worker     } else {
178*b9df5ad1SAndroid Build Coastguard Worker         speex_resampler_process_interleaved_int(rsmp->speex_resampler,
179*b9df5ad1SAndroid Build Coastguard Worker                                                 in,
180*b9df5ad1SAndroid Build Coastguard Worker                                                 (spx_uint32_t *)inFrameCount,
181*b9df5ad1SAndroid Build Coastguard Worker                                                 out,
182*b9df5ad1SAndroid Build Coastguard Worker                                                 (spx_uint32_t *)outFrameCount);
183*b9df5ad1SAndroid Build Coastguard Worker     }
184*b9df5ad1SAndroid Build Coastguard Worker 
185*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("resampler_resample_from_input() DONE in %zu out %zu", *inFrameCount, *outFrameCount);
186*b9df5ad1SAndroid Build Coastguard Worker 
187*b9df5ad1SAndroid Build Coastguard Worker     return 0;
188*b9df5ad1SAndroid Build Coastguard Worker }
189*b9df5ad1SAndroid Build Coastguard Worker 
create_resampler(uint32_t inSampleRate,uint32_t outSampleRate,uint32_t channelCount,uint32_t quality,struct resampler_buffer_provider * provider,struct resampler_itfe ** resampler)190*b9df5ad1SAndroid Build Coastguard Worker int create_resampler(uint32_t inSampleRate,
191*b9df5ad1SAndroid Build Coastguard Worker                     uint32_t outSampleRate,
192*b9df5ad1SAndroid Build Coastguard Worker                     uint32_t channelCount,
193*b9df5ad1SAndroid Build Coastguard Worker                     uint32_t quality,
194*b9df5ad1SAndroid Build Coastguard Worker                     struct resampler_buffer_provider* provider,
195*b9df5ad1SAndroid Build Coastguard Worker                     struct resampler_itfe **resampler)
196*b9df5ad1SAndroid Build Coastguard Worker {
197*b9df5ad1SAndroid Build Coastguard Worker     int error;
198*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp;
199*b9df5ad1SAndroid Build Coastguard Worker 
200*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("create_resampler() In SR %d Out SR %d channels %d",
201*b9df5ad1SAndroid Build Coastguard Worker          inSampleRate, outSampleRate, channelCount);
202*b9df5ad1SAndroid Build Coastguard Worker 
203*b9df5ad1SAndroid Build Coastguard Worker     if (resampler == NULL) {
204*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
205*b9df5ad1SAndroid Build Coastguard Worker     }
206*b9df5ad1SAndroid Build Coastguard Worker 
207*b9df5ad1SAndroid Build Coastguard Worker     *resampler = NULL;
208*b9df5ad1SAndroid Build Coastguard Worker 
209*b9df5ad1SAndroid Build Coastguard Worker     if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
210*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
211*b9df5ad1SAndroid Build Coastguard Worker     }
212*b9df5ad1SAndroid Build Coastguard Worker 
213*b9df5ad1SAndroid Build Coastguard Worker     rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
214*b9df5ad1SAndroid Build Coastguard Worker 
215*b9df5ad1SAndroid Build Coastguard Worker     rsmp->speex_resampler = speex_resampler_init(channelCount,
216*b9df5ad1SAndroid Build Coastguard Worker                                       inSampleRate,
217*b9df5ad1SAndroid Build Coastguard Worker                                       outSampleRate,
218*b9df5ad1SAndroid Build Coastguard Worker                                       quality,
219*b9df5ad1SAndroid Build Coastguard Worker                                       &error);
220*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->speex_resampler == NULL) {
221*b9df5ad1SAndroid Build Coastguard Worker         ALOGW("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
222*b9df5ad1SAndroid Build Coastguard Worker         free(rsmp);
223*b9df5ad1SAndroid Build Coastguard Worker         return -ENODEV;
224*b9df5ad1SAndroid Build Coastguard Worker     }
225*b9df5ad1SAndroid Build Coastguard Worker 
226*b9df5ad1SAndroid Build Coastguard Worker     rsmp->itfe.reset = resampler_reset;
227*b9df5ad1SAndroid Build Coastguard Worker     rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
228*b9df5ad1SAndroid Build Coastguard Worker     rsmp->itfe.resample_from_input = resampler_resample_from_input;
229*b9df5ad1SAndroid Build Coastguard Worker     rsmp->itfe.delay_ns = resampler_delay_ns;
230*b9df5ad1SAndroid Build Coastguard Worker 
231*b9df5ad1SAndroid Build Coastguard Worker     rsmp->provider = provider;
232*b9df5ad1SAndroid Build Coastguard Worker     rsmp->in_sample_rate = inSampleRate;
233*b9df5ad1SAndroid Build Coastguard Worker     rsmp->out_sample_rate = outSampleRate;
234*b9df5ad1SAndroid Build Coastguard Worker     rsmp->channel_count = channelCount;
235*b9df5ad1SAndroid Build Coastguard Worker     rsmp->in_buf = NULL;
236*b9df5ad1SAndroid Build Coastguard Worker     rsmp->in_buf_size = 0;
237*b9df5ad1SAndroid Build Coastguard Worker 
238*b9df5ad1SAndroid Build Coastguard Worker     resampler_reset(&rsmp->itfe);
239*b9df5ad1SAndroid Build Coastguard Worker 
240*b9df5ad1SAndroid Build Coastguard Worker     int frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
241*b9df5ad1SAndroid Build Coastguard Worker     rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
242*b9df5ad1SAndroid Build Coastguard Worker     frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
243*b9df5ad1SAndroid Build Coastguard Worker     rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
244*b9df5ad1SAndroid Build Coastguard Worker 
245*b9df5ad1SAndroid Build Coastguard Worker     *resampler = &rsmp->itfe;
246*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
247*b9df5ad1SAndroid Build Coastguard Worker          rsmp, &rsmp->itfe, rsmp->speex_resampler);
248*b9df5ad1SAndroid Build Coastguard Worker     return 0;
249*b9df5ad1SAndroid Build Coastguard Worker }
250*b9df5ad1SAndroid Build Coastguard Worker 
release_resampler(struct resampler_itfe * resampler)251*b9df5ad1SAndroid Build Coastguard Worker void release_resampler(struct resampler_itfe *resampler)
252*b9df5ad1SAndroid Build Coastguard Worker {
253*b9df5ad1SAndroid Build Coastguard Worker     struct resampler *rsmp = (struct resampler *)resampler;
254*b9df5ad1SAndroid Build Coastguard Worker 
255*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp == NULL) {
256*b9df5ad1SAndroid Build Coastguard Worker         return;
257*b9df5ad1SAndroid Build Coastguard Worker     }
258*b9df5ad1SAndroid Build Coastguard Worker 
259*b9df5ad1SAndroid Build Coastguard Worker     free(rsmp->in_buf);
260*b9df5ad1SAndroid Build Coastguard Worker 
261*b9df5ad1SAndroid Build Coastguard Worker     if (rsmp->speex_resampler != NULL) {
262*b9df5ad1SAndroid Build Coastguard Worker         speex_resampler_destroy(rsmp->speex_resampler);
263*b9df5ad1SAndroid Build Coastguard Worker     }
264*b9df5ad1SAndroid Build Coastguard Worker     free(rsmp);
265*b9df5ad1SAndroid Build Coastguard Worker }
266