Android 音频源码分析——AndroidRecord录音(一)
Android 音频源码分析——AndroidRecord录音(二)
Android 音频源码分析——AndroidRecord音频数据传输流程
接着上一篇继续分析AndroidRecord 源码
1 AudioRecord.read
AudioRecord read 函数有多个。
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@ReadMode int readMode)
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts)
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@ReadMode int readMode)
public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
@ReadMode int readMode)
public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes)
public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)
- audioData格式不同.
- readMode READ_BLOCKING阻塞读数据, READ_NON_BLOCKING 非阻塞读,立刻返回。
这多个函数,实现基本一致,只是格式差异,我这边以此为例进行分析:
read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)
默认readMode 为阻塞方式。
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
}
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@ReadMode int readMode) {
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION;
}
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
return ERROR_BAD_VALUE;
}
if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
|| (offsetInBytes + sizeInBytes < 0) // detect integer overflow
|| (offsetInBytes + sizeInBytes > audioData.length)) {
return ERROR_BAD_VALUE;
}
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
readMode == READ_BLOCKING);
}
native_read_in_byte_array为native 方法。
接着看jni 中对应方法;
template <typename T>
static jint android_media_AudioRecord_readInArray(JNIEnv *env, jobject thiz,
T javaAudioData,
jint offsetInSamples, jint sizeInSamples,
jboolean isReadBlocking) {
// 获取audio recorder,将从中读取新的音频样本
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL) {
ALOGE("Unable to retrieve AudioRecord object");
return (jint)AUDIO_JAVA_INVALID_OPERATION;
}
if (javaAudioData == NULL) {
ALOGE("Invalid Java array to store recorded audio");
return (jint)AUDIO_JAVA_BAD_VALUE;
}
// 获取保存数据的指针
auto *recordBuff = envGetArrayElements(env, javaAudioData, NULL);
if (recordBuff == NULL) {
ALOGE("Error retrieving destination for recorded audio data");
return (jint)AUDIO_JAVA_BAD_VALUE;
}
// 从本地AudioRecord对象读取新的音频数据
const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
ssize_t readSize = lpRecorder->read(
recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
//释放该数组的引用
envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
if (readSize < 0) {
return interpretReadSizeError(readSize);
}
return (jint)(readSize / sizeof(*recordBuff));
}
- template C++的模板,对于参数byte、short、float、ByteBuffer,使用同一方法;
- 转换需要读取的字节数量;
- 调用native AudioRecord read函数。
AudioRecord.cpp
接着看read函数
ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking)
{
if (mTransfer != TRANSFER_SYNC) {
return INVALID_OPERATION;
}
if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
// 完整性检查。 用户最有可能传递错误代码,这会使返回值不明确(actualSize vs error)。
return BAD_VALUE;
}
ssize_t read = 0;
Buffer audioBuffer;
while (userSize >= mFra