搜索本产品文档关键词
H5版
所有文档
menu

曦灵数字人开放平台

H5版

1. SDK运行原理

SDK运行原理.png


2. 接入方法

iframe支持在网页内引入其他网页,使用iframe引入WebSdk方式如下:

FAQ: 为什么使用iframe

使用iframe的方式,可以天然的和集成方代码形成隔离,形成单独的进程进行数字人的渲染工作,防范因js单线程设计可能造成的渲染卡顿问题。

// 用户侧
<iframe
    id="myIframe"
    src="https://open.xiling.baidu.com/cloud/realtime?token=自行填写&initMode=noAudio&cameraId=0
    frameBorder="0"
    allow="microphone;camera;midi;encrypted-media;autoplay;" // 可用权限
/>

3. demo使用

3.1 demo说明

此demo分别使用react,vue两种框架。针对如何发送消息驱动数字人,如何监听驱动数字人消息的完成状态,如何第一时间判断数字人已加载完成

如何解决浏览器静音策略,以及如何节省数字人资源等问题,进行了代码实现。

3.2 demo下载

React版本,下载地址https://sdk-demo.bj.bcebos.com/realtime-digital-human-demo.zip

Vue版本,下载地址https://sdk-demo.bj.bcebos.com/realtime-digital-human-vue-demo.zip

核心代码如下

/* eslint-disable @typescript-eslint/no-explicit-any */
// 参考文献 https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
import { useCallback, useEffect, useState } from 'react'
import {v4 as uuidV4} from 'uuid';
import DHIframe from '@bddh/starling-dhiframe';

import useAudioRender from './hook/useAudioRender';

import './App.css'

const dhIframe = new DHIframe('digital-human-iframe'); 

enum ReadyState {
  UNINSTANTIATED = -1,
  CONNECTING = 0,
  OPEN = 1,
  CLOSING = 2,
  CLOSED = 3,
}

// 可以有声播放则返回true,否则返回false
function checkPlayUnMute(): Promise<boolean> | boolean {
  if (typeof navigator.userActivation !== 'undefined' && typeof navigator.userActivation.hasBeenActive !== 'undefined') {
    return navigator.userActivation.hasBeenActive;
  }
  return new Promise((resolve) => {
    const audioElem: HTMLAudioElement = document.createElement('audio');
    audioElem.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA=';
    audioElem.muted = false;

    const playPromise: Promise<void> | undefined = audioElem.play();

    if (playPromise !== undefined) {
      playPromise
        .then(() => {
          // 自动播放成功
          resolve(true);
        })
        .catch((error: Error) => {
          if (error.name === "NotAllowedError" || error.name === "AbortError") {
            // 自动播放被禁止或中止
            resolve(false);
          } else {
            // 其他错误
            resolve(false);
          }
        });
        audioElem.remove();
    } else {
      // 如果 play() 返回 undefined,可能是浏览器不支持 Promise 风格的 play()
      audioElem.remove();
      resolve(false);
    }
  });
}

function App() {
  // 实时视频流远端准备完毕,可以进行textRender等驱动指令的发送
  const [realTimeVideoReady, setRealTimeVideoReady] = useState(false);
  const [wsConnected, setWsConnected] = useState(false);
  // 浏览器限制导致的有声视频无法自动播放,所以这里进行静音后自动播放
  const [videoIsMuted, setVideoIsMuted] = useState(false);
  const [commandId] = useState(uuidV4());
  // 是否可以自动播放,检测完成状态
  const [checkOver, setCheckOver] = useState(false);
  // 超时即将消失tip
  const [showTimeoutTip, setShowTimeoutTip] = useState(false);
  // 数字人前置loading页面
  const [showLoadingPage, setShowLoadingPage] = useState(false);

  const {playAudio, playMultiAudio} = useAudioRender(dhIframe); // pcm格式音频播放

  const onMessage = useCallback((msg: any) => {
    if (msg.origin === 'https://open.xiling.baidu.com') {
      const {type, content} = msg.data;
      const {action, requestId} = content;
      switch (type) {
        case 'rtcState':
          if (content.action === 'remoteVideoConnected') {
            setRealTimeVideoReady(true);
          }
          if (content.action === 'localVideoMuted' && content.body) {
            setVideoIsMuted(true);
          }
          break;
        case 'wsState':
          if (content.readyState === ReadyState.OPEN) {
            setWsConnected(true);
          }
          else if (content.readyState === ReadyState.CLOSED || content.readyState === ReadyState.CLOSING) {
            setWsConnected(false);
          }
          break;
        case 'msg':
          if (requestId === commandId && action === 'FINISHED') {
            console.info(`数字人驱动完成, 驱动id为${requestId}`);
            const newCommandId = uuidV4();
            // 解开注释可以进行持续播报
            // setCommandId(newCommandId); 
            dhIframe.sendMessage({
              action: 'TEXT_RENDER',
              body: '我已经完成一次驱动,这是我说的第n句话',
              requestId: newCommandId
            });
          }
          else if (action === 'DISCONNECT_ALERT') {
            setShowTimeoutTip(true);
          }
          else if (action === 'TIMEOUT_EXIT') {
            const iframeDom = document.getElementById('digital-human-iframe');
            iframeDom?.remove();
          }
          break;
        default:
          break;
      }
    }
  }, [commandId]);

  // 播放开场白
  const playWelcome = () => {
    setVideoIsMuted(false);
    dhIframe.sendCommand({
      subType: 'muteAudio',
      subContent: false
    });
  }

  // 打断数字人
  const handleInterrupt = () => {
    dhIframe.sendMessage({
      action: 'TEXT_RENDER',
      body: '<interrupt></interrupt>',
      requestId: commandId
    });
  }

  const goNextPage = () => {
    setShowLoadingPage(false);
    setVideoIsMuted(false);
  }

  useEffect(() => {
    const checkPlayUnMuteFun = async () => {
      const result = await checkPlayUnMute(); // 500ms左右
      setVideoIsMuted(!result);
      setCheckOver(true);
    }
    checkPlayUnMuteFun();
  }, [])

  useEffect(() => {
    if (realTimeVideoReady && wsConnected && checkOver && !videoIsMuted) {
      dhIframe.sendMessage({
        action: 'TEXT_RENDER',
        body: '这是我的开场白自我介绍,我是数字人',
        requestId: commandId
      });
  }
  }, [realTimeVideoReady, wsConnected, checkOver, videoIsMuted, commandId]);

  useEffect(() => {
    dhIframe.registerMessageReceived(onMessage);
    return () => {
      dhIframe.removeMessageReceived(onMessage);
    };
  }, [onMessage]);

  if (showLoadingPage) {
    return (
      <div onClick={goNextPage}>
        前置loading页,点击进入下个页面
      </div>
    )
  }


  return (
    <>
      {videoIsMuted && <div className="tip1" onClick={playWelcome}>取消静音,播报开场白</div>}
      {showTimeoutTip && <div className="tip2" onClick={playWelcome}>长时间无交互,数字人马上消失了,点我一下,进行交互</div>}
      <div className="button-wrapper">
        <button onClick={playWelcome}>文本播报</button>
        <button onClick={playAudio}>音频播报</button>
        <button onClick={playMultiAudio}>多段拼接音频播报</button>
        <button onClick={handleInterrupt}>打断播报</button>
      </div>
      <iframe
        id="digital-human-iframe"
        src="https://open.xiling.baidu.com/cloud/realtime?token=自行填写&initMode=noAudio&cameraId=自行填写&figureId=自行填写"
        width="450"
        height="800"
        allow="autoplay"
      >
      </iframe>
    </>
  )
}

export default App

3.3 demo运行和修改

  1. 解压后,进入目录:React版本目录名称:realtime-digital-human-demo、Vue 版本目录名称:realtime-digital-human-vue-demo
  2. 判断环境是否有 node(22 版本以上)和 yarn,如没有则进行 node, yarn 的安装: brew install node; npm install --global yarn (其他安装方式请自行搜索)
  3. 命令行执行 yarn,安装所需依赖包
  4. 命令行执行 npm run dev,启动项目
  5. 将控制台输出的ip地址,复制到浏览器地址栏进行项目预览,页面黑色并显示在 loading 中
  6. 在平台购买云渲染交互组件平台操作指南,新建应用关联组件,获取应用的appId和appkey
  7. 公共形象库中查找组件对应的人像类型的人像 id 和机位 id,替换 demo 文件中 figureId 和 cameraId 参数,文件位置:React 版本是 src/App.tsx、Vue 版本是 src/App.vue,搜索『需替换』关键字
  8. 根据接口通用说明生成鉴权参数 token,替换 demo 文件中 token 参数,文件位置:React 版本是 src/App.tsx、Vue 版本是 src/App.vue,搜索『自行填写』关键字
  9. 保存文件,刷新页面可以看到数字人成功加载出来,可以点击播报按钮驱动数字人播报

4. url参数说明

4.1 常用基础参数

参数 类型 必填 默认 备注
token string - 平台购买所需组件平台操作指南,生成鉴权凭证:生成方法查阅接口通用说明(token=Authorization)的鉴权参数生成部分
figureId string - 查找文档公共形象库,填写对应 figureId
initMode String - 用于针对特定应用场景快速批量设置关联配置的默认值,设置后关联配置无需填写,枚举类型:noAudio:无拾音模式
resolutionWidth string 当前设备宽度clientWidth 视频分辨率宽,只能是偶数,最小值400,分辨率最大不超过 1080x1920、1920x1080
resolutionHeight string 当前设备高度clientHeight 视频分辨率高,只能是偶数,最小值400,分辨率最大不超过 1080x1920、1920x1080
cameraId int - 数字人预设机位 ID,控制数字人的位置和大小,建议使用和视频分辨率比例一致的机位:高精 2D 人像:0 (横屏半身)、1(竖屏半身)详细枚举参考3D数字人2D精品数字人

4.2 高级参数

参数 类型 默认 备注
mode string inline 画面裁剪参数(inline内嵌展示未填充的地方背景色展示 、crop裁剪)
backgroundImageUrl string - 设置数字人video背景图片,不支持直接配置颜色
autoChromaKey为 true 时不生效
videoBg string - 设置页面颜色,默认黑色,iframe 宽高比和数字人视频宽高比不一致时,页面的填充色, 大多情况建议使用 transparent
autoChromaKey为 true 时不生效
autoChromaKey Boolean false 开启自动抠绿,实现数字人透明背景
chromaEffects Object - 自定义抠绿参数,使用时需将autoChromaKey设置为false;详解设置步骤参考: 常见问题7.11
ttsPer string - 音色发音人ID,可用发音人列表参考:公共音色库
ttsPitch number 5 音调,5是正常值,0-15的取值范围,越大声音越尖,默认值5 (字面量需要是整数)
ttsSpeed number 5 语速,5是正常值,0-15的取值范围。越大语速越快,默认值5 (字面量需要是整数)
ttsVolume number 5 音量,5是正常值,0-15的取值范围,越大音量越大,默认值5 (字面量需要是整数)
cp-autoAnimoji Boolean false 是否开启自动添加数字人动作,只支持高精3D/2D人像
cp-inactiveDisconnectSec int 180 长时间无交互(交互指发送 text render 让数字人播报)的断连提醒,单位秒,0 表示不开启。达到阈值时,服务端会发送 TIMEOUT_EXIT 提醒消息,父页面在收到该消息时需销毁子页面,避免数字人渲染资源浪费,目前数字人后端服务不会主动断开。
cp-preAlertSec int 10 在开启长时间无交互断连提醒,且即将到达断连阈值时,后端会先发送一条 DISCONNECT_ALERT 预提醒消息,父页面收到消息可以弹窗提醒用户。该参数用于设置断连前多少秒发送该提醒,比如无交互超时参数 cp-inactiveDisconnectSec 设置为 180(3 分钟),提醒参数 cp-preAlertSec 设置为 10 (秒),则在用户最后一次交互后的 2 分 50 秒时会收到后端发送的 DISCONNECT_ALERT 提醒消息,在 3 分钟时收到 TIMEOUT_EXIT 断连消息。
showLogo Boolean false 是否展示logo
logoUrl string - 自定义logo图片地址
entry Boolean false 是否有入口页(开启后不会自动播放)
一般用于手机端iframe集成,手机端无法自动播放

4.3 debug参数设置

参数 类型 默认 备注
appId string - 应用标识和秘钥,用于鉴权,前端直接使用可能会有泄漏风险,不建议生产环境使用,推荐使用 token 鉴权。
appKey string -
showMessage Boolean false 展示toast提示消息
textAssist Boolean false 是否展示文本辅助, 可以进行驱动
showDebugger Boolean false 展示vconsole
closeLog Boolean false 关闭sdk侧控制台日志


5. 如何与Web-Sdk通信

使用iframe的内外层window可以通过window.postMessage这个API发送消息,基于window.postMessage封装好的通信npm包@bddh/starling-dhiframe,提供了收、发消息的方法,用户可直接使用。

5.1 @bddh/starling-dhiframe的安装和使用

工具包的安装

// npm 方式:
npm i @bddh/starling-dhiframe
// yarn 方式
yarn add @bddh/starling-dhiframe

工具包的使用

import DHIframe from '@bddh/starling-dhiframe';
// digital-human-iframe需要和 iframe 的 id 地址保持一致
const dhIframe = new DHIframe('digital-human-iframe'); 
// 使用方式
dhIframe.sendMessage({
  action: 'TEXT_RENDER',
  body: '你好,这是我的开场白自我介绍,我是数字人',
  requestId: commandId
});

5.2 接收消息

用户侧可以通过如下方式接收leafletWeb抛出的消息

const onMessage = msg => {
    console.log(msg.data);
    // {type, content} = msg.data;
};

// 增加监听
dhIframe.registerMessageReceived(onMessage);
// 移除监听
dhIframe.removeMessageReceived(onMessage);

5.2.1 消息Type类型

用户侧能够接收到的消息(即Web-sdk抛出的消息)有三类,通过msg.data的type字段表示,三类消息说明如下:

type content 备注
msg msg 数字人驱动消息回调通知
rtcState rtcState webrtc 的状态
wsState wsState webSocket 的链接状态

5.2.2 rtcState数据信息

type为 rtcState 的 content 的 格式 {action, body}

action body 备注
success true rtc房间登录成功
error error rtc房间登录失败
remotevideoloading id 远端视频流开始加载
remoteVideoConnected id 成功获取远端视频流(不受视频暂停影响)
remotevideoon id 远端视频流加载完毕
localVideoMuted true 首次加载无交互导致的video静音

5.2.3 wsState数据信息

type为 wsState 的 content.readyState

状态 value 备注
UNINSTANTIATED -1 默认值 无状态
CONNECTING 0 ws 连接中
OPEN 1 ws 开启成功
CLOSING 2 ws 关闭中
CLOSED 3 ws 关闭
enum ReadyState {
  UNINSTANTIATED = -1,
  CONNECTING = 0,
  OPEN = 1,
  CLOSING = 2,
  CLOSED = 3,
}

5.2.4 msg数据信息

type为 msg 的 content.action

  • 类别:驱动数字人回调消息
状态 备注 内容数据
RENDER_START 数字人收到驱动后,驱动开始 -
FINISHED 数字人完成驱动指令,驱动完成 -
RENDER_ERROR 文本驱动错误 -
DOWN_SUBTITLE 播报内容 body
RENDER_INTERRUPTED 数字人驱动被打断 -
  • 类别:数字人退出回调消息
状态 备注 内容数据
TIMEOUT_EXIT 超时退出消息
  • 类别:数字人初始化消息回调
状态 备注 内容数据
CONNECT 连接消息 body
DISCONNECT_ALERT 长时间无交互提示

type为 msg 的 content.code

  • 错误类型:connect连接,初始化数字人报错报错
错误码 错误信息 说明
1001 服务器内部错误
1002 APP已失效
1003 APP token已过期
1004 目前线上用户较多,请您稍后再试 app 会话路数已经达到上限
1005 授权信息不存在 figureId未授权不可用
1009 App key非法
1011 裁剪参数非法 仅2D数字人存在
1012 参数不能为空
1014 分辨率/编码参数不合法
1015 无效的媒体信息 例如:传递的RTMP参数无效
1202 正在连接或已连接
1204 解析请求失败
1206 读取json失败
2001 Fail to establish 建立渲染任务失败
3001 目前线上用户较多,请您稍后再试 系统渲染资源不足导致
  • 错误类型:驱动数字人报错
错误码 错误信息 说明
-1 body非法 body内容含有非法字符
1013 DRML非法 仅2D数字人存在,不支持做该动作同时做播报,通常是走入走出的情况,面部不完整
1208 富文本格式非法 DRML格式错误
1201 操作尚未支持


5.3 发送消息

用户侧一般需要发送的消息类型有两类。

一类是发给sdk对应后端服务的消息,如驱动或查询数字人;

另一个是指令型消息,如音频静音、视频播放等。

5.3.1 sendMessage方式

playVideo针对不同消息类型分别封装了不同的方法,可直接使用。

代码实例

import {v4 as uuidV4} from 'uuid';
// data 格式类型
const jsonStr = {action: 'TEXT_RENDER', body: '你好', requestId: uuidV4()}; // requestId不加默认使用sdk自生成的id
// 发送消息
dhIframe.sendMessage({
  action: 'TEXT_RENDER',
  body: '你好,这是我的开场白自我介绍,我是数字人',
  requestId: commandId
});

requestId说明:可自定义构造requestId进行驱动数字人,驱动的回调消息会沿用自定义构造的requestId。

action说明:可选值:TEXT_RENDER,含义为进行数字人语音驱动

body说明:

TEXT_RENDER时body的可选值 备注
你好,我是数字人 播报内容
<interrupt></interrupt> 打断当前数字人播报
<speak><say-as type="telephone">110</say-as></speak> 指定读法的高级播报内容,支持SSML使用说明
<speak>开始说话<silence time="5s"></silence>停止5s后继续说话</speak> 支持播报中停顿
<speak><audio src="http://meitron-test.bj.bcebos.com/mofachengbao_part.wav"/> </speak> 音频播放
<speak interruptible="false">这段话不允许打断这段话不允许打断这段话不允许打断</speak> 播报不受打断的内容,后续textRender会在上句播报完成后开始播报,但仍可被interrupt标签打断

驱动消息回调事件,查看 【5.2.4 msg数据信息】

5.3.2 流式文本驱动方式

代码实例

dhIframe.sendMessage({
    action: 'TEXT_STREAM_RENDER',
    body: JSON.stringify({
        first: true,
        last: false,
        text: '你好啊,我是'
    }),
    requestId: commandId
});

dhIframe.sendMessage({
    action: 'TEXT_STREAM_RENDER',
    body: JSON.stringify({
        first: false,
        last: false,
        text: '数字人'
    }),
    requestId: commandId
});

dhIframe.sendMessage({
    action: 'TEXT_STREAM_RENDER',
    body: JSON.stringify({
        first: false,
        last: false,
        text: '分身'
    }),
    requestId: commandId
});

setTimeout(() => {
    dhIframe.sendMessage({
        action: 'TEXT_STREAM_RENDER',
        body: JSON.stringify({
            first: false,
            last: false,
            text: '今天天气'
        }),
        requestId: commandId
    });

    dhIframe.sendMessage({
        action: 'TEXT_STREAM_RENDER',
        body: JSON.stringify({
            first: false,
            last: true,
            text: '很好'
        }),
        requestId: commandId
    });
}, 500);

参数说明

参数 类型 解释
action TEXT_STREAM_RENDER 流式文本驱动key
body string body: JSON.stringify({
text: string, (播报内容)
first: boolean, (第一个流式数据设置first为true, 其余设置为false)
last: boolean (最后一个流式数据设置last为true, 其余设置为false)
})
requestId string 生成的随机id, 一轮流式文本驱动需使用同一个requestId

5.3.3 sendCommand方式

实例代码

// 驱使数字人视频静音指令
dhIframe.sendCommand({
    subType: 'muteAudio',
    subContent: mute // mute: true/false
});

subType参数

subType可选值 说明 dhIframe中已封装好的方法 使用方式
muteAudio 静音本地vidio, audio元素 muteAudio dhIframe.muteAudio(true)
playVideo 数字人视频被暂停时播放 playVideo dhIframe.playVideo(true)


5.3.4 sendAudioData方式

实例代码: 整段音频驱动

dhIframe.sendAudioData({
  action: 'AUDIO_RENDER',
  body: base64String,
  requestId: uuidV4()
})

// 或者
dhIframe.sendAudioData({
  action: 'AUDIO_STREAM_RENDER',
  requestId: uuidV4(),
  body: JSON.stringify({
    audio: base64String,
    first: true,
    last: true
    })
})

实例代码: 流式音频驱动

// 第一条驱动音频
const requestId = uuidV4();
dhIframe.sendAudioData({
  action: 'AUDIO_STREAM_RENDER',
  requestId,
  body: JSON.stringify({
    audio: base64String,
    first: true,
    last: false
    })
})

// 第二条驱动音频
dhIframe.sendAudioData({
  action: 'AUDIO_STREAM_RENDER',
  requestId,
  body: JSON.stringify({
    audio: base64String,
    first: false,
    last: false
    })
})

// 第三条驱动音频
dhIframe.sendAudioData({
  action: 'AUDIO_STREAM_RENDER',
  requestId,
  body: JSON.stringify({
    audio: base64String,
    first: false,
    last: true
    })
})

tip1:仅支持pcm数据,pcm数据大小 限制2M
tip3:音频属性仅支持"16k"、"16bit" 和 "单声道"

16k:这通常指的是音频的采样率为16kHz(千赫兹),意味着音频信号每秒被采样16,000次。采样率越高,能够记录的声音频率范围越宽,声音的高频细节就越丰富。16kHz的采样率一般适用于语音录音,足以覆盖人声的频率范围。

16bit:这表示音频的位深度是16位。位深度决定了音频波形的动态范围,即最小声音和最大声音之间的区别。16位音频可以提供96分贝(dB)的动态范围,适合大多数音乐和语音应用。

单声道:单声道(Mono)音频指的是所有声音都混合到一个单一的音频通道中。与立体声(Stereo)不同,立体声至少使用两个通道(通常是左右两个通道),提供空间感和方向感。单声道适合许多应用,尤其是在只需要语音清晰传达的场合,比如新闻报道、有声书等。

参数解析

参数 类型 解释
action AUDIO_RENDER | AUDIO_STREAM_RENDER 枚举:AUDIO_RENDER:整段音频驱动播报
AUDIO_STREAM_RENDER: 流式音频驱动播报
body string 整段音频驱动:
body:base64String (注: 将pcm音频数据转换为base64格式)
流式音频驱动
body: JSON.stringify({
audio: base64String, (注: 将pcm音频数据转换为base64格式)
first: boolean, (第一个流式数据设置first为true, 其余设置为false)
last: boolean (最后一个流式数据设置last为true, 其余设置为false)})
requestId string 生成的随机id

6. sdk兼容性说明

1、pc端-web测试结论

  • windows系统
  • 系统版本号: 版本:windows 10 专业版 版本号:22H2 操作系统内部版本:19045.4170

说明:--表示无法安装对应版本的浏览器

浏览器 最新版本 拉流 最低兼容版本 拉流
Chrome 129.0.6668.101 107.0.5304.107
Safari -- -- -- --
Edge 129.0.2792.89 118.0.2088.69
QQ浏览器 13.1.0 12.1.1
  • MAC系统
  • 系统版本号 芯片:Apple M1 序列号:C02F149YQ05D macOS:13.6(22G120)(Edge最低兼容版除外)
  • 备注:Edge mac最低兼容使用系统版本:

​ 芯片:Intel 序列号:FVFC226ZL412 macOS:13.6.4(22G513)

浏览器 最新版本 拉流 最低兼容版本 拉流
Chrome 129.0.6668.101 107.0.5304.110
Safari 16.6 16.6
Edge 129.0.2792.89 107.0.1418.28
QQ浏览器 5.0.7.203 -- --

2、移动端-web测试结论

  • Android

说明:--表示无法安装对应的浏览器

手机型号 系统 微信内置 QQ浏览器 Chrome 内置浏览器 UC浏览器
华为Mate 50 鸿蒙4.2.0
华为Mate 9 鸿蒙2.0.0 --
vivo IQOOneo5 安卓13
vivo IQOO9Pro 安卓14
红米K60 Ultra 安卓13
OPPO ace2 安卓12
小米6 安卓8 --
  • iOS
手机型号 系统 微信内置 Chrome Safari
iphone13 ios16.3.1
iphone14 ios17.5.1
iphoneXS ios15.3
iphone11 ios17.5.1
iphone15 ios17.5.1
iphone 12 ios 16.3.1
iphone12 ios14.6

7. 常见问题

7.1 部分浏览器视频组件层级过高

移动端部分android浏览器对视频组件进行过特殊处理,导致视频组件悬浮于页面之上,该场景无法通过代码去解决

  1. 如果只是层级过高,并不会直接全屏,那么可以使用半屏数字人或数字人头像大小,不在数字人界面上方叠加组件
  2. 如果视频组件层级高且会直接全屏,那么可以直接拦截当前浏览器对数字人的使用

7.2 移动端集成,无法自动播放问题;(实现详见结尾demo)

移动端受限于浏览器策略,无法自动播放,需要一次用户交互行为(比如点击),常见处理方案

  1. 进入数字人前有个引导页,页面上进行业务介绍与开始业务的按钮,点击按钮触发数字人的播放
  2. 提前加载数字人iframe,然后将播放事件绑定在前置流程中的按钮上
相关配置:
entry=true

按钮触发方法:
dhIframe.playVideo(true);

注意:部分浏览器只是会继承上一次的用户交互时间,一段时间后也会失效,如果为了保障数字人的稳定性,建议前置加按钮触发

7.3 驱动数字人进行开场白话术,只有唇动无声音 (实现详见篇首demo)

受限于浏览器策略,无法自动有声音视频播放,sdk侧逻辑进行静音播放;

这时需要集成侧监听sdk抛出的rtcState消息localVideoMuted,引导用户完成交互操作后,

使用dhIframe.sendCommand({ subType: 'muteAudio', subContent: false });进行取消静音

7.4 部分iphone微信浏览器打开无数字人,部分安卓浏览器打开数字人不动

iphone微信浏览器无数字人原因:

微信限制,页面需要点击后才可播放视频(静音也不可自动播放)

iphone解决方案:

同6.4,集成侧监听sdk抛出的rtcState消息localVideoMuted,引导用户完成交互操作后,

使用dhIframe.sendCommand({ subType: 'muteAudio', subContent: false });进行取消静音

部分安卓浏览器数字人不动原因:

浏览器限制,页面中用户需要点击iframe区域,才可解除播放限制

解决方案:

诱导用户点击iframe区域后,调用dhIframe.sendCommand({ subType: 'muteAudio', subContent: false })

7.5 驱动数字人后,怎么中途打断数字人播报,以及如何监听数字人播报完成(实现详见篇首demo)

打断发送消息

dhIframe.sendMessage({action: 'TEXT_RENDER', body: '<interrupt></interrupt>'});

监听正常播放完成,首先指定TEXT_RENDER的requestId, 然后监听指定requestId的FINISHED; 监听播报因打断而提前完成,监听指定requestId的RENDER_INTERRUPTED;

7.6 数字人路数较少,如何节约资源,尽可能让资源在客户不用的时候尽快释放掉 (实现详见篇首demo)

设置cp-inactiveDisconnectSec, cp-preAlertSec字段

并监听DISCONNECT_ALERT进行适当的交互提示

监听TIMEOUT_EXIT消息进行销毁iframe操作

7.7 拉流没有画面

  1. 请检查当前页面协议是否为HTTPS,若不是,请更换成HTTPS;
  2. 请按照下图所示步骤继续排查客户端是否收到流

拉流没有画面.png

  1. tab页开启h5-sdk保证已经拉流完成
  2. 新开tab页输入chrome://webrtc-internals/
  3. 点击列表中的最后一个链接

点击列表中的最后一个链接.png

  1. 页面全局搜索bytesReceived, 一直键入回车,直到找到对应页面的[bytesReceived_in_bits/s]图表,检查图标是否为空
  2. 若该图表为空,可能是浏览器插件导致,为过滤浏览器插件影响,请执行以下操作之一:

    1. 关闭所有浏览器插件,重新打开页面
    2. 或打开chrome浏览器无痕窗口,重新打开页面
    3. 或更换其他浏览器,重新打开页面

目前已知会影响RTC正常拉流的浏览器插件:PureVPN Proxy

如关闭所有浏览器插件并更换其他浏览器仍没有画面,请提交工单与我们联系;

7.8 音频驱动效果差

接受的音频数据必须是 pcm无损音频编码格式,需检测数据是否进行了压缩编码
如来源是音频 url,检测 url 后缀是否是 pcm。如是 mp3,m4a, wav等格式则不支持
另外检查音频属性是否为支持"16k"、"16bit" 和 "单声道"

7.9 如何控制数字人大小

步骤 1:通过设置 url 中参数mode=corp, resolutionWidth,resolutionHeight调整数字人原始视频流的分辨率,以及设置合适的cameraId
步骤 2:为iframe添加外层div包裹,并设置overflow: hidden
步骤 3:通过iframe 的style中的width, height, top, left等属性,调整数字人视频的大小到合适的尺寸,位置处于预期的位置

<div className="iframe-wrapper">
<iframe
    id="digital-human-iframe"
    src="https://open.xiling.baidu.com/cloud/realtime?token=自行填写&initMode=noAudio&cameraId=自行填写&figureId=自行填写&resolutionWidth=1080&resolutionHeight=1920&mode=corp"
    allow="autoplay"
>
</div>
.iframe-wrapper {
    position: absolute;
    width: 100vw;
    height: 100vh;
    top: 0;
    left: 0;
    overflow: hidden;
}

#digital-human-iframe {
    position: absolute;
    width: 140vw;
    height: 120vh;
    top: -20vh;
    left: -20vw;
}

7.10 demo运行报错如下

image.png

解决方案:使用yarn进行安装,并按照提示升级node版本

7.11 抠绿导致绿色配饰也被清除,自定义抠色参数

例如: 人像无红色配饰,使用红背景扣红方案
步骤1. url删除autoChromaKey参数, 为url添加扣色参数

chromaEffects = {"version":2,"chromaKey":{"screen":[255,0,0],"similarity":90,"edgeShrink":1,"smoothness":210,"spill":100,"opacity":1,"contrast":0,"brightness":0,"gamma":0}}

similarity: 默认70, 所抠颜色与人像视频中颜色之间的相似度,值越高,删除的相似像素越多
edgeShrink: 默认为3, 边缘收缩, 边缘收缩的幅度系数,值越高,边缘黑边收缩幅度越大
screen: 为需要抠色的三原色数组,需要和步骤2设置的背景色一致
smoothness: 默认80,所抠颜色的平滑度,值越高,抠除边缘的平滑效果越强
步骤2. 设置颜色为[255,0,0](#FF0000)的纯色背景图。
url新增参数: backgroundImageUrl=https://sdk-demo.bj.bcebos.com/red.jpg

上一篇
视频组件接入手册
下一篇
小程序版