19b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia/*
29b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * Copyright (C) 2015 The Android Open Source Project
39b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia *
49b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * Licensed under the Apache License, Version 2.0 (the "License");
59b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * you may not use this file except in compliance with the License.
69b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * You may obtain a copy of the License at
79b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia *
89b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia *      http://www.apache.org/licenses/LICENSE-2.0
99b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia *
109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * Unless required by applicable law or agreed to in writing, software
119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * distributed under the License is distributed on an "AS IS" BASIS,
129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * See the License for the specific language governing permissions and
149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * limitations under the License.
159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia */
169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciapackage com.android.cts.verifier.audio;
189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.cts.verifier.PassFailButtons;
209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.cts.verifier.R;
219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.cts.verifier.audio.wavelib.*;
229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.compatibility.common.util.ReportLog;
239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.compatibility.common.util.ResultType;
249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport com.android.compatibility.common.util.ResultUnit;
259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
26bf40d84ca078f71421bf1fff97dbf6265575df3bragoimport android.app.AlertDialog;
27e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garciaimport android.content.Context;
289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioDeviceCallback;
299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioDeviceInfo;
309b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioFormat;
319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioManager;
329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioTrack;
339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.AudioRecord;
349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.media.MediaRecorder;
359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.os.Bundle;
369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.os.Handler;
379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.os.Message;
389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.os.SystemClock;
399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.util.Log;
409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.view.View;
419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.view.View.OnClickListener;
429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.widget.Button;
439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.widget.TextView;
449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.widget.SeekBar;
459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.widget.LinearLayout;
469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garciaimport android.widget.ProgressBar;
479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia/**
499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia * Tests Audio Device roundtrip latency by using a loopback plug.
509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia */
51bf40d84ca078f71421bf1fff97dbf6265575df3bragopublic class AudioFrequencyLineActivity extends AudioFrequencyActivity implements Runnable,
529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    AudioRecord.OnRecordPositionUpdateListener {
539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private static final String TAG = "AudioFrequencyLineActivity";
549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    static final int TEST_STARTED = 900;
569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    static final int TEST_ENDED = 901;
579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    static final int TEST_MESSAGE = 902;
589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    static final double MIN_ENERGY_BAND_1 = -20.0;
599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    Context mContext;
639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
64a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie    Button mHeadsetPortYes;
65a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie    Button mHeadsetPortNo;
66a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie
679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    Button mLoopbackPlugReady;
689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    LinearLayout mLinearLayout;
699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    Button mTestButton;
709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    TextView mResultText;
719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    ProgressBar mProgressBar;
729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    //recording
739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private boolean mIsRecording = false;
749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private final Object mRecordingLock = new Object();
759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private AudioRecord mRecorder;
769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private int mMinRecordBufferSizeInSamples = 0;
779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private short[] mAudioShortArray;
789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private short[] mAudioShortArray2;
799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private final int mBlockSizeSamples = 1024;
819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private final int mSamplingRate = 48000;
82bf40d84ca078f71421bf1fff97dbf6265575df3brago    private final int mSelectedRecordSource = MediaRecorder.AudioSource.UNPROCESSED;
839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private final int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;
849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private final int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private volatile Thread mRecordThread;
869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private boolean mRecordThreadShutdown = false;
879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    PipeShort mPipe = new PipeShort(65536);
899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    SoundPlayerObject mSPlayer;
909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private DspBufferComplex mC;
929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private DspBufferDouble mData;
939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private DspWindow mWindow;
959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private DspFftServer mFftServer;
969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private VectorAverage mFreqAverageMain = new VectorAverage();
979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private VectorAverage mFreqAverage0 = new VectorAverage();
999b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private VectorAverage mFreqAverage1 = new VectorAverage();
1009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private int mCurrentTest = -1;
1029b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    int mBands = 4;
1039b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
1049b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1059b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private class OnBtnClickListener implements OnClickListener {
1069b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        @Override
1079b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public void onClick(View v) {
1089b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            switch (v.getId()) {
1099b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                case R.id.audio_frequency_line_plug_ready_btn:
1109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    Log.i(TAG, "audio loopback plug ready");
1119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    //enable all the other views.
1129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    enableLayout(true);
113bf40d84ca078f71421bf1fff97dbf6265575df3brago                    setMaxLevel();
114bf40d84ca078f71421bf1fff97dbf6265575df3brago                    testMaxLevel();
1159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    break;
1169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                case R.id.audio_frequency_line_test_btn:
1179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    Log.i(TAG, "audio loopback test");
1189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    startAudioTest();
1199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    break;
120a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                case R.id.audio_general_headset_yes:
121a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    Log.i(TAG, "User confirms Headset Port existence");
122a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    mLoopbackPlugReady.setEnabled(true);
123a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    recordHeasetPortFound(true);
124a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    mHeadsetPortYes.setEnabled(false);
125a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    mHeadsetPortNo.setEnabled(false);
126a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    break;
127a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                case R.id.audio_general_headset_no:
128a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    Log.i(TAG, "User denies Headset Port existence");
129a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    recordHeasetPortFound(false);
130a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    getPassButton().setEnabled(true);
131a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    mHeadsetPortYes.setEnabled(false);
132a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    mHeadsetPortNo.setEnabled(false);
133a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                    break;
1349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
1359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
1369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
1379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    @Override
1399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    protected void onCreate(Bundle savedInstanceState) {
1409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        super.onCreate(savedInstanceState);
1419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        setContentView(R.layout.audio_frequency_line_activity);
1429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mContext = this;
1449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
145a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
146a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        mHeadsetPortYes.setOnClickListener(mBtnClickListener);
147a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
148a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        mHeadsetPortNo.setOnClickListener(mBtnClickListener);
149a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie
1509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_line_plug_ready_btn);
1519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
152a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        mLoopbackPlugReady.setEnabled(false);
1539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_line_layout);
1549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mTestButton = (Button)findViewById(R.id.audio_frequency_line_test_btn);
1559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mTestButton.setOnClickListener(mBtnClickListener);
1569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mResultText = (TextView)findViewById(R.id.audio_frequency_line_results_text);
1579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_line_progress_bar);
1589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        showWait(false);
1599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        enableLayout(false);         //disabled all content
1609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mSPlayer = new SoundPlayerObject();
1629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.stereo_mono_white_noise_48);
1639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mSPlayer.setBalance(0.5f);
1649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        //Init FFT stuff
1669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mAudioShortArray2 = new short[mBlockSizeSamples*2];
1679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mData = new DspBufferDouble(mBlockSizeSamples);
1689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mC = new DspBufferComplex(mBlockSizeSamples);
1699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mFftServer = new DspFftServer(mBlockSizeSamples);
1709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int overlap = mBlockSizeSamples / 2;
1729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mWindow = new DspWindow(DspWindow.WINDOW_HANNING, mBlockSizeSamples, overlap);
1749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        setPassFailButtonClickListeners();
1769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        getPassButton().setEnabled(false);
1779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        setInfoResources(R.string.audio_frequency_line_test,
1789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                R.string.audio_frequency_line_info, -1);
1799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        //Init bands
1819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        bandSpecsArray[0] = new AudioBandSpecs(
1829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                50, 500,        /* frequency start,stop */
183b0d570c835aebd5d0eb8dadcb6679b57504e6851rago                4.0, -50,     /* start top,bottom value */
1849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                4.0, -4.0       /* stop top,bottom value */);
1859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        bandSpecsArray[1] = new AudioBandSpecs(
1879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                500,4000,       /* frequency start,stop */
1889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                4.0, -4.0,      /* start top,bottom value */
1899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                4.0, -4.0        /* stop top,bottom value */);
1909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        bandSpecsArray[2] = new AudioBandSpecs(
1929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                4000, 12000,    /* frequency start,stop */
1939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                4.0, -4.0,      /* start top,bottom value */
1949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                5.0, -5.0       /* stop top,bottom value */);
1959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
1969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        bandSpecsArray[3] = new AudioBandSpecs(
1979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                12000, 20000,   /* frequency start,stop */
1989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                5.0, -5.0,      /* start top,bottom value */
1999b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                5.0, -30.0      /* stop top,bottom value */);
2009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
2019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2029b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    /**
2039b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     * enable test ui elements
2049b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     */
2059b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void enableLayout(boolean enable) {
2069b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
2079b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            View view = mLinearLayout.getChildAt(i);
2089b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            view.setEnabled(enable);
2099b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
2119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    /**
2139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     * show active progress bar
2149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     */
2159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void showWait(boolean show) {
2169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (show) {
2179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mProgressBar.setVisibility(View.VISIBLE);
2189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        } else {
2199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mProgressBar.setVisibility(View.INVISIBLE);
2209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
2229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    /**
2249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     *  Start the loopback audio test
2259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     */
2269b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void startAudioTest() {
2279b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mTestThread != null && !mTestThread.isAlive()) {
2289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mTestThread = null; //kill it.
2299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2309b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mTestThread == null) {
2329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Log.v(TAG,"Executing test Thread");
2339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mTestThread = new Thread(mPlayRunnable);
2349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            getPassButton().setEnabled(false);
2359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            if (!mSPlayer.isAlive())
2369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                mSPlayer.start();
2379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mTestThread.start();
2389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        } else {
2399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Log.v(TAG,"test Thread already running.");
2409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
2429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    Thread mTestThread;
2449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    Runnable mPlayRunnable = new Runnable() {
2459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public void run() {
2469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Message msg = Message.obtain();
2479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            msg.what = TEST_STARTED;
2489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mMessageHandler.sendMessage(msg);
2499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            sendMessage("Testing Left Capture");
2519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mCurrentTest = 0;
2529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mFreqAverage0.reset();
2539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mSPlayer.setBalance(0.0f);
2549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            play();
2559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            sendMessage("Testing Right Capture");
2579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mCurrentTest = 1;
2589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mFreqAverage1.reset();
2599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mSPlayer.setBalance(1.0f);
2609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            play();
2619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mCurrentTest = -1;
2639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            sendMessage("Testing Completed");
2649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Message msg2 = Message.obtain();
2669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            msg2.what = TEST_ENDED;
2679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mMessageHandler.sendMessage(msg2);
2689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        private void play() {
2719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            startRecording();
2729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mSPlayer.play(true);
2739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            try {
2759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                Thread.sleep(2000);
2769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            } catch (InterruptedException e) {
2779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                e.printStackTrace();
2789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
2799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mSPlayer.play(false);
2819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            stopRecording();
2829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        private void sendMessage(String str) {
2859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Message msg = Message.obtain();
2869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            msg.what = TEST_MESSAGE;
2879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            msg.obj = str;
2889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mMessageHandler.sendMessage(msg);
2899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
2909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    };
2919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
2929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private Handler mMessageHandler = new Handler() {
2939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public void handleMessage(Message msg) {
2949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            super.handleMessage(msg);
2959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            switch (msg.what) {
2969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            case TEST_STARTED:
2979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                showWait(true);
2989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                getPassButton().setEnabled(false);
2999b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                break;
3009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            case TEST_ENDED:
3019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                showWait(false);
3029b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                computeResults();
3039b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                break;
3049b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            case TEST_MESSAGE:
3059b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                String str = (String)msg.obj;
3069b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (str != null) {
3079b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    mResultText.setText(str);
3089b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
3099b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                break;
3109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            default:
3119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                Log.e(TAG, String.format("Unknown message: %d", msg.what));
3129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    };
3159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private class Results {
3179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        private String mLabel;
3189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public double[] mValuesLog;
3199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int[] mPointsPerBand = new int[mBands];
3209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        double[] mAverageEnergyPerBand = new double[mBands];
3219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int[] mInBoundPointsPerBand = new int[mBands];
3229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public Results(String label) {
3239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mLabel = label;
3249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3269b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        //append results
3279b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public String toString() {
3289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            StringBuilder sb = new StringBuilder();
3299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            sb.append(String.format("Channel %s\n", mLabel));
330b0d570c835aebd5d0eb8dadcb6679b57504e6851rago            sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"Not Optimal") +"\n");
3319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int b = 0; b < mBands; b++) {
3329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                double percent = 0;
3339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (mPointsPerBand[b] > 0) {
3349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    percent = 100.0 * (double)mInBoundPointsPerBand[b] / mPointsPerBand[b];
3359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
3369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                sb.append(String.format(
3379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        " Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
3389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        b, mAverageEnergyPerBand[b],
3399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        mInBoundPointsPerBand[b],
3409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        mPointsPerBand[b],
3419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        percent,
342b0d570c835aebd5d0eb8dadcb6679b57504e6851rago                        (testInBand(b) ? "OK" : "Not Optimal")));
3439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return sb.toString();
3459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public boolean testLevel() {
3489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
3499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                return true;
3509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return false;
3529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public boolean testInBand(int b) {
3559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
3569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if ((double)mInBoundPointsPerBand[b] / mPointsPerBand[b] >
3579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                MIN_FRACTION_POINTS_IN_BAND)
3589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    return true;
3599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return false;
3619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        public boolean testAll() {
3649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            if (!testLevel()) {
3659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                return false;
3669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int b = 0; b < mBands; b++) {
3689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (!testInBand(b)) {
3699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    return false;
3709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
3719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
3729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return true;
3739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
3749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
3759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    /**
3779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     * compute test results
3789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     */
3799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void computeResults() {
3809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Results resultsLeft = new Results("Left");
3819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        computeResultsForVector(mFreqAverage0, resultsLeft);
3829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Results resultsRight = new Results("Right");
3839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        computeResultsForVector(mFreqAverage1, resultsRight);
3849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (resultsLeft.testAll() && resultsRight.testAll()) {
385e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            String strSuccess = getResources().getString(R.string.audio_general_test_passed);
386e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            appendResultsToScreen(strSuccess);
387e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia        } else {
388e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            String strFailed = getResources().getString(R.string.audio_general_test_failed);
389e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            appendResultsToScreen(strFailed + "\n");
390e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            String strWarning = getResources().getString(R.string.audio_general_deficiency_found);
391e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia            appendResultsToScreen(strWarning);
3929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
393e8a13b1bdeb1f6a610720d8c0393dd5c3e982055Ricardo Garcia        getPassButton().setEnabled(true); //Everybody passes! (for now...)
3949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
3959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void computeResultsForVector(VectorAverage freqAverage,Results results) {
3979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
3989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int points = freqAverage.getSize();
3999b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (points > 0) {
4009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //compute vector in db
4019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double[] values = new double[points];
4029b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            freqAverage.getData(values, false);
4039b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            results.mValuesLog = new double[points];
4049b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int i = 0; i < points; i++) {
4059b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                results.mValuesLog[i] = 20 * Math.log10(values[i]);
4069b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
4079b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4089b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            int currentBand = 0;
4099b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int i = 0; i < points; i++) {
4109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
4119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (freq > bandSpecsArray[currentBand].mFreqStop) {
4129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    currentBand++;
4139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    if (currentBand >= mBands)
4149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        break;
4159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
4169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (freq >= bandSpecsArray[currentBand].mFreqStart) {
4189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
4199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mPointsPerBand[currentBand]++;
4209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
4219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
4229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int b = 0; b < mBands; b++) {
4249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (results.mPointsPerBand[b] > 0) {
4259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mAverageEnergyPerBand[b] =
4269b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                            results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
4279b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
4289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
4299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4309b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //set offset relative to band 1 level
4319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int b = 0; b < mBands; b++) {
4329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                bandSpecsArray[b].setOffset(results.mAverageEnergyPerBand[1]);
4339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
4349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //test points in band.
4369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            currentBand = 0;
4379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (int i = 0; i < points; i++) {
4389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
4399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (freq >  bandSpecsArray[currentBand].mFreqStop) {
4409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    currentBand++;
4419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    if (currentBand >= mBands)
4429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        break;
4439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
4449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (freq >= bandSpecsArray[currentBand].mFreqStart) {
4469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    double value = results.mValuesLog[i];
4479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    if (bandSpecsArray[currentBand].isInBounds(freq, value)) {
4489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                        results.mInBoundPointsPerBand[currentBand]++;
4499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    }
4509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
4519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
4529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            appendResultsToScreen(results.toString());
4549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //store results
4559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            recordTestResults(results);
4569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        } else {
4579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            appendResultsToScreen("Failed testing channel " + results.mLabel);
4589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
4599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
4609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    //append results
4629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void appendResultsToScreen(String str) {
4639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        String currentText = mResultText.getText().toString();
4649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mResultText.setText(currentText + "\n" + str);
4659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
4669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    /**
4689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     * Store test results in log
4699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia     */
4709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void recordTestResults(Results results) {
4719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        String channelLabel = "channel_" + results.mLabel;
4729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        for (int b = 0; b < mBands; b++) {
4749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            String bandLabel = String.format(channelLabel + "_%d", b);
4759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            getReportLog().addValue(
4769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    bandLabel + "_Level",
4779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mAverageEnergyPerBand[b],
4789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultType.HIGHER_BETTER,
4799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultUnit.NONE);
4809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            getReportLog().addValue(
4829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    bandLabel + "_pointsinbound",
4839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mInBoundPointsPerBand[b],
4849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultType.HIGHER_BETTER,
4859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultUnit.COUNT);
4869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            getReportLog().addValue(
4889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    bandLabel + "_pointstotal",
4899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    results.mPointsPerBand[b],
4909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultType.NEUTRAL,
4919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    ResultUnit.COUNT);
4929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
4939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
4959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                results.mValuesLog,
4969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                ResultType.NEUTRAL,
4979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                ResultUnit.NONE);
4989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
4999b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG, "Results Recorded");
5009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
5019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
502a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie    private void recordHeasetPortFound(boolean found) {
503a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie        getReportLog().addValue(
504a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                "User Reported Headset Port",
505a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                found ? 1.0 : 0,
506a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                ResultType.NEUTRAL,
507a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie                ResultUnit.NONE);
508a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie    }
509a41d49723a200eec6af9c9504a961cb2df306295Daniel Xie
5109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void startRecording() {
5119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        synchronized (mRecordingLock) {
5129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mIsRecording = true;
5139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        boolean successful = initRecord();
5169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (successful) {
5179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            startRecordingForReal();
5189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        } else {
5199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            Log.v(TAG, "Recorder initialization error.");
5209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            synchronized (mRecordingLock) {
5219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                mIsRecording = false;
5229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
5239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
5259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5269b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void startRecordingForReal() {
5279b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        // start streaming
5289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mRecordThread == null) {
5299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecordThread = new Thread(AudioFrequencyLineActivity.this);
5309b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecordThread.setName("FrequencyAnalyzerThread");
5319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecordThreadShutdown = false;
5329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (!mRecordThread.isAlive()) {
5349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecordThread.start();
5359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mPipe.flush();
5389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        long startTime = SystemClock.uptimeMillis();
5409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mRecorder.startRecording();
5419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
5429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            stopRecording();
5439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return;
5449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG, "Start time: " + (long) (SystemClock.uptimeMillis() - startTime) + " ms");
5469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
5479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void stopRecording() {
5499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        synchronized (mRecordingLock) {
5509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            stopRecordingForReal();
5519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mIsRecording = false;
5529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
5549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private void stopRecordingForReal() {
5569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        // stop streaming
5589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Thread zeThread = mRecordThread;
5599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mRecordThread = null;
5609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mRecordThreadShutdown = true;
5619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (zeThread != null) {
5629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            zeThread.interrupt();
5639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            try {
5649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                zeThread.join();
5659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            } catch(InterruptedException e) {
5669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                Log.v(TAG,"Error shutting down recording thread " + e);
5679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                //we don't really care about this error, just logging it.
5689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
5699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia         // release recording resources
5719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mRecorder != null) {
5729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder.stop();
5739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder.release();
5749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder = null;
5759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
5779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    private boolean initRecord() {
5799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
5809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                mChannelConfig, mAudioFormat);
5819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG,"FrequencyAnalyzer: min buff size = " + minRecordBuffSizeInBytes + " bytes");
5829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (minRecordBuffSizeInBytes <= 0) {
5839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return false;
5849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
5859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mMinRecordBufferSizeInSamples = minRecordBuffSizeInBytes / 2;
5879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        // allocate the byte array to read the audio data
5889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mAudioShortArray = new short[mMinRecordBufferSizeInSamples];
5909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG, "Initiating record:");
5929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG, "      using source " + mSelectedRecordSource);
5939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Log.v(TAG, "      at " + mSamplingRate + "Hz");
5949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
5959b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        try {
5969b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate,
5979b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    mChannelConfig, mAudioFormat, 2 * minRecordBuffSizeInBytes);
5989b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        } catch (IllegalArgumentException e) {
59986df641ad36b8a57cc2c49db7d7df2606273261erago            Log.v(TAG, "Error: " + e.toString());
6009b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return false;
6019b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
6029b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
6039b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder.release();
6049b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mRecorder = null;
60586df641ad36b8a57cc2c49db7d7df2606273261erago            Log.v(TAG, "Error: mRecorder not initialized");
6069b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            return false;
6079b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
6089b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mRecorder.setRecordPositionUpdateListener(this);
6099b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
6109b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        return true;
6119b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
6129b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6139b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // ---------------------------------------------------------
6149b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // Implementation of AudioRecord.OnPeriodicNotificationListener
6159b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // --------------------
6169b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    public void onPeriodicNotification(AudioRecord recorder) {
6179b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int samplesAvailable = mPipe.availableToRead();
6189b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int samplesNeeded = mBlockSizeSamples;
6199b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        if (samplesAvailable >= samplesNeeded) {
6209b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mPipe.read(mAudioShortArray2, 0, samplesNeeded);
6219b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6229b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //compute stuff.
6239b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double maxval = Math.pow(2, 15);
6249b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            int clipcount = 0;
6259b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double cliplevel = (maxval-10) / maxval;
6269b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double sum = 0;
6279b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double maxabs = 0;
6289b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            int i;
6299b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            int index = 0;
6309b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6319b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (i = 0; i < samplesNeeded; i++) {
6329b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                double value = mAudioShortArray2[i] / maxval;
6339b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                double valueabs = Math.abs(value);
6349b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6359b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (valueabs > maxabs) {
6369b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    maxabs = valueabs;
6379b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
6389b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6399b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (valueabs > cliplevel) {
6409b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    clipcount++;
6419b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
6429b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6439b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                sum += value * value;
6449b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                //fft stuff
6459b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                if (index < mBlockSizeSamples) {
6469b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    mData.mData[index] = value;
6479b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                }
6489b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                index++;
6499b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
6509b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6519b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //for the current frame, compute FFT and send to the viewer.
6529b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6539b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            //apply window and pack as complex for now.
6549b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            DspBufferMath.mult(mData, mData, mWindow.mBuffer);
6559b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            DspBufferMath.set(mC, mData);
6569b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mFftServer.fft(mC, 1);
6579b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6589b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            double[] halfMagnitude = new double[mBlockSizeSamples / 2];
6599b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            for (i = 0; i < mBlockSizeSamples / 2; i++) {
6609b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
6619b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
6629b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6639b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
6649b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6659b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            switch(mCurrentTest) {
6669b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                case 0:
6679b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    mFreqAverage0.setData(halfMagnitude, false);
6689b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    break;
6699b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                case 1:
6709b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    mFreqAverage1.setData(halfMagnitude, false);
6719b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                    break;
6729b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
6739b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
6749b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
6759b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6769b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    public void onMarkerReached(AudioRecord track) {
6779b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
6789b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6799b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // ---------------------------------------------------------
6809b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // Implementation of Runnable for the audio recording + playback
6819b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    // --------------------
6829b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    public void run() {
6839b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        int nSamplesRead = 0;
6849b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia
6859b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        Thread thisThread = Thread.currentThread();
6869b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        while (mRecordThread == thisThread && !mRecordThreadShutdown) {
6879b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            // read from native recorder
6889b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBufferSizeInSamples);
6899b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            if (nSamplesRead > 0) {
6909b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia                mPipe.write(mAudioShortArray, 0, nSamplesRead);
6919b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia            }
6929b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia        }
6939b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia    }
6949b2e1681f819520fa41cf8d8c54df893f59109f5Ricardo Garcia}
695