OpenHarmony 源码解析之多媒体子系统(音频框架一) 原创 精华
作者:苑春鸽
1 简介
本文档基于 OpenHarmony 3.0-LTS 源码的轻量系统、小型系统编写
因鸿蒙系统目前处在快速发展时期,本文中的一些内容可能会过时,建议在阅读的同时参考最新代码以了解更实时的知识。
音频采集是多媒体系统中最基础最重要的部分之一,OpenHarmony audio_lite 框架有着丰富的音频采集功能,支持麦克风、电话、摄像机等多种音频输入源设备,支持PCM、AAC_LC、AAC_HE_V1等多种编解码格式,支持闹钟、音乐、铃声等多种音频流类型以及满足不同品质的音频数据需求。
1.1 多媒体子系统源码系列
【OpenHarmony 源码解析之多媒体子系统(camera) 】
【OpenHarmony 源码解析之多媒体子系统(音频框架一)】
1.2 OpenHarmony架构图

1.3 架构图

1.4 文件目录
~/foundation/multimedia/audio_lite$ tree
├── frameworks	# 框架代码
│   ├── audio_capturer.cpp	# 音频采集
│   ├── audio_capturer_impl.cpp
│   ├── audio_capturer_impl.h
│   ├── audio_encoder	# 音频编解码
│   │   ├── audio_encoder.cpp
│   │   └── include
│   │       └── audio_encoder.h
│   └── audio_source	# 音频输入源
│       ├── audio_source.cpp
│       └── include
│           └── audio_source.h
└── interfaces	# 接口
    └── kits	# 对外接口
        └── audio_capturer.h
2 环境准备
2.1 开发环境、编译环境搭建
参考官方文档,参考链接如下:搭建Ubuntu环境(获取源码及编译,Docker方式)
3 音频采集

3.1 音频信息采集流程
- 
初始化
通过AudioCapturer调用AudioCapturerImpl中的SetCapturerInfo方法,初始化采集状态,获取适配输入源类型的设备,配置并初始化输入源,编解码等
 
int32_t AudioCapturer::AudioCapturerImpl::SetCapturerInfo(const AudioCapturerInfo info)
{
    ...
    
    // 判断采集状态初始化
    if (status_ != INITIALIZED) {
        MEDIA_ERR_LOG("check state:%u failed", status_);
        return ERR_ILLEGAL_STATE;
    }
    
    // 获取设备
    std::vector<AudioDeviceDesc> devices;
    int32_t ret = audioSource_->EnumDeviceBySourceType(info.inputSource, devices);
    
    ...
    
    // 配置输入源参数并初始化
    AudioSourceConfig sourceConfig;
    sourceConfig.deviceId = devices[0].deviceId;
    ...  
    ret = audioSource_->Initialize(sourceConfig);
    ...
        
    // 配置编解码参数并初始化   
    AudioEncodeConfig encodeConfig;
    encodeConfig.audioFormat = info.audioFormat;
    ...
    ret = audioEncoder_->Initialize(encodeConfig);
       
    ...
    return SUCCESS;
}
- 
开始音频采集
调用AudioCapturerImpl中的Record方法检查采集状态,开始采集音频,绑定音频源到当前设备并开始编解码
 
bool AudioCapturer::AudioCapturerImpl::Record()
{
    ...
    
    // 开始采集音频源    
    int32_t ret = audioSource_->Start();
    ...
    // 获取当前设备Id
    ret = audioSource_->GetCurrentDeviceId(deviceId);
	
    ...
    
    // 绑定音频源到当前设备
    ret = audioEncoder_->BindSource(deviceId);
    
	...
        
    // 开始编解码
    ret = audioEncoder_->Start();
	
    ...
        
    return true;
}
- 
获取音频数据
在满足采集状态等的条件下,通过传出参数buffer获取音频数据,如果编解码格式为“PCM”或者是缺省值,则直接获取音频数据,否则进行编解码获取音频数据
 
int32_t AudioCapturer::AudioCapturerImpl::Read(uint8_t *buffer, size_t userSize, bool isBlockingRead)
{
	...
     
    // 音频帧方式
    if (info_.audioFormat == PCM || info_.audioFormat == AUDIO_DEFAULT) {
        AudioFrame frame;
        ...
            
        readLen = audioSource_->ReadFrame(frame, isBlockingRead);
        
		...
            
    } else {	//音频流方式
        AudioStream stream;
        
        ...
            
        readLen = audioEncoder_->ReadStream(stream, isBlockingRead);
        
      	...
            
    }
    return readLen;
}
3.2 音频相关结构体
// audio_capturer.h
// 音频采集信息
struct AudioCapturerInfo {
    AudioSourceType inputSource = AUDIO_MIC;	// 音频源类型
    AudioCodecFormat audioFormat = AUDIO_DEFAULT;	// 编解码格式
    int32_t sampleRate = 0;	// 采样率
    int32_t channelCount = 0;	// 通道数
    int32_t bitRate = 0;	// 码率
    AudioStreamType streamType = TYPE_MEDIA;	// 音频流类型
    AudioBitWidth bitWidth = BIT_WIDTH_16;	// 采样位宽
};
// 采集状态
enum State : uint32_t {
    INITIALIZED,	// 初始化
    PREPARED,	// 准备
    RECORDING,	// 采集中
    STOPPED,	// 停止
    RELEASED	// 销毁
};
// audio_encoder.h
// 音频编解码配置
struct AudioEncodeConfig {
    AudioCodecFormat audioFormat;//音频格式
    uint32_t bitRate = 0;//码率
    uint32_t sampleRate = 0;//采样率
    uint32_t channelCount = 0;//通道数量
    AudioBitWidth bitWidth = BIT_WIDTH_16;//采样位宽
};
// audio_source.h
struct AudioSourceConfig {
    uint32_t deviceId;//设备Id
    AudioCodecFormat audioFormat;//音频格式
    int32_t sampleRate = 0;//采样率
    int32_t channelCount = 0;//通道数量
    bool interleaved;
    AudioBitWidth bitWidth = BIT_WIDTH_16;//音频位宽
    AudioStreamType streamUsage;//音频流类型
};
// ~/foundation/multimedia/utils/lite/interfaces/kits/media_info.h
// 音频输入源类型
typedef enum {
    AUDIO_SOURCE_INVALID = -1,	// 无效的音频源
    AUDIO_SOURCE_DEFAULT = 0,	// 默认的音频源
    AUDIO_MIC = 1,	// 麦克风
    AUDIO_VOICE_UPLINK = 2,	// 电话上行
    AUDIO_VOICE_DOWNLINK = 3,	// 电话下行
    AUDIO_VOICE_CALL = 4,	// 电话含上下行
    AUDIO_CAMCORDER = 5,	// 摄像机音频源
    AUDIO_VOICE_RECOGNITION = 6,	// 语音识别
    AUDIO_VOICE_COMMUNICATION = 7,	// 电话通信
    AUDIO_REMOTE_SUBMIX = 8,	// 远程设备输入音频源
    AUDIO_UNPROCESSED = 9,	// 未被处理的音频源
    AUDIO_VOICE_PERFORMANCE = 10,	// 声乐
    AUDIO_ECHO_REFERENCE = 1997,	// 回声
    AUDIO_RADIO_TUNER = 1998,	// 广播调谐器
    AUDIO_HOTWORD = 1999,
    AUDIO_REMOTE_SUBMIX_EXTEND = 10007,	// 扩展的远程设备输入音频源
} AudioSourceType;
// 音频设备描述
typedef struct {
    std::string deviceName;	// 设备名称
    AudioSourceType inputSourceType;	// 音频输入源的类型
    uint32_t deviceId;	// 31-24位:保留位; bits 23-16:模式ID; 15-8:设备ID; 7-0:通道ID  
} AudioDeviceDesc;
// 音频流类型
typedef enum {
    TYPE_DEFAULT = -1,	// 默认类型
    TYPE_MEDIA = 0,	// 媒体
    TYPE_VOICE_COMMUNICATION = 1,	// 语音电话
    TYPE_SYSTEM = 2,	// 系统声音
    TYPE_RING = 3,	// 手机铃声
    TYPE_MUSIC = 4,	// 音乐
    TYPE_ALARM = 5,	// 闹钟
    TYPE_NOTIFICATION = 6,	// 通知声音
    TYPE_BLUETOOTH_SCO = 7,	// 蓝牙同步面向连接
    TYPE_ENFORCED_AUDIBLE = 8,	// 强制提示音
    TYPE_DTMF = 9, // 双音多频
    TYPE_TTS = 10,	// 文本转语音
    TYPE_ACCESSIBILITY = 11,	// 辅助提示音
} AudioStreamType;
// 音频编解码格式
typedef enum {
    AUDIO_DEFAULT    = 0,
    PCM              = 1,
    AAC_LC           = 2,
    AAC_HE_V1        = 3,
    AAC_HE_V2        = 4,
    AAC_LD           = 5,
    AAC_ELD          = 6,
    G711A            = 7,
    G711U            = 8,
    G726             = 9,
    FORMAT_BUTT,
} AudioCodecFormat;
// 采样位宽
typedef enum {
    BIT_WIDTH_8   = 8,
    BIT_WIDTH_16  = 16,
    BIT_WIDTH_24  = 24,
    BIT_WIDTH_32  = 32,
    BIT_WIDTH_BUTT,
} AudioBitWidth;
3.3 音频相关接口
| 类名 | 接口名 | 描述 | 
|---|---|---|
| AudioCapturer | static bool GetMinFrameCount(int32_t sampleRate, int32_t channelCount, <br /> AudioCodecFormat audioFormat, size_t &frameCount); | 获取最小帧数 | 
| AudioCapturer | uint64_t GetFrameCount() | 获取当前条件下所需的帧数 | 
| AudioCapturer | int32_t SetCapturerInfo(const AudioCapturerInfo info) | 设置采集参数 | 
| AudioCapturer | int32_t GetCapturerInfo(AudioCapturerInfo &info) | 获取采样参数 | 
| AudioCapturer | bool Start() | 开始采集 | 
| AudioCapturer | int32_t Read(uint8_t *buffer, size_t userSize, bool isBlockingRead) | 读取音频数据 | 
| AudioCapturer | State GetStatus() | 获取采集状态 | 
| AudioCapturer | bool GetAudioTime(Timestamp ×tamp, Timestamp::Timebase base) | 获取时间戳 | 
| AudioCapturer | bool Stop() | 停止采集 | 
| AudioCapturer | bool Release() | 销毁 | 
| AudioEncoder | int32_t Initialize(const AudioEncodeConfig &config) | 根据给定的配置初始化音频源 | 
| AudioEncoder | int32_t BindSource(uint32_t deviceId) | 绑定音频源到给定的设备 | 
| AudioEncoder | int32_t GetMute(bool &muted) | 获取当前编码器的静音状态 | 
| AudioEncoder | int32_t SetMute(bool muted) | 设置当前编码器的静音状态 | 
| AudioEncoder | int32_t Start() | 开始 | 
| AudioEncoder | int32_t ReadStream(AudioStream &stream, bool isBlockingRead) | 读取音频流 | 
| AudioEncoder | int32_t Stop() | 停止 | 
| AudioEncoder | int32_t Release() | 销毁 | 
| AudioSource | int32_t EnumDeviceBySourceType(AudioSourceType inputSource, <br /> std::vector<AudioDeviceDesc> &devices) | 当前音频源类型支持的设备 | 
| AudioSource | static bool GetMinFrameCount(int32_t sampleRate, int32_t channelCount,<br/> AudioCodecFormat audioFormat, size_t &frameCount) | 获取指定条件下的最小帧数 | 
| AudioSource | uint64_t GetFrameCount() | 获取当前配置条件下的帧数 | 
| AudioSource | int32_t Initialize(const AudioSourceConfig &config) | 根据给定的配置参数初始化 | 
| AudioSource | int32_t SetInputDevice(uint32_t deviceId) | 设置切换设备时输入设备的标识 | 
| AudioSource | int32_t GetCurrentDeviceId(uint32_t &deviceId) | 获取当前设备Id | 
| AudioSource | int32_t Start() | 开始 | 
| AudioSource | int32_t ReadFrame(AudioFrame &frame, bool isBlockingRead) | 读取源数据帧 | 
| AudioSource | int32_t Stop() | 停止 | 
| AudioSource | int32_t Release() | 销毁 | 
4 总结
Audio是多媒体中重要的组成部分,对于系统开发者和应用开发者来说,都很有必要去深入了解。
对于想进一步了解的同学们,敬请期待我们后续将要分享的 《OpenHarmony 源码解析之多媒体子系统(音频框架 L2)》,在这篇我们会进一步的进行分析。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。





















跟开鸿的老师一起学鸿蒙。
哈哈哈,大家相互学习
老师们,有播放器media_lite相关的详细说明吗?在线等回复......