3. Android 客户端开发指南

3.1. 概述


  本节用于指导使用 PPVIEW 客户端 SDK 开发 Android 平台手机客户端。
  在客户端的所有流程中,与平台交互的接口,可以直接调用;与设备端交互的接口,需要先创建一个P2P连接,并将这个P2P连接句柄作为参数传递给交互接口。
  请注意,这个作为交互用的P2P连接可以重复使用,但是不能并行使用。即创建后,可以在一个交互流程完成后,用于另一个交互流程,但不能同时用于两个交互流程。
  我们在内部做了P2P连接优化,当创建了多个用于交互的P2P连接时,我们会在内部进行复用,不影响这些多次创建的P2P连接的并行使用。

3.2. 开发准备(以Android Studio作为开发环境)

3.2.1. 创建Android项目



注意Minimum SDK 必须要在API 15 4.0.3以上。

3.2.2. 将jar包和动态库放到指定目录

ppview_cli.jar 依赖gson-xxx.jar,在开发时也可以自己从google 提供的 Maven里下载。

添加完成后在project structure里可以看见已经add成功

把所有的动态库放入指定位置。

3.2.3. 添加程序所需要使用到的权限

<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RIDE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.RAISED_THREAD_PRIORITY" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

3.3. 流程指南

3.3.1. 初始化流程

  • 创建与平台设备交互的对象实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();

这个对象用于和平台及设备进行交互。一个客户端应用进程创建一个交互对象实例即可,此接口采用单例模式,多次调用仅创建一个实例。

  • 初始化参数
ppviewClientInterface.SetAppInfo(vv_url, app_key, app_pass, bound_url, p2p_svr,
    p2p_port, p2p_secret, event_url);

设置平台服务器地址、P2P 服务器地址及应用ID等必要的参数。

3.3.2. 用户账号注册流程

3.3.2.1. 通过手机号注册用户

手机APP->手机APP: 1. 输入手机号
手机APP->云平台: 2. 请求短信验证码
云平台-->手机APP: 3. 请求短信验证码回复
云平台->用户: 4. 短信验证码
用户->手机APP: 5. 手工输入短信验证码
手机APP->云平台: 6. 注册新用户请求
云平台-->手机APP: 7. 注册请求回复
  • 实现并设置回调函数
ppviewClientInterface.setOnRegisterCallback(mRegisterCallback);
PpviewClientInterface.OnRegisterCallbackListener mRegisterCallback = new PpviewClientInterface.OnRegisterCallbackListener() {
    @Override
    public void on_user_regist_callback(int nResult) {
         // TODO: 处理注册用户结果回调
    }

    @Override
    public void on_get_sms_vcode_callback(int nResult) {
        // TODO: 处理取短信验证码请求结果回调
    }
};
  • 请求短信验证码
ppviewClientInterface.c2s_get_sms_vcode_fun(true, r_phonenumber);
  • 注册新用户
ppviewClientInterface.c2s_user_regist_fun(r_name, r_pass, r_name,
    r_email, r_phone, uuid, vcode);

3.3.2.2. 通过邮箱注册用户

手机APP->手机APP: 1. 输入邮箱号
手机APP->云平台: 2. 请求邮箱验证码
云平台-->手机APP: 3. 请求邮箱验证码回复
云平台->用户: 4. 邮箱验证码
用户->用户: 5. 打开邮箱,读取验证码
用户->手机APP: 6. 手工输入邮箱验证码
手机APP->云平台: 7. 注册新用户请求
云平台-->手机APP: 8. 注册请求回复
  • 实现并设回调函数
ppviewClientInterface.setOnRegisterCallback(mRegisterCallback);
PpviewClientInterface.OnRegisterCallbackListener mRegisterCallback = new PpviewClientInterface.OnRegisterCallbackListener() {

    @Override
    public void on_user_regist_callback(int nResult) {
        // TODO: 处理用户注册结果
    }

    @Override
    public void on_get_email_vcode_callback(int nResult) {
      // TODO: 处理获取邮箱注册码结果 
    }
};
  • 请求邮箱验证码
ppviewClientInterface.c2s_get_email_vcode_fun(true, email);
  • 注册新用户
ppviewClientInterface.c2s_user_regist_fun(r_name, r_pass, r_name,
    r_email, r_phone, uuid, vcode);

3.3.3. 密码重置流程

3.3.3.1. 通过手机号重置密码

手机APP->手机APP: 1. 输入手机号
手机APP->云平台: 2. 请求短信验证码
云平台->用户: 3. 短信验证码
用户->手机APP: 4. 用户手工输入验证码
手机APP->手机APP: 5. 输入新密码
手机APP->云平台: 6. 重置密码请求
云平台-->手机APP: 7. 重置密码回复
  • 实现并设置回调函数
ppviewClientInterface.setOnUserCallback(onUserCallbackListener);
ppviewClientInterface.setOnRegisterCallback(mRegisterGetPicCodeCallback);
//获得短信验证码的回调,这里只用到了on_get_sms_vcode_callback
PpviewClientInterface.OnRegisterCallbackListener mRegisterGetPicCodeCallback  = new PpviewClientInterface.OnRegisterCallbackListener() {
    @Override
    public void on_get_sms_vcode_callback(int nResult) {
        //TODO: 处理获取短信验证码结果
    }
    
    ...
};

//修改用户信息的回调,这里只用到了on_reset_pass_callback
private PpviewClientInterface.OnUserCallbackListener onUserCallbackListener = new PpviewClientInterface.OnUserCallbackListener() {

    @Override
    public void on_reset_pass_callback(int nResult, int type, String tag) {

        //TODO: 处理重置密码结果
    }

    ...
    
};

  • 请求短信验证码
ppviewClientInterface.c2s_get_sms_vcode_fun(false, phoneNumer);
  • 根据短信验证码重置密码
ppviewClientInterface.c2s_user_resetpass_sms_fun(phoneNumer2, vcode, newPass);

3.3.3.2. 通过邮箱号重置密码

手机APP->手机APP: 1. 输入邮箱号
手机APP->云平台: 2. 通过邮箱重置密码
云平台-->手机APP: 3. 回复结果
云平台->用户邮箱: 4. 发送重置邮件
用户->用户邮箱: 5. 打开邮件,点击链接
用户邮箱->云平台: 6. 跳转至平台密码重置页
云平台->云平台: 7. 重置密码

注:手机端请求平台向用户邮箱发送密码重置邮件后,流程结束,用户须登录自己的邮箱,点开邮箱中的链接进行重置。

  • 实现并设置回调函数
ppviewClientInterface.setOnUserCallback(onUserCallbackListener);
//修改用户信息的回调,这里只用到了on_reset_pass_callback
private PpviewClientInterface.OnUserCallbackListener onUserCallbackListener = new PpviewClientInterface.OnUserCallbackListener() {
    
    @Override
    public void on_reset_pass_callback(int nResult, int type, String tag) {
        // TODO: 处理重置密码结果
    }
    ...
};
  • 使用邮箱号请求重置密码
ppviewClientInterface.c2s_user_resetpass_emailv2_fun(email);

3.3.3.3. 修改密码

在密码已知的情况下,可直接修改密码,不需要使用密码重置流程。
用手机号和邮箱号新注册的用户,其默认密码为手机验证码或邮箱验证码。可以在注册的最后一步,通过修改密码接口,让用户设置一个自己容易记住的密码。

  • 修改密码
int res = c2s_user_modify_pass_fun(user,
                                oldpass,
                                newpass);

3.3.4. 登录流程

手机APP->手机APP: 1. 输入账号及密码
手机APP->云平台: 2. 登录
云平台-->手机APP: 3. 回复结果

此流程用于APP刚开启时用户登录平台验证。
在ppview android sdk中,所有与平台服务器交互的接口里,如果涉及到权限认证,都需要在调用接口时传入用户的账号和密码,因此实际上不存在登录过程。这个流程仅作为验证用户的账号密码是否正确,并用于APP的登录界面登录。开发都在开发APP时,如果通过这个流程验证,验证用户的账号密码是正确的,需要自己在程序中保存用户账号和密码,并在之后的接口调用中,传入这两个参数。

  • 实现并设置回调函数
ppviewClientInterface.SetOnC2sLoginCallback(onC2sLoginCallback);
//修改用户信息的回调,这里只用到了on_reset_pass_callback
private PpviewClientInterface.OnC2sLoginCallback onC2sLoginCallback = new PpviewClientInterface.OnC2sLoginCallback() {
    
    @Override
    public void on_c2s_login(int nResult) {
        // TODO: 处理登录结果
    }
    ...
};
  • 登录
ppviewClientInterface.c2s_login_fun(user, pass);

3.3.5. 修改用户昵称流程

手机APP->手机APP: 1. 输入新昵称
手机APP->云平台: 2. 请求修改
云平台-->手机APP: 3. 回复结果
  • 实现并设置回调函数
//注册回调
ppviewClientInterface.setOnUserCallback(onUserCallbackListener);

...

PpviewClientInterface.OnUserCallbackListener onUserCallbackListener = new PpviewClientInterface.OnUserCallbackListener() {

    @Override
    public void on_modify_nick_callback(final int nResult,final String newnick) {
        // TODO: 处理修改用户昵称返回的结果
    }
  };
  • 修改昵称
ppviewClientInterface.c2s_user_modify_nick_fun(user_name.getText().toString(),
        user_pass.getText().toString(),
        user_nick.getText().toString());

3.3.6. 获取设备列表流程

由于单个设备可能会有多个通道(摄像头),因此这个接口通常不需要调用,呈现给用户的列表通常是摄像头列表。如果需要在界面上显示设备列表,再分级显示设备下的通道的话,需要获取设备列表和摄像头列表,并自己进行组合。

手机APP->手机APP: 1. 登录(略,参见3.3.4.)
手机APP->云平台: 2. 请求获取设备列表
云平台-->手机APP: 3. 回复结果
  • 实现并设置回调函数
ppviewClientInterface.setOnDevListCallback(OnDevListCallbackListener cb)

public interface OnDevListCallbackListener {
   public void on_devlist_callback(int nResult, String devlist, Object usertag)
    {
        //TODO:处理取得的设备列表
    }
}
  • 获得设备列表
ppviewClientInterface.c2s_get_dev_list_fun(user, pass, usertag);

3.3.7. 获取摄像头列表流程

手机APP->手机APP: 1. 登录(略,参见3.3.4.)
手机APP->云平台: 2. 请求获取摄像头列表
云平台-->手机APP: 3. 回复结果
手机APP->云平台: 4. 获取摄像头缩略图
云平台-->手机APP: 5. 回复
手机APP->手机APP: 6. 打开P2P预连接
  • 实现并设置回调函数
ppviewClientInterface.setOnCamListCallback(mCamlistCallback);
PpviewClientInterface.OnCamListCallbackListener mCamlistCallback = new PpviewClientInterface.OnCamListCallbackListener() {

    @Override
    public void on_camlist_callback(int nResult, String camlist, short pre_sn) {
        //TODO: 获得摄像头列表结果回调
    }

};
  • 获得摄像头列表
int res = ppviewClientInterface.c2s_get_cam_list_fun(user, pass, cur_sn);
  • 获取摄像头缩略图
Bitmap bmp = c2s_get_cam_pic(user, pass, piccid);
  • 开启P2P预连接
int res = ppviewClientInterface.setPreConnectUUIDs(uuidArray);

注:当摄像头列表发生变化时(通常发生在同一个账号多个手机登录,并且添加或删除摄像头时),会收到摄像头列表变化推送,此时需要更新一下摄像头列表。

3.3.8. 局域网内搜索设备

手机APP->局域网: 1. 发送搜索请求
局域网->设备: 2. 搜索请求
设备-->手机APP: 3. 回复自己的信息
手机APP->手机APP: 4. 收集多个设备信息,通过回调返回给上层
  • 实现并设置代理函数
PpviewClientInterface.OnC2DCallbackListener onC2DCallbackListener = new PpviewClientInterface.OnC2DCallbackListener() {
    @Override
    public void on_vv_search_dev_callback(String json) {
        //TODO: 处理搜索设备结果回调
    }
};

ppviewClientInterface.setOnC2DCallback(onC2DCallbackListener);
  • 开始搜索
ppviewClientInterface.vv_startsearch(mActivity);

注:由于广播包在局域网内十分容易丢包,因此建议重复搜索三次,将三次的结果合并在一起。否则可能会存在部分设备没有被搜到。

  • 停止搜索
ppviewClientInterface.vv_stopsearch();

注:搜索完成后,或在搜索过程中需要中途退出时调用

3.3.9. 一键WIFI配置

手机APP->手机APP: 1. 获取当前手机使用的SSID
手机APP->手机APP: 2. 用户输入WIFI密码及设备序列号
手机APP->手机APP: 3. 开启一键WIFI配置
手机APP->无线网络: 4. 发送无线广播,开启定时器
无线网络-->设备: 5. 广播消息被设备截获
设备->设备: 6. 配置无线网络参数
手机APP->手机APP: 7. 停止配置
手机APP->设备: 8. 定时尝试建立点对点连接
设备-->手机APP: 9. 连接结果
手机APP->手机APP: 10. 移除P2P连接回调
  • 实现并设置代理函数
PpviewClientInterface.OnDevConnectCallbackListener onDevConnectCallbackListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {

        //TODO: 处理与设备建立P2P连接结果
    }

};
ppviewClientInterface.setOndevConnectCallback(onDevConnectCallbackListener);
  • 开启配置
ppviewClientInterface.wifistartconfig(mActivity,wifi_ssid.getText().toString(),
    wifi_password.getText().toString());
  • 停止配置
ppviewClientInterface.wifistopconfig();
  • 创建P2P连接
Connect = ppviewClientInterface.createConnect(dev_id, dev_user, dev_pass);

注:流程结束前,请不要将Connect用于其它接口。

建议:总的等待时间为120秒,等待第一个10秒后,开始尝试P2P连接,以后每隔5秒开启、关闭WIFI配置,一直循环直到收到P2P连接成功代理函数或总等待时间超时。

  • 断开P2P连接
ppviewClientInterface.releaseConnect(Connect);
  • 移除P2P连接回调
ppviewClientInterface.removeOndevConnectCallback(onDevConnectCallbackListener);

3.3.10. 添加和删除设备

可以将设备添加到用户账号下,我们称之为绑定,绑定后,设备将出现在用户的设备列表中。

有三种流程来添加用户,开发APP时可以按需实现其中的一种或多种。它们分别是:

  • 已接入互联网的设备,通过设备序列号和密码进行添加
  • 未接入互联网的设备,通过一键WIFI配置无线网络并添加
  • 未接入互联网的设备,通过二维码识别方式配置无线网络并添加

3.3.10.1. 通过设备序列号及密码添加

在APP开发中,设备序列号可以通过搜索局域网中的设备来获取,也可以扫描机身二维码来获取(APP自行开发,SDK不提供),或是直接由用户手工输入。

获取到设备序列号后,使用以下流程:

手机APP->手机APP: 1. 输入设备序列号及密码
手机APP->设备: 2. 尝试建立P2P连接
设备-->手机APP: 3. 连接结果(可重复1~2步共尝试3次)
手机APP->云平台: 4. 添加(绑定)设备
云平台-->手机APP: 5. 添加设备请求的回复
手机APP->设备: 6. 中断P2P连接
手机APP->手机APP: 7. 移除P2P连接回调
  • 实现并设置回调函数
PpviewClientInterface.OnDevConnectCallbackListener onDevConnectCallbackListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理与设备建立P2P连接结果
    }
};

ppviewClientInterface.setOndevConnectCallback(onDevConnectCallbackListener);
ppviewClientInterface.setOnC2DCallback(onC2DCallbackListener);
 
PpviewClientInterface.OnC2DCallbackListener onC2DCallbackListener = new PpviewClientInterface.OnC2DCallbackListener() {
    @Override
    public void on_bind_ip(int nResult, long connectHandler) {
        //TODO: 处理绑定设备结果
    }
};
  • 创建P2P连接
Connect = ppviewClientInterface.createConnect(dev_id, dev_user, dev_pass);

注:流程结束前,请不要将Connect用于其它接口。

  • 添加设备
ppviewClientInterface.Bind_Lang(Connect, svraddr, devname,
    devuser, devpass, binduser, bindpass, dev_lang);
  • 断开P2P连接
ppviewClientInterface.releaseConnect(Connect);
  • 移除P2P连接回调
ppviewClientInterface.removeOndevConnectCallback(onDevConnectCallbackListener);

3.3.10.2. 一键WIFI配置添加设备

手机APP->手机APP: 1. 一键WIFI配置(参见3.3.9.步骤1~9)
手机APP->云平台: 2. 添加(绑定)设备
云平台-->手机APP: 3. 添加设备请求的回复
手机APP->设备: 4. 中断P2P连接
  • 实现并设置回调函数
PpviewClientInterface.OnDevConnectCallbackListener onDevConnectCallbackListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理与设备建立P2P连接结果
    }
};

ppviewClientInterface.setOndevConnectCallback(onDevConnectCallbackListener);
ppviewClientInterface.setOnC2DCallback(onC2DCallbackListener);
 
PpviewClientInterface.OnC2DCallbackListener onC2DCallbackListener = new PpviewClientInterface.OnC2DCallbackListener() {
    @Override
    public void on_bind_ip(int nResult, long connectHandler) {
        //TODO: 处理绑定设备结果
    }
};
  • 添加设备
ppviewClientInterface.Bind_Lang(Connect, svraddr, devname,
    devuser, devpass, binduser, bindpass, dev_lang);
  • 断开P2P连接
ppviewClientInterface.releaseConnect(Connect);
  • 移除P2P连接回调
ppviewClientInterface.removeOndevConnectCallback(onDevConnectCallbackListener);

此处断开的P2P连接是在一键WIFI流程中创建的。

3.3.10.3. 二维码识别添加设备

手机APP->手机APP: 1. 获取当前手机使用的SSID
手机APP->手机APP: 2. 输入WIFI密码
手机APP->手机APP: 3. 生成二维码字符串
手机APP->手机APP: 4. 显示二维码
手机APP->设备: 5. 将二维码对准设备摄像头
设备->设备: 6. 识别并配置WIFI
设备->云平台: 7. 添加设备到用户
云平台->手机APP: 8. 推送添加成功消息

以上步骤请在登录后进行。

如果设备正确识别了二维码并添加到用户账号下,平台会推送一个消息给客户端,通过PpviewClientInterface.OnS2CPushCallback.on_s2c_dev_bindedPpviewClientInterface.OnS2CPushCallback.on_s2c_dev_binded_by_another_user回调给客户端。如果没有正确识别,平台是无法反馈的。

  • 实现并设置回调函数

参见推送处理部分

  • 生成二维码字符串
ppviewClientInterface.getSetupQrcode("http://ppview.vveye.com:3000/webapi/device",
        "zh",user_name.getText().toString(), user_pass.getText().toString(),
        wifi_ssid2.getText().toString(), wifi_password2.getText().toString(), out);

注:可以根据获取到的字符串利用zxing来生成二维码,之后对准设备来进行添加。

3.3.10.4. 删除设备

删除自己添加的设备,和别人分享给自己的设备,需要使用不同的接口。

  • 实现并设置代理函数

删除自己添加的设备:

OnDeleteDevCallbackListener deleteCallback = new OnDeleteDevCallbackListener() {
    @Override
    public void on_delete_dev_callback(int nResult, String devid,
          Object m_usrtag){
            //TODO:处理删除自己添加的设备结果
        }
    }
};

ppviewClientInterface.setOnDevDeleteCallback(deleteCallback);

删除分享给自己的设备:

OnC2sShareCallback shareCallback = new OnC2sShareCallback() {
   @Override
   public void on_c2s_disable_share_cam(int nResult, String dev_id,
         String cam_id) {
        //TODO: 处理删除别人分享给自己的摄像头结果
   }
};

ppviewClientInterface.setOnC2sShareCallback(shareCallback);
  • 删除自己添加的设备:
ppviewClientInterface.c2s_delete_dev_fun(user, pass, devid, usrtag);
  • 删除别人分享给自己的摄像头:
ppviewClientInterface.c2s_share_DisableShareCam_fun(user, pass, devid, camid); 

注:某些设备可能含有多个通道(即多个摄像头,如DVR),在调用PpviewClientInterface.c2s_delete_dev_fun时将删除所有的通道。而分享功能是可以细化到摄像头的,因此调用PpviewClientInterface.c2s_share_DisableShareCam_fun时,删除的仅仅是指定的摄像头。

3.3.11. 播放实时音视频流程(包括云台控制、音频开关、抓图、本地录像、码流切换)

st=>start: 开始
init=>operation: 初始化视窗
create=>operation: 创建播放实例并设置播放窗口
setcb=>operation: 实现并设置代理函数
play=>operation: 开始播放
op=>operation: 云镜控制、抓图、本地录像、音频开关
stop=>operation: 停止播放
e=>end: 结束

st->init->create->setcb->play->op->stop->e
  • 实现并设置回调
OnPlayerCallbackListener previewPlayerCallbackListener = new OnPlayerCallbackListener() {
    @Override
    public void OnPlayStatusChanged(int index, int status, String tag,int progress) {
        //TODO: 处理播放状态变化 
    }

    @Override
    public void GetWidthAndHeight(int i, int width, int height) {
        //TODO: 处理开始播放后得到视频宽高或播放过程中分辨率发生变化后得到宽高
    }

    @Override
    public void OnAudiosStatusChanged(int index, int audio_status,
                                      int p2ptalk_status, int playHandler, int sendSize) {
        //TODO: 处理音频状态变化及对讲能力回调
    }

    @Override
    public void OnCaptureEnable(int index) {
        //TODO: 判断视频是否可以截图回调(播放成功后会调用此回调),收到此回调表示可以截图
    }
};
  • 创建并初始化播放器实例

普通摄像头:

cplayerEx = new CPlayerEx(mActivity, 0, previewPlayerCallbackListener);

鱼眼摄像头:

cplayerEx = new CPlayerEx(mActivity, 0, previewPlayerCallbackListener,fishInfo);

注:此实例有两个构造函数,下面那个是专门给鱼眼摄像头播放使用的。鱼眼摄像头的相关参数可以从摄像头列表中的fisheye_params中获得。

建议:如果是鱼眼摄像头,请只使用主码流(即分辨率最高的码流),不允许切换码流。因为如果是子码流的鱼眼图像,经变形放大后,会很不清晰。如果一定要切换,请在CPlayerEx.stopPlay后,调用CPlayerEx.setFishInfo函数重设边距参数,再开始CPlayerEx.startPlay

  • 设置播放窗口
cplayerEx.setSurfaceview1(previewSfv);

注:播放过程中,如果分辨率发生变化,SDK内部会自动处理变化并继续播放,但由于分辨率分生变化时,画面的长宽比也会发生变化,因此开发者需要在变化时,调整surface_view的大小以符合长宽比。

  • 开始播放
cplayerEx.startPlay(dev_id, user, pass, chl_id, stream_id);

注:这里的devid指设备序列号

  • 云镜控制
ppviewClient.PlayerPtz(dev_id, cid, sid, cmd, param1, param2);
  • 抓图
cplayerEx.getCaptureFile(filename)
  • 开启和关闭本地录像
cplayerEx.playerStartRec(dev_id, chl_id, rec_filename, rec_snapshot_filename, max_sec);
cplayerEx.playerStopRec(dev_id, chl_id);
  • 开关音频
cplayerEx.setAudioStatus(status);

注:当多路播放时,切换当前播放的视频时,需要先调用setAudioStatus接口关掉前一路的音频,再调用setAudioStatus接口开启后一路的音频,否则,多路的音频会同时播放。

  • 停止播放r
cplayerEx.stopPlay();

3.3.12. 音频对讲流程

音频对讲流程与音视频实时播放流程相互独立,因此,可以在视频播放的过程中开启音频对讲,从而实现音视频对讲功能,也可以独立开启对讲流程进行纯音频对讲。

s=>start: 开始
e=>end: 结束
create=>operation: 创建对讲实例
setcb=>operation: 实现并设置代理函数
conn=>operation: 创建P2P连接
conncb=>operation: P2P连接结果
cond=>condition: P2P连接成功?
open=>operation: 开启对讲
sw=>operation: 对讲方向切换(可选)
close=>operation: 关闭对讲
close_conn=>operation: 释放连接
cond2=>condition: 开启对讲成功?

s->create->setcb->conn->conncb->cond
cond(yes)->open->cond2
cond(no)->close_conn
cond2(yes)->sw->close
cond2(no)->close
close->close_conn
close_conn->e

  • 创建对讲实例
vvAudio = VVAudio.getInstance();
  • 实现并设置对讲回调
OnVoiceTalkCallbackListener onVoiceTalkCallbackListener = new OnVoiceTalkCallbackListener() {
    @Override
    public void OnVoiceTalkCallback(int status) {
        //TODO: 处理开启对讲返回值
    }

};
 
vvAudio.setVoiceTalkCallback(onVoiceTalkCallbackListener);
  • 实现并设置P2P连接回调
PpviewClientInterface.OnDevConnectCallbackListener talkConnectListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理P2P连接结果
    }
}
 
ppviewClientInterface.setOndevConnectCallback(talkConnectListener);
  • 创建P2P连接
talkConnect = ppviewClientInterface.createConnect(devid, user, pass);

注:流程结束前,请不要将talkConnect用于其它接口。

  • 开启对讲
vvAudio.VVTalkStart(long connector, int chl_id, String devusr, String devpass)
  • 设置对讲模式
vvAudio.setTalkMode(mode);
  • 关闭对讲
public void VVTalkStop();
  • 释放P2P连接
ppviewClientInterface.releaseConnect(talkConnect);
ppviewClientInterface.removeOndevConnectCallback(talkConnectListener);

3.3.13. 录像回放流程(包括录像查询、远程回放、本地录像回放)

3.3.13.1. 录像查询

s=>start: 开始
e=>end: 结束
create=>operation: 创建客户端实例
setcb=>operation: 实现并设置查询结果代理函数
create_conn=>operation: 创建P2P连接
conncb=>operation: P2P连接结果代理
cond=>condition: P2P连接成功?
query_date=>operation: 查询某一月内哪些天有录像
query_min=>operation: 查询某一天内的录像列表
handle=>operation: 处理查询结果
close_conn=>operation: 释放连接
cond2=>condition: 是否继续查询

s->create->setcb->create_conn->conncb(right)->cond
cond(yes)->query_date->query_min->handle->cond2
cond(no)->close_conn->e

cond2(yes)->query_date
cond2(no)->close_conn->e

以上步骤请在登录后进行。

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置P2P连接回调
PpviewClientInterface.OnDevConnectCallbackListener talkConnectListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理P2P连接结果
    }
}
 
ppviewClientInterface.setOndevConnectCallback(talkConnectListener);
  • 实现并设置查询录像回调
PpviewClientInterface.OnC2dPlaybackGetDateListCallback onC2dPlaybackGetDateListCallback = new PpviewClientInterface.OnC2dPlaybackGetDateListCallback() {

    @Override
    public void on_c2d_PlaybackGetDateList(int nResult, ArrayList<PlaybackGetDateListItem> list) {
        //TODO: 处理查询那些天有录像的回复结果
    }

};



PpviewClientInterface.OnC2dPlaybackGetMinListCallback onC2dPlaybackGetMinListCallback = new PpviewClientInterface.OnC2dPlaybackGetMinListCallback() {
    @Override
    public void on_c2d_PlaybackGetMinList(int nResult, ArrayList<PlaybackGetMinListItem> list) {
        //TODO: 处理查询某日哪些分钟有录像的回复结果
    }

};
 
ppviewClientInterface.setOnC2dPlaybackGetDateListCallback(onC2dPlaybackGetDateListCallback);

ppviewClientInterface.setOnC2dPlaybackGetMinListCallback(onC2dPlaybackGetMinListCallback);
  • 创建P2P连接
connect = ppviewClientInterface.createConnect(devid, user, pass);

注:流程结束前,请不要将connect用于其它接口。

  • 查询某一月内哪些天有录像
ppviewClientInterface.c2d_playbackGetDateList_fun(connect, chl_id, rec_type, month);
  • 查询某一日内哪些分钟有录像
ppviewClientInterface.c2d_playbackGetMinList_fun(connect, chl_id, rec_type, date)
  • 释放P2P连接
ppviewClientInterface.releaseConnect(connect);
ppviewClientInterface.removeOndevConnectCallback(connect);

3.3.13.2. 设备端录像远程回放

s=>start: 开始
e=>end: 结束
create=>operation: 创建回放实例
setcb=>operation: 实现并设置回放代理函数
init=>operation: 设置播放窗口
start=>operation: 开始回放
ctrl=>operation: 回放控制
stop=>operation: 停止回放
cond=>condition: 开始回放成功?
cond2=>condition: 是否继续回放?

s->create->setcb->init->start(right)->cond
cond(yes)->ctrl->stop
cond(no)->stop
stop->cond2
cond2(yes, right)->start
cond2(no)->e

以上步骤请在登录后进行。

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并回放实例的回调函数
OnPlayerCallbackListener recPlayerCallbackListener = new OnPlayerCallbackListener() {

    @Override
    public void OnPlayStatusChanged(int index, int status, String tag,int progress) {
        //TODO: 处理视频播放状态改变
    }

    @Override
    public void GetWidthAndHeight(int i, int width, int height) {
        //TODO: 处理播放成功及播放过程中分辨率变化时的视频宽高回调
    }

    @Override
    public void OnAudiosStatusChanged(int index, int audio_status,
        int p2ptalk_status, int playHandler, int sendSize) {
        //TODO: 处理音频状态变化
    }

    @Override
    public void OnCaptureEnable(int index) {
        //TODO: 判断视频是否可以截图回调(播放成功后会调用此回调),收到此回调表示可以截图
    }
};
  • 创建回放实例并设置播放窗口
cplayerEx = new CPlayerEx(mActivity, index, onPlayerCallbackListener);
cplayerEx.setSurfaceview1(recSfv);
  • 开始回放
int res = startPlayBack(dev_id, user, pass, chl_id, startTime);
  • 音频开关
int res = setAudioStatus(on_or_off);
  • 停止回放
stopPlayBack();

3.3.13.3. 手机端录像(本地录像)回放

在实时音视频播放时,可以将播放的码流保存在手机上,我们称之为手机端录像或本地录像。保存在手机上的录像采用私有格式,需要通过SDK提供的接口进行回放。

回放手机端录像,不需要登录平台。

s=>start: 开始
e=>end: 结束
init=>operation: 创建并初始化播放器
set_view=>operation: 设置回放窗口
start_play=>operation: 开始回放
get_time=>operation: 取录像回放的当前时刻,并同步播放界面进度条
get_params=>operation: 各种取参数接口(可选)
set_pause=>operation: 暂停/恢复(可选)
set_seek=>operation: 重定位回放位置(可选)
stop_play=>operation: 停止回放

s->init->set_view->start_play->get_time->get_params->set_pause->set_seek->stop_play->e
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现本地回放的状态回调
OnPlayerCallbackListener recPlayerCallbackListener = new OnPlayerCallbackListener() {

    @Override
    public void OnPlayStatusChanged(int index, int status, String tag,int progress) {
        //TODO: 处理视频播放状态改变
    }

    @Override
    public void GetWidthAndHeight(int i, int width, int height) {
        //TODO: 处理播放成功及播放过程中分辨率变化时的视频宽高回调
    }

    @Override
    public void OnAudiosStatusChanged(int index, int audio_status,
        int p2ptalk_status, int playHandler, int sendSize) {
        //TODO: 处理音频状态变化
    }

    @Override
    public void OnCaptureEnable(int index) {
        //TODO: 判断视频是否可以截图回调(播放成功后会调用此回调),收到此回调表示可以截图
    }
};
  • 实现本地回放的帧位置回调
PpviewClientInterface.OnRecPlayerCallback() {

    @Override
    public void onFrameTimeCallback(int i) {
        //这里回调每一帧在文件中的位置(即当前的秒数)
        //通过录像文件总秒数(startRecPlayer返回值)和当前秒数,开发者可以在界面上动态显示本地录像回放进度。
    }
}
  • 创建本地回放实例和设置播放窗口
recPlayerEx = RecPlayerEx(context, onRecPlayerCallback, onPlayerCallbackListener);
recPlayerEx.setSurfaceview(recSfv);
  • 开始回放
int total_sec = recPlayerEx.startRecPlayer(rec_filename);

返回值是本地录像文件的总秒数

  • 暂停/恢复
recPlayerEx.setSuspend(true);//暂停
recPlayerEx.setSuspend(false);//恢复
  • 获取当前播放状态
boolean bSuspend = recPlayerEx.isSuspend();
  • 音频开关
recPlayerEx.setIsPlayAudio(on_or_off);
  • 重定位回放位置
recPlayerEx.seekRecplayer(sec);

重新设置播放位置,其参数sec表示离录像开始时的秒数,结合总秒数,开发者可以实现拖动进度条定位播放位置。

  • 取当前回放位置的UTC时间
int utc = recPlayerEx.getFrameUtcTime();

显示和控制进度条,使用秒数就行,这个utc时间,是用来在画面上添加OSD时间字幕用的。原始画面上如果已经有OSD时间,就不需要再使用。

由于鱼眼摄像头的画面在实际播放时会进行校正,因此不适合在原始图像上添加OSD时间字幕,此时在回放本地鱼眼摄像头录像时,需要自己在画面上添加时间字幕。

注:此处得到的时间是UTC时间,如果要显示本地时间,请自行转换。

  • 停止本地回放
recPlayerEx.stopRecplayer();

3.3.14. 布撤防流程

手机APP->手机APP: 1. 选择要布撤防的设备
手机APP->云平台: 2. 发送布撤防请求
云平台-->手机APP: 3. 回复
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置回调函数
PpviewClientInterface.OnC2sSetCamAlertStatusCallback onC2sSetCamAlertStatusCallback = new PpviewClientInterface.OnC2sSetCamAlertStatusCallback() {

    @Override
    public void on_c2s_set_cam_alert_status(int nResult, String camId, 
        int alert_status) {
        //设置摄像头布撤防状态回调
    }

    @Override
    public void on_c2s_set_cams_alert_status(int nResult,
                                             ArrayList<item_cams> cams, int status) {
        //设置多个摄像头布撤防状态回调
    }
};

ppviewClientInterface.SetOnC2sSetCamAlertStatusCallback(onC2sSetCamAlertStatusCallback);
  • 单摄像头布撤防
ppviewClientInterface.c2s_set_cam_alert_status_fun(user, pass, devId, camId, status)
  • 多个摄像头同时布撤防
ppviewClientInterface.c2s_set_cams_alert_status_fun(user, pass, cams, status);

3.3.15. 查询所有摄像头的事件列表流程

s=>start: 开始
e=>end: 结束
create=>operation: 创建客户端实例
setcb=>operation: 实现并设置事件相关代理函数
cond=>condition: 是否首次查询或重新查询
cond2=>condition: 是否继续读取下一页
query=>operation: 查询第一页,获取当前界面显示的事件缩略图
get_unread_count=>operation: 获取未读消息数,更新界面(可选步骤)
query_next=>operation: 查询下一页,获取当前界面显示的事件缩略图
get_unread_count2=>operation: 获取未读消息数,更新界面
read=>operation: 读取一条事件
get_url=>operation: 获取事件url,并显示事件图片
set_readed=>operation: 将所有事件置为已读(可选)
s->create->setcb->cond
cond(yes)->query->get_unread_count->read->get_url->set_readed->e
cond(no)->query_next->get_unread_count2->cond2
cond2(yes, right)->query_next
cond2(no)->read

本流程用于查询用户已添加的所有设备的事件列表。

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置事件回调函数
PpviewClientInterface.OnC2sGetUnreadEventCountCallback onC2sGetUnreadEventCountCallback = new PpviewClientInterface.OnC2sGetUnreadEventCountCallback() {

    @Override
    public void on_c2s_get_unread_event_count_callback(int nResult, int unread_count) {
        //获得该账号的未读事件数量的回调
    }
};

PpviewClientInterface.OnC2sGetEventListCallback onC2sGetEventListCallback = new PpviewClientInterface.OnC2sGetEventListCallback() {

    @Override
    public void on_c2s_get_event_list(int nResult, String json,
                                      String eventId) {
        //获取事件列表的回调
    }
};


PpviewClientInterface.OnC2sSetAllEventsReadedCallback onC2sSetAllEventsReadedCallback = new PpviewClientInterface.OnC2sSetAllEventsReadedCallback() {

    @Override
    public void on_c2s_set_all_events_readed(int nREsult) {
        //全部设为已读的回调
    }
};
 
ppviewClientInterface.SetOnC2sGetUnreadEventCountCallback(onC2sGetUnreadEventCountCallback);
ppviewClientInterface.SetOnC2sGetEventListCallback(onC2sGetEventListCallback);
ppviewClientInterface.SetOnC2sSetAllEventsReadedCallback(onC2sSetAllEventsReadedCallback);
  • 获取未读事件数量
ppviewClientInterface.c2s_get_unread_event_count(user, pass);
  • 获取事件列表
ppviewClientInterface.c2s_get_event_list(user, pass, eventId, getCount);
  • 获取事件缩略图
ppviewClientInterface.c2s_get_event_pic(user, pass, eventid);
  • 获取事件图片网址
ppviewClientInterface.c2s_get_page_event_url(eventid, user, pass);
  • 将所有事件设置为已读状态
ppviewClientInterface.c2s_set_all_events_readed(user, pass);

3.3.16. 查询单个摄像头的事件列表流程

s=>start: 开始
e=>end: 结束
create=>operation: 创建客户端实例
setcb=>operation: 实现并设置事件相关代理函数
cond=>condition: 是否首次查询或重新查询
cond2=>condition: 是否继续读取下一页
query=>operation: 查询第一页,获取当前界面显示的事件缩略图
query_next=>operation: 查询下一页,获取当前界面显示的事件缩略图
read=>operation: 读取一条事件
get_url=>operation: 获取事件url,并显示事件图片
set_readed=>operation: 将所有事件置为已读(可选)
s->create->setcb->cond
cond(yes)->query->read->get_url->set_readed->e
cond(no)->query_next->cond2
cond2(yes, right)->query_next
cond2(no)->read
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置单个摄像头事件回调函数
PpviewClientInterface.OnC2sGetCamEventListCallback onC2sGetCamEventListCallback = new PpviewClientInterface.OnC2sGetCamEventListCallback() {

    @Override
    public void on_c2s_get_cam_event_list(int nResult, String json,
         Object eventId){
        //获取指定摄像头事件列表的回调
    }
};
 
ppviewClientInterface.SetOnC2sGetCamEventListCallback(onC2sGetCamEventListCallback);
  • 获取事件列表
ppviewClientInterface.c2s_get_cam_event_list(user, pass, cam_id, event_id, get_count);

注:这里的id是摄像头id,不是设备id,因为有些设备如DVR含有多个摄像头。

  • 获取事件缩略图
Bitmap bitmap = ppviewClientInterface.c2s_get_event_pic(user, pass, eventid);
  • 获取事件图片网址
String url = ppviewClientInterface.c2s_get_page_event_url(eventid, user, pass);

3.3.17. 分组与列表管理流程

我们可以为摄像头创建分组。分组可以是树状多级结构,分组中可以包含摄像头,也可以包含子分组。摄像头和子分组可以在不同的分组中自由移动。

当删除分组后,原分组下的摄像头和子分组下的摄像头都将被移动到最顶级,即没有被分组包含的状态,原该分组下的子分组将被全部删除。

s=>start: 开始
e=>end: 结束
getsn=>operation: 获取最新流水号
func=>operation: 创建、修改、删除、移动分组,设置摄像头分组
getlist=>operation: 获取摄像头列表
getlist2=>operation: 获取摄像头列表
check=>operation: 判断错误类型
t=>operation: test

cond=>condition: 是否与已获得的流水号一致
cond2=>condition: 是否成功
cond3=>condition: 流水号不一致?

s->getsn->cond
cond(yes, right)->func
cond(no)->getlist(right)->func

func->cond2
cond2(yes, right)->e
cond2(no)->check(bottom)->cond3(bottom)

cond3(yes, right)->getlist->func
cond3(no)->e

注:由于我们允许同一个账号在不同的设备上可以登录多次,因此在进行与分组相关的操作前,最好先获取一下当前最新的摄像头列表流水号,与已获得的流水号进行比较,如果不一致,应当刷新一下摄像头列表,以保证摄像头列表是最新的。如果当前的列表不是最新的,服务器会拒绝这次操作,以防止多人同时操作时引起的列表混乱。在代理函数中得到的流水号是分组操作后最新的流水号,可用于下一次操作。

以上步骤请在登录后进行。

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置分组回调函数
PpviewClientInterface.OnCamListChangeCallbackListener onCamListChangeCallbackListener = new PpviewClientInterface.OnCamListChangeCallbackListener() {

    @Override
    public void on_camlist_sn_callback(int nResult, short sn) {
        //获取当前摄像头列表的流水号回调
    }

    @Override
    public void on_new_group_callback(int nResult, String group_id,
                                      String parentid, short pre_sn, String usrtag) {
        //新建分组回调
    }

    @Override
    public void on_move_cam_new_group_callback(int nResult, String new_group_id,
            String new_group_name, String new_group_parent,
            String move_cam_id, short pre_sn) {
        //移动摄像头到新分组回调
    }

    @Override
    public void on_move_group_new_group_callback(int nResult, String new_group_id,
            String new_group_name, String new_group_parent,
            String old_group_parent,String move_group_id,
            short pre_sn) {
        //移动分组到新建分组回调
    }

    @Override
    public void on_rename_group_callback(int nResult, String groupid,
                                         short pre_sn, String usertag) {
        //修改分组名回调
    }

    @Override
    public void on_move_group_callback(int nResult, String groupid,
                                       String newgroupid, String oldgroupid, short pre_sn,
                                       String usertag) {
        //移动分组回调
    }

    @Override
    public void on_delete_group_callback(int nResult, String groupid,
                                         String parid, short pre_sn, String usertag) {
        //删除分组回调        
    }

    @Override
    public void on_rename_camera_callback(int nResult, String cameraid,
                                          short pre_sn, String usertag) {
        //修改摄像头名称回调
    }

    @Override
    public void on_move_camera_callback(int nResult, String cameraid,
                                        String newgroupid, short pre_sn, String usertag) {
        //移动摄像头回调
    }

};

ppviewClientInterface.setOnCamListChangeCallback(onCamListChangeCallbackListener);
  • 获取最新的摄像头列表流水号
int sn = ppviewClientInterface.c2s_get_camlist_sn_fun(user, pass);
  • 获取摄像头列表
int res = ppviewClientInterface.c2s_get_cam_list_fun(user, pass, cur_sn);
  • 修改摄像头名称
int res = ppviewClientInterface.c2s_rename_cam_fun(user, pass, cur_sn, camname, camid, usrtag);
  • 添加分组
ppviewClientInterface.c2s_new_group_fun(user, pass, cur_sn, groupname, to_group, usrtag);
  • 修改分组名称
ppviewClientInterface.c2s_rename_group_fun(user, pass, cur_sn, groupname, groupid, usertag);                                                                                     
  • 移动分组
ppviewClientInterface.c2s_move_group_fun(user, pass, cur_sn,
      groupid, to_groupid, old_groupid,
      usertag);
  • 移动分组到新建分组
ppviewClientInterface.c2s_move_group_new_group_fun(user, pass, cur_sn,
    new_group_name, new_group_parent, old_group_parent, move_group_id); 
  • 移动摄像头到分组
ppviewClientInterface.c2s_move_group_fun(user, pass, cur_sn, 
    groupid, to_groupid, old_groupid, usertag);

请注意:这里的camid是摄像头编号,非设备编号

  • 移动摄像头到新分组
ppviewClientInterface.c2s_move_cam_new_group_fun(user, pass, cur_sn,
      new_group_name, new_group_parent, move_cam_id);
  • 删除分组
ppviewClientInterface.c2s_delete_group_fun(user, pass, cur_sn,
    groupid, parid, usrtag);

删除分组后,该分组所属的子分组和摄像头会自动转移到最顶下。

3.3.18. 设备参数设置流程

设备参数设置是通过P2P通道直接连接设备后进行设置的,因此所有直接与设备交互的设备参数设置流程,都需要先创建一个P2P连接(使用createConnect接口)。

多个设备参数设置流程,不能同时使用同一个P2P连接,但是如果这些设置流程是依次进行的,即前一个设置流程结束后再进行下一个,此时可以复用P2P连接。

因为设备有很多参数项可以设置,其流程都是一致的,所不同的仅仅是函数接口,因此这里只示例一种设置。

同一个函数可能会允许设置多个参数,如果用户只需要改变其中的一个值,那么调用这个函数时,除了这个改变的值以外,其它不改变的值仍需要将原值传递进去。

以安防配置为例:

s=>start: 开始
e=>end: 结束
conn=>operation: 创建P2P连接
conncb=>operation: P2P连接结果代理
cond=>condition: P2P连接成功?
set=>operation: 设置网络参数
close_conn=>operation: 释放连接
cond2=>condition: 是否下一次设置?

s->conn->conncb->cond(right)

cond(yes,right)->set(right)->cond2
cond(no)->close_conn->e

cond2(yes, right)->set
cond2(no)->close_conn->e

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置P2P连接回调
PpviewClientInterface.OnDevConnectCallbackListener talkConnectListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理P2P连接结果
    }
}
 
ppviewClientInterface.setOndevConnectCallback(talkConnectListener);
  • 创建P2P连接
connect = ppviewClientInterface.createConnect(devid, user, pass);

注:流程结束前,请不要将connect用于其它接口。

  • 实现并设置安防配置回调
PpviewClientInterface.OnC2dAlarmCfgCallback onC2dAlarmCfgCallback = new PpviewClientInterface.OnC2dAlarmCfgCallback() {

    @Override
    public void on_c2d_getAlarmCfgCallBack(int nResult , item_alarm_cfg cfg) {
       //获得设备端安防本置回调
    }



    @Override
    public void on_c2d_setAlarmCfgCallBack(int nResult , item_alarm_cfg cfg) {
        //设置设备端安防配置结果回调
    }

};

ppviewClientInterface.setOnC2dAlarmCfgCallback(onC2dAlarmCfgCallback);
  • 获得安防配置
ppviewClientInterface.c2d_getAlarmCfg_fun(connect, chl_id);
  • 设置安防配置
ppviewClientInterface.c2d_setAlarmCfg_fun(connect, chl_id, cfg);
  • 断开P2P连接
ppviewClientInterface.releaseConnect(connect);
ppviewClientInterface.removeOndevConnectCallback(connect);

以下将好友及黑名单统称为“关系”

用户A->用户A: 1. 获取自己的关系列表
用户A->用户B: 2. 添加好友请求
用户B->用户A: 3. 好友请求回复
用户A->用户A: 4. 将某用户加入到黑名单
用户A->用户A: 5. 将好友转入黑名单
用户A->用户A: 6. 删除好友或黑名单中的账号

以上步骤中,2、4、5、6可以并行进行,不需要严格按照图中的顺序。添加好友时,需要对方的确认;添加黑名单则不用。将某用户添加到黑名单后,将不再能收到该用户的好友请求。

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置关系管理回调函数
PpviewClientInterface.OnC2sFriendCallback onC2sFriendCallback = new PpviewClientInterface.OnC2sFriendCallback() {

    @Override
    public void on_c2s_getfriendList(int nResult,
        ArrayList<item_relations> relations) {
        //获取关系列表回调
    }

    @Override
    public void on_c2s_addfriendRelation(int nResult, String relation_user,
        int relation_type) {
        //添加关系回调
    }

    @Override
    public void on_c2s_modifyfriendRelation(int nResult,
        String relation_user, int relation_type, String memo) {
       //修改关系回调
    }



    @Override
    public void on_c2s_removefriendRelation(int nResult,
                                            String relation_user) {
        //删除关系回调
    }

};
 
ppviewClientInterface.setOnC2sFriendCallback(onC2sFriendCallback);
  • 获取关系(好友和黑名单)列表
ppviewClientInterface.c2s_get_user_relations_fun(user, pass);
  • 添加关系(好友或黑名单)
ppviewClientInterface.c2s_add_user_relation_fun(user, pass, relation_user, 1);//添加好友
ppviewClientInterface.c2s_add_user_relation_fun(user, pass, relation_user, 2);//添加黑名单
  • 修改关系

用于同意好友申请、把好友改为黑名单或修改备注。不能用于添加好友。如果拒绝好友申请,需要使用删除关系PpviewClientInterface.c2s_remove_user_relation_fun函数

ppviewClientInterface.c2s_modify_user_relation_fun(user, pass,
      relation_user, relation_type, memo);
  • 删除关系

将好友或黑名单从列表中删除掉。

ppviewClientInterface.c2s_remove_user_relation_fun(user, pass, relation_user);

3.3.20. 摄像头分享管理流程

这一节描述摄像头在好友间分享的流程。主要描述如何将自己的摄像头分享给好友或回收分享,应答别人的分享请求。

别人分享给自己的摄像头,可在通过获取摄像头列表获得。

  • 1. 请求别人将摄像头分享给自己
用户A->平台: 1.1 发起分享摄像头请求
平台->平台: 1.2 记录请求
平台->用户B: 1.3 推送请求
用户B-->平台: 1.4 响应分享请求
平台->用户A: 1.5 推送列表变化
用户A->用户A: 1.6 刷新列表
用户A->用户A: 1.7 删除分享给自己的摄像头
  • 2. 处理分享请求(别人向自己发送的分享请求)
手机APP->平台: 2.1 请求获取分享请求事件数量(可定时获取,实时的请求会有推送)
平台-->手机APP: 2.2 分享请求事件数量
手机APP->手机APP: 2.3 提示有分享请求
手机APP->平台: 2.4 请求获取分享请求列表
平台-->手机APP: 2.5 分享请求列表
手机APP->平台: 2.6 逐条响应分享请求
平台-->手机APP: 2.7 处理结果
  • 3. 管理自己分享给别人的摄像头
用户A->平台: 3.1 获取分享给某用户的摄像头列表
平台-->用户A: 3.2 回复分享给某用户的摄像头列表
用户A->用户A: 3.3 修改列表
用户A->平台: 3.4 设置新的分享给某用户的摄像头列表
平台->平台: 3.5 比对列表并更新
平台->用户B: 3.6 推送列表变动消息
平台-->用户A: 3.7 回复

修改列表是指在列表中添加或删除分享的摄像头

  • 4. 管理某摄像头的分享情况
用户A->平台: 4.1 获取某摄像头的分享用户列表
平台-->用户A: 4.2 某摄像头的分享用户列表回复
用户A->用户A: 4.3 在列表中添加或删除分享的用户
用户A->平台: 4.4 上传新的摄像头分享用户列表
平台->其它用户: 4.5 列表变化推送消息
平台-->用户A: 4.6 上传新的列表的回复
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置分享管理相关回调
PpviewClientInterface.OnC2sShareCallback onC2sShareCallback = new PpviewClientInterface.OnC2sShareCallback() {

    @Override
    public void on_c2s_set_cam_share_list(int nResult) {
        //上传分享给某用户的摄像头列表回调
    }

    @Override
    public void on_c2s_get_cam_share_list(int nResult, ArrayList<item_sharelist> shareList) {
        //获得分享给某用户的摄像头列表回调
    }

    @Override
    public void on_c2s_get_cam_requestshare_list(int nResult, 
        ArrayList<item_share_reqs> requestShareList) {
        //获取摄像头分享请求列表回调
    }

    @Override
    public void on_c2s_response_cam_share(int nResult, String req_id) {
        //分享摄像头请求响应回调
    }

    @Override
    public void on_c2s_disable_share_cam(int nResult, String dev_id, String cam_id) {
        //取消分享摄像头回调
    }

};
 
ppviewClientInterface.setOnC2sShareCallback(onC2sShareCallback);
  • 实现并设置分享请求相关回调
PpviewClientInterface.OnC2sRequestShareCallback onC2sRequestShareCallback = new PpviewClientInterface.OnC2sRequestShareCallback() {

    @Override
    public void on_c2s_get_dev_owner(int nResult, String devid,
                                     String ownerid, String ownernick) {
        //查询设备属主回调
    }

    @Override
    public void on_c2s_req_dev_share(int nResult, String devid) {
        //发起分享摄像头请求的回调
    }

    @Override
    public void on_c2s_get_cam_shared_userlist(int nResult, ArrayList<user> user_list) {
        //查询此摄像头分享的用户列表
    }

    @Override
    public void on_c2s_set_cam_shared_userlist(int nResult, ArrayList<user> user_list) {
        //设置摄像头分享的用户列表
    }
};
ppviewClientInterface.setOnC2sRequestShareCallback(onC2sRequestShareCallback);
  • 请求别人将设备分享给自己(1.1)
ppviewClientInterface.c2s_share_reqDevShare_fun(user, pass, devid, memo);

由于发起请求时,发起者并不知道该设备有多少个通道,因此只能针对设备发起请求,被请求者可能选择该设备下的一个或多个摄像头分享给该用户。可通过接口获取设备的归属用户,以便向该用户发起共享请求。

  • 获取设备的归属用户
ppviewClientInterface.c2s_share_getDevOwner_fun(String user, String pass, String devid);
  • 响应其它用户的分享请求(1.4、2.6) 可以有三种响应:同意,拒绝,或是为了防止骚扰而将其拉入黑名单
ppviewClientInterface.c2s_share_ResponseCamShare_fun(user, pass, req_id, cmd);

拉入黑名单请参考好友及黑名单管理流程中的”关系管理“。

  • 删除分享给自己的摄像头(1.7)
ppviewClientInterface.c2s_share_DisableShareCam_fun(user, pass, devid, camid);
  • 获取其它用户发来的分享请求条数(2.1)
ppviewClientInterface.c2s_share_getCamShareReqCount_fun(user, pass);
  • 获取其它用户发来的分享请求列表(2.4)
ppviewClientInterface.c2s_share_getRequestShareCamList_fun(user, pass);
  • 获取分享给某用户的摄像头列表(3.1)
ppviewClientInterface.c2s_share_getShareCamList_fun(user, pass, relation_user);
  • 设置新的分享给某用户的摄像头列表(3.4)
ppviewClientInterface.c2s_share_setShareCamList_fun(user, pass, relation_user, sharelist);
  • 获取某摄像头的分享用户列表(4.1)
ppviewClientInterface.c2s_share_getCamSharedUserList_fun(user, pass, devid, camid);
  • 上传新的摄像头分享用户列表(4.4)
ppviewClientInterface.c2s_share_setCamSharedUserList_fun(user, pass, devid, camid, users);

3.3.21. 透明传输通道交互流程

透明通道是为开发者预留的,可以在设备端和客户端之间P2P传输任意格式数据的接口。因此需要设备端与客户端协同才可正常工作。SDK中的DEMO仅示例了这些接口的用法,在真实环境中测试时,需要设备端也实现了相应的接口,并与客户端使用相同的自定义协议。

在客户端与设备端通过透明通道进行交互时,通过调用trchlSend函数主动发送数据,接收数据则通过OnTransparentCallbackListener回调。

s=>start: 开始
e=>end: 结束

conn=>operation: 创建P2P连接
conncb=>operation: P2P连接结果代理
cond=>condition: P2P连接成功?
open=>operation: 开启透明通道
trans=>operation: 通过透明通道接收和发送数据
close=>operation: 关闭透明通道
close_conn=>operation: 释放连接

s->conn->conncb->cond
cond(yes)->open->trans->close->close_conn->e
cond(no)->close_conn
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置P2P连接回调
PpviewClientInterface.OnDevConnectCallbackListener connectListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理P2P连接结果
    }
}
 
ppviewClientInterface.setOndevConnectCallback(connectListener);
  • 实现并设置接收数据的回调函数
PpviewClientInterface.OnTransparentCallbackListener onTransparentCallbackListener = new PpviewClientInterface.OnTransparentCallbackListener() {

    @Override
    public void on_transparent_chl_callback(long trchl_handle,byte[] info, int info_len) {
       //透明通道返回消息回调
    }
};
 
ppviewClientInterface.setTransparentCallbackListener(onTransparentCallbackListener);
  • 创建P2P连接
connect = ppviewClientInterface.createConnect(devid, user, pass);

注:流程结束前,请不要将connect用于其它接口。

  • 打开透明传输通道
int trchl_handle = ppviewClientInterface.trchlOpen(connect);
  • 通过透明通道发送数据
ppviewClientInterface.trchlSend(trchl_handle, buffer, len);

接收数据在回调中。

  • 关闭透明通道
ppviewClientInterface.trchlClose(trchl_handle);
  • 释放P2P连接
ppviewClientInterface.releaseConnect(connect);
ppviewClientInterface.removeOndevConnectCallback(connectListener);

3.3.22. 推送信息处理流程

ppview平台具备自己的推送服务器,用于向设备、手机推送消息。

需要注意的是Android 由于系统安全机制,并不能保证100%实时接收到推送,可能会存在手机进入深度休眠或者应用被kill,建议为了保持程序的存活,在应用设置里把程序设为信任,并且开放所有权限。

建议:由于推送的特殊性,建议所有推送相关代码都在Application里执行。

3.3.22.1 设置并实现推送消息回调

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 设置并实现推送消息回调
PpviewClientInterface.OnS2CPushCallback onS2CPushCallback = new PpviewClientInterface.OnS2CPushCallback() {

    @Override
    public void on_s2c_dev_status(String devId, int status) {
        //设备状态变化消息
    }

    @Override
    public void on_s2c_dev_list_changed() {
        //设备列表发生改变(建议收到此推送后重新获取设备列表)
    }

    @Override
    public void on_s2c_cam_list_changed(int camSn) {
        //摄像头列表变动消息(建议收到此推送后重新获取摄像头列表)
    }

    @Override
    public void on_s2c_event(EventListItem eventItem) {
        //事件推送消息
    }

    @Override
    public void on_s2c_cam_alert_status_changed(String devId, String camId,String camName, int status) {
        //摄像头布撤防状态发生改变消息
    }

    @Override
    public void on_s2c_event_pic_uploaded(String event_id) {
        //事件抓图已上传消息(缩略图已上传,可以重新获取缩略图)
    }
    
    @Override
    public void on_s2c_friend_list_changed(int event_type,
        String relation_user, int relation_type) {
        //好友及黑名单列表变化消息
    }

    @Override
    public void on_s2c_req_cam_share(int new_req_num) {
        //分享摄像头请求推送消息
    }

    @Override
    public void on_s2c_disable_alert_event(String cam_id) {
        //取消摄像头正在报警的状态的推送消息
    }

    @Override
    public void on_s2c_disable_low_power(String cam_id) {
        //取消摄像头正在低电量的状态的推送消息
    }

    @Override
    public void on_s2c_cam_private_status_changed(String dev_id,String cam_id,
        int chl_id,int status) {
        //摄像头隐私模式发生改变的推送消息
    }

    @Override
    public void on_s2c_dev_binded_by_another_user(String dev_id,String bind_user) {
        //通过二维码来添加摄像头的返回,此摄像头已被添加了
    }

    @Override
    public void on_s2c_dev_binded(String dev_id) {
        //通过二维码来添加摄像头的返回,添加成功
    }
};

ppviewClientInterface.SetOnS2CPushCallback(onS2CPushCallback);

3.3.22.2 初始化推送和注销推送

  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置推送回调
PpviewClientInterface.OnC2sVVPushCallback onC2sVVPushCallback = new PpviewClientInterface.OnC2sVVPushCallback() {

    @Override
    public void on_c2s_pushUnInitCallBack(int nResult) {

        // 注销推送回调
        if(nResult != 200){
            //推送注销失败
        }else{
            //推送注销成功
        }
    }

    @Override
    public void on_c2s_pushInitCallBack(final int nResult) {

        //注册推送回调
        if(nResult != 200){
            //失败,重新注册
        }else{
           //推送注册成功
        }

    }

};
 
ppviewClientInterface.setOnC2sVVPushCallback(onC2sVVPushCallback);
  • 初始化推送
ppviewClientInterface.push_init(context, svr_ip, svr_port, user, push_key, push_pass);
  • 触发一次推送心跳
ppviewClientInterface.push_TouchHb();

用于网络断开重连后立即发送心跳到推送服务器,以便实现快速注册。如不调用,内部程序会自动在2分钟内发送心跳。

  • 注销推送
ppviewClientInterface.push_uninit(context);

3.3.22.3. 取消摄像头的报警状态

当接收到摄像头报警状态变化推送时,如果APP需要在界面上显示该摄像头的报警状态,则可以根据推送信息进行相应的变化。如果需要取消这个状态,则调用c2s_disable_cam_alert_event_fun函数来取消这个状态。

如果APP没有收到实时的推送(当推送时APP不在线时),在摄像头列表中也包含有这个状态的信息。

取消摄像头的报警状态

int res = ppviewClientInterface.c2s_disable_cam_alert_event_fun(user, pass, devid, camid);

3.3.22.4. 取消外部传感器的低电状态

当接收到外部传感器低电状态推送时,如果APP需要在界面上显示外部传感器低电状态,则可以根据推送信息进行相应的变化。如果需要取消这个状态,则调用c2s_disable_cam_low_power_fun函数来取消这个状态。

如果APP没有收到实时的推送(当推送时APP不在线时),在摄像头列表中也包含有这个状态的信息。

取消外部传感器的低电状态

int res = ppviewClientInterface.c2s_disable_cam_low_power_fun(user, pass, devid, camid);

3.3.22.5. 设置摄像头隐私模式

用于设置摄像头的隐私模式,处于隐私模式下的摄像头,远程无法打开实时音视频播放。

当接收到隐私模式变化推送时,APP需要在界面上显示隐私模式状态。

如果APP没有收到实时的推送(当推送时APP不在线时),在摄像头列表中也包含有这个状态的信息。

设置摄像头隐私模式

int res = ppviewClientInterface.c2s_set_cam_private_status_fun(user, pass, devid, camid, status);

3.3.23. 传感器相关

传感器对码流程:

手机APP->设备: 创建P2P连接
设备-->手机APP: P2P连接反馈
手机APP->设备: 请求开启对码模式
设备->设备: 开启对码模式
传感器->设备: 触发信号
设备->设备: 记录新对码到的传感器或等待超时
设备->设备: 结束对码模式
设备-->手机APP: 对码结果
  • 得到客户端实例
PpviewClientInterface ppviewClientInterface = PpviewClientInterface.getInstance();
  • 实现并设置P2P连接回调
PpviewClientInterface.OnDevConnectCallbackListener talkConnectListener = new PpviewClientInterface.OnDevConnectCallbackListener() {
    @Override
    public void on_connect_callback(int msgid, long connector, int result) {
        //TODO: 处理P2P连接结果
    }
}
 
ppviewClientInterface.setOndevConnectCallback(talkConnectListener);
  • 实现并设置传感器相关回调
PpviewClientInterface.OnC2dSensorCallback onC2dSensorCallback = new PpviewClientInterface.OnC2dSensorCallback() {
    @Override
    public void on_c2d_extSensorMatch(int nResult, ArrayList<item_sensorinfo> sensors) {
        //传感器对码结果回调
    }

    @Override
    public void on_c2d_extSensorGetList(int nResult, ArrayList<item_sensorinfo> sensors) {
        //获得传感器列表回调
    }

    @Override
    public void on_c2d_extSensorRemove(int nResult, int chl_id, String sensor_id) {
        //删除传感器回调
    }

    @Override
    public void on_c2d_extSensorSetInfo(int nResult, item_sensorinfo info) {
        //设置传感器信息回调
    }

    @Override
    public void on_c2d_extSensorSetSubChlInfo(int nResult, int chl_id,String sensor_id,
                                              int sub_chl_id,String name, int alarm_linkage) {
        //设置传感器子通道参数回调
    }

    @Override
    public void on_c2d_extSensorRemoteControlSwitch(int nResult ,int chl_id,String sensor_id,
                                                    int sub_chl_id,int status) {
       //远程控制开关回调
    }
};


ppviewClientInterface.setOnC2dSensorCallback(onC2dSensorCallback);
  • 创建P2P连接
connect = ppviewClientInterface.createConnect(devid, user, pass);

注:流程结束前,请不要将connect用于其它接口。

  • 开始设备与传感器对码

通过对码,将传感器绑定到设备上。调用此接口后,需要触发一下传感器来完成配对,在完成前不可做其他操作。

ppviewClientInterface.c2d_extSensorMatch_fun(connect, chl_id);
  • 获得传感器列表
ppviewClientInterface.c2d_extSensorGetList_fun(sensorConnect, chl_id,type);
  • 设置传感器信息
ppviewClientInterface.c2d_extSensorSetInfo_fun(sensorConnect,sensorinfo);
  • 移除传感器
ppviewClientInterface.c2d_extSensorRemove_fun(sensorConnect, chl_id,sensor_id);
  • 设置传感器子通道信息
ppviewClientInterface.c2d_extSensorSetSubChlInfo_fun(sensorConnect, chl_id,
        sensor_id,sensor_child_id, sensor_child_name, alarm_linkage);
  • 传感器远程控制开关
ppviewClientInterface.c2d_extSensorRemoteControlSwitch_fun(sensorConnect, chl_id,
        sensor_id,sensor_child_id,sensor_remotecontrolswitch_state);
  • 释放P2P连接
ppviewClientInterface.releaseConnect(connect);
ppviewClientInterface.removeOndevConnectCallback(connect);