【Android RTMP】音频数据采集编码 ( FAAC 头文件与静态库拷贝到 AS | CMakeList.txt 配置 FAAC | AudioRecord 音频采样 PCM 格式 )

2023-03-27 21:35:51 浏览数 (1)

文章目录

  • 一、 FAAC 头文件与静态库拷贝到 Android Studio
  • 二、 CMakeList.txt 构建脚本配置
  • 三、 Java 层 AudioRecord 音频采样 PCM 格式
  • 四、 Java 层 AudioRecord 音频采样 PCM 格式代码示例

一、 FAAC 头文件与静态库拷贝到 Android Studio


将 PCM 音频采样编码成 AAC 格式 , 需要使用 FAAC编码器 , 在上一篇博客 【Android RTMP】音频数据采集编码 ( 音频数据采集编码 | AAC 高级音频编码 | FAAC 编码器 | Ubuntu 交叉编译 FAAC 编码器 ) 中完成了对 FAAC 音频编码器的交叉编译 , 交叉编译结果如下 :

代码语言:javascript复制
root@octopus:~/rtmp/faac-1.29.9.2/android# tree
.
└── armeabi-v7a
    ├── bin
    │   └── faac
    ├── include
    │   ├── faaccfg.h
    │   └── faac.h
    ├── lib
    │   ├── libfaac.a
    │   └── libfaac.la
    └── share
        └── man
            └── man1
                └── faac.1

2

个头文件 faaccfg.h , faac.h 拷贝到 Android Studio 项目中的 src/main/cpp/include 目录中 , 将 libfaac.a 静态库拷贝到 src/main/cpp/libs/armeabi-v7a 目录中 ;

二、 CMakeList.txt 构建脚本配置


将头文件与函数库拷贝到 Android Studio 项目中后 , 配置 CMakeList.txt 构建脚本 , 主要配置头文件与函数库的搜索路径 , 让编译工具可以找到对应的 FAAC 库的头文件与静态库 ;

1 . 设置头文件搜索路径 :

代码语言:javascript复制
# 设置头文件搜索路径
include_directories(include)

2 . 设置函数库搜索路径 :

代码语言:javascript复制
# 通过设置编译选项, 设置函数库的搜索路径
# 此处的 ANDROID_ABI 是在
# build.gradle android->defaultConfig->externalNativeBuild->cmake
# 下的 abiFilters 中设置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")

3 . 完整的 CMakeList.txt 文件 :

代码语言:javascript复制
cmake_minimum_required(VERSION 3.4.1)

# 链接 src/main/cpp/librtmp 目录下的构建脚本
add_subdirectory(librtmp)

add_library( # 函数库名称
             native-lib

             # 动态库类型
             SHARED

             # 源文件
             native-lib.cpp
             VedioChannel.cpp)

find_library( # 日志库
              log-lib

              log )

# 设置头文件搜索路径
include_directories(include)

# 通过设置编译选项, 设置函数库的搜索路径
# 此处的 ANDROID_ABI 是在
# build.gradle android->defaultConfig->externalNativeBuild->cmake
# 下的 abiFilters 中设置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")

target_link_libraries( # 链接动态库
                       native-lib

                       # 编译的 rtmp 静态库
                       rtmp
                       # 查找到的 x264 静态库
                       x264
                       # 查找到的 faac 静态库
                       faac

                       ${log-lib} )

三、 Java 层 AudioRecord 音频采样 PCM 格式


1 . 初始化 AudioRecord :

① 计算最小缓冲区大小 : 获取 44100 立体声 / 单声道 16 位采样率的最小缓冲区大小 , 使用最小缓冲区大小, 不能保证声音流畅平滑, 这里将缓冲区大小翻倍, 保证采集数据的流畅 , 否则会有电流产生

代码语言:javascript复制
int minBufferSize = AudioRecord.getMinBufferSize(44100,
        AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT) * 2;

② 创建 AudioRecord 对象 : AudioRecord 构造函数需要传入 音频来源 , 采样率 , 声道配置 , 采样位数 , 采样缓冲区大小 信息 ;

代码语言:javascript复制
AudioRecord mAudioRecord = new AudioRecord(
        MediaRecorder.AudioSource.MIC,  // 声音来源 麦克风
        44100,            // PCM 音频采样率 44100 Hz
        AudioFormat.CHANNEL_IN_STEREO,  // 立体声
        AudioFormat.ENCODING_PCM_16BIT, // 采样位数 16 位
        minBufferSize);                 // 最小采样缓冲区个数

③ AudioRecord 构造函数原型 :

代码语言:javascript复制
    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes)

① int audioSource 参数 : 声音来源, 麦克风 ;

② int sampleRateInHz 参数 : 音频采样率, 一般是 44100 Hz, 该采样率在所有设备支持比较好 ;

③ int channelConfig 参数 : 单声道 AudioFormat.CHANNEL_IN_MONO / 立体声 AudioFormat.CHANNEL_IN_STEREO ;

④ int audioFormat 参数 : 采样位数, 8 位 AudioFormat.ENCODING_PCM_8BIT / 16 , AudioFormat.ENCODING_PCM_16BIT ;

⑤ int bufferSizeInBytes 参数 : 每次采集数据的最大缓冲区大小 ;

2 . PCM 音频采样线程 :

① 独立线程封装 : 音频采样需要持续进行操作 , 并且该操作非常耗时 , 肯定要封装在一个独立线程中完成 ;

② 开始采样 : 调用 AudioRecord 对象的 startRecording 方法 , 开始进行音频采样 ;

代码语言:javascript复制
mAudioRecord.startRecording();

③ 读取数据 : 循环读取麦克风采样数据 , 调用 AudioRecord 对象的 read 方法 , 可以获取麦克风采样的数据 ;

④ 停止采样 : 调用 AudioRecord 对象的 stop 方法 , 可以停止采样 ;

代码语言:javascript复制
mAudioRecord.stop();

⑤ 代码示例 :

代码语言:javascript复制
/**
 * 音频采样线程
 */
class AudioSampling implements Runnable{
    @Override
    public void run() {
        // 开始录音采样
        mAudioRecord.startRecording();
        while (isStartPush){
            // 循环读取录音, 需要传入一系列参数
            //mAudioRecord.read( ... );
        }
        // 停止录音采样
        mAudioRecord.stop();
    }
}

四、 Java 层 AudioRecord 音频采样 PCM 格式代码示例


代码语言:javascript复制
package kim.hsl.rtmp;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 音频处理类
 * 音频采样, 编码, 推流控制
 */
public class AudioChannel {

    /**
     * 直播推流器
     */
    private LivePusher mLivePusher;

    /**
     * 音频录制对象
     */
    private AudioRecord mAudioRecord;

    /**
     * 是否已经开始推流
     */
    private boolean isStartPush;

    /**
     * 单线程线程池, 在该线程中进行音频采样
     */
    private ExecutorService mExecutorService;

    public AudioChannel(LivePusher mLivePusher) {
        this.mLivePusher = mLivePusher;

        // 初始化线程池, 单线程线程池
        mExecutorService = Executors.newSingleThreadExecutor();

        /*
            获取 44100 立体声 / 单声道 16 位采样率的最小缓冲区大小
            使用最小缓冲区大小, 不能保证声音流畅平滑, 这里将缓冲区大小翻倍, 保证采集数据的流畅
            否则会有电流产生
         */
        int minBufferSize = AudioRecord.getMinBufferSize(44100,
                AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT) * 2;
        /*
            public AudioRecord(int audioSource, int sampleRateInHz,
                               int channelConfig, int audioFormat,
                               int bufferSizeInBytes)

            int audioSource 参数 : 声音来源, 麦克风
            int sampleRateInHz 参数 : 音频采样率, 一般是 44100 Hz, 该采样率在所有设备支持比较好
            int channelConfig 参数 : 单声道 AudioFormat.CHANNEL_IN_MONO / 立体声 AudioFormat.CHANNEL_IN_STEREO,
            int audioFormat 参数 : 采样位数, 8 位 AudioFormat.ENCODING_PCM_8BIT / 16 位 AudioFormat.ENCODING_PCM_16BIT
            int bufferSizeInBytes 参数 : 每次采集数据的最大缓冲区大小

         */
        mAudioRecord = new AudioRecord(
                MediaRecorder.AudioSource.MIC,  // 声音来源 麦克风
                44100,            // PCM 音频采样率 44100 Hz
                AudioFormat.CHANNEL_IN_STEREO,  // 立体声
                AudioFormat.ENCODING_PCM_16BIT, // 采样位数 16 位
                minBufferSize);                 // 最小采样缓冲区个数
    }

    /**
     * 开始推流
     */
    public void startLive() {
        isStartPush = true;
        // 执行音频采样线程
        // 如果在启动一个线程, 后续线程就会排队等待
        mExecutorService.submit(new AudioSampling());
    }

    /**
     * 停止推流
     */
    public void stopLive() {
        isStartPush = false;
    }

    public void release(){
        //释放音频录音对象
        mAudioRecord.release();
    }

    /**
     * 音频采样线程
     */
    class AudioSampling implements Runnable{
        @Override
        public void run() {
            // 开始录音采样
            mAudioRecord.startRecording();

            while (isStartPush){
                // 循环读取录音
                mAudioRecord.read();
            }

            // 停止录音采样
            mAudioRecord.stop();
        }
    }
}

0 人点赞