summaryrefslogtreecommitdiff
path: root/android/media/ResampleInputStream.java
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
committerJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
commit10d07c88d69cc64f73a069163e7ea5ba2519a099 (patch)
tree8dbd149eb350320a29c3d10e7ad3201de1c5cbee /android/media/ResampleInputStream.java
parent677516fb6b6f207d373984757d3d9450474b6b00 (diff)
downloadandroid-28-10d07c88d69cc64f73a069163e7ea5ba2519a099.tar.gz
Import Android SDK Platform PI [4335822]
/google/data/ro/projects/android/fetch_artifact \ --bid 4335822 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4335822.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: Ic8f04be005a71c2b9abeaac754d8da8d6f9a2c32
Diffstat (limited to 'android/media/ResampleInputStream.java')
-rw-r--r--android/media/ResampleInputStream.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/android/media/ResampleInputStream.java b/android/media/ResampleInputStream.java
new file mode 100644
index 00000000..80919f7f
--- /dev/null
+++ b/android/media/ResampleInputStream.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * ResampleInputStream
+ * @hide
+ */
+public final class ResampleInputStream extends InputStream
+{
+ static {
+ System.loadLibrary("media_jni");
+ }
+
+ private final static String TAG = "ResampleInputStream";
+
+ // pcm input stream
+ private InputStream mInputStream;
+
+ // sample rates, assumed to be normalized
+ private final int mRateIn;
+ private final int mRateOut;
+
+ // input pcm data
+ private byte[] mBuf;
+ private int mBufCount;
+
+ // length of 2:1 fir
+ private static final int mFirLength = 29;
+
+ // helper for bytewise read()
+ private final byte[] mOneByte = new byte[1];
+
+ /**
+ * Create a new ResampleInputStream, which converts the sample rate
+ * @param inputStream InputStream containing 16 bit PCM.
+ * @param rateIn the input sample rate.
+ * @param rateOut the output sample rate.
+ * This only handles rateIn == rateOut / 2 for the moment.
+ */
+ public ResampleInputStream(InputStream inputStream, int rateIn, int rateOut) {
+ // only support 2:1 at the moment
+ if (rateIn != 2 * rateOut) throw new IllegalArgumentException("only support 2:1 at the moment");
+ rateIn = 2;
+ rateOut = 1;
+
+ mInputStream = inputStream;
+ mRateIn = rateIn;
+ mRateOut = rateOut;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int rtn = read(mOneByte, 0, 1);
+ return rtn == 1 ? (0xff & mOneByte[0]) : -1;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length) throws IOException {
+ if (mInputStream == null) throw new IllegalStateException("not open");
+
+ // ensure that mBuf is big enough to cover requested 'length'
+ int nIn = ((length / 2) * mRateIn / mRateOut + mFirLength) * 2;
+ if (mBuf == null) {
+ mBuf = new byte[nIn];
+ } else if (nIn > mBuf.length) {
+ byte[] bf = new byte[nIn];
+ System.arraycopy(mBuf, 0, bf, 0, mBufCount);
+ mBuf = bf;
+ }
+
+ // read until we have enough data for at least one output sample
+ while (true) {
+ int len = ((mBufCount / 2 - mFirLength) * mRateOut / mRateIn) * 2;
+ if (len > 0) {
+ length = len < length ? len : (length / 2) * 2;
+ break;
+ }
+ // TODO: should mBuf.length below be nIn instead?
+ int n = mInputStream.read(mBuf, mBufCount, mBuf.length - mBufCount);
+ if (n == -1) return -1;
+ mBufCount += n;
+ }
+
+ // resample input data
+ fir21(mBuf, 0, b, offset, length / 2);
+
+ // move any unused bytes to front of mBuf
+ int nFwd = length * mRateIn / mRateOut;
+ mBufCount -= nFwd;
+ if (mBufCount > 0) System.arraycopy(mBuf, nFwd, mBuf, 0, mBufCount);
+
+ return length;
+ }
+
+/*
+ @Override
+ public int available() throws IOException {
+ int nsamples = (mIn - mOut + mInputStream.available()) / 2;
+ return ((nsamples - mFirLength) * mRateOut / mRateIn) * 2;
+ }
+*/
+
+ @Override
+ public void close() throws IOException {
+ try {
+ if (mInputStream != null) mInputStream.close();
+ } finally {
+ mInputStream = null;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mInputStream != null) {
+ close();
+ throw new IllegalStateException("someone forgot to close ResampleInputStream");
+ }
+ }
+
+ //
+ // fir filter code JNI interface
+ //
+ private static native void fir21(byte[] in, int inOffset,
+ byte[] out, int outOffset, int npoints);
+
+}