1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 
12 /*
13  * A wrapper for resampling a numerous amount of sampling combinations.
14  */
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 
20 #include "webrtc/common_audio/resampler/include/resampler.h"
21 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
22 
23 // TODO(jesup) better adjust per platform ability
24 // Note: if these are changed (higher), you may need to change the
25 // KernelDelay values in the unit tests here and in output_mixer.
26 #if defined(WEBRTC_ANDROID)
27 #define RESAMPLER_QUALITY 2
28 #else
29 #define RESAMPLER_QUALITY 3
30 #endif
31 
32 namespace webrtc {
33 
Resampler()34 Resampler::Resampler() : state_(NULL), channels_(0)
35 {
36   // Note: Push will fail until Reset() is called
37 }
38 
Resampler(int inFreq,int outFreq,size_t num_channels)39 Resampler::Resampler(int inFreq, int outFreq, size_t num_channels)
40     : Resampler() {
41   Reset(inFreq, outFreq, num_channels);
42 }
43 
~Resampler()44 Resampler::~Resampler()
45 {
46   if (state_)
47   {
48     speex_resampler_destroy(state_);
49   }
50 }
51 
ResetIfNeeded(int inFreq,int outFreq,size_t num_channels)52 int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels)
53 {
54   if (!state_ || channels_ != num_channels ||
55       inFreq != in_freq_ || outFreq != out_freq_)
56   {
57     // Note that fixed-rate resamplers where input == output rate will
58     // have state_ == NULL, and will call Reset() here - but reset won't
59     // do anything beyond overwrite the member vars unless it needs a
60     // real resampler.
61     return Reset(inFreq, outFreq, num_channels);
62   } else {
63     return 0;
64   }
65 }
66 
Reset(int inFreq,int outFreq,size_t num_channels)67 int Resampler::Reset(int inFreq, int outFreq, size_t num_channels)
68 {
69   if (num_channels != 1 && num_channels != 2) {
70     return -1;
71   }
72 
73   if (state_)
74   {
75     speex_resampler_destroy(state_);
76     state_ = NULL;
77   }
78   channels_ = num_channels;
79   in_freq_ = inFreq;
80   out_freq_ = outFreq;
81 
82   // For fixed-rate, same-rate resamples we just memcpy and so don't spin up a resampler
83   if (inFreq != outFreq)
84   {
85     state_ = speex_resampler_init(num_channels, inFreq, outFreq, RESAMPLER_QUALITY, NULL);
86     if (!state_)
87     {
88       return -1;
89     }
90   }
91   return 0;
92 }
93 
94 // Synchronous resampling, all output samples are written to samplesOut
95 // TODO(jesup) Change to take samples-per-channel in and out
Push(const int16_t * samplesIn,size_t lengthIn,int16_t * samplesOut,size_t maxLen,size_t & outLen)96 int Resampler::Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut,
97                     size_t maxLen, size_t &outLen)
98 {
99   if (maxLen < lengthIn)
100   {
101     return -1;
102   }
103   if (!state_)
104   {
105     if (in_freq_ != out_freq_ || channels_ == 0)
106     {
107       // Push() will fail until Reset() is called
108       return -1;
109     }
110     // Same-freq "resample" - use memcpy, which avoids
111     // filtering and delay.  For non-fixed rates, where we might tweak
112     // from 48000->48000 to 48000->48001 for drift, we need to resample
113     // (and filter) all the time to avoid glitches on rate changes.
114     memcpy(samplesOut, samplesIn, lengthIn*sizeof(*samplesIn));
115     outLen = lengthIn;
116     return 0;
117   }
118   assert(channels_ == 1 || channels_ == 2);
119   spx_uint32_t len = lengthIn = (lengthIn >> (channels_ - 1));
120   spx_uint32_t out = (spx_uint32_t) (maxLen >> (channels_ - 1));
121   if ((speex_resampler_process_interleaved_int(state_, samplesIn, &len,
122                              samplesOut, &out) != RESAMPLER_ERR_SUCCESS) ||
123       len != (spx_uint32_t) lengthIn)
124   {
125     return -1;
126   }
127   outLen = (int) (channels_ * out);
128   return 0;
129 }
130 }// namespace webrtc
131