HarmonyOS 鸿蒙Next系统音频3A效果很差
HarmonyOS 鸿蒙Next系统音频3A效果很差 音频系统3A效果很差,请问有3A能实际生效的demo吗?在音频采集时使用ndk,调用OH_AudioStreamBuilder_SetCapturerInfo(),并设置属性为AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATION,实际测试3A效果很差,噪声和回声非常明显。
这边测试了下录音播放,回音噪声都在正常范围,没有出现3A效果很差的情况。
给个链接,参考下再试试呢。
https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Native/Audio
非通话场景下,不支持开启3A算法,可参考:
https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs-V5/faqs-audio-6-V5
可以通过返回值OH_AudioStream_Result 判断是否执行成功,
1)AUDIOCOMMON_RESULT_SUCCESS:函数执行成功。
2)AUDIOSTREAM_ERROR_INVALID_PARAM:
- 参数builder为nullptr;
- 参数sourceType无效。
参考一下这份代码:
// Created on 2024/7/13.
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "ohaudio_controller.h"
#include <cstddef>
#include <cstdint>
#include <ctime>
#define LOG_TAG "LatencyTest"
#include <ohaudio/native_audiostream_base.h>
#include <ohaudio/native_audiostreambuilder.h>
#include <ohaudio/native_audiorenderer.h>
#include <ohaudio/native_audiocapturer.h>
#include <hilog/log.h>
#include <mutex>
#include <sys/time.h>
static OH_AudioRenderer* audioRenderer = nullptr;
static OH_AudioCapturer* audioCapturer = nullptr;
#define CACHE_ARRAY_SIZE 10* 1024 // 10k
class RingCache {
private:
uint8_t mem_[CACHE_ARRAY_SIZE];
size_t readIndex_ = 0;
size_t availableToRead_ = 0;
size_t writeIndex_ = 0;
size_t availableToWrite_ = CACHE_ARRAY_SIZE;
std::mutex mutex_;
int32_t appLatencyMs = 0;
int64_t lastWriteMs;
int64_t lastReadTs;
int32_t sampleRate_ = 16000;
int32_t channels_ = 2;
int32_t bitWidth_ = 2;
public:
void SetSampleRate(int32_t sampleRate)
{
sampleRate_ = sampleRate;
}
void SetChannels(int32_t channels)
{
channels_ = channels;
}
void SetBitWidth(int32_t bitWidth)
{
bitWidth_ = bitWidth;
}
int32_t GetLatencyMs()
{
return appLatencyMs;;
}
int32_t Write(uint8_t* src, size_t contentSize)
{
std::lock_guard<std::mutex> guard(mutex_);
OH_LOG_INFO(LOG_APP, "Write availableToWrite_ %zu contentSize %zu availableToRead_ %zu", availableToWrite_, contentSize, availableToRead_);
if (availableToWrite_ < contentSize) {
OH_LOG_ERROR(LOG_APP, "exceeds, no available space to write availableToWrite_ %zu contentSize %zu", availableToWrite_, contentSize);
return 0;
}
timeval tv;
gettimeofday(&tv, nullptr);
lastWriteMs = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (writeIndex_ + contentSize < CACHE_ARRAY_SIZE) {
memcpy(mem_ + writeIndex_, src, contentSize);
writeIndex_ += contentSize;
} else {
memcpy(mem_ + writeIndex_, src, CACHE_ARRAY_SIZE - writeIndex_);
memcpy(mem_, src + CACHE_ARRAY_SIZE - writeIndex_, writeIndex_ + contentSize - CACHE_ARRAY_SIZE);
writeIndex_ = (writeIndex_ + contentSize) % CACHE_ARRAY_SIZE;
}
availableToWrite_ -= contentSize;
availableToRead_ += contentSize;
return contentSize;
}
int32_t Read(uint8_t* dest, size_t requestSize)
{
OH_LOG_INFO(LOG_APP, "Read availableToWrite_ %zu requestSize %zu availableToRead_ %zu", availableToWrite_, requestSize, availableToRead_);
std::lock_guard<std::mutex> guard(mutex_);
if (availableToRead_ < requestSize) {
OH_LOG_ERROR(LOG_APP, "exceeds, no available data to read");
return 0;
}
timeval tv;
gettimeofday(&tv, nullptr);
int64_t offset = tv.tv_sec * 1000 + tv.tv_usec / 1000 - lastWriteMs;
appLatencyMs = offset + (availableToRead_ - requestSize) * 1000 / sampleRate_ / channels_ / bitWidth_;
if (readIndex_ + requestSize < CACHE_ARRAY_SIZE) {
memcpy(dest, mem_ + readIndex_, requestSize);
readIndex_ += requestSize;
} else {
memcpy(dest, mem_ + readIndex_, CACHE_ARRAY_SIZE - readIndex_);
memcpy(dest + CACHE_ARRAY_SIZE - readIndex_, mem_, requestSize - (CACHE_ARRAY_SIZE - readIndex_));
readIndex_ = (readIndex_ + requestSize) % CACHE_ARRAY_SIZE;
}
availableToWrite_ += requestSize;
availableToRead_ -= requestSize;
return requestSize;
}
};
static RingCache rc;
static int32_t CaptureCallabck(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t lenth)
{
rc.Write(static_cast<uint8_t*>(buffer), lenth);
return 0;
}
static int32_t CapturerOnInterrupt(OH_AudioCapturer *capturer, void *userData, OH_AudioInterrupt_ForceType type,
OH_AudioInterrupt_Hint hint)
{
OH_LOG_INFO(LOG_APP, "%s OH_AudioInterrupt_ForceType %d, OH_AudioInterrupt_Hint %d", __FUNCTION__, type, hint );
return 0;
}
static int32_t CaptureOnError(OH_AudioCapturer *capturer, void *userData, OH_AudioStream_Result error)
{
OH_LOG_ERROR(LOG_APP, "capture error %d", error);
return 0;
}
static OH_AudioCapturer_Callbacks captureCallback = {
.OH_AudioCapturer_OnReadData = CaptureCallabck,
.OH_AudioCapturer_OnStreamEvent = nullptr, // 不使用时,必须置空
.OH_AudioCapturer_OnInterruptEvent = CapturerOnInterrupt,
.OH_AudioCapturer_OnError = CaptureOnError,
};
static bool CreateAudioCapturer(int32_t sampleRate, int32_t mode)
{
OH_LOG_INFO(LOG_APP, "create audio capture with samplerate %d, mode: %s", sampleRate, mode == 0? "VoIP": "Normal");
OH_AudioStreamBuilder *builder;
OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER);
OH_AudioStreamBuilder_SetSamplingRate(builder, sampleRate);
OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
OH_AudioStreamBuilder_SetChannelCount(builder, 2);
if (mode == 0) {
OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATION);
} else {
OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
}
OH_AudioStreamBuilder_SetCapturerCallback(builder, captureCallback, nullptr);
OH_AudioStream_Result res = AUDIOSTREAM_SUCCESS;
if ((res = OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer)) != AUDIOSTREAM_SUCCESS) {
audioCapturer = nullptr;
OH_LOG_ERROR(LOG_APP, "create audio capture failed %d", res);
return false;
}
return true;
}
static int32_t RenderCallback(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t lenth)
{
rc.Read(static_cast<uint8_t*>(buffer), lenth);
return 0;
}
static int32_t RenderOnError(OH_AudioRenderer *render, void *userData, OH_AudioStream_Result error) {
OH_LOG_ERROR(LOG_APP, "render error %d", error);
return 0;
}
static OH_AudioRenderer_Callbacks renderCallback = {
.OH_AudioRenderer_OnWriteData = RenderCallback,
.OH_AudioRenderer_OnStreamEvent = nullptr, // 不使用时,必须置空
.OH_AudioRenderer_OnInterruptEvent = nullptr,// 不使用时,必须置空
.OH_AudioRenderer_OnError = RenderOnError,
};
static OH_AudioRenderer_Callbacks renderCallback5;
static bool CreateAudioRenderer(int32_t sampleRate, int32_t mode)
{
OH_LOG_INFO(LOG_APP, "create audio render with samplerate %d, mode: %s", sampleRate, mode == 0? "VoIP": "Normal");
OH_AudioStreamBuilder* builder;
OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_RENDERER);
OH_AudioStreamBuilder_SetSamplingRate(builder, sampleRate);
if (mode == 0) {
OH_AudioStreamBuilder_SetRendererInfo(builder, AUDIOSTREAM_USAGE_VOICE_COMMUNICATION);
} else {
OH_AudioStreamBuilder_SetRendererInfo(builder, AUDIOSTREAM_USAGE_MOVIE);
}
OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
OH_AudioStreamBuilder_SetChannelCount(builder, 2);
OH_AudioStreamBuilder_SetFrameSizeInCallback(builder, 20 * sampleRate / 1000);
OH_AudioStreamBuilder_SetRendererCallback(builder, renderCallback, nullptr);
OH_AudioStream_Result res = AUDIOSTREAM_SUCCESS;
if ((res = OH_AudioStreamBuilder_GenerateRenderer(builder, &audioRenderer)) != AUDIOSTREAM_SUCCESS) {
audioRenderer = nullptr;
OH_LOG_ERROR(LOG_APP, "create audio render failed %d", res);
return false;
}
return true;
}
void Start(int32_t sampleRate, int32_t mode)
{
rc.SetSampleRate(sampleRate);
Stop();
if (audioRenderer == nullptr) {
CreateAudioRenderer(sampleRate, mode);
}
if (audioCapturer == nullptr) {
CreateAudioCapturer(sampleRate, mode);
}
if (audioRenderer != nullptr) {
OH_AudioRenderer_Start(audioRenderer);
}
if (audioCapturer != nullptr) {
OH_AudioCapturer_Start(audioCapturer);
}
}
void Stop()
{
if (audioRenderer != nullptr) {
OH_AudioRenderer_Stop(audioRenderer);
OH_AudioRenderer_Release(audioRenderer);
audioRenderer = nullptr;
}
if (audioCapturer != nullptr) {
OH_AudioCapturer_Stop(audioCapturer);
OH_AudioCapturer_Release(audioCapturer);
audioCapturer = nullptr;
}
}
int32_t GetAppLatency()
{
return rc.GetLatencyMs();
}
更多关于HarmonyOS 鸿蒙Next系统音频3A效果很差的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
针对“HarmonyOS 鸿蒙Next系统音频3A(自动增益控制AGC、自动噪声消除ANC、回声消除AEC)效果很差”的问题,以下是一些可能的解决方案及原因概述:
-
系统版本与驱动更新:
- 确保你的鸿蒙Next系统为最新版本,因为新版本可能修复了旧版本中的音频处理bug。
- 检查音频驱动是否最新,过时的驱动可能导致音频处理性能不佳。
-
硬件兼容性:
- 某些硬件设备可能与鸿蒙Next系统的音频处理算法不完全兼容。尝试在不同设备上测试,以确定是否为硬件问题。
-
应用与设置:
- 检查音频应用的设置,确保3A效果已正确开启并调整至适合的场景模式。
- 关闭不必要的后台应用,以减少对音频处理资源的占用。
-
系统优化:
- 尝试清理系统缓存,以释放更多资源给音频处理。
- 如果可能,重启设备以刷新系统状态。
-
特定场景问题:
- 在某些特定环境(如嘈杂、回声严重的场景)下,3A效果可能受限。尝试在不同环境下测试以评估性能。
如果上述方法均未能改善音频3A效果,可能是由于系统或硬件层面的深层次问题。此时,建议直接联系官网客服以获取更专业的技术支持。官网地址是: https://www.itying.com/category-93-b0.html