即构+小游戏ASR 接入(Android)

SudMGP提供的互动小游戏,你画我猜、你说我猜、数字炸弹, 支持玩家用语音命中,提高可玩性,增强社交属性。接入步骤十分便捷,本文介绍接入SudMGP SDK的ASR功能的步骤。

一、背景

小游戏可以带有语音命中能力,App只要从即构RTC获得特定格式PCM数据,以指定方式传入SudMGP SDK, 即可。 在此以hello-sud-plus-android 为例,hello-sud-plus-android源码地址: https://github.com/SudTechnology/hello-sud-plus-android hello-sud-plus-android以SudMGPWrapper封装集成 SudMGP SDK, 我们建议客户用SudMGPWrapper集成SDK。

二、集成步骤

SDK Github地址:https://github.com/SudTechnology/sud-mgp-android 请使用最新版本,可用Maven方式集成, 以V1.3.2.1154版本举例:

  • 集成SudMGP SDK: 标准版: implementation 'tech.sud.mgp:SudMGP:1.3.2.1154' Lite版: implementation 'tech.sud.mgp:SudMGP-lite:1.3.2.1154'
  • 集成语音识别SudASR SDK: implementation 'tech.sud.mgp:SudASR:1.3.2.1154'

说明:

三、小游戏启动语音识别(ASR)

小游戏进入语音识别场景时,会自动启动ASR能力,此时,会向App发送MG_COMMON_GAME_ASR状态, isOpen == true, 见: SudFSMMGListener.onGameMGCommonGameASR

四、App 启动RTC音频流监听

App收到 MG_COMMON_GAME_ASR状态, isOpen == true后: 调用即构接口开启获取音频PCM数据功能,启动即构本端PCM数据采集 ZegoExpressEngine.startAudioDataObserver(int bitmask, ZegoAudioFrameParam param)实现IZegoAudioDataHandler接口对象,调用接口设置原始音频PCM数据回调 ZegoExpressEngine.setAudioDataHandler(IZegoAudioDataHandler handler)

  • 1.调用ZegoExpressEngine.startAudioDataObserver 和ZegoExpressEngine.setAudioDataHandler:

    @Override
    public void startPCMCapture() {
     ZegoExpressEngine engine = getEngine();
     if (engine != null) {
        /* 开启获取PCM数据功能 */
        ZegoAudioFrameParam param = new ZegoAudioFrameParam();
        int bitmask = 0;
        param.channel = ZegoAudioChannel.MONO;
        param.sampleRate = ZegoAudioSampleRate.ZEGO_AUDIO_SAMPLE_RATE_16K;
        bitmask |= ZegoAudioDataCallbackBitMask.CAPTURED.value();
        engine.startAudioDataObserver(bitmask, param);
    
        /* 设置原始音频数据回调 */
        engine.setAudioDataHandler(zegoAudioDataHandler);
     }
    }
    

    startAudioDataObserver() 用于设置PCM数据格式: 调用pushAudio传入的音频切片是从RTC获取的PCM数据 PCM数据格式必须是:采样率:16000, 采样位数:16, 声道数: MONO PCM数据长度可以根据效果调整,长度大: 精确度好但延时长 长度小:延时短但牺牲精确度

即构的音频切片默认是10ms,可以根据效果调整下面传给pushAudio的音频切片长度

  • 2.实现IZegoAudioDataHandler接口对象:

    private final IZegoAudioDataHandler zegoAudioDataHandler = new IZegoAudioDataHandler() {
    @Override
     public void onCapturedAudioData(ByteBuffer data, int dataLength, ZegoAudioFrameParam param) {
        super.onCapturedAudioData(data, dataLength, param);
        ISudAudioEventListener listener = mISudAudioEventListener;
        if (listener != null) {
           AudioPCMData audioPCMData = new AudioPCMData();
           audioPCMData.data = data;
           audioPCMData.dataLength = dataLength;
           listener.onCapturedPCMData(audioPCMData);
        }
     }
    };
    

    onCapturedAudioData()回调方法返回RTC采集的本端PCM数据,处理方法请见下节

  • 3.将RTC采集的PCM数据传给SDK onCapturedAudioData()回调方法返回本端PCM数据切片,最终调用如下方法将PCM数据传给SDK:

// 音频流数据 public void onCapturedAudioData(AudioPCMData audioPCMData) { sudFSTAPPDecorator.pushAudio(audioPCMData.data, audioPCMData.dataLength); }

pushAudio接口可以在工作线程中调用 即构的音频切片默认是10ms,可以根据效果调整传给pushAudio的音频切片长度

五、App关闭RTC音频流监听

小游戏在命中或超时导致退出语音识别场景后,会向App发送状态提示关闭PCM数据捕获 App收到 MG_COMMON_GAME_ASR状态, isOpen == false后, 调用即构接口ZegoExpressEngine.setAudioDataHandler(null) 和ZegoExpressEngine.stopAudioDataObserver(), 关闭即构本端PCM数据采集

@Override
public void stopPCMCapture() {
ZegoExpressEngine engine = getEngine();
    if (engine != null) {
        /* 置空原始音频数据回调 */
        engine.setAudioDataHandler(null);
        engine.stopAudioDataObserver();
}
}

六、只用ASR玩游戏时

只用ASR玩游戏时,App只需要处理MG_COMMON_GAME_ASR状态,负责开启/关闭本端PCM数据采集。不需要像文字命中一样向游戏发mg_common_key_word_to_hit

七、用文字输入玩小游戏的文字命中场景

有语音识别场景的小游戏,通常也能并行使用文字输入来进行命中。游戏会通过mg_common_key_word_to_hit状态通知App命中场景开始, App会通过回调接口接收: SudFSMMGListener.onGameMGCommonKeyWordToHit(ISudFSMStateHandle handle, SudMGPMGState.MGCommonKeyWordToHit model) 文字命中场景,小游戏分两类 1.让App持有关键字的小游戏,如你画我猜,你说我猜,model.word不为空,App需要在本地比较判断是否命中,判断命中后,再通过接口方法sudFSTAPPDecorator.notifyAPPCommonSelfTextHitState 通知游戏 2.不让App持有关键字的小游戏,如数字炸弹,model.word为空,App需要每次将文字送给游戏,由游戏判断是否命中

public void sendMsgCompleted(String msg) {
    if (msg == null || msg.isEmpty()) {
        return;
    }
    // 数字炸弹
    if (sudFSMMGDecorator.isHitBomb() && HSTextUtils.isInteger(msg)) {
        sudFSTAPPDecorator.notifyAPPCommonSelfTextHitState(false, null, msg, null, null, null);
        return;
    }
    String keyword = gameKeywordLiveData.getValue();
    if (keyword == null || keyword.isEmpty()) {
        return;
}
    // 你画我猜, 判断是否命中了关键字,这里是contains判断。接入方可根据自身业务使用equals或者其它自定义的条件。
    if (msg.contains(keyword)) {
        sudFSTAPPDecorator.notifyAPPCommonSelfTextHitState(true, keyword, msg, null, null, null);
        gameKeywordLiveData.setValue(null);
    }
}

results matching ""

    No results matching ""