我正在尝试编写一个记录和播放语音的应用程序。我为此使用了AudioRecord / AudioTrack API。要求是我需要对从AudioRecord对象读取的音频数据进行编码,并在将其写入要播放的AudioTrack对象之前使用opus编解码器对其进行解码。我能够实现录制和编码。但录制的音频在解码后无法播放。
以下是我使用的文件:
Playback.java
public class Playback {
private static String TAG = "Playback";
public boolean isPlaying = false;
public boolean isStopped = false;
private boolean shouldStopPlaying = false;
private int frequency = 48000;
private int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int numberOfChannels = 1;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
private int frameSize = 120;
private final int audioRecBufferSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
public void playFile (File file)
{
this.shouldStopPlaying = false;
this.isPlaying = true;
FileInputStream inputStream = this.initInputStreamForFile(file);
AudioTrack atrack = new AudioTrack(AudioManager.STREAM_MUSIC,frequency,
channelConfiguration, audioEncoding, audioRecBufferSize,
AudioTrack.MODE_STREAM);
atrack.play();
int bytesRead = 0;
short[] buffer = new short[audioRecBufferSize];
OpusDecoder decoder = new OpusDecoder(inputStream, frequency, numberOfChannels,
frameSize);
Log.d(TAG, "Audio length of file to be played: " + file.length());
while (!shouldStopPlaying && bytesRead < file.length()) {
try {
bytesRead += decoder.read(buffer);
atrack.write(buffer, 0, buffer.length);
//atrack.flush();
//Log.d(TAG, "Buffer size in frames: " + atrack.getBufferSizeInFrames());
//Log.d(TAG, "Buffer length: " + buffer.length);
//Log.d(TAG, "Audio buffer after decoding: " + Arrays.toString(buffer));
}
catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage(), e);
break;
}
}
atrack.stop();
this.isPlaying = false;
}
private FileInputStream initInputStreamForFile(File file) {
try {
return new FileInputStream(file);
}
catch (FileNotFoundException e) {
Log.e(TAG, e.getLocalizedMessage(), e);
return null;
}
}
public void stopPlaying() {
this.shouldStopPlaying = true;
}
}
OpusDecoder
public class OpusDecoder extends FilterInputStream {
private static String TAG = "OpusDecoder";
private native boolean nativeInitDecoder(int samplingRate, int numberOfChannels, int frameSize);
private native int nativeDecodeBytes(byte[] in, short[] out);
private native boolean nativeReleaseDecoder();
private InputStream in;
static
{
try
{
System.loadLibrary("OpusDecoder");
}
catch (Exception e)
{
Log.e(TAG, "Could not load SystemLibrary 'OpusDecoder");
}
}
protected OpusDecoder(InputStream in)
{
this(in, 48000, 1, 5760);
}
public OpusDecoder(InputStream in, int frequency, int numberOfChannels, int frameSize)
{
super(in);
this.in = in;
this.nativeInitDecoder(frequency, numberOfChannels, frameSize);
}
@Override
public int read() throws IOException {
throw new UnsupportedOperationException("Method not implemented in inheriting class");
}
@Override
public int read(byte[] buffer) throws IOException {
throw new UnsupportedOperationException(("Method not implemented in inheriting class for " +
"byte[]. Please use short[]."));
}
public int read(short[] buffer) throws IOException {
Log.d(TAG, "Buffer Size: " + buffer.length);
byte[] encodedBuffer;
int bytesEncoded = this.in.read();
int bytesDecoded = 0;
Log.d(TAG, bytesEncoded + " bytes read from input stream");
if (bytesEncoded >= 0) {
encodedBuffer = new byte[bytesEncoded];
int bytesRead = this.in.read(encodedBuffer);
// Log.d(TAG, "Bytes read before decoding: " + bytesRead);
// Log.d(TAG, "Buffer before decoding: " + Arrays.toString(encodedBuffer));
bytesDecoded = nativeDecodeBytes(encodedBuffer, buffer);
// Log.d(TAG, bytesDecoded + " bytes decoded");
}
return bytesDecoded;
}
@Override
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
throw new UnsupportedOperationException("Method not implemented in inheriting class");
}
@Override
public void close() throws IOException {
this.in.close();
this.nativeReleaseDecoder();
}
}