Android 音频源码分析——AndroidRecord录音(二)

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
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android系统源码是按照功能进行分类的,主要分为系统代码、工具、文档、开发环境、虚拟机、配置脚本和编译脚本等类别。其中,系统代码是Android系统的核心部分,包含了各个功能模块的实现代码。工具包括了用于Android系统开发和调试的工具,例如adb、emulator等。文档部分包含了Android系统的开发文档和相关说明。开发环境是Android系统的开发所需的各种环境、库和工具。虚拟机是用于运行Android应用程序的Dalvik虚拟机。配置脚本和编译脚本是用于配置和编译Android系统的脚本文件。 Android系统采用的是一个从BSD继承而来的标准的系统函数库bionic。它是一个轻量级的C库,专门为Android系统进行了优化和定制。在源码根目录下有bionic文件夹,它包含了bionic库的源代码和相关文件。 Android4.3程序库的类型非常多,功能也非常强大。其中一些常用且重要的系统程序库包括: - libcore:Android系统的核心库,提供了Java核心类库的实现,包括集合、IO、网络等功能。 - libandroid_runtime:Android运行时库,提供了Android应用程序运行所需的功能,例如应用程序的启动和管理、进程间通信等。 - libui:Android系统的用户界面库,提供了绘制窗口、图形渲染等功能。 - libsqlite:SQLite数据库库,提供了数据库的管理和操作功能。 - libmedia:媒体库,提供了音频和视频的播放和录制功能。 以上是Android系统源码分析的一些基本信息。如果你有更具体的问题,可以告诉我,我会尽力帮助你。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值