跳到主要内容

实时渲染(C/C++)

从API version 22开始,OHAudioSuite给开发者提供音频实时渲染能力,即音频实时播放时可进行自定义音效(仅支持均衡器节点)。例如,可以使用均衡器中预置的音效,改变音乐的风格。

开发基础配置

开发者使用OHAudioSuite提供的实时渲染能力,添加对应的头文件。

在CMake脚本中链接动态库

target_link_libraries(sample PUBLIC libohaudio.so libohaudiosuite.so)

添加头文件

开发者通过引入头文件<native_audio_suite_base.h>、<native_audio_suite_engine.h>、<native_audiostreambuilder.h>和<native_audiorenderer.h>使用音频编创和音频播放相关API。

#include <ohaudiosuite/native_audio_suite_base.h>
#include <ohaudiosuite/native_audio_suite_engine.h>
#include <ohaudio/native_audiorenderer.h>
#include <ohaudio/native_audiostreambuilder.h>

开发步骤

接口调用

详细的API说明请参考OHAudioSuite

均衡器效果

图1:实时播放示意图

开发者可以通过以下步骤来实现一个简单的均衡器效果节点实时播放功能。

  1. 在初始化时,创建OHAudioSuite管线(包括输入节点、均衡器节点、输出节点)。

    struct AudioDataInfo {
    uint8_t *buffer = nullptr; // 音频数据。
    int32_t bufferSize = 0; // 音频数据总大小。
    int32_t totalWriteSize = 0; // 处理过的音频数据总大小。
    };

    // 输入节点请求数据的回调函数。
    static int32_t InputNodeWriteDataCallBack(
    OH_AudioNode *audioNode,
    void *userData,
    void *audioData,
    int32_t audioDataSize,
    bool *finished)
    {
    if ((audioNode == nullptr) || (userData == nullptr) ||
    (audioData == nullptr) || (audioDataSize <= 0) || (finished == nullptr)) {
    return -1;
    }

    struct AudioDataInfo *info = static_cast<struct AudioDataInfo *>(userData);
    // 要处理的音频大小。
    int32_t actualDataSize = std::min(audioDataSize, info->bufferSize - info->totalWriteSize);
    // 将PCM音频数据写入audioData。
    memcpy(static_cast<void *>(audioData), info->buffer + info->totalWriteSize, actualDataSize);
    info->totalWriteSize += actualDataSize;

    // 音频数据全部处理完。
    if (info->totalWriteSize >= info->bufferSize) {
    *finished = true;
    }
    return actualDataSize;
    }

    // 创建引擎。
    OH_AudioSuiteEngine *audioSuiteEngine = nullptr;
    OH_AudioSuiteEngine_Create(&audioSuiteEngine);

    // 创建实时渲染的管线。
    OH_AudioSuitePipeline *audioSuitePipeline;
    OH_AudioSuiteEngine_CreatePipeline(audioSuiteEngine, &audioSuitePipeline,
    OH_AudioSuite_PipelineWorkMode::AUDIOSUITE_PIPELINE_REALTIME_MODE);

    // 创建节点构造器。
    OH_AudioNodeBuilder *nodeBuilder = nullptr;
    OH_AudioSuiteNodeBuilder_Create(&nodeBuilder);
    OH_AudioSuiteNodeBuilder_SetNodeType(nodeBuilder, OH_AudioNode_Type::INPUT_NODE_TYPE_DEFAULT);

    // 配置音频数据格式,开发者根据要处理的音频数据格式设置采样率、声道分布、声道数、位深、编码格式参数。
    OH_AudioFormat audioFormatInput;
    audioFormatInput.samplingRate = OH_Audio_SampleRate::SAMPLE_RATE_48000;
    audioFormatInput.channelLayout = OH_AudioChannelLayout::CH_LAYOUT_STEREO;
    audioFormatInput.channelCount = 2;
    audioFormatInput.sampleFormat = OH_Audio_SampleFormat::AUDIO_SAMPLE_S16LE;
    audioFormatInput.encodingType = OH_Audio_EncodingType::AUDIO_ENCODING_TYPE_RAW;
    OH_AudioSuiteNodeBuilder_SetFormat(nodeBuilder, audioFormatInput);
    // 设置音频流的回调。
    struct AudioDataInfo audioInfo;
    audioInfo.buffer = nullptr; // 开发者根据业务场景存放要处理的音频数据。
    audioInfo.bufferSize = 0; // 开发者根据业务场景存放要处理的音频数据大小。
    audioInfo.totalWriteSize = 0;
    void *userData = static_cast<void *>(&audioInfo);
    OH_AudioSuiteNodeBuilder_SetRequestDataCallback(nodeBuilder, InputNodeWriteDataCallBack, userData);
    // 创建输入节点。
    OH_AudioNode *inputNode = nullptr;
    OH_AudioSuiteEngine_CreateNode(audioSuitePipeline, nodeBuilder, &inputNode);

    // 重置构造器配置并设置为均衡器节点类型。
    OH_AudioSuiteNodeBuilder_Reset(nodeBuilder);
    OH_AudioSuiteNodeBuilder_SetNodeType(nodeBuilder, OH_AudioNode_Type::EFFECT_NODE_TYPE_EQUALIZER);
    // 创建均衡器节点。
    OH_AudioNode *eqNode = nullptr;
    OH_AudioSuiteEngine_CreateNode(audioSuitePipeline, nodeBuilder, &eqNode);
    // 设置均衡器节点效果为默认。
    OH_AudioSuiteEngine_SetEqualizerFrequencyBandGains(eqNode, OH_EQUALIZER_PARAM_DEFAULT);

    // 重置构造器配置并设置为输出节点类型。
    OH_AudioSuiteNodeBuilder_Reset(nodeBuilder);
    OH_AudioSuiteNodeBuilder_SetNodeType(nodeBuilder, OH_AudioNode_Type::OUTPUT_NODE_TYPE_DEFAULT);
    // 配置音频数据格式,开发者根据预期输出的音频格式设置采样率、声道分布、声道数、位深、编码格式参数。
    OH_AudioFormat audioFormatOutput;
    audioFormatOutput.samplingRate = OH_Audio_SampleRate::SAMPLE_RATE_48000;
    audioFormatOutput.channelLayout = OH_AudioChannelLayout::CH_LAYOUT_STEREO;
    audioFormatOutput.channelCount = 2;
    audioFormatOutput.sampleFormat = OH_Audio_SampleFormat::AUDIO_SAMPLE_S16LE;
    audioFormatOutput.encodingType = OH_Audio_EncodingType::AUDIO_ENCODING_TYPE_RAW;
    OH_AudioSuiteNodeBuilder_SetFormat(nodeBuilder, audioFormatOutput);
    // 创建输出节点。
    OH_AudioNode *outputNode = nullptr;
    OH_AudioSuiteEngine_CreateNode(audioSuitePipeline, nodeBuilder, &outputNode);

    // 销毁节点构造器。
    OH_AudioSuiteNodeBuilder_Destroy(nodeBuilder);

    // 连接各个节点组成组网。
    OH_AudioSuiteEngine_ConnectNodes(inputNode, eqNode);
    OH_AudioSuiteEngine_ConnectNodes(eqNode, outputNode);

    离线编辑和实时渲染在创建管线时有区别。

    • 实时渲染:OH_AudioSuite_PipelineWorkMode::AUDIOSUITE_PIPELINE_REALTIME_MODE
    • 离线编辑:OH_AudioSuite_PipelineWorkMode::AUDIOSUITE_PIPELINE_EDIT_MODE
  2. 创建OH_AudioRendererStruct实例,并在其AudioRendererOnWriteData()回调函数中调用OHAudioSuite管线的OH_AudioSuiteEngine_RenderFrame()接口来处理数据。

    请参考音频播放完成音频播放功能开发:使用OHAudio开发音频播放功能(C/C++)

  3. 在播放器的回调函数中,将处理后的数据复制到OH_AudioRenderer实例的缓冲区中,实现音频播放过程中实时渲染。

    static OH_AudioData_Callback_Result AudioRendererOnWriteData(
    OH_AudioRenderer* renderer,
    void* userData,
    void* audioData,
    int32_t audioDataSize)
    {
    bool finishedFlag = false;
    int32_t writeSize = 0;
    OH_AudioSuite_Result result = OH_AudioSuiteEngine_RenderFrame(
    static_cast<OH_AudioSuitePipeline *>(userData), audioData, audioDataSize, &writeSize, &finishedFlag);
    if (result != OH_AudioSuite_Result::AUDIOSUITE_SUCCESS) {
    // 音频编创渲染失败。
    return AUDIO_DATA_CALLBACK_RESULT_INVALID;
    }
    // 音频编创渲染完成。
    if (finishedFlag) {
    // 开发者自定义的行为。
    }

    return AUDIO_DATA_CALLBACK_RESULT_VALID;
    }

    // 创建构建器
    OH_AudioStreamBuilder *rendererBuilder = nullptr;
    OH_AudioStreamBuilder_Create(&rendererBuilder, OH_AudioStream_Type::AUDIOSTREAM_TYPE_RENDERER);
    OH_AudioStreamBuilder_SetSamplingRate(rendererBuilder, 48000);
    OH_AudioStreamBuilder_SetChannelCount(rendererBuilder, 2);
    OH_AudioStreamBuilder_SetSampleFormat(rendererBuilder, AUDIOSTREAM_SAMPLE_S16LE);
    OH_AudioStreamBuilder_SetEncodingType(rendererBuilder, AUDIOSTREAM_ENCODING_TYPE_RAW);
    OH_AudioStreamBuilder_SetRendererInfo(rendererBuilder, AUDIOSTREAM_USAGE_MUSIC);

    int32_t byteSize = 2; // AUDIOSTREAM_SAMPLE_S16LE格式对应的字节大小。
    // 1000是时间转换单位,20表示的是20ms的音频采样数据,如果samplingRate为11025请使用40ms来计算。
    int32_t frameSize = 20 * audioFormatOutput.samplingRate * audioFormatOutput.channelCount * byteSize / 1000;
    // 设置audioDataSize长度(待播放的数据大小)。
    OH_AudioStreamBuilder_SetFrameSizeInCallback(rendererBuilder, frameSize);
    // 配置写入音频数据回调函数。
    OH_AudioStreamBuilder_SetRendererWriteDataCallback(
    rendererBuilder, AudioRendererOnWriteData, static_cast<void *>(audioSuitePipeline));

    // 启动管线。
    OH_AudioSuiteEngine_StartPipeline(audioSuitePipeline);

    // 开发者可以自行创建renderer流,播放音频。
    // ...

    // 停止管线。
    OH_AudioSuiteEngine_StopPipeline(audioSuitePipeline);
  4. 资源销毁。

    // 销毁流构造器。
    OH_AudioStreamBuilder_Destroy(rendererBuilder);

    // 销毁节点。
    OH_AudioSuiteEngine_DestroyNode(inputNode);
    OH_AudioSuiteEngine_DestroyNode(eqNode);
    OH_AudioSuiteEngine_DestroyNode(outputNode);

    // 销毁管线。
    OH_AudioSuiteEngine_DestroyPipeline(audioSuitePipeline);

    // 销毁引擎。
    OH_AudioSuiteEngine_Destroy(audioSuiteEngine);

注意事项

  • 音频实时渲染过程中,不支持重新创建新的效果节点,只支持修改效果节点的参数。
  • 音频编创错误码具体报错信息请参考:OH_AudioSuite_Result