实现方案

当与其他应用的音频发生冲突,多个音频流同时播放时,系统预设了音频打断策略,对多音频的并发进行管控,只有持有音频焦点的音频流才可以正常播放,避免多个音频流无序并发播放的现象出现。为了维持应用和系统的状态一致性,保证符合用户直觉的交互体验,推荐应用监听音频打断事件,并在收到音频打断事件(InterruptEvent)时做出相应处理。对于视频类应用,被各种类型的其他应用音频打断场景和效果如下表所示:

被打断视频期望效果

参考打断效果

涉及的后起流应用音频类型

参考代码示例

打断暂停

后播应用播放时,先播应用暂停播放;后播应用停止播放后,先播应用恢复播放(音频停止后,如果存在对应的播放画面也建议将其停止)。

电话

audioRenderer.on('audioInterrupt', async(interruptEvent: audio.InterruptEvent) => {
  if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
    // 强制打断类型(INTERRUPT_FORCE):音频相关处理已由系统执行,应用需更新自身状态,做相应调整
    switch (interruptEvent.hintType) {
      case audio.InterruptHint.INTERRUPT_HINT_PAUSE:
      // 此分支表示系统已将音频流暂停(临时失去焦点),为保持状态一致,应用需切换至音频暂停状态
      // 临时失去焦点:待其他音频流释放音频焦点后,本音频流会收到resume对应的音频打断事件,到时可自行继续播放
        isPlay = false; // 此句为简化处理,代表应用切换至音频暂停状态的若干操作
        break;
      default:
        break;
    }
  }
}) 
// 订阅通话业务状态变化
import { observer } from '@kit.TelephonyKit';
observer.on('callStateChange', (data: observer.CallStateInfo) => {
  console.log("on callStateChange, data:" + JSON.stringify(data));
  if(data.state == call.CallState.CALL_STATE_IDLE) {
  // 电话挂断后被暂停的音频流此时可以继续播放,建议应用继续播放,切换至音频播放状态
  // 若应用此时不想继续播放,可以忽略此音频打断事件,不进行处理即可
  // 继续播放,此处主动执行start(),以标识符变量started记录start()的执行结果
    await audioRenderer.start().then(() => {
      started = true; // start()执行成功
    }).catch((err: BusinessError) => {
      started = false; // start()执行失败
    });
    // 若start()执行成功,则切换至音频播放状态
    if (started) {
      isPlay = true; // 此句为简化处理,代表应用切换至音频播放状态的若干操作
    } else {
    // 音频继续播放执行失败
    }
  }
});

闹钟

audioRenderer.on('audioInterrupt', async (interruptEvent: audio.InterruptEvent) => {
  if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
    // 强制打断类型(INTERRUPT_FORCE):音频相关处理已由系统执行,应用需更新自身状态,做相应调整
    switch (interruptEvent.hintType) {
      case audio.InterruptHint.INTERRUPT_HINT_PAUSE:
      // 此分支表示系统已将音频流暂停(临时失去焦点),为保持状态一致,应用需切换至音频暂停状态
      // 临时失去焦点:待其他音频流释放音频焦点后,本音频流会收到resume对应的音频打断事件,到时可自行继续播放
        isPlay = false; // 此句为简化处理,代表应用切换至音频暂停状态的若干操作
        break;
      default:
        break;
    }
  } else if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_SHARE) {
    // 共享打断类型(INTERRUPT_SHARE):应用可自主选择执行相关操作或忽略音频打断事件
    switch (interruptEvent.hintType) {
      case audio.InterruptHint.INTERRUPT_HINT_RESUME:
      // 此分支表示临时失去焦点后被暂停的音频流此时可以继续播放,建议应用继续播放,切换至音频播放状态
      // 若应用此时不想继续播放,可以忽略此音频打断事件,不进行处理即可
      // 继续播放,此处主动执行start(),以标识符变量started记录start()的执行结果
        await audioRenderer.start().then(() => {
          started = true; // start()执行成功
        }).catch((err: BusinessError) => {
          started = false; // start()执行失败
        });
      // 若start()执行成功,则切换至音频播放状态
        if (started) {
          isPlay = true; // 此句为简化处理,代表应用切换至音频播放状态的若干操作
        } else {
          // 音频继续播放执行失败
        }
        break;
      default:
        break;
    }
  }
});

铃声

VOIP 铃声(全屏呼叫/呼叫页面/横幅呼叫)

VOIP 通话

VOIP MESSAGE(微信语音/畅联)

打断停止

后播应用播放/录制时,先播应用停止播放;后播应用停止播放/录制后,先播应用不再恢复播放。

音乐

audioRenderer.on('audioInterrupt', async (interruptEvent: audio.InterruptEvent) => {
  if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
    // 强制打断类型(INTERRUPT_FORCE):音频相关处理已由系统执行,应用需更新自身状态,做相应调整
    switch (interruptEvent.hintType) {
      case audio.InterruptHint.INTERRUPT_HINT_STOP:
      // 此分支表示系统已将音频流停止(永久失去焦点),为保持状态一致,应用需切换至音频暂停状态
      // 永久失去焦点:后续不会再收到任何音频打断事件,若想恢复播放,需要用户主动触发。
        isPlay = false; // 此句为简化处理,代表应用切换至音频暂停状态的若干操作
        break;
      default:
        break;
    }
  }
});

视频

普通录音

音量压低

后播应用播放时,先播应用降低音量持续播放;后播应用停止播放后,先播应用恢复音量继续播放。

导航

audioRenderer.on('audioInterrupt', async (interruptEvent: audio.InterruptEvent) => {
  if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
    // 强制打断类型(INTERRUPT_FORCE):音频相关处理已由系统执行,应用需更新自身状态,做相应调整
    switch (interruptEvent.hintType) {
      case audio.InterruptHint.INTERRUPT_HINT_DUCK:
      // 此分支表示系统已将音频音量降低(默认降到正常音量的20%)
        isDucked = true; // 此句为简化处理,代表应用切换至降低音量播放状态的若干操作
        break;
      case audio.InterruptHint.INTERRUPT_HINT_UNDUCK:
      // 此分支表示系统已将音频音量恢复正常
        isDucked = false; // 此句为简化处理,代表应用切换至正常音量播放状态的若干操作
        break;
      default:
        break;
    }
  }
});

TextReader控件朗读语音

语音助手类短语音

并发播放

先播、后播应用并发混音播放。

游戏

此行为是系统默认行为,应用侧不需要适配。

系统音效(锁屏/按键)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐