1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19import android.util.Config; 20import android.util.Log; 21 22import java.io.InputStream; 23import java.io.IOException; 24 25 26/** 27 * ResampleInputStream 28 * @hide 29 */ 30public final class ResampleInputStream extends InputStream 31{ 32 static { 33 System.loadLibrary("media_jni"); 34 } 35 36 private final static String TAG = "ResampleInputStream"; 37 38 // pcm input stream 39 private InputStream mInputStream; 40 41 // sample rates, assumed to be normalized 42 private final int mRateIn; 43 private final int mRateOut; 44 45 // input pcm data 46 private byte[] mBuf; 47 private int mBufCount; 48 49 // length of 2:1 fir 50 private static final int mFirLength = 29; 51 52 // helper for bytewise read() 53 private final byte[] mOneByte = new byte[1]; 54 55 /** 56 * Create a new ResampleInputStream, which converts the sample rate 57 * @param inputStream InputStream containing 16 bit PCM. 58 * @param rateIn the input sample rate. 59 * @param rateOut the output sample rate. 60 * This only handles rateIn == rateOut / 2 for the moment. 61 */ 62 public ResampleInputStream(InputStream inputStream, int rateIn, int rateOut) { 63 // only support 2:1 at the moment 64 if (rateIn != 2 * rateOut) throw new IllegalArgumentException("only support 2:1 at the moment"); 65 rateIn = 2; 66 rateOut = 1; 67 68 mInputStream = inputStream; 69 mRateIn = rateIn; 70 mRateOut = rateOut; 71 } 72 73 @Override 74 public int read() throws IOException { 75 int rtn = read(mOneByte, 0, 1); 76 return rtn == 1 ? (0xff & mOneByte[0]) : -1; 77 } 78 79 @Override 80 public int read(byte[] b) throws IOException { 81 return read(b, 0, b.length); 82 } 83 84 @Override 85 public int read(byte[] b, int offset, int length) throws IOException { 86 if (mInputStream == null) throw new IllegalStateException("not open"); 87 88 // ensure that mBuf is big enough to cover requested 'length' 89 int nIn = ((length / 2) * mRateIn / mRateOut + mFirLength) * 2; 90 if (mBuf == null) { 91 mBuf = new byte[nIn]; 92 } else if (nIn > mBuf.length) { 93 byte[] bf = new byte[nIn]; 94 System.arraycopy(mBuf, 0, bf, 0, mBufCount); 95 mBuf = bf; 96 } 97 98 // read until we have enough data for at least one output sample 99 while (true) { 100 int len = ((mBufCount / 2 - mFirLength) * mRateOut / mRateIn) * 2; 101 if (len > 0) { 102 length = len < length ? len : (length / 2) * 2; 103 break; 104 } 105 // TODO: should mBuf.length below be nIn instead? 106 int n = mInputStream.read(mBuf, mBufCount, mBuf.length - mBufCount); 107 if (n == -1) return -1; 108 mBufCount += n; 109 } 110 111 // resample input data 112 fir21(mBuf, 0, b, offset, length / 2); 113 114 // move any unused bytes to front of mBuf 115 int nFwd = length * mRateIn / mRateOut; 116 mBufCount -= nFwd; 117 if (mBufCount > 0) System.arraycopy(mBuf, nFwd, mBuf, 0, mBufCount); 118 119 return length; 120 } 121 122/* 123 @Override 124 public int available() throws IOException { 125 int nsamples = (mIn - mOut + mInputStream.available()) / 2; 126 return ((nsamples - mFirLength) * mRateOut / mRateIn) * 2; 127 } 128*/ 129 130 @Override 131 public void close() throws IOException { 132 try { 133 if (mInputStream != null) mInputStream.close(); 134 } finally { 135 mInputStream = null; 136 } 137 } 138 139 @Override 140 protected void finalize() throws Throwable { 141 if (mInputStream != null) { 142 close(); 143 throw new IllegalStateException("someone forgot to close ResampleInputStream"); 144 } 145 } 146 147 // 148 // fir filter code JNI interface 149 // 150 private static native void fir21(byte[] in, int inOffset, 151 byte[] out, int outOffset, int npoints); 152 153} 154