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相关的详细说明吗?在线等回复......