OpenHarmony 源码解析之多媒体子系统(音频框架一) 原创 精华

深开鸿
发布于 2021-11-18 17:03
浏览
3收藏

作者:苑春鸽

1 简介

本文档基于 OpenHarmony 3.0-LTS 源码的轻量系统、小型系统编写

因鸿蒙系统目前处在快速发展时期,本文中的一些内容可能会过时,建议在阅读的同时参考最新代码以了解更实时的知识。

音频采集是多媒体系统中最基础最重要的部分之一,OpenHarmony audio_lite 框架有着丰富的音频采集功能,支持麦克风、电话、摄像机等多种音频输入源设备,支持PCM、AAC_LC、AAC_HE_V1等多种编解码格式,支持闹钟、音乐、铃声等多种音频流类型以及满足不同品质的音频数据需求。

1.1 多媒体子系统源码系列

【OpenHarmony 源码解析之多媒体子系统(camera) 】

【OpenHarmony 源码解析之多媒体子系统(音频框架一)】

1.2 OpenHarmony架构图

OpenHarmony 源码解析之多媒体子系统(音频框架一) -鸿蒙开发者社区

1.3 架构图

OpenHarmony 源码解析之多媒体子系统(音频框架一) -鸿蒙开发者社区

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 音频采集

OpenHarmony 源码解析之多媒体子系统(音频框架一) -鸿蒙开发者社区

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 &timestamp, 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开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
audio_lite.tar.gz 189.07K 46次下载
已于2021-12-30 17:55:31修改
3
收藏 3
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

跟开鸿的老师一起学鸿蒙。

回复
2021-11-18 17:48:39
深开鸿
深开鸿 回复了 红叶亦知秋
跟开鸿的老师一起学鸿蒙。

哈哈哈,大家相互学习

回复
2021-11-18 18:01:07
不见不念o
不见不念o

老师们,有播放器media_lite相关的详细说明吗?在线等回复......

回复
2023-3-25 16:27:59
回复
    相关推荐