娃娃机 web 端场景的主要结构及流程如下图所示:
请注意:
上图中的
用户选择上机
步骤,可使用 jZego.js SDK 拉流切换实现。**开发者注意区分
娃娃机 App 端
和娃娃机
**。前者指的是,提供给玩家抓娃娃的、安装在 iOS 或 Android 平台的 App。后者指的是,直接与娃娃机通过串口通信的、安装在 Android 平台上的 App,类似于娃娃机 Server。为了便于开发者更快理解 WaWaJi Client 中的逻辑,下述每节会将功能核心源码片段挑出来并加以讲解。开发者亦可直接阅读 WaWaJi Client 源码,两者是一致的。
1、安装娃娃机控制端APK到安卓板子上
2、娃娃机启动,推流成功后,Zego后台会给业务后台POST 流创建的相关信息(业务后台提供回调地址),用于业务侧维护娃娃机列表
3、客户端的开发
娃娃机系统实现流程如下图所示。该方案中,娃娃机控制端无需与业务后台直接通信。
//new 一个实例
var zg = new ZegoClient();
// 1.配置参数
zg.config({
appid: appid, // 必填,应用id,由即构分配
idName: idName, // 必填,用户自定义id
nickName: nickName, // 必填,用户自定义昵称
server: server // 必填,接入服务器地址, 由即构分配
logUrl: logUrl // 必填,logServer地址,由即构分配
});
以下所有步骤均基于登录房间成功的前提
。WaWaJi Web 中相关源码片段如下,仅供参考:
// 2. 登录
zg.login(roomID, role, token, function(streamList){
// 登录成功回调
// code
}, function(err){
// 登录失败回调
// code
});
观众想看到娃娃机画面,需先拉流
WaWaJi Web 中拉流相关源码片段如下,仅供参考:
// 3. 初始化流 流信息可在登录成功回调函数中获得
// 得到流信息后,传入流ID和指定的原生canvas元素,播放与该ID对应的视频流
// 正面
zg.startPlayingStream(useStreamList[0].stream_id, frontView);
// 正面流音量设置为最大
zg.setPlayVolume(useStreamList[0].stream_id, 100);
// 侧面
zg.startPlayingStream(useStreamList[1].stream_id, sideview);
// 侧面流音量设置为静音
zg.setPlayVolume(useStreamList[1].stream_id, 0);
stopPlayingStream
停止播放指定流startPlayingStream
重新播放指定流请注意:
目前 WaWaJi Web 使用的方案是,进入房间后,创建两个 view 分别播放两条流数据,用户可通过手动切换 view,继而切换当前可见流。
这里需要注意的是,如果某一条流从可见切换为不可见,需要调用
setPlayVolume
改变流播放声音为无声,否则可能造成流画面和流声音混乱的情况。反之亦然。
用户需要调用 sendCustomCommand
接口发送指令给娃娃机(此处的娃娃机,指的是控制娃娃机硬件的 Server 端,后面简称为娃娃机),娃娃机收到指令后,做出对应的响应。
请注意,此处指令是发送给娃娃机控制端,而不是房间里的其他玩家或自己。
WaWaJi Web 中发出指令相关源码片段如下,仅供参考:
zg.sendCustomCommand(
[anchor_id],
custom_msg,
function(seq, custom_content){
console.log('customCMD 成功', custom_content);
},
function(err, seq, custom_content) {
console.log('customCMD 失败', custom_content);
}
);
娃娃机客户端与控制端信令交互流程请参考:娃娃机-信令交互
WaWaJi Web 端可以通过 onRecvCustomCommand
接受娃娃机返回的命令:
// 接收消息接口
zg.onRecvCustomCommand = function(from_userid, from_idName, custom_content) {
// code
})
娃娃机客户端与控制端信令交互流程请参考:娃娃机-信令交互
如果用户不再进行游戏,退出当前的娃娃机房间,注意调用退出房间,确保停止拉流,并清空状态。
WaWaJi Client 中退出房间相关源码片段如下,仅供参考:
// 登出
zg.stopPlayingStream(useStreamList[1].stream_id);
zg.stopPlayingStream(useStreamList[0].stream_id);
zg.logout()
{
“ver": 1, //int类型
"hash": 710a5199398176a316ebcc88bc5b4470, //字符串类型
“nonce": 随机串,需要保证同一USER_ID在失效时间内不重复, 建议按guid生成, //字符串类型
"expired": 失效时间,unix_timestamp //int64类型,单位秒
}
login_token信息由业务后台负责,其中hash的生成算法如下:
hash=MD5(app_id+app_key_32+id_name+nonce+expired)。
app_key_32: 通过app_key运算获得。
算法:剔除app_key里的"0x", ","字符后,获取前面32字节即为app_key_32(具体算法可参考以下代码)
id_name:为客户登录时候传入的字符串用户id
nonce: 一次性随机字符串串
expired: 过期时间
login_token传输过程中,经过base64加密。
每次登录都要重新获取login_token
go语言login_token生成示例代码
func makeTokenSample(appid uint32, app_key string, idname string, expired_add int64) (ret string, err error){
nonce := UniqueId()
expired := time.Now().Unix() + expired_add //单位:秒
app_key = strings.Replace(app_key, "0x","",-1)
app_key = strings.Replace(app_key, ",", "", -1)
if len(app_key) < 32 {
return "", fmt.Errorf("app_key wrong")
}
app_key_32 := app_key[0:32]
source := fmt.Sprintf("%d%s%s%s%d",appid,app_key_32,idname,nonce,expired)
sum := GetMd5String(source)
token := tokenInfo{}
token.Ver = 1
token.Hash = sum
token.Nonce = nonce
token.Expired = expired
buf, err := json.Marshal(token)
if err != nil {
return "", err
}
encodeString := base64.StdEncoding.EncodeToString(buf)
return encodeString, nil
}
// 获取MD5加密
func GetMd5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
php语言login_token生成示例代码
public function getToken(int $app_id, string $app_key, string $idname, int $expired_add)
{
$nonce = uniqid();
$expired = time() + $expired_add; //单位:秒
$app_key = str_replace("0x", "", $app_key);
$app_key = str_replace(",", "", $app_key);
if(strlen($app_key) < 32) {
return false;
}
$app_key_32 = substr($app_key, 0, 32);
$source = $app_id.$app_key_32.$idname.$nonce.$expired;
$sum = md5($source);
$tokenInfo = [
'ver' => 1,
'hash' => $sum,
'nonce' => $nonce,
'expired' => $expired,
];
$token = base64_encode(json_encode($tokenInfo));
return $token;
}
如何保证获取Token信息的过程是安全的? 业务APP需要和业务后台建立一种安全通讯和鉴权机制,业务APP使用自有的账户体系/第三方认证体系的登录完成后,业务APP和业务后台交互获取该login_token, AppSecret是存储在业务后台的。
msg_token对Zego是透明的,由业务设计具体方案去实施,对于业务APP很自然的方案是在业务APP使用自有的账户体系/第三方认证体系的登录完成后,业务APP和业务后台交互获取和更新该Token.
联系我们
文档反馈