web

web

SDK 兼容 JSON

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 225 次浏览 • 2021-01-05 16:04 • 来自相关话题

最近在集成融云 SDK,于是看了下融云的 SDK 源码,发现源码中有一段针对 JSON 的适配,由于针对 IE9 以下不支持 JSON 对象的处理方式,在此分享下1、优点: 除中文外的字符都会转为 Unicode 。2、缺点:JSON.parse() 使用 e... ...查看全部

最近在集成融云 SDK,于是看了下融云的 SDK 源码,发现源码中有一段针对 JSON 的适配,由于针对 IE9 以下不支持 JSON 对象的处理方式,在此分享下

1、优点: 除中文外的字符都会转为 Unicode 。

2、缺点:JSON.parse() 使用 eval 进行转换的,这个方法不是很安全,还看到人介绍用 new Function ,但是没有测试,这里暂时标记下,有空测试下。

if (!window["JSON"]) {
window["JSON"] = (function () {
    function JSON() {
    }
    JSON.parse = function (sJSON) {
        return eval('(' + sJSON + ')');
    };
    JSON.stringify = function (value) {
        return this.str("", { "": value });
    };
    JSON.str = function (key, holder) {
        var i, k, v, length, mind = "", partial, value = holder[key], me = this;
        if (value && typeof value === "object" && typeof value.toJSON === "function") {
            value = value.toJSON(key);
        }
        switch (typeof value) {
            case "string":
                return me.quote(value);
            case "number":
                return isFinite(value) ? String(value) : "null";
            case "boolean":
            case "null":
                return String(value);
            case "object":
                if (!value) {
                    return "null";
                }
                partial = [];
                if (Object.prototype.toString.apply(value) === "[object Array]") {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = me.str(i, value) || "null";
                    }
                    v = partial.length === 0 ? "[]" : "[" + partial.join(",") + "]";
                    return v;
                }
                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = me.str(k, value);
                        if (v) {
                            partial.push(me.quote(k) + ":" + v);
                        }
                    }
                }
                v = partial.length === 0 ? "{}" : "{" + partial.join(",") + "}";
                return v;
        }
    };
    JSON.quote = function (string) {
        var me = this;
        me.rx_escapable.lastIndex = 0;
        return me.rx_escapable.test(string) ? '"' + string.replace(me.rx_escapable, function (a) {
            var c = me.meta[a];
            return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    };
    JSON.rx_escapable = new RegExp('[\\\"\\\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]', "g");
    JSON.meta = {
        "\b": "\\b",
        "    ": "\\t",
        "\n": "\\n",
        "\f": "\\f",
        "\r": "\\r",
        '"': '\\"',
        "''": "\\''",
        "\\": "\\\\"
    };
    return JSON;
})();
}

看到这段代码,觉得融云 SDK 在兼容性上还是有处理的,又在 IE7 下做了测试,果然可以稳定运行(这年头还有 IE7 ,是不是很神奇)

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 IM SDK 发送语音消息

IM即时通讯苏道 发表了文章 • 0 个评论 • 241 次浏览 • 2021-01-05 16:04 • 来自相关话题

由于公司既有移动端又有 web 端,所以在语音消息这遇到了些小问题。解决的过程最近整理了下也分享给大家作为参考。遇到问题web 端发送语音的问题。移动端发送来的 VoiceMessage 在 web 端不知道如何处理。解决办法问题一 融云只负责发消息,不提供录... ...查看全部

由于公司既有移动端又有 web 端,所以在语音消息这遇到了些小问题。解决的过程最近整理了下也分享给大家作为参考。

遇到问题

  1. web 端发送语音的问题。

  2. 移动端发送来的 VoiceMessage 在 web 端不知道如何处理。

解决办法

  1. 问题一 融云只负责发消息,不提供录制。

所以这边自己找了些录制的插件,这里参考了一个小示例https://blog.csdn.net/qq_37310318/article/details/88312013
拿到后改了改实现了音频录制,修改了上传的逻辑,上传逻辑使用的融云的上传插件,参考的文档 https://docs.rongcloud.cn/v4/views/im/noui/guide/private/msgmanage/msgsend/web.html#FileMsg

  1. 移动端同事说他们用的是融云的 IMKit,于是提工单问了下,融云的同事给解决办法。

Android 枚举类型

/**
* 语音消息类型
*/
public enum VoiceMessageType {
  /**
    * 普通音质语音消息
    */
  Ordinary,
  /**
    * 高音质语音消息
    */
  HighQuality
}

Android

RongIM.getInstance().setVoiceMessageType(RongIM.VoiceMessageType.HighQuality);

iOS

[RCIMClient sharedRCIMClient].voiceMsgType = RCVoiceMessageTypeHighQuality;

把上上述方法在初始化 init 时设置下即可发送高清语音消息。完美解决。

实现中参考的文献:
web 实现语音录制:https://blog.csdn.net/qq_37310318/article/details/88312013

融云文档:https://docs.rongcloud.cn/v4/views/im/noui/guide/private/msgmanage/msgsend/web.html#FileMsg

融云官网:https://www.rongcloud.cn/


集成融云 IM 问题总结

IM即时通讯苏道 发表了文章 • 0 个评论 • 238 次浏览 • 2021-01-05 14:37 • 来自相关话题

最近项目里用到了 IM 相关能力,并且之前也有了解融云,所以直接就用了,下面自己总结一些注意事项,在这些点上花了一丢丢时间,在此记录下1、融云是通过他们自己的 AppKey 来隔离不同应用之间的消息的,只有在一个 AppKey 的用户可互发消息2、连接融云的时... ...查看全部

最近项目里用到了 IM 相关能力,并且之前也有了解融云,所以直接就用了,下面自己总结一些注意事项,在这些点上花了一丢丢时间,在此记录下

1、融云是通过他们自己的 AppKey 来隔离不同应用之间的消息的,只有在一个 AppKey 的用户可互发消息

2、连接融云的时候,需要一个 Token,这个 Token 是通过融云的 Server 获取的,并且只能通过自己的 Server 调用,否则有安全问题,调试时可以用他们开发者后台提供的调试工具来获取 Token,写死在页面调试,这点很重要,就不用等后端接口了

3、历史消息默认不存,需要单独开通,这个也是看到了错误码才理解,之前一直在琢磨,咋没有最近聊过天的人列表

4、如果需要浏览器多个 Tab 同时连接,需要单独开通,打开多个浏览器,之前的 Tab 连接就断了,也许要单独开通,不过开发环境免费,可以随便造,哈哈

5、A 给 B 发消息,只需要知道 B 的 Id 就可以发了,B 再上线就可以收到,模拟两个发消息,可以打开两个浏览器分别模拟 A 和 B 发送和接收消息

6、A 给 B 发送消息,A 的 targetId 是 B,B 的 targetId 是 A,消息的发送人是 A,这个逻辑有点绕,简单理解为 A 的 targetId 是 B,B 的 targetId 是 A,消息的发送人 Id 不变,我滴妈呀,有点像饶舌,来哼起来 哈哈哈~

完毕,虽然没啥逻辑,记录下,好记性不如烂笔头,以免后续再用~

有需要可以去官方查看更多内容:

官网主页:https://www.rongcloud.cn

文档主页:https://docs.rongcloud.cn/v4


融云 Web SDK 如何实现只有一个设备登入

IM即时通讯苏道 发表了文章 • 0 个评论 • 235 次浏览 • 2021-01-05 14:37 • 来自相关话题

背景在集成融云的即时通讯时,产品脑门一拍说:咋们要实现一个功能,不管是 Web 端还是移动端登入,必须只能一个端登入成功并且后登入成功的账号需要踢掉前面登入的账号。咋的一听感觉还蛮简单的,融云不是有一个服务嘛:叫做多设备消息同步,我把该服务关掉不就行了~~ O... ...查看全部

背景

在集成融云的即时通讯时,产品脑门一拍说:咋们要实现一个功能,不管是 Web 端还是移动端登入,必须只能一个端登入成功并且后登入成功的账号需要踢掉前面登入的账号

咋的一听感觉还蛮简单的,融云不是有一个服务嘛:叫做多设备消息同步,我把该服务关掉不就行了~~ O(∩_∩)O哈哈~

但是……. ┭┮﹏┭┮
是我想的太简单了,服务关掉之后 Web 端的确可以进行互踢了,但是移动端和 Web 端还是可以在线呀,原来默认的情况下,融云仅支持 1 个 Web 端、1 个 桌面端、1 个移动端同时在线

这个是融云多端同时在线详情:https://docs.rongcloud.cn/v4/views/im/noui/guide/group/connection/multiclient/

话不多说,开始揭开谜底

1、首先将多设备消息同步 - 关闭,关闭连接:https://developer.rongcloud.cn/advance/index/YTrydqMSdEsmBtX2zX0Amg

2、这时如果多端登入状态监听会监听到状态码 6 时,执行断开链接

代码示例

im.watch({
  conversation: function(event){
    var updatedConversationList = event.updatedConversationList; // 更新的会话列表
    console.log('更新会话汇总:', updatedConversationList);
    console.log('最新会话列表:', im.Conversation.merge({
        conversationList,
        updatedConversationList
      }));
  },
  message: function(event){
    var message = event.message;
    console.log('收到新消息:', message);
  },
  status: function(event){
     console.log('连接状态码:', status);
     var status = event.status;
     if(status == 6){
       im.disconnect().then(function() {
        console.log('断开链接成功');
       });
     }
  }
});

3、通过发送自定义消息,来执行断开连接方法

比如您有两个设备 A,B,用户开始在 A 设备登入,然后再 B 设备登入成功后给自己或者给别人发一条自定义消息,A 设备在监听中根据该自定义消息判断,调用断开连接方法,即可做到只有一个设备登入

//发送自定义消息
var conversation = im.Conversation.get({
  targetId: '接收方的 userId',
  type: RongIMLib.CONVERSATION_TYPE.PRIVATE
});
conversation.send({
  messageType: 's:person', // 填写开发者定义的 messageType
  content: { // 填写开发者定义的消息内容
    name: 'RongCloud',
    age: 12
  },
  isPersited: true,// 是否存储在服务端,默认为 true
  isCounted: true  // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
}).then(function(message){
  console.log('发送 s:person 消息成功', message);
});

通过上面的步骤,就可以实现只能单设备登入了,但是需要注意您使用的 SDK 版本,一开始我用 3.0.5 SDK 来做,但是有一个问题:执行断开连接还是会进行重连,所以要使用 SDK 3.0.6 版本以上的 SDK 哦

融云 Web 播放声音(AMR 、WAVE)

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 28 次浏览 • 2021-01-05 11:50 • 来自相关话题

最近甚是苦闷,做语音播放降级,跳进了很多坑,别提有多惨了,不过结果还是不错滴,纵观前后,一句话足以概括 “痛并快乐着” ~~~ok,我少说废话,下面来总结下 Web 播放声音一些注意事项。说到 Web 我第一件事想起的就是浏览器兼容性,播放声音当然也难逃苦海,... ...查看全部

最近甚是苦闷,做语音播放降级,跳进了很多坑,别提有多惨了,不过结果还是不错滴,纵观前后,一句话足以概括 “痛并快乐着” ~~~

ok,我少说废话,下面来总结下 Web 播放声音一些注意事项。

说到 Web 我第一件事想起的就是浏览器兼容性,播放声音当然也难逃苦海,需要注意以 Trident 为内核 (IE为主) 的浏览器,和 FF、Chrome等浏览器的区别。

1、技术准备

① FF、Chrome等支持


② IE 浏览器下不支持(IE9以下


2、详细说明

为避免文章过于冗长,针对以上两种情况分别总结:

① 使用 AMR (Audio) 播放 : http://www.cnblogs.com/yuhongda0315/p/5224188.html

② 使用 Flash 播放 :http://www.cnblogs.com/yuhongda0315/p/5224450.html

3、资料下载

ActionScript : player-as3源码.rar

完整的demo : amrPlayer-jsdemo.rar

ActionScript 播放 Wave 文件 :wavePlayer-as3源码.rar

所需要的JS(amr.js 在 libamr-min.js 最下方):所需JS.rar

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224064.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 Web 播放声音 — Flash 篇 (播放 AMR、WAV)

WebRTC赵炳东 发表了文章 • 0 个评论 • 244 次浏览 • 2021-01-05 11:50 • 来自相关话题

本文主要介绍 Flash 播放 AMR 格式 Base64码 音频。在此之前么有接触过 Flash ,接触 AS3 是一头雾水,不过幸好有 TypeScript 和 JavaScript 的基础看起来不是很费劲,现学现卖的就是开了 ”跳坑“ 之旅~~~1、实现... ...查看全部

本文主要介绍 Flash 播放 AMR 格式 Base64码 音频。

在此之前么有接触过 Flash ,接触 AS3 是一头雾水,不过幸好有 TypeScript 和 JavaScript 的基础看起来不是很费劲,现学现卖的就是开了 ”跳坑“ 之旅~~~

1、实现思路

起初一点实现思路都木有,不知道该从何做起,只知道用 Flash 播放 AMR ,度娘谷姐的一顿找,结果可想而知,没有糟糕,只有十分糟糕,哈哈。

后来想了想,凡事都得有个思路,不能闷头干,瞬间恍然大悟,为自己浪费的快一天的时间,感到羞愧和害怕…..

① Flash 都能播放哪些音频。

② 在 ActionScript 中AMR 是如何转换成 Flash 可播放的音频的。

③ JS 中如何调用 ActionScript 中方法,如何交互。

④ 如何把 SWF 文件嵌入到 HTML 页面中。

⑤ 如何把 AMR(Audio) 和 Flash 播放AMR 两种方式封装起来。

2、逐一破解

① Flash 都能播放哪些音频:

MP3 格式是 Flash 默认支持的音频格式,WAVE 格式需要转换可以播放,其他格式也是需要转换的,因为先做的 Chrome 下播放声音,对 WAVE 音频多少有些了解,所以决定从 WAVE 音频入手,所以按照上述的套路来 ”屡思路“:

(1) 不管如何转换,肯定要操作字节数组,所以第一步把 AMR 格式的 base64 码 转换为 ByteArray 数组。

(2) 如何把 AMR 的 ByteArray 转换成 WAVE 格式的 ByteArray 数组,毫无疑问 ,肯定需要解码的过程。

按照这两个小步骤逐一做,很快找到了 base64 的转码过程(开始是自己用 AS 实现了 JS 中的的 转码过程,可用但不完美,最终借鉴 github 上大牛的转换过程),但 AMR 转换 WAVE 这个就没有那么容易了,最终确定,AS 解 AMR 比较费劲,需要 用 C 语言来解码,然后用 CrossBirdge 生成可以供 Flash 调用的 SWC 文件。

OK,到这为止,第一步就完美解决了。

② 在 ActionScript 中AMR 是如何转换成 Flash 可播放的音频的:

    上文中有提到,需要用 C 语言 进行对 AMR 解码,下文中会给出 C 语言解码和生成 SWC 的教程(借鉴大牛的)。

③ JS 中如何调用 ActionScript 中方法,如何交互,下文中会贴出完整代码(一定要看注释、注释、注释),此处写出 JS 调用过程。

JS 代码:

function callFlashMethod() {
  // play 是 flash 代码中定义的 ExternalInterface.addCallback("play",this.play); 下文中会有详细介绍。
  thisMovie("嵌入页面上<object>的ID").play("base64str");
}
function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        return window[movieName]
    }
    else {
        return document[movieName]
    }
}
document.getElementById("playId").onclick = function(){
    callFlashMethod();
};

④ 如何把 SWF 文件嵌入到 HTML 页面中:

使用 swfobject.js 可以将 swf 文件嵌入到 HTML 页面中,参考资料 :http://www.cnblogs.com/Carpe-Diem/articles/2310831.html

⑤ 如何把 AMR(Audio) 和 Flash 播放AMR 两种方式封装起来:

有了上面的铺垫,轻而易举的就可以封装啦(主要看 isIE 为 true 的情况):

var RongIMLib;
(function (RongIMLib) {
    var RongIMVoice = (function () {
        function RongIMVoice() {
        }
        /**
        * 初始化声音库
        */
        RongIMVoice.init = function () {
            if (this.isIE) {
                var div = document.createElement("div");
                div.setAttribute("id", "flashContent");
                document.body.appendChild(div);
                var script = document.createElement("script");
                script.src = "http://cdn.ronghub.com/swfobject-2.0.0.min.js";
                var header = document.getElementsByTagName("head")[0];
                header.appendChild(script);
                setTimeout(function () {
                    var swfVersionStr = "11.4.0";
                    var flashvars = {};
                    var params = {};
                    params.quality = "high";
                    params.bgcolor = "#ffffff";
                    params.allowScriptAccess = "always";
                    params.allowfullscreen = "true";
                    var attributes = {};
                    attributes.id = "player";
                    attributes.name = "player";
                    attributes.align = "middle";
                    swfobject.embedSWF("http://cdn.ronghub.com/player-2.0.2.swf", "flashContent", "1", "1", swfVersionStr, null, flashvars, params, attributes);
                }, 200);
            }
            else {
                var list = ["http://cdn.ronghub.com/pcmdata-2.0.0.min.js", "http://cdn.ronghub.com/libamr-2.0.1.min.js"];
                for (var i = 0, len = list.length; i < len; i++) {
                    var script = document.createElement("script");
                    script.src = list[i];
                    document.head.appendChild(script);
                }
            }
            this.isInit = true;
        };
        /**
        * 开始播放声音
        * @param data {string} amr 格式的 base64 码
        * @param duration {number} 播放大概时长 用 data.length / 1024
        */
        RongIMVoice.play = function (data, duration) {
            this.checkInit("play");
            var me = this;
            if (me.isIE) {
                me.thisMovie().doAction("init", data);
            }
            else {
                me.palyVoice(data);
                me.onCompleted(duration);
            }
        };
        /**
        * 停止播放声音
        */
        RongIMVoice.stop = function () {
            this.checkInit("stop");
            var me = this;
            if (me.isIE) {
                me.thisMovie().doAction("stop");
            }
            else {
                if (me.element) {
                    me.element.stop();
                }
            }
        };
        /**
        * 播放声音时调用的方法
        */
        RongIMVoice.onprogress = function () {
            this.checkInit("onprogress");
        };
        RongIMVoice.checkInit = function (postion) {
            if (!this.isInit) {
                throw new Error("RongIMVoice not initialized,postion:" + postion);
            }
        };
        RongIMVoice.thisMovie = function () {
            return eval("window['player']");
        };
        RongIMVoice.onCompleted = function (duration) {
            var me = this;
            var count = 0;
            var timer = setInterval(function () {
                count++;
                me.onprogress();
                if (count >= duration) {
                    clearInterval(timer);
                }
            }, 1000);
            if (me.isIE) {
                me.thisMovie().doAction("play");
            }
        };
        RongIMVoice.base64ToBlob = function (base64Data, type) {
            var mimeType;
            if (type) {
                mimeType = { type: type };
            }
            base64Data = base64Data.replace(/^(.*)[,]/, '');
            var sliceSize = 1024;
            var byteCharacters = atob(base64Data);
            var bytesLength = byteCharacters.length;
            var slicesCount = Math.ceil(bytesLength / sliceSize);
            var byteArrays = new Array(slicesCount);
            for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
                var begin = sliceIndex * sliceSize;
                var end = Math.min(begin + sliceSize, bytesLength);
                var bytes = new Array(end - begin);
                for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
                    bytes[i] = byteCharacters[offset].charCodeAt(0);
                }
                byteArrays[sliceIndex] = new Uint8Array(bytes);
            }
            return new Blob(byteArrays, mimeType);
        };
        RongIMVoice.palyVoice = function (base64Data) {
            var reader = new FileReader(), blob = this.base64ToBlob(base64Data, "audio/amr"), me = this;
            reader.onload = function () {
                var samples = new AMR({
                    benchmark: true
                }).decode(reader.result);
                me.element = AMR.util.play(samples);
            };
            reader.readAsBinaryString(blob);
        };
        RongIMVoice.isIE = /Trident/.test(navigator.userAgent);
        RongIMVoice.isInit = false;
        return RongIMVoice;
    })();
    RongIMLib.RongIMVoice = RongIMVoice;
    //兼容AMD CMD
    if ("function" === typeof require && "object" === typeof module && module && module.id && "object" === typeof exports && exports) {
        module.exports = RongIMVoice;
    }
    else if ("function" === typeof define && define.amd) {
        define("RongIMVoice", [], function () {
            return RongIMVoice;
        });
    }
})(RongIMLib || (RongIMLib = {}));

 

截止到这里,Flash 播放 AMR 格式 base64 码 就说完了,主要是介绍下大概思路

以上是融云 SDK 里的源码,不过最近推出了直接使用 Audio 方式播放 AAC 格式的音频文件

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224450.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 231 次浏览 • 2021-01-05 10:55 • 来自相关话题

1、必备资料 github AMR 开源库 :https://github.com/jpemartins/amr.js 用心把这个项目看一遍,对于我下面说的话,可以忽略啦,代码是最好的文章,哈哈~~2、核心 JS 库 :amr.js 、pcmdata... ...查看全部

1、必备资料 github AMR 开源库 :https://github.com/jpemartins/amr.js 用心把这个项目看一遍,对于我下面说的话,可以忽略啦,代码是最好的文章,哈哈~~

2、核心 JS 库 :amr.js 、pcmdata.min.js、libamr-nb.js (g上述ithub项目中有另外三个js,我给合成一个amr.js,不要混乱)这三个 JS 是播放声音的主要依赖,下面一 一 介绍下:

① amr.js : 可以理解成 “桥” 的概念,连接底层解码和客户端调用的桥梁。

② pcmdata.min.js : 封装 pcm data, PCM是一种编码格式 , PCM 添加上 RIFF 头 可以组成 Wave 音频(Wave 不止这一种编码方式),细节太深,小弟也不懂啦~~,有空深挖。

③ libamr-nb.js : amr转换的核心库,这个文件比较大,压缩后大概也要 600kb 左右。

④ 如果下载三个核心库,建议从上篇 “Web 播放声音 — 介绍篇” 中的附件中卸载,在 github 现在的核心库,在 Chrome 下只能播放一次,把这个问题修复了一下,原因是以同样的 Audio.src 创建 Audio 在 Chrome 下就不能二次播放,网上说法各异,最终自己动手解决了,详细可以在 amr.js 中的 global.util.play 方法中看。

3、具体用法

说了有一阵子白话了,该上点代码了,下面是我封装的播放 AMR 格式 Base64 码 的插件,直接在页面引用可以 ,下载地址可以在 “Web 播放声音 — 介绍篇” 下载。

页面一点样式都没有加,只有两个按钮,小伙伴凑合凑合,哈哈~~

代码中只引入了 voice.js 一个 js,其他 js 动态引用了。(公司有 cdn 所以直接放在上面了)。

步骤:

第一步:执行初始化。

第二步:调用相应方法。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Example</title>
<script src="js/voice.js"></script>
</head>
<body>
<input type="button" value="play" id="playId"/>
<input type="button" value="stop" id="stopId"/>
</body>
<script type="text/javascript">
//初始化
RongIMLib.RongIMVoice.init();
//播放
document.getElementById("playId").onclick = function(){
   // base64Str : amr 格式的 base64 码,可以用 HTML5 FileReader 或者canvas 进行转换 。 
   var base64Str = "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";
    RongIMLib.RongIMVoice.play(base64Str );
};
//暂停
document.getElementById("stopId").onclick = function(){ RongIMLib.RongIMVoice.stop(); }; 
</script> 
</html>

在这里也把 “voice.js” 的代码贴出来,使用 typescript 写完后生成出来的,方便小伙伴们查看:

var RongIMLib;
(function (RongIMLib) {
 var RongIMVoice = (function () {
  function RongIMVoice() {
  }
  /**
  * 初始化声音库
  */
  RongIMVoice.init = function () {
      if (this.isIE) {
          var div = document.createElement("div");
          div.setAttribute("id", "flashContent");
          document.body.appendChild(div);
          var script = document.createElement("script");
          script.src = "http://cdn.ronghub.com/swfobject-2.0.0.min.js";
          var header = document.getElementsByTagName("head")[0];
          header.appendChild(script);
          setTimeout(function () {
              var swfVersionStr = "11.4.0";
              var flashvars = {};
              var params = {};
              params.quality = "high";
              params.bgcolor = "#ffffff";
              params.allowscriptaccess = "always";
              params.allowfullscreen = "true";
              var attributes = {};
              attributes.id = "player";
              attributes.name = "player";
              attributes.align = "middle";
              swfobject.embedSWF("http://cdn.ronghub.com/player-2.0.2.swf", "flashContent", "1", "1", swfVersionStr, null, flashvars, params, attributes);
          }, 200);
      }
      else {
          var list = ["http://cdn.ronghub.com/pcmdata-2.0.0.min.js", "http://cdn.ronghub.com/libamr-2.0.1.min.js"];
          for (var i = 0, len = list.length; i < len; i++) {
              var script = document.createElement("script");
              script.src = list[i];
              document.head.appendChild(script);
          }
      }
      this.isInit = true;
  };
  /**
  * 开始播放声音
  * @param data {string} amr 格式的 base64 码
  * @param duration {number} 播放大概时长 用 data.length / 1024
  */
  RongIMVoice.play = function (data, duration) {
      this.checkInit("play");
      var me = this;
      if (me.isIE) {
          me.thisMovie().doAction("init", data);
      }
      else {
          me.palyVoice(data);
          me.onCompleted(duration);
      }
  };
  /**
  * 停止播放声音
  */
  RongIMVoice.stop = function () {
      this.checkInit("stop");
      var me = this;
      if (me.isIE) {
          me.thisMovie().doAction("stop");
      }
      else {
          if (me.element) {
              me.element.stop();
          }
      }
  };
  /**
  * 播放声音时调用的方法
  */
  RongIMVoice.onprogress = function () {
      this.checkInit("onprogress");
  };
    /** 
     * 校验是否初始化
      */
  RongIMVoice.checkInit = function (postion) {
      if (!this.isInit) {
          throw new Error("RongIMVoice not initialized,postion:" + postion);
      }
  };
  RongIMVoice.thisMovie = function () {
      return eval("window['player']");
  };
  RongIMVoice.onCompleted = function (duration) {
      var me = this;
      var count = 0;
      var timer = setInterval(function () {
          count++;
          me.onprogress();
          if (count >= duration) {
              clearInterval(timer);
          }
      }, 1000);
      if (me.isIE) {
          me.thisMovie().doAction("play");
      }
  };
  RongIMVoice.base64ToBlob = function (base64Data, type) {
      var mimeType;
      if (type) {
          mimeType = { type: type };
      }
      base64Data = base64Data.replace(/^(.*)[,]/, '');
      var sliceSize = 1024;
      var byteCharacters = atob(base64Data);
      var bytesLength = byteCharacters.length;
      var slicesCount = Math.ceil(bytesLength / sliceSize);
      var byteArrays = new Array(slicesCount);
      for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
          var begin = sliceIndex * sliceSize;
          var end = Math.min(begin + sliceSize, bytesLength);
          var bytes = new Array(end - begin);
          for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
              bytes[i] = byteCharacters[offset].charCodeAt(0);
          }
          byteArrays[sliceIndex] = new Uint8Array(bytes);
      }
      return new Blob(byteArrays, mimeType);
  };
  RongIMVoice.palyVoice = function (base64Data) {
      var reader = new FileReader(), blob = this.base64ToBlob(base64Data, "audio/amr"), me = this;
      reader.onload = function () {
          var samples = new AMR({
              benchmark: true
          }).decode(reader.result);
          me.element = AMR.util.play(samples);
      };
      reader.readAsBinaryString(blob);
  };
  RongIMVoice.isIE = /Trident/.test(navigator.userAgent);
  RongIMVoice.isInit = false;
  return RongIMVoice;
})();
RongIMLib.RongIMVoice = RongIMVoice;
//兼容AMD CMD
if ("function" === typeof require && "object" === typeof module && module && module.id && "object" === typeof exports && exports) {
  module.exports = RongIMVoice;
}
else if ("function" === typeof define && define.amd) {
  define("RongIMVoice", [], function () {
      return RongIMVoice;
  });
}
})(RongIMLib || (RongIMLib = {}));

好啦,到此本文结束,会尽快更新 Flash 下播放 AMR 格式 Base64 码,代码中哪里有错误或者有异议麻烦小伙伴们联系我,一起讨论,有则改之无法加冕,一起进步,thx~~。

以上是融云 SDK 里的源码,不过最近推出了直接使用 Audio 方式播放 AAC 格式的音频文件,非常方便

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224188.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 IM 那些事儿

IM即时通讯苏道 发表了文章 • 0 个评论 • 235 次浏览 • 2021-01-05 10:55 • 来自相关话题

最近闲来无事在网上冲浪,看到关注公众号推送了一篇 《Zoom大火之后,这家国内公司也很值得关注啊》 的文章,看样子八成是融云的运营稿(融云的朋友看到别打我…),不过不重要,重要的因为这篇文章确实让我对 IM 和 RTC 提起了浓厚的兴趣,因为疫情期间还没有离职... ...查看全部

最近闲来无事在网上冲浪,看到关注公众号推送了一篇 《Zoom大火之后,这家国内公司也很值得关注啊》 的文章,看样子八成是融云的

运营稿(融云的朋友看到别打我…),不过不重要,重要的因为这篇文章确实让我对 IM 和 RTC 提起了浓厚的兴趣,因为疫情期间还没有离职

公司每天都用 Zoom,后来 Zoom 这家伙宣布停止对中国提供服务后,鬼知道老板是为了彰显爱国主义情节还是怕服务不稳定,老板果断切换为腾讯会议

离职后虽然用的少了,但偶尔开个会啥的,也会用腾讯会议或者微信的音视频进行和伙伴进行线上沟通,这么说来接触音视频 Saas 也有一段时间了

但对底层如何实现的通话一无所知,你知道的,作为一个有追求的码农,知其然必知其所以然,正赶上看了前面提到的文章,于是马上动手开始研究融云的

IM 和 RTC,先从 IM 开始说起~

我是从以下几步分别了解:官网开发者后台开发文档

官网

从官网得到了以下个信息:

产品分类

1、IM + RTC: 之前在公司听同事说过融云做 IM,不知道啥时候也做了 RTC ,还挺有意思,不知道具体原因,个人理解也许 IM 的天花板比较低或者变现难,并且音视频在未来网络基础设置越来越好、流量越来越廉价、5G 的到来等种种因素,音视频还是很有前景的,才杀入 RTC 战场,分一杯羹

2、支持平台: Android、iOS、Web、小程序、Electron、Flutter 主流平台都支持

支持四种部署方式

1、公有云: 大家公用一个盘子,有点过去大通铺的赶脚,我要是胖我睡的面积就大,当然了我要是胖可能还挤到你,可能会有资源抢占的情况,不过这要看融云的预留冗余资源了

2、专有云: 相比大通铺,这个就高级多了,类似单间,空间、卫浴均为独立,并且私密性比较好

3、海外云: 海外大通铺,在线咨询了下,海外用户也能直接用国内数据中心,估计他们自己的网络链路,具体原因没有再细问,毕竟暂时也不用,不太好意思,我是一个腼腆的人儿

4、私有云: 相比单间,这就是自己盖房子了,融云提供设计图,并且找施工队给你单独盖一个琉璃大瓦房,但后续怎么维护没看到说明,有可能和通用外包的维护费用类似,比如:每年维护费是合同款的 10%,费用是我自己 YY 的,不会用也没好意思去找他们人了解

目前正在搞的活动

1、黑客马拉松:印象最深的银子,第一名给五万,我是看到晚要不一定参加,这样可以弥补一点离职期间经济损失,毕竟离职前薪资也一个月 xxx 呢(一不小心差点把工资说出来,万一媳妇看见小金库可就没有了…..慌的一批,哈哈哈)

2、WICC:全名好长,全球互联网通信云大会,不和全球占点关系,都不好意说自己是互联网公司,哈哈,不过看他们也有海外节点,这么说也合理,地址不在北京,可惜去不了,要不真的可以去 see see

3、聆听:这是一个收集建议的系统包括吐槽啥的,看样子还是比较注重客户服务,在这样一个技术可快速复制的时代,也许客户服务等软技能还是挺重要的,尤其是 ToB 企业

其他

1、其他的都是一些案例介绍,这些东各家公司如出一辙,秀秀肌肉、吹吹牛啥的,就没多看,目前我不关注这块

开发者后台

功能丰富

进入后台第一眼真的是功能丰富,看出来确实是积累了很多功能,不过产品逻辑不是很好,有点无从下手,研究了一会理解了

调试工具

调试工具点个赞,把所有服务端的接口都做了可在线调试的 API,如果集成初期没有自己 Server 接口,完全可以用这个来集成,非常方便,很惊喜

小槽点

开发者后台的界面略丑,看起来有点像智能手机和老人机的排版布局差异,虽说不影响使用吧,但作为一个有追求的青年咋能对美不挑剔呢,不对,应该少年,不对不对,是青少年,文章暂停下,我先倒腾下措辞….(两个小时后,是少年,我还是从前那个少年,没有一丝丝改变…..)

开发文档

文档分类倒是简单,IM、RTC、运营服务, 下面逐个介绍下感受

1、IM: 不愧是做 IM 起家的 Paas 厂商,支持的能力确实很出色,尤其聊天室的功能格外丰富,在线和客服妹子聊说人数无上限,支持弹性扩所容

2、RTC: 看完文档就能知道在音视频沉淀还有不够,为啥这么说,在文档投入精力一定不够,或者资源在忙于其他更重要的事情未开始规划,后台看了看发布的第一版音视频 SDK,是在去年三月份,和感觉还比较像,瞬间觉得自己像老司机一样,哈哈

3、粗略过了一遍文档,体验了下官方 Demo SealRTC,音视频质量相当不错,晚上纽约的老铁视频用的就是这个东东,非常流畅,好感度暴涨

————华丽的人肉分割线————-

整体感觉就这些,这里没有涉及技术集成,后面再集成试试,写完感觉像给融云写了一篇产品介绍的稿子,不知道融云的朋友看到会不会给我发稿费 哈哈

就写到这里了吧,太阳快出来了,睡觉~~~

另外赠从下融云相关链接

官网:https://www.rongcloud.cn

文档:https://docs.rongcloud.cn/v4


集成融云 Web 音视频通话踩坑之旅

WebRTC苏道 发表了文章 • 0 个评论 • 264 次浏览 • 2020-12-29 16:44 • 来自相关话题

前言最近有个项目需要使用的融云的 CallLib SDK 实现类似微信的视频通话,所以在项目还未正式启动的时候,我已经偷偷的开始进行集成了,以免到时候不熟一顿加班那真的欲哭无泪了,好消息就是我已经使用过融云家的 IMLib SDK 做过即时通讯的功能,所以整个... ...查看全部

前言

最近有个项目需要使用的融云的 CallLib SDK 实现类似微信的视频通话,所以在项目还未正式启动的时候,我已经偷偷的开始进行集成了,以免到时候不熟一顿加班那真的欲哭无泪了,好消息就是我已经使用过融云家的 IMLib SDK 做过即时通讯的功能,所以整个注册流程和开发者后台的使用已经比较熟了,当然,即时不熟也没关系,跟着他们的文档一步一步来,也能很快的就上手了。
融云官网:https://www.rongcloud.cn/

下面是集成的时候碰到的一些需要注意的问题:

1、Web 站点必须为 localhost 或 https
2、必须成功连接 IM 后, 才可进行 CallLib 通话
3、新版谷歌浏览器(86版本)会报错,我集成的 RTC 版本是 3.2.3
4、音视频通话接通不了

综上问题,我会逐一解答,关于具体的集成可以直接参考:https://docs.rongcloud.cn/v4/views/rtc/call/noui/quick/web.html

还有具体的 demo 也可以参考一下 https://github.com/rongcloud-snippets/web-call-quickstart

Web 站点必须为 localhost 或 https:
这个是融云的使用音视频通话的前置条件,本来在本地调试的时候好好的,可是发布到线上的时候就不能用了,最后提交工单询问融云的技术人员上线是否还需要配置什么,最后排查一圈发现生产环境使用的站点是 http(欲哭无泪。。。),童鞋们引以为戒啊!!

必须成功连接 IM 后, 才可进行 CallLib 通话:
直接看代码:

// appKey 可在融云开发者后台获取
const im = RongIMLib.init({ appkey: '<your-appkey>' })
// 添加事件监听器
im.watch({
  // 连接状态监听
  status(evt) {
    console.log('连接状态码:', evt.status);
  },
  // 消息监听
  message(evt) {
    console.log('收到新消息:', evt.message);
  }
})
// CallLib 初始化
var config = {
    timeout: 20000,
    RongIMLib: RongIMLib,
    RongRTC: RongRTC
};
rongCallLib = RongCallLib.init(config);
//token 可从开发者后台获取 或 Server API
const token = ''
im.connect({ token }).then(user => {
  console.log('链接成功, 链接用户 id 为: ', user.id);
}).catch(error => {
  console.log('链接失败: ', error.code, error.msg);
});

新版谷歌浏览器会报错:
由于浏览器更新,导致 SDK 需要升级,升级到最新版本的 RTC SDK 下载地址:https://cdn.ronghub.com/RongRTC-3.2.6.min.js
需要注意,如果使用的 SDK 2.X 也需要升级到 2.5.10 以上

音视频通话接通不了:
这种情况我总结分析了一下几种情况,如下:

代码传参错误或者书写错误
这个好像没什么说的,只能怪自己不仔细吧!跟着文档来呗

结束通话没有调用挂断方法 hungup
用户主动发起挂断,在 rongCallLib.commandWatch 监听中收到 HungupMessage 消息,可以调用 rongCallLib.hungup 来挂断通话,不然下次呼叫时会出现报错,提示对方正忙

如何识别挂断原因
HungupMessage 消息中 reason 字段及 SummaryMessage 消息中 status 字段都为挂断原因,详情地址参考:https://docs.rongcloud.cn/rtc/calllib/web/code/

因为对音视频的集成也刚开始,还在学习当中。后续随着继续深入,也会同步音视频相关的集成问题,方便复习记录也希望能帮到需要的童鞋!!!


结合融云 WebSDK 了解 WebSocket 基本原理

WebRTC赵炳东 发表了文章 • 0 个评论 • 242 次浏览 • 2020-12-29 16:44 • 来自相关话题

近期使用融云开发聊天页面, 通过抓包, 发现融云 SDK 使用 WebSocket 实现与服务端通讯, 因此简单了解 WebSocket 的实现原理融云 SDK 文档: https://docs.rongcloud.cn/v4/WebSocket 与... ...查看全部

近期使用融云开发聊天页面, 通过抓包, 发现融云 SDK 使用 WebSocket 实现与服务端通讯, 因此简单了解 WebSocket 的实现原理

融云 SDK 文档: https://docs.rongcloud.cn/v4/

WebSocket 与 HTTP

1、HTTP 协议没有为了 WebSocket 的出现改变

2、WebSocket 属于 HTTP 之后的新协议

3、两者有交集, 也各有不同

4、WebSocket 借用 HTTP 协议完成一部分握手

WebSocket 握手

通过抓包融云 WebSocket 请求, 重点关注以下几个字段

以上为发起 WebSocekt 请求抓包, 首先关注比 HTTP 多出的数值:

// 告知服务器, 发起的是 WebSocket 协议, 服务需进行 WebSocket 处理Upgrade: websocketConnection: Upgrade
Sec-WebSocket-Key: aI0TsvW7jltfmNOF+1eSqg== // Base64, 浏览器随机生成. 与后面服务端响应的 Sec-WebSocket-Accept 配套, 提供基本的防护. 比如恶意的连接, 或者无意的连接Sec-WebSocket-Version: 13 // 表示 websocket 的版本. 如果服务端不支持该版本, 需要返回一个 Sec-WebSocket-Versionheader, 里面包含服务端支持的版本号

再查看 Response Headers:

Sec-WebSocket-Accept: OfEosYlCAcvV/jdwbW33VU0B50k= // 安全验证. 根据客户端请求首部 Sec-WebSocket-Key 计算 ( base64(sha1($Sec-WebSocket-Accept,'258EAFA5-E914-47DA-95CA-C5AB0DC85B11')) )
// 告知客户端, 已成功升级为 WebSocketUpgrade: websocketConnection: Upgrade

替代方案

浏览器没有完美替代 WebSocket 的方案. 只能用 ajax 轮询 或 长轮训(long poll) 模拟, 两者都有性能问题且耗费资源

ajax 轮询、长轮训说明: https://zhuanlan.zhihu.com/p/25690011


万维网的诞生 | 当我们在浏览器输入网址并回车后,发生了什么?

IM即时通讯徐凤年 发表了文章 • 0 个评论 • 239 次浏览 • 2020-06-30 17:08 • 来自相关话题

编者按:1989年3月12日,欧洲粒子物理研究所软件顾问蒂姆&middot;李提交一个构建信息管理系统的计划&ldquo;Information Management: A Proposal&rdquo;,以便更好地管理实验室研究信息。... ...查看全部

编者按:1989年3月12日,欧洲粒子物理研究所软件顾问蒂姆&middot;李提交一个构建信息管理系统的计划&ldquo;Information Management: A Proposal&rdquo;,以便更好地管理实验室研究信息。该计划促使了万维网(WWW)诞生。1994年,中科院高能所架设了中国第一台WWW服务器,并推出第一个网站www.ihep.ac.cn,这项工程的亲历者许榕生研究员讲述了万维网(WWW)诞生的历史。

风靡世界的互联网环球信息技术World Wide Web(简称WWW)的发明源自上世纪八十年代。英国人蒂姆&middot;伯纳斯&middot;李(Tim Berners-Lee)于1989年成功地开发出世界上第一个Web服务器和第一个Web客户端软件,把互联网的应用推上了一个崭新的台阶,极大地促进了人类社会的信息化进程。因&ldquo;发明万维网、第一个浏览器和使万维网得以扩展的基本协议和算法&rdquo;而授予了蒂姆&middot;伯纳斯&middot;李图灵奖(2016年)。

互联网的雏形早在1960年代就诞生了,为什么没有迅速流传开来呢?其实,很重要的原因是早年联接到网络上需要经过一系列复杂的操作,并且不同的计算机具有不同的操作系统和不同的文件结构格式,使得跨平台的信息文件只能相互独立地划成孤岛。蒂姆曾经用一副非常形象的图画表明了他的创意(图1),即通过一种超文本方式,把分布在网络上的不同计算机内的信息有机地结合在一起,通过超文本传输协议(HTTP)从任意的Web服务器转到一台Web浏览器上进行无障碍的信息检索。这个叫Web的软件还能支持图文并茂的信息,甚至还允许发布音频和视频。这就使得后来的互联网远程教育及在线购物等等得以实现!此外,互联网的许多其它功能,如E-mail、Telnet、FTP、WAIS等内容也都可通过Web框架进行实现。

1990年12月25日,蒂姆和法国网络高手罗伯特&middot;卡里奥(Robert Cailliau)在西欧高能物理中心(CERN)一起成功地通过互联网展现了基于Web原理的HTTP代理与服务器的第一次通讯。短短的时间内,这项技术推广到了全世界。


图1 蒂姆&middot;伯纳斯&middot;李用这张图说明了WWW的创意,使原来不同计算机上的信息无法沟通,而现在可以用任何一台计算机对任何Web服务器上的信息库进行调用。


英国女皇伊丽莎白二世2004年向伯纳斯&middot;李颁发大英帝国爵级司令勋章。2009年4月,他获选为美国国家科学院外籍院士。2012年夏季奥林匹克运动会开幕典礼上,蒂姆获得了&ldquo;万维网发明者&rdquo;的美誉,他本人也参与了开幕典礼。

根据有关资料介绍,蒂姆&middot;伯纳斯&middot;李出生于英格兰伦敦西南部,他的父母都参加过世界上第一台商业计算机的建造。1973年,他中学毕业进入牛津大学王后学院深造,1976年从牛津大学物理系毕业后曾经供职于一些高科技公司,从事集成电路和系统设计的研究。1980年,一个偶然的机会,蒂姆来到瑞士的日内瓦,进入到CERN的一个实验室组里。该实验室组的首席是华裔物理学家、诺贝尔奖获得者丁肇中教授。

享誉世界的实验物理学家丁肇中教授在基本粒子研究方面取得一系列重大突破,独立发现了第四种夸克的束缚态,即J粒子,由此开拓了基本粒子研究的新领域。那段时期,丁教授在欧洲高能物理研究中心领导着L3的实验,该实验组首次邀请了由美国、前苏联、中国、欧洲等600名科学家共同参加大型国际合作研究。

在那里,年轻的蒂姆接受了一项极富挑战性的工作:为了使实验组里各国的高能物理学家能通过计算机网络及时沟通并传递信息,实验组委托他开发一个软件,以便让分布在各国实验组成员能够把最新的信息、数据、设计图资料等及时地提供给全体人员共享,随时随地犹如大家都在一起地方同步工作。早在牛津大学主修物理时蒂姆就不断地思索,是否可以找到一个"点",就好比人脑,能够透过神经传递、自主作出反应。以此为思路,蒂姆经过一段努力,终于编制成功了第一个高效局部存取浏览器"Enquire",并把它应用于数据共享浏览中。

1984年蒂姆作为正式成员重返欧洲核子物理实验室,他恢复了过去的工作,并正式写下了世界上第一个网页浏览器(World Wide Web)和第一个网页服务器(httpd)的软件源码。这时蒂姆把目标瞄向了建立一个全球范围的信息检索系统,以彻底打破信息存取的孤立行为。1989年3 月,蒂姆向CERN递交了一份立项建议书,建议采用超文本技术(Hypertext)首先把CERN内部的各个实验室连接起来,在系统建成后,可以扩展到全世界。这个激动人心的建议在CERN引起轩然大波,但开始没有被上司通过。

蒂姆并没有灰心,关键是他看到了突破口,是金子总会闪亮的!他花了2个月重新修改了建议书的措辞,最后终于得到了批准。于是蒂姆有了一笔经费,购买了一台NEXT计算机,并率领一批助手在上面开发系统。在1991年8月6日,蒂姆建立了第一个WWW网站(也是世界上第一个网站),网址是http://info.cern.ch/,在这个网站里还罗列出了各国跟进的WWW网站名单。这项利用互联网+超链接的闪亮原创就在CERN顺理成章地迅速推广开来。


蒂姆&middot;伯纳斯&middot;李

时值90年代初,中国建立了北京正负电子对撞机工程,为推动我国高能物理网络环境的进一步发展,我到了位于日内瓦的CERN考察,在访问期间就被安排在蒂姆原来的办公室内,很幸运地接触到这位WWW发明人。蒂姆在办公室门口贴了一张大黑蜘蛛趴在网上的图画,他给我解释说英文里Web也是网。他热情推荐我参加当年(1994年)4月10日召开的第一届国际WWW技术论坛大会,他做主题演讲,我亲眼看到会上会下群情振奋,所有人都感觉到一个重大的事件即将在世界上发生。那天他在屏幕上专门打出一张世界地图,用颜色标明已经推广了WWW技术的国家(当时主要集中在欧美各国),然后他刻意指着中国区域预言这里也快了。因为他知道我已经在组织策划国内着手启用WWW这项技术。

几天后,位于北京的高能物理所架设了中国第一台WWW服务器,推出了第一个网站www.ihep.ac.cn和英文网页,此刻在亚洲还没几个Web网站出现。

那年我也曾经邀请蒂姆到中国做报告,但他当时在世界各国的报告都已经安排满满的了,便派了他的助手到北京介绍WWW。差不多二十年后的2013年蒂姆才第一次得以访问了中国。

今天作为Web之父的蒂姆已经功成名就。但并不像大多数普通人都认为的那样,WWW的建立是通向致富的捷径。与那些依托互联网一夜暴富之士相比,蒂姆仍然坚守在学术研究岗位上,那种视富贵如浮云的胸襟,真正表现了一个献身科学的学者风度。回顾过去,我们看到伟大的全球互联网事业,正是由无数像蒂姆&middot;伯纳斯&middot;李这样的先驱们的无私耕耘才成长起来的。

在WWW诞生29周年之际,63岁的蒂姆发表了一封公开信,信中强调了目前互联网发展似乎正面临着一些威胁。蒂姆意识到了网络的无穷威力将给政府、企业和社会带来的剧烈改变。他预见这个发明一旦落入不适当的人手中,将成为世界的灾难。有人忙着打造一个接一个的社群网络、在线商业平台,很少会去设想他们可能带来什么后遗症。而蒂姆过去近三十年的时间里却都在努力保护互联网的纯洁,使自己的这项发明更好地造福人类,尽管他从未曾因为这个发明而直接获利。

互联网的安全问题日益显示出许多弱点,尤其过去几年里,脸书外泄超过了8000万用户个人资料,更多的网络运营商在想方设法收集个人隐私。

今年初,蒂姆出席了美国华盛顿的全球信息网基金会(World Wide Web Foundation)年度会议,这个基金会致力于保障数字环境中的人权。他认为这是一项迫切的任务,因为据他的估计,到今年下半年全球网络人口将达到四十亿。随着越来越多人在网络上分享他们的履历、政治倾向、DNA信息,网络将变得更加强大、更有价值,但同时也更加危险。

一开始,WWW技术确实是开放、自由、不受任何公司或团体所控制。不过,这种免费与开放的精神,却也成了它的弱点。如今我们几乎是自愿地让某些网络运营商控制着我们要去哪里买东西、要看到什么新闻、要对什么人点赞。

在早年网络泡沫时期,有人评论在中国WWW网站的涌现率比人口出生率还高。实际上,我们有世界上最多的用户,但是也有很多的问题。涉及到网络安全,不能不说我们用户和运营商的安全意识还需努力提高。网络安全形势不可小视,蒂姆给我们表示的忧虑不是空穴来风,它预示着互联网新的一波挑战又在开始。不管是加固WWW的系统,还是采用所谓&ldquo;去中心化&rdquo;的架构,我们都拭目以待。

来源:中国科学院高能物理研究所

SDK 兼容 JSON

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 225 次浏览 • 2021-01-05 16:04 • 来自相关话题

最近在集成融云 SDK,于是看了下融云的 SDK 源码,发现源码中有一段针对 JSON 的适配,由于针对 IE9 以下不支持 JSON 对象的处理方式,在此分享下1、优点: 除中文外的字符都会转为 Unicode 。2、缺点:JSON.parse() 使用 e... ...查看全部

最近在集成融云 SDK,于是看了下融云的 SDK 源码,发现源码中有一段针对 JSON 的适配,由于针对 IE9 以下不支持 JSON 对象的处理方式,在此分享下

1、优点: 除中文外的字符都会转为 Unicode 。

2、缺点:JSON.parse() 使用 eval 进行转换的,这个方法不是很安全,还看到人介绍用 new Function ,但是没有测试,这里暂时标记下,有空测试下。

if (!window["JSON"]) {
window["JSON"] = (function () {
    function JSON() {
    }
    JSON.parse = function (sJSON) {
        return eval('(' + sJSON + ')');
    };
    JSON.stringify = function (value) {
        return this.str("", { "": value });
    };
    JSON.str = function (key, holder) {
        var i, k, v, length, mind = "", partial, value = holder[key], me = this;
        if (value && typeof value === "object" && typeof value.toJSON === "function") {
            value = value.toJSON(key);
        }
        switch (typeof value) {
            case "string":
                return me.quote(value);
            case "number":
                return isFinite(value) ? String(value) : "null";
            case "boolean":
            case "null":
                return String(value);
            case "object":
                if (!value) {
                    return "null";
                }
                partial = [];
                if (Object.prototype.toString.apply(value) === "[object Array]") {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = me.str(i, value) || "null";
                    }
                    v = partial.length === 0 ? "[]" : "[" + partial.join(",") + "]";
                    return v;
                }
                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = me.str(k, value);
                        if (v) {
                            partial.push(me.quote(k) + ":" + v);
                        }
                    }
                }
                v = partial.length === 0 ? "{}" : "{" + partial.join(",") + "}";
                return v;
        }
    };
    JSON.quote = function (string) {
        var me = this;
        me.rx_escapable.lastIndex = 0;
        return me.rx_escapable.test(string) ? '"' + string.replace(me.rx_escapable, function (a) {
            var c = me.meta[a];
            return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    };
    JSON.rx_escapable = new RegExp('[\\\"\\\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]', "g");
    JSON.meta = {
        "\b": "\\b",
        "    ": "\\t",
        "\n": "\\n",
        "\f": "\\f",
        "\r": "\\r",
        '"': '\\"',
        "''": "\\''",
        "\\": "\\\\"
    };
    return JSON;
})();
}

看到这段代码,觉得融云 SDK 在兼容性上还是有处理的,又在 IE7 下做了测试,果然可以稳定运行(这年头还有 IE7 ,是不是很神奇)

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 IM SDK 发送语音消息

IM即时通讯苏道 发表了文章 • 0 个评论 • 241 次浏览 • 2021-01-05 16:04 • 来自相关话题

由于公司既有移动端又有 web 端,所以在语音消息这遇到了些小问题。解决的过程最近整理了下也分享给大家作为参考。遇到问题web 端发送语音的问题。移动端发送来的 VoiceMessage 在 web 端不知道如何处理。解决办法问题一 融云只负责发消息,不提供录... ...查看全部

由于公司既有移动端又有 web 端,所以在语音消息这遇到了些小问题。解决的过程最近整理了下也分享给大家作为参考。

遇到问题

  1. web 端发送语音的问题。

  2. 移动端发送来的 VoiceMessage 在 web 端不知道如何处理。

解决办法

  1. 问题一 融云只负责发消息,不提供录制。

所以这边自己找了些录制的插件,这里参考了一个小示例https://blog.csdn.net/qq_37310318/article/details/88312013
拿到后改了改实现了音频录制,修改了上传的逻辑,上传逻辑使用的融云的上传插件,参考的文档 https://docs.rongcloud.cn/v4/views/im/noui/guide/private/msgmanage/msgsend/web.html#FileMsg

  1. 移动端同事说他们用的是融云的 IMKit,于是提工单问了下,融云的同事给解决办法。

Android 枚举类型

/**
* 语音消息类型
*/
public enum VoiceMessageType {
  /**
    * 普通音质语音消息
    */
  Ordinary,
  /**
    * 高音质语音消息
    */
  HighQuality
}

Android

RongIM.getInstance().setVoiceMessageType(RongIM.VoiceMessageType.HighQuality);

iOS

[RCIMClient sharedRCIMClient].voiceMsgType = RCVoiceMessageTypeHighQuality;

把上上述方法在初始化 init 时设置下即可发送高清语音消息。完美解决。

实现中参考的文献:
web 实现语音录制:https://blog.csdn.net/qq_37310318/article/details/88312013

融云文档:https://docs.rongcloud.cn/v4/views/im/noui/guide/private/msgmanage/msgsend/web.html#FileMsg

融云官网:https://www.rongcloud.cn/


集成融云 IM 问题总结

IM即时通讯苏道 发表了文章 • 0 个评论 • 238 次浏览 • 2021-01-05 14:37 • 来自相关话题

最近项目里用到了 IM 相关能力,并且之前也有了解融云,所以直接就用了,下面自己总结一些注意事项,在这些点上花了一丢丢时间,在此记录下1、融云是通过他们自己的 AppKey 来隔离不同应用之间的消息的,只有在一个 AppKey 的用户可互发消息2、连接融云的时... ...查看全部

最近项目里用到了 IM 相关能力,并且之前也有了解融云,所以直接就用了,下面自己总结一些注意事项,在这些点上花了一丢丢时间,在此记录下

1、融云是通过他们自己的 AppKey 来隔离不同应用之间的消息的,只有在一个 AppKey 的用户可互发消息

2、连接融云的时候,需要一个 Token,这个 Token 是通过融云的 Server 获取的,并且只能通过自己的 Server 调用,否则有安全问题,调试时可以用他们开发者后台提供的调试工具来获取 Token,写死在页面调试,这点很重要,就不用等后端接口了

3、历史消息默认不存,需要单独开通,这个也是看到了错误码才理解,之前一直在琢磨,咋没有最近聊过天的人列表

4、如果需要浏览器多个 Tab 同时连接,需要单独开通,打开多个浏览器,之前的 Tab 连接就断了,也许要单独开通,不过开发环境免费,可以随便造,哈哈

5、A 给 B 发消息,只需要知道 B 的 Id 就可以发了,B 再上线就可以收到,模拟两个发消息,可以打开两个浏览器分别模拟 A 和 B 发送和接收消息

6、A 给 B 发送消息,A 的 targetId 是 B,B 的 targetId 是 A,消息的发送人是 A,这个逻辑有点绕,简单理解为 A 的 targetId 是 B,B 的 targetId 是 A,消息的发送人 Id 不变,我滴妈呀,有点像饶舌,来哼起来 哈哈哈~

完毕,虽然没啥逻辑,记录下,好记性不如烂笔头,以免后续再用~

有需要可以去官方查看更多内容:

官网主页:https://www.rongcloud.cn

文档主页:https://docs.rongcloud.cn/v4


融云 Web SDK 如何实现只有一个设备登入

IM即时通讯苏道 发表了文章 • 0 个评论 • 235 次浏览 • 2021-01-05 14:37 • 来自相关话题

背景在集成融云的即时通讯时,产品脑门一拍说:咋们要实现一个功能,不管是 Web 端还是移动端登入,必须只能一个端登入成功并且后登入成功的账号需要踢掉前面登入的账号。咋的一听感觉还蛮简单的,融云不是有一个服务嘛:叫做多设备消息同步,我把该服务关掉不就行了~~ O... ...查看全部

背景

在集成融云的即时通讯时,产品脑门一拍说:咋们要实现一个功能,不管是 Web 端还是移动端登入,必须只能一个端登入成功并且后登入成功的账号需要踢掉前面登入的账号

咋的一听感觉还蛮简单的,融云不是有一个服务嘛:叫做多设备消息同步,我把该服务关掉不就行了~~ O(∩_∩)O哈哈~

但是……. ┭┮﹏┭┮
是我想的太简单了,服务关掉之后 Web 端的确可以进行互踢了,但是移动端和 Web 端还是可以在线呀,原来默认的情况下,融云仅支持 1 个 Web 端、1 个 桌面端、1 个移动端同时在线

这个是融云多端同时在线详情:https://docs.rongcloud.cn/v4/views/im/noui/guide/group/connection/multiclient/

话不多说,开始揭开谜底

1、首先将多设备消息同步 - 关闭,关闭连接:https://developer.rongcloud.cn/advance/index/YTrydqMSdEsmBtX2zX0Amg

2、这时如果多端登入状态监听会监听到状态码 6 时,执行断开链接

代码示例

im.watch({
  conversation: function(event){
    var updatedConversationList = event.updatedConversationList; // 更新的会话列表
    console.log('更新会话汇总:', updatedConversationList);
    console.log('最新会话列表:', im.Conversation.merge({
        conversationList,
        updatedConversationList
      }));
  },
  message: function(event){
    var message = event.message;
    console.log('收到新消息:', message);
  },
  status: function(event){
     console.log('连接状态码:', status);
     var status = event.status;
     if(status == 6){
       im.disconnect().then(function() {
        console.log('断开链接成功');
       });
     }
  }
});

3、通过发送自定义消息,来执行断开连接方法

比如您有两个设备 A,B,用户开始在 A 设备登入,然后再 B 设备登入成功后给自己或者给别人发一条自定义消息,A 设备在监听中根据该自定义消息判断,调用断开连接方法,即可做到只有一个设备登入

//发送自定义消息
var conversation = im.Conversation.get({
  targetId: '接收方的 userId',
  type: RongIMLib.CONVERSATION_TYPE.PRIVATE
});
conversation.send({
  messageType: 's:person', // 填写开发者定义的 messageType
  content: { // 填写开发者定义的消息内容
    name: 'RongCloud',
    age: 12
  },
  isPersited: true,// 是否存储在服务端,默认为 true
  isCounted: true  // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
}).then(function(message){
  console.log('发送 s:person 消息成功', message);
});

通过上面的步骤,就可以实现只能单设备登入了,但是需要注意您使用的 SDK 版本,一开始我用 3.0.5 SDK 来做,但是有一个问题:执行断开连接还是会进行重连,所以要使用 SDK 3.0.6 版本以上的 SDK 哦

融云 Web 播放声音(AMR 、WAVE)

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 28 次浏览 • 2021-01-05 11:50 • 来自相关话题

最近甚是苦闷,做语音播放降级,跳进了很多坑,别提有多惨了,不过结果还是不错滴,纵观前后,一句话足以概括 “痛并快乐着” ~~~ok,我少说废话,下面来总结下 Web 播放声音一些注意事项。说到 Web 我第一件事想起的就是浏览器兼容性,播放声音当然也难逃苦海,... ...查看全部

最近甚是苦闷,做语音播放降级,跳进了很多坑,别提有多惨了,不过结果还是不错滴,纵观前后,一句话足以概括 “痛并快乐着” ~~~

ok,我少说废话,下面来总结下 Web 播放声音一些注意事项。

说到 Web 我第一件事想起的就是浏览器兼容性,播放声音当然也难逃苦海,需要注意以 Trident 为内核 (IE为主) 的浏览器,和 FF、Chrome等浏览器的区别。

1、技术准备

① FF、Chrome等支持


② IE 浏览器下不支持(IE9以下


2、详细说明

为避免文章过于冗长,针对以上两种情况分别总结:

① 使用 AMR (Audio) 播放 : http://www.cnblogs.com/yuhongda0315/p/5224188.html

② 使用 Flash 播放 :http://www.cnblogs.com/yuhongda0315/p/5224450.html

3、资料下载

ActionScript : player-as3源码.rar

完整的demo : amrPlayer-jsdemo.rar

ActionScript 播放 Wave 文件 :wavePlayer-as3源码.rar

所需要的JS(amr.js 在 libamr-min.js 最下方):所需JS.rar

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224064.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 Web 播放声音 — Flash 篇 (播放 AMR、WAV)

WebRTC赵炳东 发表了文章 • 0 个评论 • 244 次浏览 • 2021-01-05 11:50 • 来自相关话题

本文主要介绍 Flash 播放 AMR 格式 Base64码 音频。在此之前么有接触过 Flash ,接触 AS3 是一头雾水,不过幸好有 TypeScript 和 JavaScript 的基础看起来不是很费劲,现学现卖的就是开了 ”跳坑“ 之旅~~~1、实现... ...查看全部

本文主要介绍 Flash 播放 AMR 格式 Base64码 音频。

在此之前么有接触过 Flash ,接触 AS3 是一头雾水,不过幸好有 TypeScript 和 JavaScript 的基础看起来不是很费劲,现学现卖的就是开了 ”跳坑“ 之旅~~~

1、实现思路

起初一点实现思路都木有,不知道该从何做起,只知道用 Flash 播放 AMR ,度娘谷姐的一顿找,结果可想而知,没有糟糕,只有十分糟糕,哈哈。

后来想了想,凡事都得有个思路,不能闷头干,瞬间恍然大悟,为自己浪费的快一天的时间,感到羞愧和害怕…..

① Flash 都能播放哪些音频。

② 在 ActionScript 中AMR 是如何转换成 Flash 可播放的音频的。

③ JS 中如何调用 ActionScript 中方法,如何交互。

④ 如何把 SWF 文件嵌入到 HTML 页面中。

⑤ 如何把 AMR(Audio) 和 Flash 播放AMR 两种方式封装起来。

2、逐一破解

① Flash 都能播放哪些音频:

MP3 格式是 Flash 默认支持的音频格式,WAVE 格式需要转换可以播放,其他格式也是需要转换的,因为先做的 Chrome 下播放声音,对 WAVE 音频多少有些了解,所以决定从 WAVE 音频入手,所以按照上述的套路来 ”屡思路“:

(1) 不管如何转换,肯定要操作字节数组,所以第一步把 AMR 格式的 base64 码 转换为 ByteArray 数组。

(2) 如何把 AMR 的 ByteArray 转换成 WAVE 格式的 ByteArray 数组,毫无疑问 ,肯定需要解码的过程。

按照这两个小步骤逐一做,很快找到了 base64 的转码过程(开始是自己用 AS 实现了 JS 中的的 转码过程,可用但不完美,最终借鉴 github 上大牛的转换过程),但 AMR 转换 WAVE 这个就没有那么容易了,最终确定,AS 解 AMR 比较费劲,需要 用 C 语言来解码,然后用 CrossBirdge 生成可以供 Flash 调用的 SWC 文件。

OK,到这为止,第一步就完美解决了。

② 在 ActionScript 中AMR 是如何转换成 Flash 可播放的音频的:

    上文中有提到,需要用 C 语言 进行对 AMR 解码,下文中会给出 C 语言解码和生成 SWC 的教程(借鉴大牛的)。

③ JS 中如何调用 ActionScript 中方法,如何交互,下文中会贴出完整代码(一定要看注释、注释、注释),此处写出 JS 调用过程。

JS 代码:

function callFlashMethod() {
  // play 是 flash 代码中定义的 ExternalInterface.addCallback("play",this.play); 下文中会有详细介绍。
  thisMovie("嵌入页面上<object>的ID").play("base64str");
}
function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        return window[movieName]
    }
    else {
        return document[movieName]
    }
}
document.getElementById("playId").onclick = function(){
    callFlashMethod();
};

④ 如何把 SWF 文件嵌入到 HTML 页面中:

使用 swfobject.js 可以将 swf 文件嵌入到 HTML 页面中,参考资料 :http://www.cnblogs.com/Carpe-Diem/articles/2310831.html

⑤ 如何把 AMR(Audio) 和 Flash 播放AMR 两种方式封装起来:

有了上面的铺垫,轻而易举的就可以封装啦(主要看 isIE 为 true 的情况):

var RongIMLib;
(function (RongIMLib) {
    var RongIMVoice = (function () {
        function RongIMVoice() {
        }
        /**
        * 初始化声音库
        */
        RongIMVoice.init = function () {
            if (this.isIE) {
                var div = document.createElement("div");
                div.setAttribute("id", "flashContent");
                document.body.appendChild(div);
                var script = document.createElement("script");
                script.src = "http://cdn.ronghub.com/swfobject-2.0.0.min.js";
                var header = document.getElementsByTagName("head")[0];
                header.appendChild(script);
                setTimeout(function () {
                    var swfVersionStr = "11.4.0";
                    var flashvars = {};
                    var params = {};
                    params.quality = "high";
                    params.bgcolor = "#ffffff";
                    params.allowScriptAccess = "always";
                    params.allowfullscreen = "true";
                    var attributes = {};
                    attributes.id = "player";
                    attributes.name = "player";
                    attributes.align = "middle";
                    swfobject.embedSWF("http://cdn.ronghub.com/player-2.0.2.swf", "flashContent", "1", "1", swfVersionStr, null, flashvars, params, attributes);
                }, 200);
            }
            else {
                var list = ["http://cdn.ronghub.com/pcmdata-2.0.0.min.js", "http://cdn.ronghub.com/libamr-2.0.1.min.js"];
                for (var i = 0, len = list.length; i < len; i++) {
                    var script = document.createElement("script");
                    script.src = list[i];
                    document.head.appendChild(script);
                }
            }
            this.isInit = true;
        };
        /**
        * 开始播放声音
        * @param data {string} amr 格式的 base64 码
        * @param duration {number} 播放大概时长 用 data.length / 1024
        */
        RongIMVoice.play = function (data, duration) {
            this.checkInit("play");
            var me = this;
            if (me.isIE) {
                me.thisMovie().doAction("init", data);
            }
            else {
                me.palyVoice(data);
                me.onCompleted(duration);
            }
        };
        /**
        * 停止播放声音
        */
        RongIMVoice.stop = function () {
            this.checkInit("stop");
            var me = this;
            if (me.isIE) {
                me.thisMovie().doAction("stop");
            }
            else {
                if (me.element) {
                    me.element.stop();
                }
            }
        };
        /**
        * 播放声音时调用的方法
        */
        RongIMVoice.onprogress = function () {
            this.checkInit("onprogress");
        };
        RongIMVoice.checkInit = function (postion) {
            if (!this.isInit) {
                throw new Error("RongIMVoice not initialized,postion:" + postion);
            }
        };
        RongIMVoice.thisMovie = function () {
            return eval("window['player']");
        };
        RongIMVoice.onCompleted = function (duration) {
            var me = this;
            var count = 0;
            var timer = setInterval(function () {
                count++;
                me.onprogress();
                if (count >= duration) {
                    clearInterval(timer);
                }
            }, 1000);
            if (me.isIE) {
                me.thisMovie().doAction("play");
            }
        };
        RongIMVoice.base64ToBlob = function (base64Data, type) {
            var mimeType;
            if (type) {
                mimeType = { type: type };
            }
            base64Data = base64Data.replace(/^(.*)[,]/, '');
            var sliceSize = 1024;
            var byteCharacters = atob(base64Data);
            var bytesLength = byteCharacters.length;
            var slicesCount = Math.ceil(bytesLength / sliceSize);
            var byteArrays = new Array(slicesCount);
            for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
                var begin = sliceIndex * sliceSize;
                var end = Math.min(begin + sliceSize, bytesLength);
                var bytes = new Array(end - begin);
                for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
                    bytes[i] = byteCharacters[offset].charCodeAt(0);
                }
                byteArrays[sliceIndex] = new Uint8Array(bytes);
            }
            return new Blob(byteArrays, mimeType);
        };
        RongIMVoice.palyVoice = function (base64Data) {
            var reader = new FileReader(), blob = this.base64ToBlob(base64Data, "audio/amr"), me = this;
            reader.onload = function () {
                var samples = new AMR({
                    benchmark: true
                }).decode(reader.result);
                me.element = AMR.util.play(samples);
            };
            reader.readAsBinaryString(blob);
        };
        RongIMVoice.isIE = /Trident/.test(navigator.userAgent);
        RongIMVoice.isInit = false;
        return RongIMVoice;
    })();
    RongIMLib.RongIMVoice = RongIMVoice;
    //兼容AMD CMD
    if ("function" === typeof require && "object" === typeof module && module && module.id && "object" === typeof exports && exports) {
        module.exports = RongIMVoice;
    }
    else if ("function" === typeof define && define.amd) {
        define("RongIMVoice", [], function () {
            return RongIMVoice;
        });
    }
})(RongIMLib || (RongIMLib = {}));

 

截止到这里,Flash 播放 AMR 格式 base64 码 就说完了,主要是介绍下大概思路

以上是融云 SDK 里的源码,不过最近推出了直接使用 Audio 方式播放 AAC 格式的音频文件

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224450.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 231 次浏览 • 2021-01-05 10:55 • 来自相关话题

1、必备资料 github AMR 开源库 :https://github.com/jpemartins/amr.js 用心把这个项目看一遍,对于我下面说的话,可以忽略啦,代码是最好的文章,哈哈~~2、核心 JS 库 :amr.js 、pcmdata... ...查看全部

1、必备资料 github AMR 开源库 :https://github.com/jpemartins/amr.js 用心把这个项目看一遍,对于我下面说的话,可以忽略啦,代码是最好的文章,哈哈~~

2、核心 JS 库 :amr.js 、pcmdata.min.js、libamr-nb.js (g上述ithub项目中有另外三个js,我给合成一个amr.js,不要混乱)这三个 JS 是播放声音的主要依赖,下面一 一 介绍下:

① amr.js : 可以理解成 “桥” 的概念,连接底层解码和客户端调用的桥梁。

② pcmdata.min.js : 封装 pcm data, PCM是一种编码格式 , PCM 添加上 RIFF 头 可以组成 Wave 音频(Wave 不止这一种编码方式),细节太深,小弟也不懂啦~~,有空深挖。

③ libamr-nb.js : amr转换的核心库,这个文件比较大,压缩后大概也要 600kb 左右。

④ 如果下载三个核心库,建议从上篇 “Web 播放声音 — 介绍篇” 中的附件中卸载,在 github 现在的核心库,在 Chrome 下只能播放一次,把这个问题修复了一下,原因是以同样的 Audio.src 创建 Audio 在 Chrome 下就不能二次播放,网上说法各异,最终自己动手解决了,详细可以在 amr.js 中的 global.util.play 方法中看。

3、具体用法

说了有一阵子白话了,该上点代码了,下面是我封装的播放 AMR 格式 Base64 码 的插件,直接在页面引用可以 ,下载地址可以在 “Web 播放声音 — 介绍篇” 下载。

页面一点样式都没有加,只有两个按钮,小伙伴凑合凑合,哈哈~~

代码中只引入了 voice.js 一个 js,其他 js 动态引用了。(公司有 cdn 所以直接放在上面了)。

步骤:

第一步:执行初始化。

第二步:调用相应方法。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Example</title>
<script src="js/voice.js"></script>
</head>
<body>
<input type="button" value="play" id="playId"/>
<input type="button" value="stop" id="stopId"/>
</body>
<script type="text/javascript">
//初始化
RongIMLib.RongIMVoice.init();
//播放
document.getElementById("playId").onclick = function(){
   // base64Str : amr 格式的 base64 码,可以用 HTML5 FileReader 或者canvas 进行转换 。 
   var base64Str = "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";
    RongIMLib.RongIMVoice.play(base64Str );
};
//暂停
document.getElementById("stopId").onclick = function(){ RongIMLib.RongIMVoice.stop(); }; 
</script> 
</html>

在这里也把 “voice.js” 的代码贴出来,使用 typescript 写完后生成出来的,方便小伙伴们查看:

var RongIMLib;
(function (RongIMLib) {
 var RongIMVoice = (function () {
  function RongIMVoice() {
  }
  /**
  * 初始化声音库
  */
  RongIMVoice.init = function () {
      if (this.isIE) {
          var div = document.createElement("div");
          div.setAttribute("id", "flashContent");
          document.body.appendChild(div);
          var script = document.createElement("script");
          script.src = "http://cdn.ronghub.com/swfobject-2.0.0.min.js";
          var header = document.getElementsByTagName("head")[0];
          header.appendChild(script);
          setTimeout(function () {
              var swfVersionStr = "11.4.0";
              var flashvars = {};
              var params = {};
              params.quality = "high";
              params.bgcolor = "#ffffff";
              params.allowscriptaccess = "always";
              params.allowfullscreen = "true";
              var attributes = {};
              attributes.id = "player";
              attributes.name = "player";
              attributes.align = "middle";
              swfobject.embedSWF("http://cdn.ronghub.com/player-2.0.2.swf", "flashContent", "1", "1", swfVersionStr, null, flashvars, params, attributes);
          }, 200);
      }
      else {
          var list = ["http://cdn.ronghub.com/pcmdata-2.0.0.min.js", "http://cdn.ronghub.com/libamr-2.0.1.min.js"];
          for (var i = 0, len = list.length; i < len; i++) {
              var script = document.createElement("script");
              script.src = list[i];
              document.head.appendChild(script);
          }
      }
      this.isInit = true;
  };
  /**
  * 开始播放声音
  * @param data {string} amr 格式的 base64 码
  * @param duration {number} 播放大概时长 用 data.length / 1024
  */
  RongIMVoice.play = function (data, duration) {
      this.checkInit("play");
      var me = this;
      if (me.isIE) {
          me.thisMovie().doAction("init", data);
      }
      else {
          me.palyVoice(data);
          me.onCompleted(duration);
      }
  };
  /**
  * 停止播放声音
  */
  RongIMVoice.stop = function () {
      this.checkInit("stop");
      var me = this;
      if (me.isIE) {
          me.thisMovie().doAction("stop");
      }
      else {
          if (me.element) {
              me.element.stop();
          }
      }
  };
  /**
  * 播放声音时调用的方法
  */
  RongIMVoice.onprogress = function () {
      this.checkInit("onprogress");
  };
    /** 
     * 校验是否初始化
      */
  RongIMVoice.checkInit = function (postion) {
      if (!this.isInit) {
          throw new Error("RongIMVoice not initialized,postion:" + postion);
      }
  };
  RongIMVoice.thisMovie = function () {
      return eval("window['player']");
  };
  RongIMVoice.onCompleted = function (duration) {
      var me = this;
      var count = 0;
      var timer = setInterval(function () {
          count++;
          me.onprogress();
          if (count >= duration) {
              clearInterval(timer);
          }
      }, 1000);
      if (me.isIE) {
          me.thisMovie().doAction("play");
      }
  };
  RongIMVoice.base64ToBlob = function (base64Data, type) {
      var mimeType;
      if (type) {
          mimeType = { type: type };
      }
      base64Data = base64Data.replace(/^(.*)[,]/, '');
      var sliceSize = 1024;
      var byteCharacters = atob(base64Data);
      var bytesLength = byteCharacters.length;
      var slicesCount = Math.ceil(bytesLength / sliceSize);
      var byteArrays = new Array(slicesCount);
      for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
          var begin = sliceIndex * sliceSize;
          var end = Math.min(begin + sliceSize, bytesLength);
          var bytes = new Array(end - begin);
          for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
              bytes[i] = byteCharacters[offset].charCodeAt(0);
          }
          byteArrays[sliceIndex] = new Uint8Array(bytes);
      }
      return new Blob(byteArrays, mimeType);
  };
  RongIMVoice.palyVoice = function (base64Data) {
      var reader = new FileReader(), blob = this.base64ToBlob(base64Data, "audio/amr"), me = this;
      reader.onload = function () {
          var samples = new AMR({
              benchmark: true
          }).decode(reader.result);
          me.element = AMR.util.play(samples);
      };
      reader.readAsBinaryString(blob);
  };
  RongIMVoice.isIE = /Trident/.test(navigator.userAgent);
  RongIMVoice.isInit = false;
  return RongIMVoice;
})();
RongIMLib.RongIMVoice = RongIMVoice;
//兼容AMD CMD
if ("function" === typeof require && "object" === typeof module && module && module.id && "object" === typeof exports && exports) {
  module.exports = RongIMVoice;
}
else if ("function" === typeof define && define.amd) {
  define("RongIMVoice", [], function () {
      return RongIMVoice;
  });
}
})(RongIMLib || (RongIMLib = {}));

好啦,到此本文结束,会尽快更新 Flash 下播放 AMR 格式 Base64 码,代码中哪里有错误或者有异议麻烦小伙伴们联系我,一起讨论,有则改之无法加冕,一起进步,thx~~。

以上是融云 SDK 里的源码,不过最近推出了直接使用 Audio 方式播放 AAC 格式的音频文件,非常方便

原始文章连接:https://www.cnblogs.com/yuhongda0315/p/5224188.html

融云官网:https://www.rongcloud.cn

融云文档:https://docs.rongcloud.cn/v4


融云 IM 那些事儿

IM即时通讯苏道 发表了文章 • 0 个评论 • 235 次浏览 • 2021-01-05 10:55 • 来自相关话题

最近闲来无事在网上冲浪,看到关注公众号推送了一篇 《Zoom大火之后,这家国内公司也很值得关注啊》 的文章,看样子八成是融云的运营稿(融云的朋友看到别打我…),不过不重要,重要的因为这篇文章确实让我对 IM 和 RTC 提起了浓厚的兴趣,因为疫情期间还没有离职... ...查看全部

最近闲来无事在网上冲浪,看到关注公众号推送了一篇 《Zoom大火之后,这家国内公司也很值得关注啊》 的文章,看样子八成是融云的

运营稿(融云的朋友看到别打我…),不过不重要,重要的因为这篇文章确实让我对 IM 和 RTC 提起了浓厚的兴趣,因为疫情期间还没有离职

公司每天都用 Zoom,后来 Zoom 这家伙宣布停止对中国提供服务后,鬼知道老板是为了彰显爱国主义情节还是怕服务不稳定,老板果断切换为腾讯会议

离职后虽然用的少了,但偶尔开个会啥的,也会用腾讯会议或者微信的音视频进行和伙伴进行线上沟通,这么说来接触音视频 Saas 也有一段时间了

但对底层如何实现的通话一无所知,你知道的,作为一个有追求的码农,知其然必知其所以然,正赶上看了前面提到的文章,于是马上动手开始研究融云的

IM 和 RTC,先从 IM 开始说起~

我是从以下几步分别了解:官网开发者后台开发文档

官网

从官网得到了以下个信息:

产品分类

1、IM + RTC: 之前在公司听同事说过融云做 IM,不知道啥时候也做了 RTC ,还挺有意思,不知道具体原因,个人理解也许 IM 的天花板比较低或者变现难,并且音视频在未来网络基础设置越来越好、流量越来越廉价、5G 的到来等种种因素,音视频还是很有前景的,才杀入 RTC 战场,分一杯羹

2、支持平台: Android、iOS、Web、小程序、Electron、Flutter 主流平台都支持

支持四种部署方式

1、公有云: 大家公用一个盘子,有点过去大通铺的赶脚,我要是胖我睡的面积就大,当然了我要是胖可能还挤到你,可能会有资源抢占的情况,不过这要看融云的预留冗余资源了

2、专有云: 相比大通铺,这个就高级多了,类似单间,空间、卫浴均为独立,并且私密性比较好

3、海外云: 海外大通铺,在线咨询了下,海外用户也能直接用国内数据中心,估计他们自己的网络链路,具体原因没有再细问,毕竟暂时也不用,不太好意思,我是一个腼腆的人儿

4、私有云: 相比单间,这就是自己盖房子了,融云提供设计图,并且找施工队给你单独盖一个琉璃大瓦房,但后续怎么维护没看到说明,有可能和通用外包的维护费用类似,比如:每年维护费是合同款的 10%,费用是我自己 YY 的,不会用也没好意思去找他们人了解

目前正在搞的活动

1、黑客马拉松:印象最深的银子,第一名给五万,我是看到晚要不一定参加,这样可以弥补一点离职期间经济损失,毕竟离职前薪资也一个月 xxx 呢(一不小心差点把工资说出来,万一媳妇看见小金库可就没有了…..慌的一批,哈哈哈)

2、WICC:全名好长,全球互联网通信云大会,不和全球占点关系,都不好意说自己是互联网公司,哈哈,不过看他们也有海外节点,这么说也合理,地址不在北京,可惜去不了,要不真的可以去 see see

3、聆听:这是一个收集建议的系统包括吐槽啥的,看样子还是比较注重客户服务,在这样一个技术可快速复制的时代,也许客户服务等软技能还是挺重要的,尤其是 ToB 企业

其他

1、其他的都是一些案例介绍,这些东各家公司如出一辙,秀秀肌肉、吹吹牛啥的,就没多看,目前我不关注这块

开发者后台

功能丰富

进入后台第一眼真的是功能丰富,看出来确实是积累了很多功能,不过产品逻辑不是很好,有点无从下手,研究了一会理解了

调试工具

调试工具点个赞,把所有服务端的接口都做了可在线调试的 API,如果集成初期没有自己 Server 接口,完全可以用这个来集成,非常方便,很惊喜

小槽点

开发者后台的界面略丑,看起来有点像智能手机和老人机的排版布局差异,虽说不影响使用吧,但作为一个有追求的青年咋能对美不挑剔呢,不对,应该少年,不对不对,是青少年,文章暂停下,我先倒腾下措辞….(两个小时后,是少年,我还是从前那个少年,没有一丝丝改变…..)

开发文档

文档分类倒是简单,IM、RTC、运营服务, 下面逐个介绍下感受

1、IM: 不愧是做 IM 起家的 Paas 厂商,支持的能力确实很出色,尤其聊天室的功能格外丰富,在线和客服妹子聊说人数无上限,支持弹性扩所容

2、RTC: 看完文档就能知道在音视频沉淀还有不够,为啥这么说,在文档投入精力一定不够,或者资源在忙于其他更重要的事情未开始规划,后台看了看发布的第一版音视频 SDK,是在去年三月份,和感觉还比较像,瞬间觉得自己像老司机一样,哈哈

3、粗略过了一遍文档,体验了下官方 Demo SealRTC,音视频质量相当不错,晚上纽约的老铁视频用的就是这个东东,非常流畅,好感度暴涨

————华丽的人肉分割线————-

整体感觉就这些,这里没有涉及技术集成,后面再集成试试,写完感觉像给融云写了一篇产品介绍的稿子,不知道融云的朋友看到会不会给我发稿费 哈哈

就写到这里了吧,太阳快出来了,睡觉~~~

另外赠从下融云相关链接

官网:https://www.rongcloud.cn

文档:https://docs.rongcloud.cn/v4


集成融云 Web 音视频通话踩坑之旅

WebRTC苏道 发表了文章 • 0 个评论 • 264 次浏览 • 2020-12-29 16:44 • 来自相关话题

前言最近有个项目需要使用的融云的 CallLib SDK 实现类似微信的视频通话,所以在项目还未正式启动的时候,我已经偷偷的开始进行集成了,以免到时候不熟一顿加班那真的欲哭无泪了,好消息就是我已经使用过融云家的 IMLib SDK 做过即时通讯的功能,所以整个... ...查看全部

前言

最近有个项目需要使用的融云的 CallLib SDK 实现类似微信的视频通话,所以在项目还未正式启动的时候,我已经偷偷的开始进行集成了,以免到时候不熟一顿加班那真的欲哭无泪了,好消息就是我已经使用过融云家的 IMLib SDK 做过即时通讯的功能,所以整个注册流程和开发者后台的使用已经比较熟了,当然,即时不熟也没关系,跟着他们的文档一步一步来,也能很快的就上手了。
融云官网:https://www.rongcloud.cn/

下面是集成的时候碰到的一些需要注意的问题:

1、Web 站点必须为 localhost 或 https
2、必须成功连接 IM 后, 才可进行 CallLib 通话
3、新版谷歌浏览器(86版本)会报错,我集成的 RTC 版本是 3.2.3
4、音视频通话接通不了

综上问题,我会逐一解答,关于具体的集成可以直接参考:https://docs.rongcloud.cn/v4/views/rtc/call/noui/quick/web.html

还有具体的 demo 也可以参考一下 https://github.com/rongcloud-snippets/web-call-quickstart

Web 站点必须为 localhost 或 https:
这个是融云的使用音视频通话的前置条件,本来在本地调试的时候好好的,可是发布到线上的时候就不能用了,最后提交工单询问融云的技术人员上线是否还需要配置什么,最后排查一圈发现生产环境使用的站点是 http(欲哭无泪。。。),童鞋们引以为戒啊!!

必须成功连接 IM 后, 才可进行 CallLib 通话:
直接看代码:

// appKey 可在融云开发者后台获取
const im = RongIMLib.init({ appkey: '<your-appkey>' })
// 添加事件监听器
im.watch({
  // 连接状态监听
  status(evt) {
    console.log('连接状态码:', evt.status);
  },
  // 消息监听
  message(evt) {
    console.log('收到新消息:', evt.message);
  }
})
// CallLib 初始化
var config = {
    timeout: 20000,
    RongIMLib: RongIMLib,
    RongRTC: RongRTC
};
rongCallLib = RongCallLib.init(config);
//token 可从开发者后台获取 或 Server API
const token = ''
im.connect({ token }).then(user => {
  console.log('链接成功, 链接用户 id 为: ', user.id);
}).catch(error => {
  console.log('链接失败: ', error.code, error.msg);
});

新版谷歌浏览器会报错:
由于浏览器更新,导致 SDK 需要升级,升级到最新版本的 RTC SDK 下载地址:https://cdn.ronghub.com/RongRTC-3.2.6.min.js
需要注意,如果使用的 SDK 2.X 也需要升级到 2.5.10 以上

音视频通话接通不了:
这种情况我总结分析了一下几种情况,如下:

代码传参错误或者书写错误
这个好像没什么说的,只能怪自己不仔细吧!跟着文档来呗

结束通话没有调用挂断方法 hungup
用户主动发起挂断,在 rongCallLib.commandWatch 监听中收到 HungupMessage 消息,可以调用 rongCallLib.hungup 来挂断通话,不然下次呼叫时会出现报错,提示对方正忙

如何识别挂断原因
HungupMessage 消息中 reason 字段及 SummaryMessage 消息中 status 字段都为挂断原因,详情地址参考:https://docs.rongcloud.cn/rtc/calllib/web/code/

因为对音视频的集成也刚开始,还在学习当中。后续随着继续深入,也会同步音视频相关的集成问题,方便复习记录也希望能帮到需要的童鞋!!!


结合融云 WebSDK 了解 WebSocket 基本原理

WebRTC赵炳东 发表了文章 • 0 个评论 • 242 次浏览 • 2020-12-29 16:44 • 来自相关话题

近期使用融云开发聊天页面, 通过抓包, 发现融云 SDK 使用 WebSocket 实现与服务端通讯, 因此简单了解 WebSocket 的实现原理融云 SDK 文档: https://docs.rongcloud.cn/v4/WebSocket 与... ...查看全部

近期使用融云开发聊天页面, 通过抓包, 发现融云 SDK 使用 WebSocket 实现与服务端通讯, 因此简单了解 WebSocket 的实现原理

融云 SDK 文档: https://docs.rongcloud.cn/v4/

WebSocket 与 HTTP

1、HTTP 协议没有为了 WebSocket 的出现改变

2、WebSocket 属于 HTTP 之后的新协议

3、两者有交集, 也各有不同

4、WebSocket 借用 HTTP 协议完成一部分握手

WebSocket 握手

通过抓包融云 WebSocket 请求, 重点关注以下几个字段

以上为发起 WebSocekt 请求抓包, 首先关注比 HTTP 多出的数值:

// 告知服务器, 发起的是 WebSocket 协议, 服务需进行 WebSocket 处理Upgrade: websocketConnection: Upgrade
Sec-WebSocket-Key: aI0TsvW7jltfmNOF+1eSqg== // Base64, 浏览器随机生成. 与后面服务端响应的 Sec-WebSocket-Accept 配套, 提供基本的防护. 比如恶意的连接, 或者无意的连接Sec-WebSocket-Version: 13 // 表示 websocket 的版本. 如果服务端不支持该版本, 需要返回一个 Sec-WebSocket-Versionheader, 里面包含服务端支持的版本号

再查看 Response Headers:

Sec-WebSocket-Accept: OfEosYlCAcvV/jdwbW33VU0B50k= // 安全验证. 根据客户端请求首部 Sec-WebSocket-Key 计算 ( base64(sha1($Sec-WebSocket-Accept,'258EAFA5-E914-47DA-95CA-C5AB0DC85B11')) )
// 告知客户端, 已成功升级为 WebSocketUpgrade: websocketConnection: Upgrade

替代方案

浏览器没有完美替代 WebSocket 的方案. 只能用 ajax 轮询 或 长轮训(long poll) 模拟, 两者都有性能问题且耗费资源

ajax 轮询、长轮训说明: https://zhuanlan.zhihu.com/p/25690011