开放能力
开发平台
行业应用
生态合作
开发与教学
资讯 社区 控制台
技术能力
语音技术
文字识别
人脸与人体
图像技术
语言与知识
视频技术
AR与VR
数据智能
场景方案
部署方案
行业应用
智能教育
智能医疗
智能零售
智能工业
企业服务
智能政务
信息服务
智能园区

虚拟形象Android开发文档

虚拟形象Android开发文档

简介

百度虚拟形象sdk是基于图像识别、语音识别与合成、人像建模等人工智能技术,以电子屏、VR等设备为载体,实现人机交互的虚拟人,面向餐饮、金融、广电、教育、营销等行业,提供全新智能对客服务,降低人力成本,提升服务质量和效率。同时基于百度AR技术,塑造卡通形象,打造更有亲和力的虚拟形象。

开发指南

概述

DigitalHuman SDK 以DigitalHuman API的形式提供给开发者,包含JAVA,Objective-C两种语言形式。

功能

DigitalHuman SDK 实现功能包括:

  • 播报

    输入文本进行语音播报

  • 对话

    输入文本或录音进行对话聊天

  • 模型渲染

    初始化完成即可将虚拟形象渲染在页面上

  • 切换配饰

    切换虚拟形象的配饰,包括但不限于服装和发型

  • 动作和表情触发

    输入不同参数来触发不同的动作和表情

  • 视角变换

    切换虚拟形象全身和半身

开发配置

  • Android Studio 3.1及以上
  • android系统4.4及以上

SDK Java API 快速入门

概述

demo文件夹内是使用DigitalHuman SDK相关api实现虚拟形象功能的demo工程源码。

文件列表

  • digitalhuman.aar

    虚拟形象相关服务集合的SDK文件,与digitalhumansdk.jar、so可以二选一使用。点击下载

  • digitalhumansdk.jar、so

    虚拟形象相关服务的SDK⽂件,与digitalhuman.aar可以二选一使用。点击下载

  • dumix.license

    使用虚拟形象相关服务的鉴权文件,由开发者提供应用包名后生成;初始SDK中不包含license。

  • demo

    sdk相关接口接入示例,点击下载

  • DigitalHumandemo.apk

    虚拟形象样板体验demo,点击下载

工程设置

  1. 资源配置

    sdk有两种接入方式,推荐使用jar方式引入不可同时使用两种方式!!!

    (1)、aar方式接入。将digitalhuman.arr和dumix.license分别放入libs和assets工程目录下

    image

    (2)、jar和so接入。将digitalhumansdk.jar和相关so文件复制到libs目录

  2. 添加依赖

    在app目录下的build.gradle中添加依赖

    android{
    	... // 其它配置
    
    	defaultConfig{
    		...
    
    		minSdkVersion 19
    		targetSdkVersion 28
    
    	}
    
    	repositories {
        	flatDir {
            	dirs 'libs'
        	}
    	}
      
      // jar方式引入需添加如下代码
      sourceSets {
          main {
              jniLibs.srcDirs = ['libs']
          }
      }
    }
    dependencies {
    	implementation fileTree(dir: 'libs', include: ['*.jar'])
      
    	// aar形式引入SDK
    	// implementation(name: 'digitalhumansdk', ext: 'aar')
    }
  3. 添加权限

    配置清单文件 app/src/main/AndroidManifest.xml中添加以下权限

    <!--访问网络权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--文件读写权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--录音权限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
  4. 混淆忽略配置

    ### 使用digitalhumansdk时添加如下忽略
    -keep class com.baidu.ar.** {*;}
    -keep interface com.baidu.ar.** { *; }

接入示例

  1. 权限申请

    private static final String[] ALL_PERMISSIONS = new String[]{
            Manifest.permission.INTERNET,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.RECORD_AUDIO};
    
    
    private void checkPermissions() {
        // 6.0以下版本直接同意使用权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!hasNecessaryPermission()) {
                requestPermissions(ALL_PERMISSIONS, REQUEST_CODE_ASK_ALL_PERMISSIONS);
            } else {
                initDigitalHuman(); // 权限申请成功后才能进行sdk初始化
            }
        } else {
            initDigitalHuman();
        }
    }
    /**
     * 检查权限
     *
     * @return
     */
    private boolean hasNecessaryPermission() {
        List<String> permissionsList = new ArrayList();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (String permission : ALL_PERMISSIONS) {
                if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                    permissionsList.add(permission);
                }
            }
        }
        return permissionsList.size() == 0;
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                               @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (hasNecessaryPermission()) {
            initDigitalHuman();
        }
    }
  2. sdk初始化

    digitalHuman = DigitalHuman
                    .getInstance()
                    .setContext(ARActivity.this)	// 设置上下文
                    .setResolution(720, 1280)					// 设置渲染分辨率
    //                .setCasePath(casePath) 			// 可使用本地模型资源,默认下发
                    .setDumixListener(new DumixListener() {	// 设置sdk中系列状态监听
                        @Override
                        public void onStateChanged(final int type, final String msg) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                  // 状态监听结果处理
                                    stateChangeResult(type, msg);
                                }
                            });
                        }
                         // 交互回调
                        @Override
                        public void onDrawViewTouch(MotionEvent event) {
                            switch (event.getAction()) {
                                case MotionEvent.ACTION_DOWN:
    
                                    break;
                            }
                        }
                    })
                    .initDumix(mDrawView); // 初始化并启动虚拟形象sdk
  3. 文本播报

    digitalHuman.sendReadingMessage(sendMsg, new DigitalHuman.SubtitleCallback() {
        @Override
        public void subtitle(final String text) {
            // 虚拟形象播报的文本,在播报开始时返回
        }
    });
  4. 文本输入对话

    digitalHuman.sendChatMessage(sendMsg, new DigitalHuman.SubtitleCallback() {
        @Override
        public void subtitle(String text) {
            // 虚拟形象播报的文本,在播报开始时返回
        }
    });
  5. 语音输入对话

    // 开始录音
    digitalHuman.startRecordAudio(new DigitalHuman.AudioProcessListener() {
        @Override
        public void audioProcessResult(final TextResponseBodyWrap responseBody) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (responseBody.isCompleted()) {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                // UI修改,停止录音,发送语音解析结果
                              	mDigitalHuman.finishRecordAudio();
                                sendMsg(responseBody.getContent(););
                            }
                        }, 500);
                    }
                }
            });
        }
    });
    
    // 结束录音。主动调用完成录音或者语句间隔超过2秒会自动结束录音
    digitaHuman.finishRecordAudio();
    
    /**
     * 发送文本开始对话
     * sendMsg 录音语音解析结果
     */
    private void sendMsg(String sendMsg){
    		digitalHuman.sendChatMessage(sendMsg, new DigitalHuman.SubtitleCallback() {
        		@Override
        		public void subtitle(String text) {
            		// 虚拟形象播报的文本,在播报开始时返回
        		}
    		});
    }
  6. 切换配饰

    以切换服装为例,实际调用changeRenderParameter,参数列表见Api说明。

    /**
     * 切换衣服
     *
     * @param clothName
     */
    private void changeClothes(String clothName) {
        HashMap<String, Object> message = new HashMap<>();
        message.put("event_name", "change_outfit_operation");
        HashMap<String, Object> dataWrapper = new HashMap<>();
        dataWrapper.put("node", "avatar");
        dataWrapper.put("outfit", clothName);
        message.put("event_data", dataWrapper);
        digitalHuman.changeRenderParameter(message);
    }
  7. 打断

    该方法打断当前的数字人播报,动作和口型回归初始态,被打断的语句信息丢失。

    // 打断当前的播报或者对话
    private void interruptReading() {
        if (digitalHuman != null) {
            digitalHuman.breakAudio();
        }
    }
  8. 暂停

    系统暂停后,相关的渲染和交互都会停止,推荐在activity的onPause中调用。

    if (digitalHuman != null) {
        digitalHuman.pause();
    }
  9. 继续

    继续之前暂停的渲染和交互,推荐在activity的onResume中调用

    if (digitalHuman != null) {
        digitalHuman.resume();
    }
  10. 退出

    退出并销毁虚拟形象,推荐在activity的onDestroy中调用

    if (digitalHuman != null) {
        digitalHuman.destroy();
    }
  11. 通过pcm音频数据获取表情数据

    // 发送开始标志
    mDigitalHuman.queryBlendShape(BlendShapeRequest.begin());
    while ((len = inputStream.read(buffer)) != -1) {
      // 发送 pcm 数据,需 Base64 转码
      mDigitalHuman.queryBlendShape(BlendShapeRequest.audio(Base64.encodeToString(buffer, 0, len, Base64.NO_WRAP)));
    }
    // 发送结束标志,需发送文本和音频信息:采样率、采样位宽、声道数
    mDigitalHuman.queryBlendShape(BlendShapeRequest.end(text, sampleRate, bitsPerSample, numChannel));
    
    // 注册 BlendShape 数据结果回调
    mDigitalHuman.setQueryBlendShapeListener(new IQueryBlendShapeCallback() {
                @Override
                public void onBlendShapeResponse(BlendShapeResponse blendShapeResponse) {
                  		// 获取 BlendShape 数据
                      List<HashMap<String, Double>> blendShapeMaps = blendShapeResponse.getBlendShapeMaps();
                  		// 设置表情数据,并开始播放
                  		 blendShapePlayer.setDataSource(blendShapeResponse.getBlendShapeMaps());
                       blendShapePlayer.start();
    									
                }
            });
    
    // 构造表情播放器
    blendShapePlayer = new BlendShapePlayer(mDigitalHuman);
  12. BlendShape表情播放

    // 构造表情播放器
    BlendShapePlayer  blendShapePlayer = new BlendShapePlayer(digitalHuman);
    
    // 设置表情数据
    blendShapePlayer.setDataSource(blendShapeMaps);
    
    // 开始播放
    blendShapePlayer.start();
    
    // 暂停播放
    blendShapePlayer.pause();
    
    // 恢复播放
    blendShapePlayer.resume();
    
    // 停止播放
    blendShapePlayer.stop();
    
    // 设置播放完成监听
    blendShapePlayer.setOnCompletionListener(new BlendShapePlayer.OnCompletionListener() {
                @Override
                public void onCompletion() {
                }
            });
  13. 发送对话消息 For Unit
// 构造Unit消息参数
ReqExtra reqExtra = new ReqExtra();    reqExtra.setAccessToken("24.0ed6db25a484b872536031ae17403e10.2592000.1614333577.282335-23178123");
reqExtra.setLogId("UNITTEST_10000");
reqExtra.setServiceId("S42464");
reqExtra.setUserId("88888");
reqExtra.setSkillIds("");  多个id用,分隔
reqExtra.setSessionId(mUnitSession); // session信息,通过14. Unit Session信息回调获取

digitalHuman.sendChatMessageForUnit(sendMsg,reqExtra, new DigitalHuman.SubtitleCallback() {
                @Override
                public void subtitle(String text) {
                    
                }
            });

Unit消息参数信息,请通过智能对话定制与服务平台 UNIT获取

  1. Unit Session信息回调

     digitalHuman.setUnitSessionListener(new IUnitSessionListener() {
                @Override
                public void onUnitSessionResult(String sessionStr) {
                    mUnitSession = sessionStr;
                }
            });

API参考

DigitalHuman.java

public static DigitalHuman getInstance();

获取DigitalHuman的实例化对象

public DigitalHuman setContext(Context context);

设置上下文

public DigitalHuman setRatio(int width, int height);

设置设置渲染分辨率

public DigitalHuman setDumixListener(DumixListener dumixListener);
public interface DumixListener {
    void stateChange(int type, String msg);

    void onDrawViewTouch(MotionEvent event);
}

设置状态监听。type取值参考DumixConstance.java

public DigitalHuman setCasePath(String casePath);

设置模型资源路径。需要使用本地的模型资源时调用该接口(资源模型默认下发)

public DigitalHuman setUrl(String url)

设置服务地址(如果是自己搭建的服务,可使用该设置)

public DigitalHuman initDumix(TextureView mSurfaceView);

初始化并启动SDK

public void sendReadingMessage(String textMsg, SubtitleCallback subtitleCallback);

发送文本进行播报

public void sendChatMessage(String textMsg, SubtitleCallback subtitleCallback);

发送文本进行聊天

/**
 * 开始录音
 * @param processListener 录音音频解析成文本的监听
 */
public void startRecordAudio(AudioProcessListener processListener);
/**
 * 主动完成录音
 */
public void finishRecordAudio();

语音对话,录音解析完成后需要调用文本对话服务

public void interruptReading()

播报打断

/**
 * 修改渲染参数
 *
 * @param params 参数
 */
public void changeRenderParameter(HashMap<String, Object> params);

切换配饰+动作+表情触发+视角变换

参数构造请参考changeRenderParameter参数说明

DumixConstance.java

DumixState public Eunm:

状态名 状态值 含义
LOAD_CASE_COMPLETED 0 资源加载成功
REQUEST_SUCCESS 2 播报请求成功
REQUEST_FAIL 3 播报请求失败
START_PLAY_RADIO 4 开始播报
RADIO_PLAY_COMPLETED 5 播报完毕
SOCKET_CONNECT 6 流式服务连接成功
SOCKET_FAIL 7 流式服务连接失败

changeRenderParameter参数说明

投建的HashMap需要包含event_name和event_data字段,字段里内容如下,event_data内部为多级HashMap:

含义 event_name event_data 备注
换装(裙装/西装) change_outfit_operation node avatar 节点:预留字段
outfit dress/suit 服装:裙装/西装
换发型(短发/马尾辫) change_hair_operation node avatar 节点:预留字段
Hair short/ponytail 发型:短发/马尾
动作触发 animation_operation node avatar 节点:预留字段
repeat_count n(整数) 动画循环次数:0代表无穷
chip idle(聆听态)/right_hand(右伸手)/front_hand(前伸手)/wave(招手)/emphasize(强调) 动画短名称:聆听态/右伸手/前伸手/招手/强调
operation play/stop 操作:播放/停止
相机位置切换 camera_position_operation position ArrayList 数组,数组长度为3 全身相机姿态参数:0,8,47半身相机姿态参数:0,10.5,25调用例子中见调用示例,三个Float代表相机位置的三维坐标,其中第二个(y坐标)控制相机高低,第三个(z坐标)控制远近,如果效果不佳,可以根据这个参数意义微调。
胸章Logo切换 change_logo_operation node avatar
logo none/baidu/baidu_paw/net/net_icon 对应胸牌:无胸牌、百度胸牌、百度熊掌、智能云胸牌、智能云图标调用例子中见调用示例