需求概要:實現視訊撥打、接聽、結束通話、視訊介面大小視窗、點選小視窗實現大小視窗互換。
實現思路:一方撥打後,另一方要能收到相應事件,然後接聽。接通後,渲染對方視訊畫面。那麼己方視訊畫面什麼時候渲染呢?對於呼叫方,可以在呼叫後開始渲染,也可以接通事件事件發生後再開始渲染。對於接通方可以在點選接聽按鈕後開始渲染,也可以在接通事件發生後開始渲染。
有了上述思路,在模組文件中查詢相應api,編寫程式碼,就可以驗證我們的思路是否可以實現。如果遇到問題,再調整實現思路。
以下是融雲模組文件連結:https://docs.apicloud.com/Cli...
簡要介紹用到的主要API:
**startCall 發起音視訊通話
addCallReceiveListener 音視訊來電事件監聽
accept 接聽來電
addCallSessionListener 音視訊通話事件的監聽(包含響鈴、接通、結束通話等多個事件監聽)setVideoView 設定視訊區域
resetVideoView 重設視訊區域
removeVideoView 移除視訊區域
hangup 結束通話**
下面講解程式碼。
要呼叫音視訊通話功能前應先呼叫 api.hasPermission 介面檢查是否有麥克風、相機許可權,如果沒有,要先申請許可權。
api.requestPermission({
list: ['microphone', 'camera', 'storage', 'photos'],
code: 1
})
融雲初始化成功之後,可新增相應事件的監聽。didReceiveCall 接到來電事件後,彈出接聽頁面。接聽後,會執行到 didConnect 事件, 此時可設定本地視窗 setVideoView ;稍後會執行到remoteUserDidJoin (對端使用者加入通話事件),此時可以通過 setVideoView 設定對端使用者視窗。通過videoViewBringToFront 介面將本地小視窗調整到最前方。
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)
}
})
}
});
};
實現效果如下:
其他經驗總結:
返回錯誤碼34001,重啟loader可解決,可能換賬號登入,wifi 同步重啟loader 有快取使用者資訊導致。
接聽不到來電事件,可嘗試用4g 網路測試。有些公司防火牆,或者電腦共享的wifi 熱點網路有限制或不穩定。
以上經驗都是無數次排錯總結出來的,看了至少能幫你節省兩個工作日。
最後貼下完整程式碼:
<!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>