2. IOS 客户端开发指南
- 2.1. 概述
- 2.2. 开发准备
-
2.3. 流程指南
- 2.3.1. 初始化流程
- 2.3.2. 用户账号注册流程
- 2.3.3. 密码重置流程
- 2.3.4. 用户登录
- 2.3.5. 修改用户昵称流程
- 2.3.6. 获取设备列表流程
- 2.3.7. 获取摄像头列表流程
- 2.3.8. 局域网内搜索设备
- 2.3.9. 一键WIFI配置
- 2.3.10. 添加和删除设备
- 2.3.11. 播放实时音视频流程(包括云台控制、音频开关、抓图、本地录像、码流切换)
- 2.3.12. 音频对讲流程
- 2.3.13. 录像回放流程(包括录像查询、远程回放、本地录像回放)
- 2.3.14. 布撤防流程
- 2.3.15. 查询所有摄像头的事件列表流程
- 2.3.16. 查询单个摄像头的事件列表流程
- 2.3.17. 分组管理流程
- 2.3.18. 设备参数设置流程
- 2.3.20. 摄像头分享管理流程
- 2.3.21. 透明传输通道交互流程
- 2.3.22. 推送信息处理流程
- 2.3.23. APP前后台切换或网络通断时需要调用的函数
- 2.3.24. 传感器相关
2.1. 概述
本节用于指导使用 PPVIEW 客户端 SDK 开发 IOS 平台手机客户端。
在客户端的所有流程中,与平台交互的接口,可以直接调用;与设备端交互的接口,需要先创建一个P2P连接,并将这个P2P连接句柄作为参数传递给交互接口。
请注意,这个作为交互用的P2P连接可以重复使用,但是不能并行使用。即创建后,可以在一个交互流程完成后,用于另一个交互流程,但不能同时用于两个交互流程。
我们在内部做了P2P连接优化,当创建了多个用于交互的P2P连接时,我们会在内部进行复用,不影响这些多次创建的P2P连接的并行使用。
2.2. 开发准备
2.2.1. 创建IOS项目
创建IOS项目。
2.2.2. 导入库
将开发包中 goe_lib 文件夹下的头文件和库文件复制到项目中
并确保“Build Phases/Link Binary With Libraries”中已包含了 SDK 中的库文件。
2.2.3. 导入必需的系统库
2.2.4. 在main.m中忽略管道破裂信号
int main(int argc, char * argv[])
{
//忽略管道破裂信号
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, 0);
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
如果不忽略,会因为 Socket 关闭而导致程序崩溃退出。
2.3. 流程指南
2.3.1. 初始化流程
- 创建与平台交互的对象实例
#import "ppview_cli.h"
ppview_cli *cli = [ppview_cli getInstance];
一个客户端应用进程创建一个平台交互对象实例即可,此接口采用单例模式,多次调用仅创建一个实例。
- 初始化参数
[cli setAppInfo:@"http://ppview.vveye.com:3000/webapi/client/"
devurl:@"http://ppview.vveye.com:3000/webapi/device/"
eventurl:@"http://ppview.vveye.com:3000/webapi/page"
appid:@"C6460838-D5D0-0001-CB18-B1491FFB1DCE"
vendorpass:@"H10Yz6fJS5oPX1Hj"
with_p2p_svr:@"nat.vveye.net"
with_p2p_port:8000
with_secret:@""];
设置平台服务器地址、P2P 服务器地址及应用ID等必要的参数。
- 参考
- 获得库实例:getInstance
- 初始化:setAppInfo
2.3.2. 用户账号注册流程
2.3.2.1. 通过手机号注册用户
手机APP->手机APP: 1. 输入手机号
手机APP->云平台: 2. 请求短信验证码
云平台-->手机APP: 3. 请求短信验证码回复
云平台->用户: 4. 短信验证码
用户->手机APP: 5. 手工输入短信验证码
手机APP->云平台: 6. 注册新用户请求
云平台-->手机APP: 7. 注册请求回复
- 实现并设置代理函数
- (void)cli_lib_GetSmsVcode_CALLBACK:(int)HttpRes
{
//TODO: 处理获取短信验证码请求的回复
}
...
cli.cli_vercode_delegate = self;
- (void)cli_lib_Register_CALLBACK:(int)HttpRes
{
//TODO: 处理注册请求的回复
}
...
cli.cli_register_delegate = self;
- 请求短信验证码
[cli cli_lib_GetSmsVcode:m_mobile bCheck:1];
- 注册
[cli cli_lib_Register:m_usr regpass:m_pass vcode:m_pass mail:m_email mobile:m_mobile myses:nil with_nick:nil];
- 参考
- 请求短信验证码(2): cli_lib_GetSmsVcode
- 短信验证码回复代理(3):cli_lib_GetSmsVcode_CALLBACK
- 注册新用户(6):cli_lib_Register
- 注册请求回复代理(7):cli_lib_Register_CALLBACK
2.3.2.2. 通过邮箱注册用户
手机APP->手机APP: 1. 输入邮箱号
手机APP->云平台: 2. 请求邮箱验证码
云平台-->手机APP: 3. 请求邮箱验证码回复
云平台->用户: 4. 邮箱验证码
用户->用户: 5. 打开邮箱,读取验证码
用户->手机APP: 6. 手工输入邮箱验证码
手机APP->云平台: 7. 注册新用户请求
云平台-->手机APP: 8. 注册请求回复
- 实现并设置代理函数
- (void)cli_lib_GetMailVcode_CALLBACK:(int)HttpRes
{
//TODO: 处理获取邮箱验证码请求的回复
}
...
cli.cli_vercode_delegate = self;
- (void)cli_lib_Register_CALLBACK:(int)HttpRes
{
//TODO: 处理注册请求的回复
}
...
cli.cli_register_delegate = self;
- 请求邮箱验证码
[cli cli_lib_GetMailVcode:m_email language:m_lang_tag bCheck:1];
- 注册
[cli cli_lib_Register:m_usr regpass:m_pass vcode:m_pass mail:m_email mobile:m_mobile myses:nil with_nick:nil];
- 参考
- 请求邮箱验证码(2): cli_lib_GetMailVcode
- 请求邮箱验证码回复消息代理(3):cli_lib_GetMailVcode_CALLBACK
- 注册新用户(7):cli_lib_Register
- 注册回复代理(8):cli_lib_Register_CALLBACK
2.3.3. 密码重置流程
2.3.3.1. 通过手机号重置密码
手机APP->手机APP: 1. 输入手机号
手机APP->云平台: 2. 请求短信验证码
云平台->用户: 3. 短信验证码
用户->手机APP: 4. 用户手工输入验证码
手机APP->手机APP: 5. 输入新密码
手机APP->云平台: 6. 重置密码请求
云平台-->手机APP: 7. 重置密码回复
- 实现并设置代理函数
- (void)cli_lib_GetSmsVcode_CALLBACK:(int)HttpRes
{
//TODO: 处理获取短信验证码请求的回复
}
...
cli.cli_vercode_delegate = self;
- (void)cli_lib_ResetPassword_sms_CALLBACK:(int)HttpRes with_vercode:(NSString *)vercode
{
//TODO: 处理重置密码请求的回复
}
...
cli.cli_register_delegate = self;
- 请求短信验证码
[cli cli_lib_GetSmsVcode:m_mobile bCheck:0];
- 验证短信验证码
[cli cli_lib_CheckSmsVcode:m_vercode mobile:m_mobile];
- 参考
- 请求短信验证码(2):cli_lib_GetSmsVcode
- 短信验证码回复代理(3):cli_lib_GetSmsVcode_CALLBACK
- 重置密码(6):cli_lib_user_resetpass_mobile
- 重置密码回复消息代理(7):cli_lib_ResetPassword_sms_CALLBACK
2.3.3.2. 通过邮箱号重置密码
手机APP->手机APP: 1. 输入邮箱号
手机APP->云平台: 2. 通过邮箱重置密码
云平台-->手机APP: 3. 回复结果
云平台->用户邮箱: 4. 发送重置邮件
用户->用户邮箱: 5. 打开邮件,点击链接
用户邮箱->云平台: 6. 跳转至平台密码重置页
云平台->云平台: 7. 重置密码
注:手机端请求平台向用户邮箱发送密码重置邮件后,流程结束,用户须登录自己的邮箱,点开邮箱中的链接进行重置。
- 实现并设置代理函数
-(void)cli_lib_ResetPassword_mail_CALLBACK:(int)HttpRes with_mail:(NSString*)mail
{
//TODO: 处理通过邮箱重置密码请求的回复
}
...
cli.cli_set_delegate = self;
- 通过邮箱重置密码
int res = [cli_lib_user_resetpass_email_v2:email language:language];
- 参考
- 通过邮箱重置密码(2):cli_lib_user_resetpass_email_v2
- 邮箱重置密码请求回复消息的代理(3):cli_lib_ResetPassword_mail_CALLBACK
2.3.3.3. 修改密码
在密码已知的情况下,可直接修改密码,不需要使用密码重置流程。
用手机号和邮箱号新注册的用户,其默认密码为手机验证码或邮箱验证码。可以在注册的最后一步,通过修改密码接口,让用户设置一个自己容易记住的密码。
- 修改密码
int res = [cli_lib_ModifyPassword_v2:usr oldpass:oldpass new_pass:newpass];
- 参考
- 修改密码:cli_lib_ModifyPassword_v2
- 修改密码回复消息代理:cli_lib_ModifyPassword_CALLBACK
2.3.4. 用户登录
手机APP->手机APP: 1. 输入账号及密码
手机APP->云平台: 2. 登录
云平台-->手机APP: 3. 回复结果
用户登录只需要被执行一次。
- 实现并设置代理函数
- (void)cli_lib_login_callback:(int)HttpRes
{
//TODO: 处理登录请求的回复
}
...
cli.cli_login_delegate = self;
- 登录
[cli cli_lib_login:m_login_usr pass:m_login_pass];
- 参考
- 登录(2):cli_lib_login
- 登录请求回复消息的代理(3):cli_lib_login_callback
2.3.5. 修改用户昵称流程
手机APP->手机APP: 1. 输入新昵称
手机APP->云平台: 2. 请求修改
云平台-->手机APP: 3. 回复结果
以上步骤请在登录后进行。
- 实现并设置代理函数
-(void)cli_lib_ModifyNick_CALLBACK:(int)HttpRes newnick:(NSString*)new_nick
{
//TODO: 处理修改结果
}
...
cli.cli_set_delegate = self;
- 请求修改昵称
int res = [cli cli_lib_ModifyNick:m_new_nick];
- 参考
- 修改昵称(2~3):cli_lib_ModifyNick
2.3.6. 获取设备列表流程
由于单个设备可能会有多个通道(摄像头),因此这个接口通常不需要调用,呈现给用户的列表通常是摄像头列表。如果需要在界面上显示设备列表,再分级显示设备下的通道的话,需要获取设备列表和摄像头列表,并自己进行组合。
手机APP->手机APP: 1. 登录(略,参见2.3.4.)
手机APP->云平台: 2. 请求获取设备列表
云平台-->手机APP: 3. 回复结果
以上步骤请在登录后进行。
- 实现并设置代理函数
- (void)cli_lib_GetDevList_CALLBACK:(int)HttpRes data:(NSData *)data
{
//TODO: 处理获取设备列表请求的回复
}
...
cli.cli_devlist_delegate = self;
- 取设备列表
[cli cli_lib_GetDevList];
- 参考
- 获取设备列表(2):cli_lib_GetDevList
- 获取设备列表回复消息的代理(3):cli_lib_GetDevList_CALLBACK
2.3.7. 获取摄像头列表流程
手机APP->手机APP: 1. 登录(略,参见2.3.4.)
手机APP->云平台: 2. 请求获取摄像头列表
云平台-->手机APP: 3. 回复结果
手机APP->云平台: 4. 获取摄像头缩略图
云平台-->手机APP: 5. 回复
手机APP->手机APP: 6. 打开P2P预连接
以上步骤请在登录后进行。
- 实现并设置代理函数
- (void)cli_lib_GetCamlist_CALLBACK:(int)HttpRes data:(NSData *)data
{
//TODO: 处理获取摄像头列表请求的回复
}
...
cli.cli_camlist_delegate = self;
- 取摄像头列表
[cli cli_lib_getcamlist_ex];
- 获取摄像头缩略图
//返回jpeg数据
NSData *jpeg = [cli cli_lib_GetCamThumbnail:camid];
- 开启P2P预连接
int res = [cli cli_lib_set_preconnects: devs_array];
注:当摄像头列表发生变化时(通常发生在同一个账号多个手机登录,并且添加或删除摄像头时),会收到摄像头列表变化推送,此时需要更新一下摄像头列表。
- 参考
- 获取摄像头列表(2):cli_lib_getcamlist_ex
- 获取摄像头列表回复消息的代理(3):cli_lib_GetCamlist_CALLBACK
- 获取摄像头缩略图(4~5):cli_lib_GetCamThumbnail
- P2P预连接:cli_lib_set_preconnects
2.3.8. 局域网内搜索设备
手机APP->局域网: 1. 发送搜索请求
局域网->设备: 2. 搜索请求
设备-->手机APP: 3. 回复自己的信息
手机APP->手机APP: 4. 收集多个设备信息,通过代理返回给上层
- 实现并设置代理函数
- (void)cli_lib_vv_search_callback:(NSData *)searchdata
{
//TODO: 处理搜索到的设备列表
}
...
cli.cli_devadd_delegate = self;
- 开始搜索
[cli cli_lib_start_search];
注:由于广播包在局域网内十分容易丢包,因此建议重复搜索三次,将三次的结果合并在一起。否则可能会存在部分设备没有被搜到。
- 参考
- 搜索局域网设备(1):cli_lib_start_search
- 搜索结果代理(4):cli_lib_vv_search_callback
2.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. 连接结果
- 实现并设置代理函数
- (void)cli_lib_devconnect_CALLBACK:(int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- 开启配置
[cli cli_lib_wifi_start_config:str_ssid pass:str_ssidpass];
- 停止配置
[cli cli_lib_wifi_stop_config];
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:str_devid devuser:@"admin" devpass:str_devpass tag:nil];
注:流程结束前,请不要将
h_connector
用于其它接口。建议:总的等待时间为120秒,等待第一个10秒后,开始尝试P2P连接,以后每隔5秒开启、关闭WIFI配置,一直循环直到收到P2P连接成功代理函数或总等待时间超时。
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 开启配置(3):cli_lib_wifi_start_config
- 停止配置(7):cli_lib_wifi_stop_config
- 创建P2P连接(8):cli_lib_createconnect
- 断开P2P连接(6):cli_lib_releaseconnect
- 连接代理(9):cli_lib_devconnect_CALLBACK
2.3.10. 添加和删除设备
可以将设备添加到用户账号下,我们称之为绑定,绑定后,设备将出现在用户的设备列表中。
有三种流程来添加用户,开发APP时可以按需实现其中的一种或多种。它们分别是:
- 已接入互联网的设备,通过设备序列号和密码进行添加
- 未接入互联网的设备,通过一键WIFI配置无线网络并添加
- 未接入互联网的设备,通过二维码识别方式配置无线网络并添加
2.3.10.1. 通过设备序列号及密码添加
在APP开发中,设备序列号可以通过搜索局域网中的设备来获取,也可以扫描机身二维码来获取(APP自行开发,SDK不提供),或是直接由用户手工输入。
获取到设备序列号后,使用以下流程:
手机APP->手机APP: 1. 输入设备序列号及密码
手机APP->设备: 2. 尝试建立P2P连接
设备-->手机APP: 3. 连接结果(可重复1~2步共尝试3次)
手机APP->云平台: 4. 添加(绑定)设备
云平台-->手机APP: 5. 添加设备请求的回复
手机APP->设备: 6. 中断P2P连接
以上步骤请在登录后进行。
- 实现并设置代理函数
- (void)cli_lib_devconnect_CALLBACK:(int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- (void)cli_lib_binduser_callback:(int)result my_sess:(NSString *)bindsess
{
//TODO: 处理添加(绑定)设备结果
}
...
cli.cli_devadd_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
注:流程结束前,请不要将
h_connector
用于其它接口。
- 添加设备
[cli cli_lib_bind_lang:h_connector devname:m_devname devusr:m_devusr devpass:m_devpass bind_sess:m_bind_sess lang:lang];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 创建P2P连接(2):cli_lib_createconnect
- P2P连接结果代理(3):cli_lib_devconnect_CALLBACK
- 添加设备(4):cli_lib_bind_lang
- 添加设备结果代理(5):cli_lib_binduser_callback
- 断开P2P连接(6):cli_lib_releaseconnect
2.3.10.2. 一键WIFI配置添加设备
手机APP->手机APP: 1. 一键WIFI配置(参见2.3.9.步骤1~9)
手机APP->云平台: 2. 添加(绑定)设备
云平台-->手机APP: 3. 添加设备请求的回复
手机APP->设备: 4. 中断P2P连接
以上步骤请在登录后进行。
- 实现并设置代理函数
- (void)cli_lib_binduser_callback:(int)result my_sess:(NSString *)bindsess
{
//TODO: 处理添加(绑定)设备结果
}
...
cli.cli_devadd_delegate = self;
- 添加设备
[cli cli_lib_bind_lang:h_connector devname:m_devname devusr:m_devusr devpass:m_devpass bind_sess:m_bind_sess lang:lang];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
此处断开的P2P连接是在一键WIFI流程中创建的。
- 参考
- 添加设备(2):cli_lib_bind_lang
- 添加设备结果代理(3):cli_lib_binduser_callback
- 断开P2P连接(4):cli_lib_releaseconnect
2.3.10.3. 二维码识别添加设备
手机APP->手机APP: 1. 获取当前手机使用的SSID
手机APP->手机APP: 2. 输入WIFI密码
手机APP->手机APP: 3. 生成二维码字符串
手机APP->手机APP: 4. 显示二维码
手机APP->设备: 5. 将二维码对准设备摄像头
设备->设备: 6. 识别并配置WIFI
设备->云平台: 7. 添加设备到用户
云平台->手机APP: 8. 推送添加成功消息
以上步骤请在登录后进行。
如果设备正确识别了二维码并添加到用户账号下,平台会推送一个消息给客户端,通过cli_lib_qrcode_bind_callback回调给客户端。如果没有正确识别,平台是无法反馈的。
- 实现并设置代理函数
- (void)cli_lib_qrcode_bind_callback:(int)res devid:(NSString *)devid dev_ower:(NSString *)dev_ower
{
//TODO: 处理添加(绑定)设备结果
}
...
cli.cli_c2s_push_msg_ex_delegate = self;
- 生成二维码字符串
NSString *qrcode = [cli cli_lib_getwifi_qrcode:str_ssid ssidpass:str_ssidpass lang:@"zh"];
- 参考
- QRCode添加设备结果代理(3):cli_lib_qrcode_bind_callback
2.3.10.4. 删除设备
删除自己添加的设备,和别人分享给自己的设备,需要使用不同的接口。
- 实现并设置代理函数
- (void)cli_lib_deleteDev_CALLBACK:(int)HttpRes devid:(NSString *)dev_id
{
//TODO: 处理删除设备结果
}
...
cli.cli_devdelete_delegate = self;
- (void)cli_lib_DeleteShareCam_CALLBACK:(int)HttpRes camid:(NSString *)cam_id devid:(NSString *)devid my_sn:(int)sn
{
//TODO: 处理删除别人分享给自己的摄像头结果
}
...
cli.cli_camlist_delegate = self;
- 删除自己添加的设备:
[cli cli_lib_DeleteDevice:devid];
- 删除别人分享给自己的摄像头:
[cli cli_lib_delete_shared_camera:devid camid:camid sn:cursn];
注:某些设备可能含有多个通道(即多个摄像头,如DVR),在调用
cli_lib_DeleteDevice
时将删除所有的通道。而分享功能是可以细化到摄像头的,因此调用cli_lib_delete_shared_camera
时,删除的仅仅是指定的摄像头。
- 参考
- 删除设备:cli_lib_DeleteDevice
- 删除设备结果代理:cli_lib_deleteDev_CALLBACK
- 删除别人分享给自己的摄像头:cli_lib_delete_shared_camera
- 删除别人分享给自己的摄像头结果代理:cli_lib_DeleteShareCam_CALLBACK
2.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
以上步骤请在登录后进行。
- 初始化视窗
m_playview = [[VideoWnd alloc]initWithFrame:CGRectMake(0, 0, 320, 240)];//VideoWnd是一个自定义的OpenGL View,请参考SDK中自带的DEMO
......
- 创建并初始化播放器实例
m_player = [[vv_real_player alloc]init:0 fisheyetype:0 left:0 right:0 top:0 bottom:0];
注:鱼眼摄像头的相关参数可以从摄像头列表中的fisheye_params中获得。
建议:如果是鱼眼摄像头,请只使用主码流(即分辨率最高的码流),不允许切换码流。因为如果是子码流的鱼眼图像,经变形放大后,会很不清晰。如果一定要切换,请在stop_play后,调用set_fisheye_param函数重设边距参数,再开始start_play
- 实现并设置代理函数
-(void)on_play_audio_cap_callback:(int)exist play_id:(int)index
{
//TODO: 处理当前播放的码流是否存在音频
}
-(void)on_play_status_callback:(int)status play_id:(int)index tag:(NSString*)tag
{
//TODO: 处理播放状态变化
}
-(void)on_snap_jpg_callback:(int)res jpgdata:(NSData*)data
{
//TODO:处理抓图
}
-(void)on_resolution_changed_callback:(int)width height:(int)height index:(int)index
{
//TODO: 处理播放过程中,码流的分辨率发生变化
}
...
m_player.delegate = self;
注:播放过程中,如果分辨率发生变化,SDK内部会自动处理变化并继续播放,但由于分辨率分生变化时,画面的长宽比也会发生变化,因此开发者需要在变化时,调整surface_view的大小以符合长宽比。
- 设置播放窗口
[m_player set_surfaceview:m_playview];
- 开始播放
[m_player start_play:chl_id stream_id:stream_id devid:m_devid user:m_devusr pass:m_devpass;
注:这里的devid指设备序列号
- 云镜控制
[m_player ptz_ctrl:cmd with_speed:50 with_times:0];
- 抓图
[m_player snap_picture];
- 开启和关闭本地录像
[m_player start_record:filename_video thumbil_filename:filename_pic];
[m_player stop_record];
- 开关音频
[m_player set_audio_status:status];
注:当多路播放时,切换当前播放的视频时,需要先调用
set_audio_status
接口关掉前一路的音频,再调用set_audio_status
接口开启后一路的音频,否则,多路的音频会同时播放。
- 获取音频开关状态
int status = [m_player get_audio_status];
- 停止播放r
[m_player stop_play];
- 参考
- 实时播放类:vv_real_player
- 代理函数接口:vv_real_play_interface
- 初始化:init
- 设置播放窗口:set_surfaceview
- 开启播放:start_play
- 云镜控制:ptz_ctrl
- 抓图:snap_picture
- 开启本地录像:start_record
- 关闭本地录像:stop_record
- 开关音频:set_audio_status
- 获取音频开关状态:get_audio_status
- 停止播放:stop_play
2.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
以上步骤请在登录后进行。
- 创建对讲实例
m_talk = [CTalk getInstance];
- 实现并设置代理函数
- (void)on_voicetalk_status_callback: (int)status
{
//TODO: 处理对讲流程中状态变化
}
...
m_talk.delgate = self;
- (void)cli_lib_devconnect_CALLBACK: (int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
注:流程结束前,请不要将
h_connector
用于其它接口。
- 开启对讲
int res = [m_talk vv_voicetalk_start:h_connector chlid:chl_id user:str_user pass:str_pass talk_type:talk_type];
- 切换音频方向(只针对半双工模式)
[m_talk voice_switch:1];//声音方向:APP->设备
[m_talk voice_switch:0];//声音方向:设备->APP
- 关闭对讲
[m_talk vv_voicetalk_stop];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 创建P2P连接:cli_lib_createconnect
- P2P连接代理:cli_lib_devconnect_CALLBACK
- 释放P2P连接:cli_lib_releaseconnect
- 开启对讲:vv_voicetalk_start
- 关闭对讲:vv_voicetalk_stop
- 对讲状态变化代理on_voicetalk_status_callback
- 切换音频方向:voice_switch
2.3.13. 录像回放流程(包括录像查询、远程回放、本地录像回放)
2.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
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置客户端实例代理代理函数
- (void)cli_lib_devconnect_CALLBACK: (int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
接口:c2d_cam_query_record_interface
-(void)cli_lib_cam_record_date_callback:(int)res days:(NSString*)days with_date:(NSString*)str_date
{
//TODO: 处理查询得到的某一月内哪些天有录像
}
-(void)cli_lib_cam_record_min_callback:(int)res timelists:(NSMutableArray*)lists
{
//TODO: 处理查询得到的某一天内哪些分钟有录像
}
...
cli.cli_c2d_query_record_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
注:流程结束前,请不要将
h_connector
用于其它接口。
- 查询某一月内哪些天有录像
int res = [cli cli_lib_record_get_date_list:hconnector with_chlid:chlid with_rec_type:rec_type with_date:@"201609"];
- 查询某一日内哪些分钟有录像
int res = [cli cli_lib_record_get_min_list:h_connector with_chlid:n_chl with_rec_type:rec_type with_date:@"20160901"];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 创建P2P连接:cli_lib_createconnect
- P2P连接代理:cli_lib_devconnect_CALLBACK
- 释放P2P连接:cli_lib_releaseconnect
- 查询某一月内哪些天有录像:cli_lib_record_get_date_list
- 查询某一天内哪些天有录像结果代理:cli_lib_cam_record_date_callback
- 查询某一天内哪些分钟有录像:cli_lib_record_get_min_list
- 查询某一天内哪些分钟有录像结果代理:cli_lib_cam_record_min_callback
2.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
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 创建回放实例
m_playbacker = [[vv_playback_player alloc]init:0 fisheyetype:fisheye_type left:left right:right top:top bottom:bottom];
- 实现并设置回放实例的代理函数
接口:vv_playback_player_interface
- (void)on_play_audio_cap_callback:(int)exist play_id:(int)index
{
//TODO: 处理回放中是否存在音频
}
- (void)on_play_status_callback:(int)status progress:(int)progress play_id:(int)index
{
//TODO: 处理回放过程中播放状态变化
}
- (void)on_resolution_changed_callback:(int)width height:(int)height index:(int)index
{
//TODO: 处理回放过程中视频分辨率变化
}
- (void)on_snap_jpg_callback:(int)res jpgdata:(NSData *)data
{
//TODO: 处理回放过程中抓图结果
}
...
m_playbacker.delegate = self;
- 设置回放窗口
[m_playbacker set_surfaceview:view_gl];
- 开始回放
[m_playbacker start_play:n_chl devid:str_devid user:str_devuser pass:str_devpass start_time:m_play_date_str];
- 音频开关
[m_playbacker set_audio_status: on_or_off];
- 获取音频开关状态
int status = [m_playbacker get_audio_status];
- 停止回放
[m_playbacker stop_play];
- 参考
- 回放代理接口:vv_playback_player_interface
- 初始化并创建实例:init
- 设置回放窗口:set_surfaceview
- 开始回放:start_play
- 音频开关:set_audio_status
- 获取音频开关状态:get_audio_status
- 停止回放:stop_play
2.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
- 得到客户端实例
cli = [ppview_cli getInstance];
- 创建本地回放实例
m_player = [[vv_local_player alloc]init:0 fisheyetype:fisheye_type left:left right:right top:top bottom:bottom];
- 实现并设置本地回放实例的代理函数
- (void)on_play_audio_cap_callback:(int)exist play_id:(int)index
{
//TODO: 处理本地回放中是否存在音频
}
- (void)on_play_status_callback:(int)status play_id:(int)index total_sec:(long)total_sec
{
//TODO: 处理本地回放过程中播放状态变化
}
- (void)on_resolution_changed_callback:(int)width height:(int)height index:(int)index
{
//TODO: 处理本地回放过程中视频分辨率变化
}
- 设置本地回放窗口
[m_player set_surfaceview:view_gl];
view必须是opengl类型。
- 开始回放
[m_player start_play:filename];
- 暂停/恢复
[m_player true];//暂停
[m_player false];//恢复
- 获取本地回放实例索引号
int index = [m_player get_index];
本地回放实例索引号是在init时传入的,APP中存在多个本地回放实例时,用索引号来标识。
- 音频开关
[m_player set_audio_status: on_or_off];
- 获取音频开关状态
int status = [m_player get_audio_status];
- 取本地回放的视频的宽高值
int width = [m_player get_video_width];
int height = [m_player get_video_height];
- 取当前回放位置的秒数
int sec = [m_player get_cur_sec];
获取当前已播放的秒数(距离录像开始位置),录像文件总的秒数,在start_play后通过代理on_play_status_callback中得到。
通过录像文件总秒数和当前秒数,开发者可以在界面上动态显示本地录像回放进度。
- 重定位回放位置
int res = [m_player set_seek:sec];
重新设置播放位置,其参数sec表示离录像开始时的秒数,结合总秒数,开发者可以实现拖动进度条定位播放位置。
- 取当前回放位置的UTC时间
int utc = [m_player get_cur_frame_utctime];
显示和控制进度条,使用秒数就行,这个utc时间,是用来在画面上添加OSD时间字幕用的。原始画面上如果已经有OSD时间,就不需要再使用。
由于鱼眼摄像头的画面在实际播放时会进行校正,因此不适合在原始图像上添加OSD时间字幕,此时在回放本地鱼眼摄像头录像时,需要自己在画面上添加时间字幕。
注:此处得到的时间是UTC时间,如果要显示本地时间,请自行转换。
- 停止本地回放
[m_player stop_play];
- 参考
- 本地回放代理接口:vv_local_player_interface
- 初始化并创建实例:init
- 设置本地回放窗口:set_surfaceview
- 开始本地回放:start_play
- 暂停/恢复:set_pause
- 获取本地回放实例索引号:get_index
- 音频开关:set_audio_status
- 获取音频开关状态:get_audio_status
- 获取视频宽度:get_video_width
- 获取视频高度:get_video_height
- 取当前回放位置的秒数:get_cur_sec
- 重定位回放位置:set_seek
- 取当前回放位置的UTC时间:get_cur_frame_utctime
- 停止回放:stop_play
2.3.14. 布撤防流程
手机APP->手机APP: 1. 选择要布撤防的设备
手机APP->云平台: 2. 发送布撤防请求
云平台-->手机APP: 3. 回复
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置客户端实例代理函数
- (void)cli_lib_SetCamAlert_CALLBACK:(int)HttpRes camid:(NSString *)cam_id status:(int)status
{
//TODO: 处理布撤防请求回复
}
...
cli.cli_camlist_delegate = self;
- 单摄像头布撤防
[cli cli_lib_ModifyCamAlertStatus:str_camid devid:str_devid status:on_or_off];
- 多摄像头布撤防
[cli cli_lib_ModifyCamsAlertStatus:cams status:on_or_off];
- 参考
- 单摄像头布撤防结果代理:cli_lib_SetCamAlert_CALLBACK
- 单摄像头布撤防:cli_lib_ModifyCamAlertStatus
- 多摄像头布撤防结果代理:cli_lib_SetCamsAlert_CALLBACK
- 多摄像头布撤防:cli_lib_ModifyCamsAlertStatus
2.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
本流程用于查询用户已添加的所有设备的事件列表。
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置客户端实例代理函数
- (void)cli_lib_events_callback:(int)res event_id:(NSString *)event_id events:(NSData *)events
{
//TODO: 处理分页查询事件列表回复
}
- (void)cli_lib_unreadeventcount_callback:(int)res count:(int)count
{
//TODO: 处理获取未读条数回复
}
- (void)cli_lib_set_allevents_read_callback:(int)res
{
//TODO: 处理设置所有事件已读回复
}
...
cli.cli_c2s_msg_delegate = self;
- 获取事件列表
[cli cli_lib_get_event_list:@"0" items_count:10];//第一个参数为"0"表示第一页
- 获取未读事件数量
[cli cli_lib_get_unreadevent_count];
注:这个函数不一定要在流程图中标识的步骤中进行,可以在APP启动或从后台切换到前台时取一次。在APP处理激活状态时,未读事件数量会通过推送获取到。
- 获取事件缩略图
//返回jpeg数据
NSData *data = [cli cli_lib_GetEventThumbnail:camid eventid:eventid];
- 获取事件图片网址
NSString *url = [cli cli_lib_GetEventUrl:event_id];
//TODO: 用webviewer打开url显示报警图片
- 将所有事件设置为已读状态
[cli cli_lib_set_all_events_readed];
- 参考
- 事件查询代理接口:c2s_msg_interface
- 获取事件列表:cli_lib_get_event_list
- 获取未读事件数量:cli_lib_get_unreadevent_count
- 获取事件缩略图:cli_lib_GetEventThumbnail
- 获取事件图片网址:cli_lib_GetEventUrl
- 将所有事件设置为已读状态:cli_lib_set_all_events_readed
2.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
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置客户端实例代理函数
- (void)cli_lib_cam_events_callback:(int)res cam_id:(NSString *)cam_id event_id:(NSString *)event_id events:(NSData *)events
{
//TODO: 处理分页查询单摄像头事件列表回复
}
...
cli.cli_c2s_cam_msg_delegate = self;
- 获取事件列表
[cli cli_lib_get_cam_event_list:str_camid, event_id:@"0" items_count:10];//第二个参数为"0"表示第一页
注:这里的id是摄像头id,不是设备id,因为有些设备如DVR含有多个摄像头。
- 获取事件缩略图
//返回jpeg数据
NSData *data = [cli cli_lib_GetEventThumbnail:camid eventid:eventid];
- 获取事件图片网址
NSString *url = [cli cli_lib_GetEventUrl:event_id];
//TODO: 用webviewer打开url显示报警图片
- 参考
- 单摄像头事件查询代理接口:c2s_cam_msg_interface
- 获取单个摄像头的事件列表:cli_lib_get_cam_event_list
- 获取事件缩略图:cli_lib_GetEventThumbnail
- 获取事件图片网址:cli_lib_GetEventUrl
2.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
注:由于我们允许同一个账号在不同的设备上可以登录多次,因此在进行与分组相关的操作前,最好先获取一下当前最新的摄像头列表流水号,与已获得的流水号进行比较,如果不一致,应当刷新一下摄像头列表,以保证摄像头列表是最新的。如果当前的列表不是最新的,服务器会拒绝这次操作,以防止多人同时操作时引起的列表混乱。在代理函数中得到的流水号是分组操作后最新的流水号,可用于下一次操作。
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置客户端实例代理函数
- (void)cli_lib_GetCamlistSn_CALLBACK:(int)HttpRes sn:(short)list_sn;
{
//TODO: 处理获得的最新摄像头列表流水号
}
- (void)cli_lib_AddNewGroup_CALLBACK:(int)HttpRes groupid:(NSString *)group_id parentid:(NSString *)parent_id new_name:(NSString *)newname my_sn:(int)sn
{
//TODO: 处理创建分组的回复
}
- (void)cli_lib_ModifyGroupName_CALLBACK:(int)HttpRes groupid:(NSString *)group_id new_name:(NSString *)newname parentid:(NSString *)parent_id my_sn:(int)sn
{
//TODO: 处理修改分组名称的回复
}
- (void)cli_lib_Deletegroup_CALLBACK:(int)HttpRes groupid:(NSString *)group_id my_sn:(int)sn
{
//TODO: 处理删除分组的回复
}
- (void)cli_lib_MoveGroup_CALLBACK:(int)HttpRes groupid:(NSString *)group_id old_parid:(NSString *)oldparid new_parid:(NSString *)newparid my_sn:(int)sn
{
//TODO: 处理移动分组的回复
}
- (void)cli_lib_MoveCamera_CALLBACK:(int)HttpRes camid:(NSString *)cam_id old_parid:(NSString *)parent_old new_parid:(NSString *)parent_new my_sn:(int)sn
{
//TODO: 处理移动摄像头到分组的回复
}
...
cli.cli_camlist_delegate = self;
- 获取最新的摄像头列表流水号
[cli cli_lib_GetCamlistSn];
- 获取摄像头列表
[cli cli_lib_getcamlist_ex];
- 添加分组
[cli cli_lib_AddNewGroup:groupid new_name:groupname sn:sn];
- 修改分组名称
[cli cli_lib_ModifyGroupName:groupid new_name:newname with_parid:parent_group_id sn:sn];
- 移动分组
[cli cli_lib_MoveGroup:groupid oldparid:old_parent_group_id destgroupid:dest_parent_group_id sn:sn];
- 移动分组到新建分组
[cli cli_lib_MoveGroup_to_newgroup:groupid oldparid:old_parid new_groupname:new_groupname newgroup_parid:newgroup_parid sn:sn];
- 移动摄像头到分组
[cli cli_lib_MoveCamera:camid cam_type:cam_type old_groupid:oldgroupid destgroupid:destgroupid sn:sn];
请注意:这里的camid是摄像头编号,非设备编号
- 移动摄像头到新分组
[cli cli_lib_MoveCamera_to_newgroup:camid cam_type:cam_type old_groupid:oldgroupid new_groupname:new_groupname newgroup_parid:newgroup_parid sn:sn];
- 删除分组
[cli cli_lib_DeleteGroup:groupid sn:sn];
删除分组后,该分组所属的子分组和摄像头会自动转移到最顶下。
- 参考
- 分组相关代理接口:cameralist_interface
- 获取最新的摄像头列表流水号:cli_lib_get_cam_event_list
- 添加分组:cli_lib_AddNewGroup
- 修改分组:cli_lib_ModifyGroupName
- 移动分组:cli_lib_MoveGroup
- 移动分组到新建分组:cli_lib_MoveGroup_to_newgroup
- 移动摄像头:cli_lib_MoveCamera
- 移动摄像头到新分组:cli_lib_MoveCamera_to_newgroup
- 删除分组:cli_lib_DeleteGroup
2.3.18. 设备参数设置流程
设备参数设置是通过P2P通道直接连接设备后进行设置的,因此所有直接与设备交互的设备参数设置流程,都需要先创建一个P2P连接(使用cli_lib_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
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置代理函数
- (void)cli_lib_devconnect_CALLBACK: (int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- (void)cli_lib_netif_cli_get_CALLBACK:(int)res with_data:(NSData *)net_data
{
//TODO: 处理获取设备网络配置结果
}
- (void)cli_lib_netif_cli_set_CALLBACK:(int)res
{
//TODO: 处理设置设备网络配置结果
}
...
cli.cli_devconnect_single_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
注:流程结束前,请不要将
h_connector
用于其它接口。
- 获取网络配置
[cli cli_lib_cli_get_netif_settings:hconnector];
- 设置网络配置
[cli cli_lib_cli_set_netif:hconnector set_json:str_setjson];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
参考
- 创建P2P连接:cli_lib_createconnect
- P2P连接代理:cli_lib_devconnect_CALLBACK
- 释放P2P连接:cli_lib_releaseconnect
- 获取网络配置:cli_lib_cli_get_netif_settings
- 设置网络配置:cli_lib_cli_set_netif
2.3.19. 好友及黑名单管理流程
以下将好友及黑名单统称为“关系”。
用户A->用户A: 1. 获取自己的关系列表
用户A->用户B: 2. 添加好友请求
用户B->用户A: 3. 好友请求回复
用户A->用户A: 4. 将某用户加入到黑名单
用户A->用户A: 5. 将好友转入黑名单
用户A->用户A: 6. 删除好友或黑名单中的账号
以上步骤请在登录后进行。
以上步骤中,2、4、5、6可以并行进行,不需要严格按照图中的顺序。添加好友时,需要对方的确认;添加黑名单则不用。将某用户添加到黑名单后,将不再能收到该用户的好友请求。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置代理函数
接口:c2s_usr_relations_interface
- (void)cli_lib_GetUsrRelations_CALLBACK:(int)HttpRes data:(NSData *)data
{
//TODO: 处理获取到的关系列表
}
- (void)cli_lib_AddUsrRelations_CALLBACK:(int)HttpRes relation_usr:(NSString *)relation_usr relation_type:(int)relation_type
{
//TODO: 处理添加关系的回复
}
- (void)cli_lib_ModifyUsrRelations_CALLBACK:(int)HttpRes relation_usr:(NSString *)relation_usr relation_type:(int)relation_type memo:(NSString *)memo
{
//TODO: 处理修改关系的回复
}
- (void)cli_lib_DeleteUsrRelations_CALLBACK:(int)HttpRes relation_usr:(NSString *)relation_usr
{
//TODO: 处理删除关系的回复
}
...
cli.cli_c2s_usrrelations_delegate = self;
- 获取关系(好友和黑名单)列表
[cli cli_lib_get_usr_relations];
- 添加关系(好友或黑名单)
[cli cli_lib_add_usr_relations:m_new_usr relation_type:1];//添加好友
[cli cli_lib_add_usr_relations:m_new_usr relation_type:2];//添加黑名单
- 修改关系
用于同意好友申请、把好友改为黑名单或修改备注。不能用于添加好友。如果拒绝好友申请,需要使用删除关系cli_lib_delete_usr_relations
函数
[cli cli_lib_modify_usr_relations:relation_usr relation_type:relation_type memo:memo];
- 删除关系
将好友或黑名单从列表中删除掉。
[cli cli_lib_delete_usr_relations:relation_usr];
- 参考
- 关系管理相关代理接口:c2s_usr_relations_interface
- 获取关系列表:cli_lib_get_usr_relations
- 添加关系:cli_lib_add_usr_relations
- 修改关系:cli_lib_modify_usr_relations
- 删除关系:cli_lib_delete_usr_relations
2.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 上传新的列表的回复
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置代理函数
接口:c2s_usr_relations_interface
- (void)cli_lib_GetShareCams_CALLBACK:(int)HttpRes relation_user:(NSString *)relation_usr data:(NSData *)data
{
//TODO: 处理获取到的“分享给某用户的摄像头列表”
}
- (void)cli_lib_SetShareCams_CALLBACK:(int)HttpRes relation_usr:(NSString *)relation_usr
{
//TODO: 处理“设置分享给某用户的摄像头列表请求”结果
}
- (void)cli_lib_ReqShareDev_CALLBACK:(int)HttpRes devid:(NSString *)devid
{
//TODO: 处理“向其它用户申请分享设备请求”的回复
}
- (void)cli_lib_GetDevBelong_CALLBACK:(int)HttpRes devid:(NSString *)devid belongto:(NSString *)belong_usr
{
//TODO: 处理“获取设备归属用户请求”的回复
}
- (void)cli_lib_GetCam_shareusrs_CALLBACK:(int)HttpRes camid:(NSString *)camid data:(NSData *)data
{
//TODO: 处理“某摄像头分享的用户列表”,即这个摄像头分享给了哪些用户
}
- (void)cli_lib_SetShareFriends_CALLBACK:(int)HttpRes camid:(NSString *)camid
{
//TODO: 处理“将某摄像头分享给某些用户请求”的回复,即告诉平台,这个摄像头分享给了哪些用户后,平台的回复
}
...
cli.cli_c2s_sharecams_delegate = self;
- 请求其它用户分享摄像头(1.1)
[cli cli_lib_req_share_devid:devid with_msg:msg];
由于发起请求时,发起者并不知道该设备有多少个通道,因此只能针对设备发起请求,被请求者可能选择该设备下的一个或多个摄像头分享给该用户。可通过接口获取设备的归属用户,以便向该用户发起共享请求。
- 获取设备的归属用户
int res = [cli_lib_get_dev_belong:devid];
- 响应其它用户的分享请求(1.4、2.6) 可以有三种响应:同意,拒绝,或是为了防止骚扰而将其拉入黑名单
[cli cli_lib_response_sharereq_cam:reqid cmd:1];//同意
[cli cli_lib_response_sharereq_cam:reqid cmd:0];//拒绝
拉入黑名单请参考好友及黑名单管理流程中的”关系管理“。
- 删除分享给自己的摄像头(1.7)
int res = [cli cli_lib_delete_shared_camera:devid camid:camid sn:cursn];
- 获取其它用户发来的分享请求条数(2.1)
int count = [cli cli_lib_get_sharecam_req_count];
- 获取其它用户发来的分享请求列表(2.4)
int res = [cli cli_lib_get_sharereqs_cams];
- 获取分享给某用户的摄像头列表(3.1)
int res = [cli cli_lib_get_shared_cams:relation_usr];
- 设置新的分享给某用户的摄像头列表(3.4)
int res = [cli cli_lib_set_shared_cams:relation_usr cam_json:cam_json];
- 获取某摄像头的分享用户列表(4.1)
int res = [cli cli_lib_get_cam_shareusr_list:devid camid:camid];
- 上传新的摄像头分享用户列表(4.4)
int res = [cli cli_lib_set_shared_friends:camid devid:devid friends_json:friends_json];
- 参考
- 相关的代理接口:c2s_usr_relations_interface
- 请求其它用户分享摄像头(1.1):cli_lib_req_share_devid
- 同意或拒绝分享请求(1.4、2.6):cli_lib_response_sharereq_cam
- 删除分享给自己的摄像头(1.7):cli_lib_delete_shared_camera
- 获取其它用户发来的分享请求条数(2.1):cli_lib_get_sharecam_req_count
- 获取其它用户发来的分享请求列表(2.4):cli_lib_get_sharereqs_cams
- 获取分享给某用户的摄像头列表(3.1):cli_lib_get_shared_cams
- 设置新的分享给某用户的摄像头列表(3.4):cli_lib_set_shared_cams
- 获取某摄像头的分享用户列表(4.1):cli_lib_get_cam_shareusr_list
- 上传新的摄像头分享用户列表(4.4):cli_lib_set_shared_friends
2.3.21. 透明传输通道交互流程
透明通道是为开发者预留的,可以在设备端和客户端之间P2P传输任意格式数据的接口。因此需要设备端与客户端协同才可正常工作。SDK中的DEMO仅示例了这些接口的用法,在真实环境中测试时,需要设备端也实现了相应的接口,并与客户端使用相同的自定义协议。
在客户端与设备端通过透明通道进行交互时,通过调用cli_lib_trchl_send
函数主动发送数据,接收数据则通过cli_lib_trchl_receive_callback
代理。
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
以上步骤请在登录后进行。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置代理函数
- (void)cli_lib_devconnect_CALLBACK: (int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- (void)cli_lib_trchl_receive_callback:(int)trchlhandle data:(NSData *)data datalen:(int)datalen
{
//TODO: 处理从透明通道获取到的数据(即从设备端->客户端)
}
...
cli.cli_c2d_trchl_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
- 打开透明传输通道
h_trchl_handle = [cli cli_lib_trchl_open:h_connector];
- 通过透明通道发送数据
int len = [cli_lib cli_lib_trchl_send:h_trchl_handle buffer:data size:data_size];
接收数据在代理中进行。
- 关闭透明通道
[cli cli_lib_trchl_close:h_trchl_handle];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 创建P2P连接:cli_lib_createconnect
- P2P连接代理:cli_lib_devconnect_CALLBACK
- 释放P2P连接:cli_lib_releaseconnect
- 开启透明通道:cli_lib_trchl_open
- 透明通道接收数据代理:cli_lib_trchl_receive_callback
- 通过透明通道发送数据:cli_lib_trchl_send
- 关闭透明通道:cli_lib_trchl_close
2.3.22. 推送信息处理流程
ppview平台具备自己的推送服务器,用于向设备、手机推送消息。
iOS的推送消息分为前台消息和后台消息。前台消息是指APP在前台时,所能收到的消息,这些消息需要在程序中通过代理函数来处理,参见实现推送消息处理代理函数;后台消息是APP处于后台是,在系统中显示的推送消息,APP不需要处理。
iOS的前台消息,由平台服务器直接推送给手机APP。
iOS后台推送消息,由平台服务器推送给苹果推送服务器后,再由苹果推送服务器推送至手机。因此开发者需要在平台中上传推送用的签名证书文件(包括开发版和发布版),或将文件发送开技术支持,由技术支持来处理。
2.3.22.1 初始化并注册APNS消息类型
在AppDelegate.m
中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ppview_cli cli_lib_vv_registerForPush_types:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) launchingOption:launchOptions];
return YES;
}
- 参见
- 初始化并注册APNS消息类型接口:cli_lib_vv_registerForPush_types
2.3.22.2 向服务器注册手机的设备Token
在AppDelegate.m
中:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[ppview_cli cli_lib_vv_registerDeviceToken:deviceToken];
}
- 参考
- 注册手机的设备Token接口:cli_lib_vv_registerDeviceToken
2.3.22.3 设置推送标记
在ViewController.m
中:
cli_lib.cli_c2s_msg_delegate = self;
// client_type 0:开发版 1:发布版
[cli_lib cli_lib_vv_setTags_ex:@"user_name" language:@"language tag" push_svr:@"push server address" push_svr_port:8080 push_key:@"pushkey" push_pass:@"pushpass" client_type:0 version:@"1.0"];
注:以上代码中函数调用中的各个参数仅做示例用,在实际开发时,需要替换成正确的值。其中第一个参数必须为用户名,language为语言标记,push_svr、push_svr_port、push_key、push_pass分别为推送服务器地址、端口、推送key和推送pass,在注册为开发者账号时自动分配,或向技术支持索取。
特别注意:client_type用于指定开发版或发布版,在发布版中务必要将值设置为1,否则可能会引起无法接收到推送消息,或是出现混乱的情况。
- 参考
- 设置推送标记:cli_lib_vv_setTags_ex
2.3.22.4 实现推送消息处理代理函数
// 以下为推送消息代理函数
- (void)cli_lib_push_register_callback:(int)res
{
//TODO: 处理注册请求返回的结果
}
- (void)cli_lib_push_unregister_callback:(int)res
{
//TODO: 处理注销请求返回的结果
}
- (void)cli_lib_devstatus_change_callback:(NSString *)devid status:(int)status
{
//TODO: 处理设备状态变化推送
}
- (void)cli_lib_devlist_change_callback
{
//TODO: 处理设备列表变化推送
}
- (void)cli_lib_eventpic_change_callback:(NSString *)eventid
{
//TODO: 处理事件图片变化推送(因为事件消息是即时送达的,事件图片需要稍后才能完成上传,因此图片完成上传后会有推送消息,方便界面上更新图片)
}
- (void)cli_lib_camlist_change_callback:(short)sn
{
//TODO: 处理摄像头列表变化推送
}
- (void)cli_lib_alarm_callback:(NSDictionary *)event
{
//TODO: 处理事件消息推送
}
- (void)cli_lib_alert_change_callback:(NSString *)camid status:(int)status
{
//TODO: 处理布撤防状态变化推送
}
- (void)cli_lib_disable_alert_event_callback:(NSString *)camid
{
//TODO: 处理清除报警状态推送(有些APP会有当摄像头报警时,在摄像头上显示报警状态的需求,当用户取消这个状态时,会触发这个推送,并被推送到所有已用该账号登录的APP上)
}
- (void)cli_lib_disable_lowpower_event_callback:(NSString *)camid
{
//TODO: 处理清除低电压状态推送(有些外部传感器会触发低电状态,此时所有使用该账号登录的账号都会接收到低电事件。此时,如果有其中一个客户端清除了低电状态,所有其它客户端均会收到清除低电状态的推送,以便在界面上更新状态)
}
- (void)cli_lib_camprivate_change_callback:(NSString *)camid status:(int)status
{
//TODO: 处理隐私模式开关变化推送(在隐私模式下,无法远程查看音视频)
}
- (void)cli_lib_req_cam_sharenum_change_callback:(int)num
{
//TODO: 处理分享请求数变化推送(别人向你请求分享的消息)
}
- (void)cli_lib_user_relations_changed_callback:(NSDictionary *)dic
{
//TODO: 用户关系(好友、黑名单)变化推送
}
- 参考
- 注销推送接口:vvpush_msg_interface
2.3.22.5 从推送服务器上注销
在APP中,如果要注销当前用户,或者还需要切换到其它用户时,必须先注销推送,否则在注销状态下,iphone后台仍会收到该用户的推送消息。
[cli cli_lib_vv_push_stop];
- 参考
- 注销推送接口:cli_lib_vv_push_stop
2.3.23. APP前后台切换或网络通断时需要调用的函数
IOS客户端切换到后台后,所有网络连接都会被挂起,或者发生网络中断时,会导致已创建的P2P连接中断,重新切换到前台或网络恢复后,虽然P2P连接也会自动恢复,但所需时间较长,为了有更好的体验,需要在前后台切换或网络连接断开时调用切换通知函数,以便SDK库能够及时做出响应。
- 恢复网络(从后台切换到前台,或网络从中断状态恢复时):
int res = [cli cli_lib_cli_active_status:1];
- 中断网络(从前台切换到后台,或网络发生中断时):
int res = [cli cli_lib_cli_active_status:0];
[cli cli_lib_clear_player_cache];
- 参考
2.3.24. 传感器相关
传感器对码流程:
手机APP->设备: 创建P2P连接
设备-->手机APP: P2P连接反馈
手机APP->设备: 请求开启对码模式
设备->设备: 开启对码模式
传感器->设备: 触发信号
设备->设备: 记录新对码到的传感器或等待超时
设备->设备: 结束对码模式
设备-->手机APP: 对码结果
传感器相关操作是通过P2P通道直接连接设备后进行设置的,因此需要先创建一个P2P连接(使用cli_lib_createconnect接口)。
多个操作流程,不能同时使用同一个P2P连接,但是如果这些操作是依次进行的,即前一个设置操作结束后再进行下一个,此时可以复用P2P连接。
某些传感器(也可以称为智能设备)内部,包含有多个子通道,如含有三个插口的智能插座,或者含有多个开关的智能开关组。
- 得到客户端实例
cli = [ppview_cli getInstance];
- 实现并设置代理函数
- (void)cli_lib_devconnect_CALLBACK: (int)msg_id connector:(int)connector result:(int)res
{
//TODO: 处理与设备建立P2P连接结果
}
...
cli.cli_devconnect_single_delegate = self;
- (void)cli_lib_get_sensors_callback:(int)res data:(NSData*)data
{
//TODO: 处理获取到的传感器列表信息
}
- (void)cli_lib_sensor_codding_callback:(int)res data:(NSData*)data
{
//TODO: 处理对码结果
}
- (void)cli_lib_sensor_delete_callback:(int)res sensor_id:(NSString*)sensor_id;
{
//TODO: 处理删除传感器结果
}
- (void)cli_lib_sensor_set_callback:(int)res tag:(int)tag sensorid:(NSString*)sensorid name:(NSString*)name preset:(int)preset isalarm:(int)isalarm;
{
//TODO: 处理设置传感器信息结果
}
- (void)cli_lib_sensor_subchl_set_callback:(int)res tag:(NSString*)tag sensorid:(NSString*)sensorid chlid:(int)chlid name:(NSString*)name alarm_linkage:(int)alarm_linkage;
{
//TODO: 处理设置传感器子通道信息结果
}
- (void)cli_lib_sensor_subchl_remote_ctrl_callback:(int)res sensor_id:(NSString*)sensor_id chlid:(int)chlid status:(int)status;
{
//TODO: 处理远程控制子通道结果
}
...
cli.cli_c2s_sensors_delegate = self;
- 创建P2P连接
h_connector = [cli cli_lib_createconnect:m_devid devuser:m_devusr devpass:m_devpass];
注:流程结束前,请不要将
h_connector
用于其它接口。
- 开始设备与传感器对码
通过对码,将传感器绑定到设备上。调用此接口后,需要触发一下传感器来完成配对,在完成前不可做其他操作。
[cli cli_lib_coding_sensors:hconnector with_chlid:chlid];
- 获得传感器列表
[cli cli_lib_get_sensors:hconnector with_chlid:chlid sensor_type:sensor_type];
- 设置传感器信息
[cli cli_lib_set_sensors:hconnector with_chlid:chlid with_id:sensorid name:name preset:preset isalarm:isalarm with_tag:tag];
- 移除传感器
[cli cli_lib_delete_sensor:hconnector with_chlid:chlid sensorid:sensorid];
- 设置传感器子通道信息
[cli cli_lib_set_sensor_subchl:hconnector with_chlid:chlid with_id:sensorid subchl_id:subchl_id name:name alarm_linkage:alarm_linkage with_tag:tag];
- 远程控制传感器开关
[cli cli_lib_sensor_remote_ctl:hconnector sensor_id:sensor_id chlid:chlid subchlid:subchlid status:status];
- 断开P2P连接
[cli cli_lib_releaseconnect:h_connector];
- 参考
- 创建P2P连接:cli_lib_createconnect
- P2P连接代理:cli_lib_devconnect_CALLBACK
- 释放P2P连接:cli_lib_releaseconnect
- 开始设备与传感器对码:cli_lib_coding_sensors
- 获得传感器列表:cli_lib_get_sensors
- 设置传感器信息:cli_lib_set_sensors
- 移除传感器:cli_lib_delete_sensor
- 设置传感器子通道信息:cli_lib_set_sensor_subchl
- 传感器远程控制开关:cli_lib_sensor_remote_ctl
- 传感器操作相关代理接口:c2s_sensors_interface