19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*---------------------------------------------------------------------------*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  MicrophoneInputStream.java                                               *
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *                                                                           *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  Copyright 2007 Nuance Communciations, Inc.                               *
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *                                                                           *
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  Licensed under the Apache License, Version 2.0 (the 'License');          *
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  you may not use this file except in compliance with the License.         *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *                                                                           *
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  You may obtain a copy of the License at                                  *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0                           *
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *                                                                           *
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software      *
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  distributed under the License is distributed on an 'AS IS' BASIS,        *
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  See the License for the specific language governing permissions and      *
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  limitations under the License.                                           *
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *                                                                           *
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *---------------------------------------------------------------------------*/
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.speech.srec;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.IllegalStateException;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * PCM input stream from the microphone, 16 bits per sample.
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class MicrophoneInputStream extends InputStream {
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.loadLibrary("srec_jni");
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String TAG = "MicrophoneInputStream";
37bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private long mAudioRecord = 0;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private byte[] mOneByte = new byte[1];
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * MicrophoneInputStream constructor.
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sampleRate sample rate of the microphone, typically 11025 or 8000.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks.
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This determines how long an application may delay before losing data.
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioRecord = AudioRecordNew(sampleRate, fifoDepth);
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?");
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int status = AudioRecordStart(mAudioRecord);
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (status != 0) {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close();
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IOException("AudioRecord start failed: " + status);
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read() throws IOException {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord == 0) throw new IllegalStateException("not open");
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read(byte[] b) throws IOException {
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord == 0) throw new IllegalStateException("not open");
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return AudioRecordRead(mAudioRecord, b, 0, b.length);
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int read(byte[] b, int offset, int length) throws IOException {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord == 0) throw new IllegalStateException("not open");
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // TODO: should we force all reads to be a multiple of the sample size?
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return AudioRecordRead(mAudioRecord, b, offset, length);
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes this stream.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() throws IOException {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord != 0) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioRecordStop(mAudioRecord);
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    AudioRecordDelete(mAudioRecord);
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } finally {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAudioRecord = 0;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAudioRecord != 0) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close();
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IOException("someone forgot to close MicrophoneInputStream");
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // AudioRecord JNI interface
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //
105bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private static native long AudioRecordNew(int sampleRate, int fifoDepth);
106bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private static native int AudioRecordStart(long audioRecord);
107bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private static native int AudioRecordRead(long audioRecord, byte[] b, int offset, int length) throws IOException;
108bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private static native void AudioRecordStop(long audioRecord) throws IOException;
109bdebe1ad9573eec25f4acff89085530f490cc178Ashok Bhat    private static native void AudioRecordDelete(long audioRecord) throws IOException;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
111