openharmony 鸿蒙 audio-ear-monitor-loopback

2026-08-25 浏览 (1)

实现音频低时延耳返

从API version 20开始,支持音频低时延耳返。

AudioLoopback是音频返听器,可将音频以更低时延的方式实时传输到耳机中,让用户可以实时听到自己或者其他的相关声音。

常用于K歌类应用,将录制的人声和背景音乐实时传送到耳机中,使用户通过反馈即时进行调整,获得更好的使用体验。

当启用音频返听时,系统会创建低时延渲染器与低时延采集器,实现低时延耳返功能。采集的音频直接通过内部路由返回到渲染器。对于渲染器,其音频焦点策略与STREAM_USAGE_MUSIC相匹配。对于采集器,其音频焦点策略与SOURCE_TYPE_MIC相匹配。

输入/输出设备由系统自动选择。如果当前输入/输出不支持低时延,则音频返听无法启用。在运行过程中,如果音频焦点被另一个音频流抢占,输入/输出设备切换到不支持低时延的设备,系统会自动禁用音频返听。

使用前提

  • 当前仅支持通过有线耳机实现低时延返听功能,音频由有线耳机进行采集并播放。

  • 低功耗渲染器和低时延渲染器在API version 20不能实现并发。若要启用渲染器,建议采用STREAM_USAGE_UNKNOWN;系统内决策采用STREAM_USAGE_MUSIC创建普通渲染器。

开发指导

使用AudioLoopback音频返听涉及到isAudioLoopbackSupported返听能力查询、AudioLoopback实例创建、返听音量设置、返听状态监听与返听启用禁用等。本开发指导将以一次启用返听的过程为例,向开发者讲解如何使用AudioLoopback进行音频返听,建议搭配AudioLoopback的API说明阅读。

下图展示了AudioLoopback的状态变化。在创建实例后,调用对应的方法可以进入指定的状态实现对应行为。

需要注意的是在确定的状态执行不合适的方法可能导致AudioLoopback发生错误,建议开发者在调用状态转换的方法前进行状态检查,避免程序运行产生预期以外的结果。

AudioLoopback状态变化示意图

AudioLoopback status change

使用on('statusChange')方法可以监听AudioLoopback的状态变化,每个状态对应值与说明见AudioLoopbackStatus

开发步骤及注意事项

以下各步骤示例为片段代码,可通过示例代码右下方链接获取完整示例

  1. 查询返听能力并创建AudioLoopback实例,音频返听模式可以查看AudioLoopbackMode

    说明:

    返听需要申请麦克风权限ohos.permission.MICROPHONE,申请方式参考:向用户申请授权

    import { audio } from '@kit.AudioKit'; // 导入audio模块。
    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
    let mode: audio.AudioLoopbackMode = audio.AudioLoopbackMode.HARDWARE;
    let audioLoopback: audio.AudioLoopback|undefined = undefined;
    // ...
      let isSupported = audio.getAudioManager().getStreamManager().isAudioLoopbackSupported(mode);
      if (isSupported) {
        audio.createAudioLoopback(mode).then((loopback) => {
          console.info('Invoke createAudioLoopback succeeded.');
          // ...
          audioLoopback = loopback;
        }).catch((err: BusinessError) => {
          console.error(`Invoke createAudioLoopback failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        });
      } else {
        console.error('Audio loopback is unsupported.');
        // ...
      }
    
  2. 调用getStatus方法,查询当前返听状态。

    注意:

    音频返听状态受音频焦点、低时延管控、采集与播放设备等因素影响。

    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
        audioLoopback.getStatus().then((status: audio.AudioLoopbackStatus) => {
          console.info(`getStatus success, status is ${status}.`);
          // ...
        }).catch((err: BusinessError) => {
          console.error(`getStatus failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        })
    
  3. 调用setVolume方法,设置音频返听音量。

    注意:

    • 在启用返听前设置音量,音量将在启用返听成功后生效。
    • 在启用返听后设置音量,音量将立即生效。
    • 启用返听前未设置音量,启用返听时将采用默认音量0.5。
    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
        try {
          await audioLoopback.setVolume(volume);
          console.info(`Invoke setVolume ${volume} succeeded.`);
          // ...
        } catch (err) {
          console.error(`Invoke setVolume failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        }
    
  4. 从API21开始,支持调用setReverbPreset方法,设置音频返听的混响模式。

    注意:

    • 在启用返听前设置混响模式,混响模式将在启用返听成功后生效。
    • 在启用返听后设置混响模式,混响模式将立即生效。
    • 启用返听前未设置混响模式,启用返听时将采用默认混响模式THEATER
    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
        try {
          audioLoopback.setReverbPreset(preset);
          console.info(`setReverbPreset( ${preset} succeeded.`);
          // ...
          currentReverbPreset = audioLoopback.getReverbPreset(); // 查询当前的混响模式,防止设置失败。
        } catch (err) {
          console.error(`setReverbPreset( failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        }
    
  5. 从API21开始,支持调用getReverbPreset方法,查询当前的音频返听的混响模式。

    注意:

    若未设置混响模式,查询得到将是默认混响模式THEATER

    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
        try {
          let reverbPreset = audioLoopback.getReverbPreset();
        } catch (err) {
          console.error(`getReverbPreset:ERROR: ${err}`);
          // ...
        }
    
  6. 从API21开始,支持调用setEqualizerPreset方法,设置音频返听的均衡器类型。

    注意:

    • 在启用返听前设置均衡器类型,均衡器类型将在启用返听成功后生效。
    • 在启用返听后设置均衡器类型,均衡器类型将立即生效。
    • 启用返听前未设置均衡器类型,启用返听时将采用默认均衡器类型FULL
    import { BusinessError } from '@kit.BasicServicesKit';
    try {
      audioLoopback.setEqualizerPreset(audio.AudioLoopbackEqualizerPreset.FULL);
    } catch (err) {
      console.error(`setEqualizerPreset :ERROR: ${err}`);
    }
    
  7. 从API21开始,支持调用getEqualizerPreset方法,查询当前的音频返听的均衡器类型。

    注意:

    若未设置均衡器类型,查询得到将是默认均衡器类型FULL

    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
        try {
          let equalizerPreset = audioLoopback.getEqualizerPreset();
        } catch (err) {
          console.error(`getEqualizerPreset:ERROR: ${err}`);
          // ...
        }
    
  8. 调用enable方法,启用或禁用音频返听功能。

    import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
    // ...
    // 设置监听事件,启用音频返听。
    async function enable(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
      if (audioLoopback !== undefined) {
        try {
          let status = await audioLoopback.getStatus();
          if (status == audio.AudioLoopbackStatus.AVAILABLE_IDLE) {
            // 注册监听。
            audioLoopback.on('statusChange', statusChangeCallback);
            // 启动返听。
            let success = await audioLoopback.enable(true);
            if (success) {
              console.info('Invoke enable succeeded');
              // ...
            } else {
              status = await audioLoopback.getStatus();
              statusChangeCallback(status);
            }
          } else {
            statusChangeCallback(status);
          }
        } catch (err) {
          console.error(`Invoke enable failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        }
      } else {
        console.error('Audio loopback not created.');
        // ...
      }
    }
    
    // 禁用音频返听,关闭监听事件。
    async function disable(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
      if (audioLoopback !== undefined) {
        try {
          let status = await audioLoopback.getStatus();
          if (status == audio.AudioLoopbackStatus.AVAILABLE_RUNNING) {
            // 禁用返听。
            let success = await audioLoopback.enable(false);
            if (success) {
              console.info('Invoke disable succeeded');
              // ...
              // 关闭监听。
              audioLoopback.off('statusChange', statusChangeCallback);
            } else {
              status = await audioLoopback.getStatus();
              statusChangeCallback(status);
            }
          } else {
            statusChangeCallback(status);
          }
        } catch (err) {
          console.error(`Invoke disable failed, code is ${err.code}, message is ${err.message}.`);
          // ...
        }
      } else {
        console.error('Audio loopback not created.');
        // ...
      }
    }
    

完整示例

使用AudioLoopback启用音频低时延返听示例代码如下所示。

import { audio } from '@kit.AudioKit'; // 导入audio模块。
import { BusinessError } from '@kit.BasicServicesKit'; // 导入BusinessError。
import { common, abilityAccessCtrl, PermissionRequestResult } from '@kit.AbilityKit'; // 导入UIAbilityContext。

const TAG = 'AudioLoopbackDemo';
let mode: audio.AudioLoopbackMode = audio.AudioLoopbackMode.HARDWARE;
let audioLoopback: audio.AudioLoopback|undefined = undefined;
let currentReverbPreset: audio.AudioLoopbackReverbPreset = audio.AudioLoopbackReverbPreset.THEATER;
let currentEqualizerPreset: audio.AudioLoopbackEqualizerPreset = audio.AudioLoopbackEqualizerPreset.FULL;
// ...

// ...

// 查询能力,创建实例。
function init(updateCallback?: (msg: string, isError: boolean) => void): void {
  let isSupported = audio.getAudioManager().getStreamManager().isAudioLoopbackSupported(mode);
  if (isSupported) {
    audio.createAudioLoopback(mode).then((loopback) => {
      console.info('Invoke createAudioLoopback succeeded.');
      // ...
      audioLoopback = loopback;
    }).catch((err: BusinessError) => {
      console.error(`Invoke createAudioLoopback failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    });
  } else {
    console.error('Audio loopback is unsupported.');
    // ...
  }
}

// 设置音频返听音量。
async function setVolume(volume: number, updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioLoopback !== undefined) {
    try {
      await audioLoopback.setVolume(volume);
      console.info(`Invoke setVolume ${volume} succeeded.`);
      // ...
    } catch (err) {
      console.error(`Invoke setVolume failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    }
  } else {
    console.error('Audio loopback not created.');
    // ...
  }
}

// 设置音频返听的混响模式。
async function setReverbPreset(preset: audio.AudioLoopbackReverbPreset, updateCallback?: (msg: string,
  isError: boolean) => void): Promise<void> {
  if (audioLoopback !== undefined) {
    try {
      audioLoopback.setReverbPreset(preset);
      console.info(`setReverbPreset( ${preset} succeeded.`);
      // ...
      currentReverbPreset = audioLoopback.getReverbPreset(); // 查询当前的混响模式,防止设置失败。
    } catch (err) {
      console.error(`setReverbPreset( failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    }
  } else {
    console.error('Audio loopback not created.');
    // ...
  }
}

// 设置音频返听的均衡器类型。
async function setEqualizerPreset(preset: audio.AudioLoopbackEqualizerPreset, updateCallback?:
  (msg: string, isError: boolean) => void): Promise<void> {
  if (audioLoopback !== undefined) {
    try {
      audioLoopback.setEqualizerPreset(preset);
      console.info(`setEqualizerPreset ${preset} succeeded.`);
      // ...
      currentEqualizerPreset = audioLoopback.getEqualizerPreset(); // 查询当前的均衡器类型,防止设置失败。
    } catch (err) {
      console.error(`setEqualizerPreset failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    }
  } else {
    console.error('Audio loopback not created.');
    // ...
  }
}

// 设置监听事件,启用音频返听。
async function enable(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioLoopback !== undefined) {
    try {
      let status = await audioLoopback.getStatus();
      if (status == audio.AudioLoopbackStatus.AVAILABLE_IDLE) {
        // 注册监听。
        audioLoopback.on('statusChange', statusChangeCallback);
        // 启动返听。
        let success = await audioLoopback.enable(true);
        if (success) {
          console.info('Invoke enable succeeded');
          // ...
        } else {
          status = await audioLoopback.getStatus();
          statusChangeCallback(status);
        }
      } else {
        statusChangeCallback(status);
      }
    } catch (err) {
      console.error(`Invoke enable failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    }
  } else {
    console.error('Audio loopback not created.');
    // ...
  }
}

// 禁用音频返听,关闭监听事件。
async function disable(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioLoopback !== undefined) {
    try {
      let status = await audioLoopback.getStatus();
      if (status == audio.AudioLoopbackStatus.AVAILABLE_RUNNING) {
        // 禁用返听。
        let success = await audioLoopback.enable(false);
        if (success) {
          console.info('Invoke disable succeeded');
          // ...
          // 关闭监听。
          audioLoopback.off('statusChange', statusChangeCallback);
        } else {
          status = await audioLoopback.getStatus();
          statusChangeCallback(status);
        }
      } else {
        statusChangeCallback(status);
      }
    } catch (err) {
      console.error(`Invoke disable failed, code is ${err.code}, message is ${err.message}.`);
      // ...
    }
  } else {
    console.error('Audio loopback not created.');
    // ...
  }
}

你可能感兴趣的鸿蒙文章

openharmony 鸿蒙 using-ohmidi

openharmony 鸿蒙 public-audio-spatialization-management

openharmony 鸿蒙 audio-session-management

openharmony 鸿蒙 using-opensl-es-for-playback

openharmony 鸿蒙 using-ohaudio-for-recording

openharmony 鸿蒙 audio-kit-intro

openharmony 鸿蒙 audio-workgroup

openharmony 鸿蒙 audio-collaborative-management-sys

openharmony 鸿蒙 audio-recording-concurrency

openharmony 鸿蒙 audio-recording-overview

  • 所属分类: 后端技术
  • 本文标签: 软件 鸿蒙
  • 版权声明: 本文链接 https://seaxiang.com/blog/sO3nb8ei