关于android:APICloud平台使用融云模块实现音视频通话实践经验总结分享

28次阅读

共计 8382 个字符,预计需要花费 21 分钟才能阅读完成。

需要概要:实现视频拨打、接听、挂断、视频界面大小窗口、点击小窗口实现大小窗口调换。

实现思路:一方拨打后,另一方要能收到相应事件,而后接听。接通后,渲染对方视频画面。那么己方视频画面什么时候渲染呢?对于呼叫方,能够在呼叫后开始渲染,也能够接通事件事件产生后再开始渲染。对于接通方能够在点击接听按钮后开始渲染,也能够在接通事件产生后开始渲染。

有了上述思路,在模块文档中查找相应 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>

正文完
 0