远程双录

通过阅读本文,您可以快速接入 IDRS SDK,实现远程双录的相关功能,关于远程双录的更多信息请参见 概述

前提条件

在接入 IDRS SDK 远程双录之前,请确保您已完成以下操作:

  1. 申请阿里云公有云用户,并开通金融云账号。

  2. 购买并开通智能双录质检服务。

  3. 在 智能双录质检控制台中创建应用,并获取应用 ID,详细信息请参见 创建应用

  4. 在控制台中为登录用户创建 AK/SK,并获取用户的 AK/SK 信息。

    关于如何使用 SDK 的更多信息请参见 新用户如何开始使用手机端 SDK

说明

如果您在远程双录中使用水印功能,请确保已在控制台中创建水印,更多信息请参见 创建水印

创建项目工程

打开 Android Studio IDE,用 Android Studio 创建一个项目工程。

说明

Android Studio 下载地址请参见 Android Studio 下载文件归档

接入 IDRS

配置项目环境

  1. 在根目录下的 build.gradle 中添加 Maven 源。

    buildscript {
        ext.mpaas_artifact = "mpaas-baseline"
        ext.mpaas_baseline = "10.2.3-8"
    }
    
    allprojects {
        repositories {
    	  //...
    	maven {
                url 'http://mvn.cloud.alipay.com/nexus/content/repositories/releases/'
                name 'alipay'
                credentials {
                    username 'mvn_read_ws'
                    password 'mrk8929'
                }
            }
    	  //...
    	}
    }
  2. 在应用目录下的 build.gradle(:app) 中引入依赖。

  3. defaultConfig{
      ndk {
               abiFilters "armeabi","armeabi-v7a", "arm64-v8a" 
    			//如果要设置指定abi 在初始化之前调用IdrsSdk.getInstance().setOsType();	
            }
    }
    
    
    dependencies {
      	implementation platform("com.mpaas.android:$mpaas_artifact:$mpaas_baseline")
        implementation ('com.mpaas.android:idrs')//双录原子能力库
      	implementation 'com.aliyun.openservices:aliyun-log-android-sdk:2.6.2'//日志库
        implementation 'com.squareup.okhttp3:okhttp:3.11.0'//网络库
        implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'//网络库
        implementation "com.alibaba:fastjson:1.1.54.android"//json库
    }
  4. 在应用目录下的 AndroidManifest.xml中为 IDRS SDK 申请权限。

        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.CAMERA" />
    
        <uses-feature android:name="android.hardware.camera" />
        <uses-feature android:name="android.hardware.camera.autofocus" />
        <uses-feature android:name="android.hardware.microphone" />
    
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

IDRS 使用流程

初始化 IDRS

路径:com.mpaas.idrs.IdrsSdk#init

初始化方法仅对 IDRS SDK 初始化所在的 activity 进行前台监听,因此为了精确地计算使用时长,您可以在 Application onCreate 中调用初始化方法。

IdrsAppLifecycle.init(this);

在所需场景中初始化 IDRS SDK 的方法如下:

/**
 * 初始化
 * @param idrsParams 用户数据
 * @param sdkInitCallBack 创建回调 成功(可获取artvc实例设置监听)/失败
 * @param progressCallBack 资源下载进度,不使用动态获取资源可以不传 
 */
 public void init(Context context, 
                  IdrsParams idrsParams, 
                  SdkInitCallBack sdkInitCallBack, 
                  SdkResourceProgress progressCallBack)
/**
 * sAppId 控制台获取
 * AK 控制台获取
 * SK 控制台获取
 * sUid 身份标识、推荐数字、字母
 * sType IdrsSdk.TYPE_REMOTE 远程  IdrsSdk.TYPE_LOCAL 本地
 * sSecurityToken  定制版本密钥,阿里云用户直接传null 
 * engineTypes 使用的模块
 */
public class IdrsParams {
    public String sAppId;
    public String AK;
    public String SK;
    public String sUid;
    public String sType;
    public String sSecurityToken;
    public Set<EngineType> engineTypes;
}

public interface SdkInitCallBack {
     void success();
     void fail(String message);
}
public interface SdkResourceProgress {
    void progress(int progress);
}
/**
 * 智能双录包含的引擎模块
 */
public enum EngineType {
    AUDIO_DETECT_ENGINE,    //语音识别
    FACE_DETECT_ENGINE,     //人脸检测
    HAND_DETECT_ENGINE,     //手势识别
    OCR_DETECT_ENGINE,      //OCR
    LOCAL_RECORDE_ENGINE,   //本地录制
}

动态获取资源文件

//设置动态获取资源
implementation platform("com.mpaas.android:$mpaas_artifact:$mpaas_baseline")
implementation ('com.mpaas.android:idrs') {
    exclude module:'idrs-dynamic-res-local-pkg-build' //云端资源本地包模块
}
//默认arm64-v8a 设置指定so库

public void setABIType(Set<ABIType> abiType)

/**
 * @param 下载资源回调 
 *
 */
public  void getSdkResourceData(SdkResourceCallback SdkResourceCallback)

创建房间

路径:com.mpaas.idrs.IdrsSdk#createRoom

/**
 * 创建房间
 * @param context Activity Context
 * @param sdkInitCallBack 创建回调 成功(可获取ARTVC实例设置监听)/失败
 */
public void createRoom(Context context, final SdkInitCallBack sdkInitCallBack)

获取 ARTVC 实例

路径:com.mpaas.idrs.IdrsSdk#getRtcEngineInstance

调用 getRtcEngineInstance 接口可以实现 ARTVC 的相关功能,更多信息请参见 Android 进阶功能

public AlipayRtcEngine getRtcEngineInstance()

加入房间

路径:com.mpaas.idrs.IdrsSdk#joinRoom

/**
 * 加入房间
 * @param context Activity Context
 * @param roomId 房间号
 * @param token 房间密码
 * @param sdkInitCallBack 加入回调 成功/失败
 */
public void joinRoom(Context context, String roomId, String token, final SdkInitCallBack sdkInitCallBack)

开启录制

路径:com.mpaas.idrs.IdrsSdk#startRTCRecord

/**
 * 开启录制
 * @param waterMarkId 水印ID
 */
public void startRTCRecord(String waterMarkId)

开启录制扩展

路径:com.mpaas.idrs.IdrsSdk#startRTCRecord(java.lang.String, java.lang.String, java.util.Map<java.lang.String,java.lang.String>, com.mpaas.idrs.RecordParam)

/**
     * 开启RTC服务端录制
     * @param waterMarkId 水印ID 传null则为自定义水印模式
     * @param tagFilter   数据流tag 传null则为合流录制模式
     * @param config      占位符水印显示配置
     * @return RequestId   录制Id 需要保存后通过stopRTCRecord停止对应流的录制
     * ----------------------------------------------------------------------
     * 如果是在createRoom extra参数开启的录制,会在onRecordInfo回调给到recordId
     * 其余的都在rtcEngine.customRawRequest 调用,在AlipayRtcEngineEventExtendListener的onCustomRawResp透出服务器结果
     * requestId = rtcEngine.customRawRequest(MSG_SERVER_RECORD_START,new JSONObject());
     * if(requestId == null){
     *     Log.e(TAG,"customRawRequest faill");
     * }
     */
    public Long startRTCRecord(String waterMarkId, String tagFilter, Map<String, String> config, RecordParam recordParamObj)

变更录制配置

路径:com.mpaas.idrs.IdrsSdk#modifyRTCRecordConfig

/**
     * 变更录制配置
     * @param recordId       录制Id
     * @param tagPositions   布局配置
     * @param overlaps       水印配置
     * @return  requestId
     */
    public Long modifyRTCRecordConfig(String recordId, TagPositions tagPositions, Overlaps overlaps)

结束录制

路径:com.mpaas.idrs.IdrsSdk#stopRTCRecord

/**
 * 结束录制
 * @param recordId 录制ID
 * @param reportRequest 上传录制参数
 * @param callBack 上传回调 成功/失败
 */
public void stopRTCRecord(String recordId, UploadReportRequest reportRequest, UploadReportCallBack callBack)

自定义音频发布

publishConfig.videoSource = VIDEO_SOURCE_NULL;
publishConfig.audioSource = PublishAudioSource.AUDIO_SOURCE_CUSTOM;
publishConfig.customAudioOptions = new CustomAudioOptions();
publishConfig.customAudioOptions.customAudioListener  = createRtcCustomAudioListener(publishConfig.videoSource);
        rtcEngine.publish( publishConfig );

public RtcCustomAudioListener createRtcCustomAudioListener(PublishVideoSource publishVideoSource){
        final String pcmFileName = "licai.pcm";
        final InputStream inputStream;
        try{
            inputStream = getAssets().open(pcmFileName);
        }catch (Exception e){
            Log.e(TAG,"openfile:"+e.toString());
            return null;
        }
        if(inputStream == null){
            Log.e(TAG,"inputStream == null");
            return null;
        }
        CustomAudioListener listener = null;
        try {
            listener = new CustomAudioListener(inputStream,publishVideoSource);
        }catch (RuntimeException e){
            Log.e(TAG,e.toString());
            e.printStackTrace();
        }
        if(listener != null){
            listener.setVolume(100);
        }

        return listener;
    }
 
// CustomAudioListener.java
import java.io.InputStream;
import java.nio.ByteBuffer;

import android.util.Log;
import com.alipay.mobile.artvc.constants.PublishAudioSource;
import com.alipay.mobile.artvc.constants.PublishVideoSource;
import com.alipay.mobile.artvc.engine.AlipayRtcEngine;
import com.alipay.mobile.artvc.engine.CustomAudioResult;
import com.alipay.mobile.artvc.engine.RtcCustomAudioListener;
import com.alipay.mobile.artvc.params.UnpublishConfig;

public class CustomAudioListener extends RtcCustomAudioListener {
    final public static String TAG = "CustomAudioListener";
    private byte[]buffer;   //临时变量
    private final AlipayRtcEngine rtcEngine;
    private final InputStream inputStream;
    private final CustomAudioResult result = new CustomAudioResult(); //返回值
    UnpublishConfig unpublishConfig = new UnpublishConfig();
    //※※※InputStream仅做demo使用,如果要上线需要考虑io读取问题。
    public CustomAudioListener(InputStream inputStream, PublishVideoSource publishVideoSource){
        rtcEngine = AlipayRtcEngine.getOnlyInstance();
        if(rtcEngine == null){
            throw new RuntimeException("rtcEngine is null");
        }
        this.inputStream = inputStream;
        unpublishConfig.videoSource = publishVideoSource;
    }
    @Override
    public void onCustomAudioRecordStarted(ByteBuffer byteBuffer) {
        //初始化ByteBuffer的position等参数,onNeedCustomAudioData可直接向array填写数据。
        //也可以直接通过position、limit等方法初始化。
        byteBuffer.rewind();
        byteBuffer.put(new byte[byteBuffer.capacity()]);
    }

    @Override
    public void onCustomAudioRecordStopped() {
        Log.i(TAG,"onCustomAudioRecordStopped");
        unpublishConfig.audioSource = PublishAudioSource.AUDIO_SOURCE_CUSTOM;
        rtcEngine.unpublish(unpublishConfig);
    }

    //返回读取的数据长度,若返回-1表示结束录制,将会转到onCustomAudioRecordStopped()并结束线程。若要重新开始需要重新推流。
    @Override
    public CustomAudioResult onNeedCustomAudioData(ByteBuffer byteBuffer) {
        try{
            buffer = byteBuffer.array();
            result.lenth = inputStream.read(buffer,byteBuffer.arrayOffset(),byteBuffer.capacity());
            if(result.lenth < byteBuffer.capacity()){
                Log.i(TAG,"pcm读取完毕");
                result.noMoreAudioData = true;
                return result;
            }
        }catch (Exception e){
            Log.e(TAG,"[error]onNeedCustomAudioData:"+e.toString());
            result.noMoreAudioData = true;
            result.lenth = 0;
        }
        return result;
    }

    //0表示静音,100表示正常音量。范围0~100
    public void setVolume(final int newVolume) {
        result.volume = newVolume;
    }
}

本地音频旁路回调

mAlipayRtcEngineAudioListener.setEnableAudioCaptured(true);
rtcEngine.setAlipayRtcEngineAudioListener(mAlipayRtcEngineAudioListener, null);

private AlipayRtcEngineAudioListener mAlipayRtcEngineAudioListener = new AlipayRtcEngineAudioListener() {
        @Override
        public boolean getEnableAudioCaptured() {
            return super.getEnableAudioCaptured();
        }

        @Override
        public boolean getEnableAudioSoundVolume() {
            return super.getEnableAudioSoundVolume();
        }

        @Override
        public void onWebRtcAudioCapturered(AlipayRtcAudioInfo alipayRtcAudioInfo) {
            super.onWebRtcAudioCapturered(alipayRtcAudioInfo);
            Log.i(TAG, "AudioCapture onSoundVolume: " + JSON.toJSONString(alipayRtcAudioInfo));
        }

        @Override
        public void onSoundVolume(AlipayRtcAudioSoundInfo info) {
            super.onSoundVolume(info);
            Log.i(TAG, "onSoundVolume: " + JSON.toJSONString(info));
        }
    };

远端音频旁路回调

rtcEngine.setAudioTrackListener(new AlipayRtcEngineAudioTrackListener() {
            //不要阻塞此回调。
            @Override
            public void onWebRtcAudioTrackData(AlipayRtcAudioInfo alipayRtcAudioInfo) {
                if (alipayRtcAudioInfo != null && alipayRtcAudioInfo.data != null) {
                    Log.i(CallActivity.TAG, "AudioCapture remote: " + JSON.toJSONString(alipayRtcAudioInfo));
                }
            }
        }.setEnableAudioTrackCopy(true),null);

退出房间

路径:com.mpaas.idrs.IdrsSdk#release

退出房间即释放 IDRS。

public void release()

IDRS 对外能力接口

回传双录结果

/**
     * 回传双录结果
     * @param resultBean 录制结果
     * @param callback 上传回调
     */
    public static void uploadFiles(final IdrsProcessResultBean resultBean, UploadCallback callback)

获取房间信息

public void setRoomInfo(RoomInfo roomInfo)

设置房间信息

public void setRoomInfo(RoomInfo roomInfo)

获取 RTC 实例

public AlipayRtcEngine getRtcEngineInstance()

置用户 ID

public void setUserId(String userId)

获取 AppData

public DataBean getAppData()

开启语音识别

public int startDialogforData(Handler handler)

停止语音识别

public void stopDialog()

创建面部识别检测器

/**
     * 创建面部识别检测器
     * @param callBack 初始化回调 
     * @return FaceDetector
     */
    public FaceDetector createFaceDetector(SdkInitCallBack callBack)

创建 OCR 检测器

public OCRDetector createOCRDetector(SdkInitCallBack callBack)

创建手势识别检测器

public HandDetector createHandDetector(SdkInitCallBack callBack)

监听屏幕旋转

     /**
     * 监听屏幕旋转
     */
    public void detectScreenRotate(Context context)

开启手势识别

/**
     * 开启手势识别
     * @param data 图像帧
     * @param imageWidth 宽
     * @param imageHeight 高
     * @param angle 角度
     * @param isFrontCamera 是否前置摄像头
     * @param isStatic 是否静态识别
     * @return 识别结果
     */
    public ArrayList<HandDetectionResult> startHandDetection(byte[] data, int imageWidth, int imageHeight, int angle, boolean isFrontCamera, boolean isStatic)

开启人脸检测

/**
     * 人脸检测
     *
     * @param data
     * @param imageWidth
     * @param imageHeight
     * @param angle
     * @param needFlipX
     * @return
     */
    public DectetResult[] startDetectFace(byte[] data, int imageWidth, int imageHeight, int angle, boolean needFlipX)

获取人脸特征

public float[] getFeature(DectetResult dectetResult)

获取位图特征

public float[] getBitmapFeature(Bitmap bitmap)

人脸识别相关度

public float faceRecognitionSimilarity(float[] features1, float[] features2)

画面实时标记

public RectF viewRectToFrameRect(RectF viewRect, int viewWidth, int viewHeight, int frameWidth, int frameHeight, boolean mirror, int rotate)

身份证识别

/**
     * 身份证识别
     * @param width 宽
     * @param height 高
     * @param data 数据帧
     * @param roi
     * @param rotation 角度
     * @param mirror 是否镜像
     * @param isFront
     * @return
     */
    public String ocr_run(int width, int height, byte[] data, float[] roi, int rotation, boolean mirror, boolean isFront)

手写体识别

public String classify_run(int width, int height, byte[] data, float[] roi, int rotation, boolean mirror)

TTS 相关

/**
     * 开启tts
     * @param text 
     * @param listener
     */
    public void startTTs(String text, AudioService.TTsListener listener) 

    /**
     * 取消tts
     */
    public void cancelTts() 

    /**
     * 暂停tts
     */
    public void pauseTts() 

    /**
     * 当前是否暂停
     * @return 
     */
    public boolean isPauseTts() 

    /**
     * 是否正在播放
     * @return 
     */
    public boolean isPlayTts()

    /**
     * 恢复tts
     */
    public void resumeTts() 

    /**
     * 设置tts参数
     * @param key 
     * @param value
     */
    public void setparamTts(String key, String value)