blob: 94db1767a86a42d74cf6e3b9ceec79f16b010805 [file] [log] [blame]
/*---------------------------------------------------------------------------*
* MicrophoneInputStream.java *
* *
* Copyright 2007 Nuance Communciations, Inc. *
* *
* 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.speech.srec;
import java.io.IOException;
import java.io.InputStream;
import java.lang.IllegalStateException;
/**
* PCM input stream from the microphone, 16 bits per sample.
*/
public final class MicrophoneInputStream extends InputStream {
static {
System.loadLibrary("srec_jni");
}
private final static String TAG = "MicrophoneInputStream";
private long mAudioRecord = 0;
private byte[] mOneByte = new byte[1];
/**
* MicrophoneInputStream constructor.
* @param sampleRate sample rate of the microphone, typically 11025 or 8000.
* @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks.
* This determines how long an application may delay before losing data.
*/
public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException {
mAudioRecord = AudioRecordNew(sampleRate, fifoDepth);
if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?");
int status = AudioRecordStart(mAudioRecord);
if (status != 0) {
close();
throw new IOException("AudioRecord start failed: " + status);
}
}
@Override
public int read() throws IOException {
if (mAudioRecord == 0) throw new IllegalStateException("not open");
int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1);
return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1;
}
@Override
public int read(byte[] b) throws IOException {
if (mAudioRecord == 0) throw new IllegalStateException("not open");
return AudioRecordRead(mAudioRecord, b, 0, b.length);
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if (mAudioRecord == 0) throw new IllegalStateException("not open");
// TODO: should we force all reads to be a multiple of the sample size?
return AudioRecordRead(mAudioRecord, b, offset, length);
}
/**
* Closes this stream.
*/
@Override
public void close() throws IOException {
if (mAudioRecord != 0) {
try {
AudioRecordStop(mAudioRecord);
} finally {
try {
AudioRecordDelete(mAudioRecord);
} finally {
mAudioRecord = 0;
}
}
}
}
@Override
protected void finalize() throws Throwable {
if (mAudioRecord != 0) {
close();
throw new IOException("someone forgot to close MicrophoneInputStream");
}
}
//
// AudioRecord JNI interface
//
private static native long AudioRecordNew(int sampleRate, int fifoDepth);
private static native int AudioRecordStart(long audioRecord);
private static native int AudioRecordRead(long audioRecord, byte[] b, int offset, int length) throws IOException;
private static native void AudioRecordStop(long audioRecord) throws IOException;
private static native void AudioRecordDelete(long audioRecord) throws IOException;
}