1f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent/*
2f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * Copyright (C) 2010 The Android Open Source Project
3f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent *
4f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * Licensed under the Apache License, Version 2.0 (the "License");
5f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * you may not use this file except in compliance with the License.
6f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * You may obtain a copy of the License at
7f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent *
8f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent *      http://www.apache.org/licenses/LICENSE-2.0
9f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent *
10f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * Unless required by applicable law or agreed to in writing, software
11f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * distributed under the License is distributed on an "AS IS" BASIS,
12f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * See the License for the specific language governing permissions and
14f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent * limitations under the License.
15f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent */
16f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
17f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentpackage com.android.musicvis;
18f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
19f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentimport android.util.Log;
2018d8fa67c3efc037ddb0be266dd38c5cf35a22c7Eric Laurentimport android.media.audiofx.Visualizer;
21f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
22f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentimport java.util.Arrays;
23f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
24f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentpublic class AudioCapture {
25f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
26f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    private byte [] mRawVizData;
27f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    private int [] mFormattedVizData;
28e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent    private byte [] mRawNullData = new byte[0];
29e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent    private int [] mFormattedNullData = new int[0];
30e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent
31f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    private Visualizer mVisualizer;
32f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    private int mType;
33f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
34e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent    private static long MAX_IDLE_TIME_MS = 3000;
35e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent    private long mLastValidCaptureTimeMs;
36e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent
37f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public static final int TYPE_PCM = 0;
38f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public static final int TYPE_FFT = 1;
39f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
40e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent
41f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public AudioCapture(int type, int size) {
42f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        mType = type;
43f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        int[] range = new int[2];
44f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
45f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        range = Visualizer.getCaptureSizeRange();
46f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
47f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        if (size < range[0]) {
48f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            size = range[0];
49f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
50f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        if (size > range[1]) {
51f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            size = range[1];
52f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
53f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
54f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        mRawVizData = new byte[size];
55f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        mFormattedVizData = new int[size];
56f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
57f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        mVisualizer = null;
58f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        try {
59f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            mVisualizer = new Visualizer(0);
60f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            if (mVisualizer != null) {
61f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mVisualizer.getEnabled()) {
62f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mVisualizer.setEnabled(false);
63f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
64f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mVisualizer.setCaptureSize(mRawVizData.length);
65f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
66f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } catch (UnsupportedOperationException e) {
67f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            Log.e("AudioCapture", "Visualizer cstor UnsupportedOperationException");
68f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } catch (IllegalStateException e) {
69f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            Log.e("AudioCapture", "Visualizer cstor IllegalStateException");
70f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } catch (RuntimeException e) {
71f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            Log.e("AudioCapture", "Visualizer cstor RuntimeException");
72f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
73f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
74f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
75f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public void start() {
76f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        if (mVisualizer != null) {
77f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            try {
78f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (!mVisualizer.getEnabled()) {
79f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mVisualizer.setEnabled(true);
80e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    mLastValidCaptureTimeMs = System.currentTimeMillis();
81f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
82f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            } catch (IllegalStateException e) {
83f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                Log.e("AudioCapture", "start() IllegalStateException");
84f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
85f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
86f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
87f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
88f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public void stop() {
89f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        if (mVisualizer != null) {
90f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            try {
91f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mVisualizer.getEnabled()) {
92f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mVisualizer.setEnabled(false);
93f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
94f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            } catch (IllegalStateException e) {
95f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                Log.e("AudioCapture", "stop() IllegalStateException");
96f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
97f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
98f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
99f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
100f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public void release() {
101f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        if (mVisualizer != null) {
102f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            mVisualizer.release();
103f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            mVisualizer = null;
104f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
105f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
106f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
107f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public byte[] getRawData() {
108e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        if (captureData()) {
109e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            return mRawVizData;
110e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        } else {
111e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            return mRawNullData;
112e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        }
113f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
114f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
115f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    public int[] getFormattedData(int num, int den) {
116e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        if (captureData()) {
117e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            if (mType == TYPE_PCM) {
118e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                for (int i = 0; i < mFormattedVizData.length; i++) {
119e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    // convert from unsigned 8 bit to signed 16 bit
120e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    int tmp = ((int)mRawVizData[i] & 0xFF) - 128;
121e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    // apply scaling factor
122e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    mFormattedVizData[i] = (tmp * num) / den;
123e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                }
124e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            } else {
125e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                for (int i = 0; i < mFormattedVizData.length; i++) {
126e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    // apply scaling factor
127e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    mFormattedVizData[i] = ((int)mRawVizData[i] * num) / den;
128e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                }
129f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
130e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            return mFormattedVizData;
131f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } else {
132e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            return mFormattedNullData;
133f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
134f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
135f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
136e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent    private boolean captureData() {
137f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        int status = Visualizer.ERROR;
138e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        boolean result = true;
139f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        try {
140f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            if (mVisualizer != null) {
141f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mType == TYPE_PCM) {
142f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    status = mVisualizer.getWaveForm(mRawVizData);
143f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                } else {
144f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    status = mVisualizer.getFft(mRawVizData);
145f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
146f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
147f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } catch (IllegalStateException e) {
148f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            Log.e("AudioCapture", "captureData() IllegalStateException: "+this);
149f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        } finally {
150f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            if (status != Visualizer.SUCCESS) {
151f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                Log.e("AudioCapture", "captureData() :  "+this+" error: "+ status);
152e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                result = false;
153e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent            } else {
154e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                // return idle state indication if silence lasts more than MAX_IDLE_TIME_MS
155e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                byte nullValue = 0;
156e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                int i;
157f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mType == TYPE_PCM) {
158e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    nullValue = (byte)0x80;
159e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                }
160e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                for (i = 0; i < mRawVizData.length; i++) {
161e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    if (mRawVizData[i] != nullValue) break;
162e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                }
163e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                if (i == mRawVizData.length) {
164e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    if ((System.currentTimeMillis() - mLastValidCaptureTimeMs) >
165e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                         MAX_IDLE_TIME_MS) {
166e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                        result = false;
167e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    }
168f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                } else {
169e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent                    mLastValidCaptureTimeMs = System.currentTimeMillis();
170f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
171f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
172f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        }
173e024bb9ab683bfb161ac11acb4df30fd8c9efe9cEric Laurent        return result;
174f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent    }
175f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent}
176