Requirement summary: realize video dialing, answering, hanging up, video interface size window, click on the small window to realize the exchange of large and small windows.
Implementation idea: After one party makes a call, the other party must be able to receive the corresponding event, and then answer it. After connecting, render the other party's video screen. So when will your own video screen be rendered? For the caller, the rendering can be started after the call, or the rendering can be started after the connected event event occurs. The connected party can start rendering after clicking the answer button, or it can start rendering after the connect event occurs.
With the above ideas, we can verify whether our ideas can be realized by looking up the corresponding api in the module documentation and writing the code. If you encounter problems, then adjust the implementation ideas.
The following is the link to the Rongyun module documentation: https://docs.apicloud.com/Client-API/Open-SDK/rongCloud2
A brief introduction to the main APIs used:
**startCall initiates an audio and video call
addCallReceiveListener audio and video incoming call event listener
accept to answer an incoming call
addCallSessionListener Monitor audio and video call events (including multiple event monitors such as ringing, connecting, hanging up, etc.) setVideoView Set the video area
resetVideoView resets the video area
removeVideoView removes the video area
hangup hang up**
The code is explained below.
Before calling the audio and video call function, you should call the api.hasPermission interface to check whether there are microphone and camera permissions. If not, you must apply for permissions first.
api.requestPermission({
list: ['microphone', 'camera', 'storage', 'photos'],
code: 1
})
After Rongyun is successfully initialized, you can add listeners for corresponding events. didReceiveCall pops up the answering page after receiving the incoming call event. After answering, the didConnect event will be executed, and the local window setVideoView can be set at this time; the remoteUserDidJoin will be executed later (the peer user joins the call event), and the peer user window can be set through setVideoView at this time. Adjust the local widget to the front through the videoViewBringToFront interface.
apiready = function () {
rong = api.require('rongCloud2');
rong.init({
huaweiPush: false
}, function (ret, err) {
if (ret.status == 'error') {
api.toast({
msg: err.code
});
} else {
console.log('初始化成功');
rong.setConnectionStatusListener(function (ret, err) {
console.log("连接状态监听:" + ret.result.connectionStatus);
});
//收到来电事件监听
rong.addCallReceiveListener({
target: 'didReceiveCall'
}, function (ret) {
console.log('didReceiveCall:' + JSON.stringify(ret))
callId = ret.callSession.callId;
api.toast({
msg: '来电请接听'
})
fnopenbtnframe(); //打开接听、挂断按钮所在的frame
});
// 通话连接成功监听
rong.addCallSessionListener({
target: 'didConnect'
}, function (ret) {
console.log('didConnect:' + JSON.stringify(ret))
var myname = api.getPrefs({
sync: true,
key: 'myname'
});
//打开本地窗口
fnsetVideoView(api.winWidth - 200, 100, 160, 200, myname);
//将本地窗口显示到最前方
setTimeout(function () {
rong.videoViewBringToFront({
userId: myname
})
}, 1000)
})
//通话已结束的事件
rong.addCallSessionListener({
target: 'didDisconnect'
}, function (ret) {
console.log('didDisconnect:' + JSON.stringify(ret))
})
//对端用户加入了通话的事件
rong.addCallSessionListener({
target: 'remoteUserDidJoin'
}, function (ret) {
console.log("对端用户加入了通话的事件:" + JSON.stringify(ret));
var uid = ret.userId;
//设置远端窗口
fnsetVideoView(0, 0, api.winWidth, api.winHeight, uid);
});
//监听视频区域点击事件,实现大小窗口切换
rong.addVideoViewListener(function (ret) {
//判断点击的是否是初始小窗口
if (ret.userId == myname && meissmall) {
fnresetVideoView(0, 0, api.winWidth, api.winHeight, ret.userId);
fnresetVideoView(api.winWidth - 200, 100, 160, 200, hename);
meissmall = false;
setTimeout(function () {
rong.videoViewBringToFront({
userId: hename
})
}, 1000)
setTimeout(function () {
fnopenbtnframe()
}, 1200)
}
if (ret.userId == hename && !meissmall) {
fnresetVideoView(0, 0, api.winWidth, api.winHeight, ret.userId);
fnresetVideoView(api.winWidth - 200, 100, 160, 200, myname);
meissmall = true;
setTimeout(function () {
rong.videoViewBringToFront({
userId: myname
})
}, 1000)
setTimeout(function () {
fnopenbtnframe()
}, 1200)
}
})
}
});
};
The effect is as follows:
Other lessons learned:
The error code 34001 is returned. Restarting the loader can solve the problem. It may be possible to log in with another account. The wifi synchronization restarting the loader may cause the user information to be cached.
If you can't answer the incoming call event, you can try to use the 4g network test. Some corporate firewalls, or wifi hotspot networks shared by computers are limited or unstable.
The above experience is summed up after countless troubleshooting, and reading it can save you at least two working days.
Finally paste the complete code:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="maximum-scale=2.0,minimum-scale=1.0,user-scalable=1,width=device-width,initial-scale=1.0" />
<meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
<title>Hello APP</title>
<link rel="stylesheet" type="text/css" href="../css/api.css" />
<script src="../script/sha1.js"></script>
<style>
body {
margin-top: 90px;
}
button {
padding: 10px
}
</style>
</head>
<body id="bd">
<button onclick="fnrequestPermission()">fnrequestPermission</button>
<input id="useName" placeholder="输入用户名" style="display: block" />
<div id="stauseName" style="display: none">
**用户已登录
</div>
<input id="fridendName" placeholder="输入好友用户名" style="" />
<br>
<button onclick="login()">
登录
</button>
<br>
<button onclick="fnstartCall()">
fnstartCall
</button>
<br>
<br><br>
<p>
<ul>
<li>1. 测试步骤</li>
<li>2. 准备两部手机A和B</li>
<li>3. A手机在【输入用户名】【输入好友用户名】处分别输入a, b;然后点登录</li>
<li>4. B手机在【输入用户名】【输入好友用户名】处分别输入b, a;然后点登录</li>
<li>5. 一部手机点fnstartCall</li>
<li>6. 另一部手机在弹出‘来电请接听提示后’,会弹出底部按钮frame,点击【接听】</li>
<li>7. 接通后,弹出大小视频窗口。点击小窗口可实现切换。</li>
</ul>
</p>
</body>
<script type="text/javascript" src="../script/api.js"></script>
<script type="text/javascript">
var rong;
var myname = '';
var hename = '';
var meissmall = true;
function fnrequestPermission() {
api.requestPermission({
list: ['microphone', 'camera', 'storage', 'photos'],
code: 1
})
}
apiready = function () {
rong = api.require('rongCloud2');
rong.init({
huaweiPush: false
}, function (ret, err) {
if (ret.status == 'error') {
api.toast({
msg: err.code
});
} else {
console.log('初始化成功');
rong.setConnectionStatusListener(function (ret, err) {
alert("setConnectionStatusListener::::::" + ret.result.connectionStatus);
});
rong.addCallReceiveListener({
target: 'didReceiveCall'
}, function (ret) {
console.log('didReceiveCall:' + JSON.stringify(ret))
callId = ret.callSession.callId;
api.toast({
msg: '来电请接听'
})
fnopenbtnframe();
});
rong.addCallSessionListener({
target: 'didConnect'
}, function (ret) {
console.log('didConnect:' + JSON.stringify(ret))
var myname = api.getPrefs({
sync: true,
key: 'myname'
});
//打开本地窗口
fnsetVideoView(api.winWidth - 200, 100, 160, 200, myname);
setTimeout(function () {
rong.videoViewBringToFront({
userId: myname
})
}, 1000)
})
rong.addCallSessionListener({
target: 'didDisconnect'
}, function (ret) {
console.log('didDisconnect:' + JSON.stringify(ret))
})
rong.addCallSessionListener({
target: 'remoteUserDidJoin'
}, function (ret) {
console.log("对端用户加入了通话的事件:" + JSON.stringify(ret));
var uid = ret.userId;
fnsetVideoView(0, 0, api.winWidth, api.winHeight, uid);
});
rong.addVideoViewListener(function (ret) {
//判断点击的是否是初始小窗口
if (ret.userId == myname && meissmall) {
fnresetVideoView(0, 0, api.winWidth, api.winHeight, ret.userId);
fnresetVideoView(api.winWidth - 200, 100, 160, 200, hename);
meissmall = false;
setTimeout(function () {
rong.videoViewBringToFront({
userId: hename
})
}, 1000)
setTimeout(function () {
fnopenbtnframe()
}, 1200)
}
if (ret.userId == hename && !meissmall) {
fnresetVideoView(0, 0, api.winWidth, api.winHeight, ret.userId);
fnresetVideoView(api.winWidth - 200, 100, 160, 200, myname);
meissmall = true;
setTimeout(function () {
rong.videoViewBringToFront({
userId: myname
})
}, 1000)
setTimeout(function () {
fnopenbtnframe()
}, 1200)
}
})
}
});
};
//打开视频区域
function fnsetVideoView(x, y, w, h, uid) {
rong.setVideoView({
rect: {
x: x,
y: y,
w: w,
h: h
},
userId: uid,
bg: '#ff0000',
renderModel: 'fit',
fixedOn: '',
fixed: false
});
}
function fnresetVideoView(x, y, w, h, uid) {
rong.resetVideoView({
rect: {
x: x,
y: y,
w: w,
h: h
},
userId: uid,
bg: '#ff0000',
renderModel: 'fit'
});
}
//移除视频区域
function fnremoveVideoView(ruid) {
rong.removeVideoView({
userId: ruid
});
}
function fnstartCall() {
myname = api.getPrefs({
sync: true,
key: 'myname'
});
hename = api.getPrefs({
sync: true,
key: 'hename'
});
rong.startCall({
targetId: hename,
mediaType: 'video',
conversationType: 'PRIVATE',
userIdList: [hename]
}, function (ret) {
console.log('startCall:' + JSON.stringify(ret))
callId = ret.callSession.callId;
});
fnopenbtnframe();
}
//打开按钮页面
function fnopenbtnframe() {
api.openFrame({
name: 'btframe',
url: 'button.html',
rect: {
marginLeft: 0,
marginBottom: 0,
h: 100,
w: 'auto'
}
})
}
function fnaccept() {
//同步返回结果:
myname = api.getPrefs({
sync: true,
key: 'myname'
});
hename = api.getPrefs({
sync: true,
key: 'hename'
});
rong.accept({
mediaType: 'video',
callId: callId
});
}
function fnhangup() {
rong.hangup();
fnremoveVideoView(hename);
fnremoveVideoView(myname);
api.closeFrame({
name: 'btframe'
})
}
function fngetCallSession() {
rong.getCallSession(function (ret) {
api.alert({
msg: JSON.stringify(ret)
});
});
}
//请求token
function login() {
var now = new Date();
var number = now.getSeconds();
//这将产生一个基于目前时间的0到59的整数。
var timestamp = Date.parse(new Date());
timestamp = timestamp / 1000;
var AppKey = "pwe86ga5p****"; //填写自己的参数
var appSecret = "Eo1hnmggH****"; //填写自己的参数
var Nonce = number;
var Timestamp = timestamp;
var Signature = SHA1(appSecret + Nonce + Timestamp);
var uid = document.getElementById('useName').value;
var uid2 = document.getElementById('fridendName').value;
api.setPrefs({
key: 'myname',
value: uid
})
api.setPrefs({
key: 'hename',
value: uid2
})
api.ajax({
url: 'http://api.cn.ronghub.com/user/getToken.json',
method: 'post',
headers: {
"Content-Type": "Application/x-www-form-urlencoded",
"App-Key": AppKey,
"Nonce": Nonce,
"Timestamp": Timestamp,
"Signature": Signature
},
data: {
'values': {
userId: uid,
name: uid,
}
}
}, function (ret, err) {
if (ret) {
token = ret.token;
connect();
var labelUsename = document.getElementById('stauseName');
labelUsename.style.display = "block";
labelUsename.innerHTML = uid + "已登录";
} else {
api.alert({
msg: JSON.stringify(err)
});
}
})
}
function logout() {
rong.logout(function (ret, err) {
console.log(JSON.stringify(ret));
if (ret.status == 'error')
api.toast({
msg: err.code
});
});
}
function connect() {
rong.connect({
token: token
}, function (ret, err) {
if (ret.status == 'success') {
console.log(ret.result.userId);
} else {
console.log(err.code)
}
});
}
function getConnectionStatus() {
rong.getConnectionStatus(function (ret, err) {
api.toast({
msg: ret.result.connectionStatus
});
})
}
</script>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。