关于websocket的实现网上很多资料这里就不详说,这里大概讲我在websocket传输大文件的时的方法,websocket传输单个文件最大不能超过7kg,否则前段自动断掉,当我们用来语音通讯时,通常语音文件都比较大,传输单个语音文件显然是不现实的,网上查了关于微信的语音实现,当然具体的源码是看不到的,不过有人亲测过微信语音大概的实现过程。

微信实现语音的过程是边录音边传输,把一段语音切割成很多个小片段的语音传输到后台,后台在进行合并处理,后台向前段传输语音时同理,我的项目中大概实现如下:

前段用recorder.js实现浏览器录音,录音完成后得到语音文件为blob,blob是js里的一个大文件对象,是原始二进制数据,实现为

var blob = new Blob(chuanks[],{type:"audio/wav"});

其中chuanks[]可以示多种数据类型,arraybuffer,blob等,我的实现方法是把blob大文件通过bolb.slice()切割成多个小blob文件,然后用

var reader = new FileReader();把文件转成base64传输到后台合并处理,blob文件只能通过FileReader对象来读取文件内容,下面直接上代码

   //前台
recorder && recorder.exportWAV(function(blob) {
//将文件转为base64
console.log(blob);
var type = "audio/wav";
var chunk = 5 * 1024;
var messageid = new Date().toISOString() + RndNum(5);
var chunks = [];
var start = 0;
var islast = false;
//文件切割
for (var i = 0; i < Math.ceil(blob.size / chunk); i++) {
var end = start + chunk;
chunks[i] = blob.slice(start , end, type);
start = end;
if(blob.size<end){islast=true;}
send(chunks[i], type, messageid, i, islast);
}
//发送文件
function send(val,type, messageid, i, islast){
var reader = null;
var postValue={}
reader = new FileReader()
reader.readAsDataURL(val,"UTF-8");//转成base64
reader.onload = function () {
str = reader.result.split(",")[1];
postValue.voicetype=type;
postValue.content=str;
postValue.messageid=messageid;
postValue.sequence=i;
postValue.islast=islast;
socket.send(JSON.stringify(postValue));//websocket发送文件 }; }
//后台接收
String messageId = req.getMessageid();
boolean isLast = req.isIslast();
int sequence = req.getSequence();
String content = req.getContent();
org.json.JSONObject result = null;
try {
SplitMessage saveMessage = spiltmessages.get(messageId);
if(isLast==true && saveMessage==null ) {
result = BaiduIntelligeVoiceUtil.asr(content,req.getVoicetype());
}else{
if((saveMessage==null ||saveMessage.getContent()==null) && isLast==false && sequence==0){
byte[] splitBytes = Base64Utils.decodeFromString(content);
SplitMessage splitMessageNew = new SplitMessage(sequence,splitBytes);
spiltmessages.put(messageId,splitMessageNew);
return;
}else if(saveMessage !=null && saveMessage.getContent()!=null && isLast==false){
byte[] saveContent = saveMessage.getContent();
if((sequence)!=saveMessage.getSequence()+1){
SimpleResponse simpleResponse = SimpleResponse.failureResp("接收语音文件格式转化时发生错误","text");
return;
}
byte[] splitBytes = Base64Utils.decodeFromString(content);
//新保存的字节数组
byte[] saveBytesNew = new byte[splitBytes.length+saveContent.length];
System.arraycopy(saveContent,0,saveBytesNew,0,saveContent.length);
System.arraycopy(splitBytes, 0, saveBytesNew, saveContent.length, splitBytes.length);
saveMessage.setContent(saveBytesNew);
saveMessage.setSequence(sequence);
return;
}else if(saveMessage !=null && saveMessage.getContent()!=null && isLast==true){
if((sequence-1)!=saveMessage.getSequence()){
SimpleResponse simpleResponse = SimpleResponse.failureResp("接收语音文件格式转化时发生错误","text");
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
return;
}
byte[] saveContent = saveMessage.getContent();
byte[] splitBytes = Base64Utils.decodeFromString(content);
//新保存的字节数组
byte[] saveBytesNew = new byte[splitBytes.length+saveContent.length];
System.arraycopy(saveContent,0,saveBytesNew,0,saveContent.length);
System.arraycopy(splitBytes, 0, saveBytesNew, saveContent.length, splitBytes.length);
spiltmessages.remove(messageId); //TODO 解析语音成文字
result = BaiduIntelligeVoiceUtil.asrForSplit(saveBytesNew,"pcm",16000,null);
}else {
SimpleResponse simpleResponse = SimpleResponse.failureResp("对不起,不能解析您的语音","text");
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
return;
}
} }catch (IOException e){
logger.error("clientId为 :"+clientId + " 的用户语音文件格式转化时发生错误 : " + e.toString());
SimpleResponse simpleResponse = SimpleResponse.failureResp("语音文件格式转化时发生错误","text");
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
return;
} catch (InterruptedException e) {
logger.error("clientId为 :"+clientId + " 的用户语音文件格式转化时发生错误 : " + e.toString());
SimpleResponse simpleResponse = SimpleResponse.failureResp("语音文件格式转化时发生错误","text");
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
return;
}

后台发送
//TODO 合成回答语音
TtsResponse syncResp = BaiduIntelligeVoiceUtil.synthesis(respmessage);
byte[] bytes = syncResp.getData();
if(bytes!=null){
List<byte[]> byteList = ByteMergeAndSplitUtil.splitBytesBySize(bytes,5120); for(int i=0;i<byteList.size();i++){
String spilitMsg = Base64Utils.encodeToString(byteList.get(i));
SimpleResponse simpleResponse = SimpleResponse.successResp(spilitMsg,"mp3");
simpleResponse.setMessageid(messageId);
simpleResponse.setSequence(i);
if(i<byteList.size()-1) {
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
}else {
simpleResponse.setIslast(true);
simpleResponse.setVoicetotext(question);
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
}
}
return; }else {
SimpleResponse simpleResponse = SimpleResponse.failureResp("语音合成失败", "text");
sendMessageToUser(clientId, new TextMessage(JSONObject.toJSONString(simpleResponse)));
return;
}
//前台接收信息
var chunks = [];
socket.onmessage = function (msg) {
console.log(msg.data);
var str = {};
var reVal = JSON.parse(msg.data);
str.content = reVal.content;
str.errno = reVal.errno;
str.islast = reVal.islast;
str.sequence = reVal.sequence;
str.type = reVal.type;
chunks[reVal.sequence] = base64ToBlob(str.content);
if(str.islast){
var blob = new Blob(chunks,{type : reVal.type});
var url = URL.createObjectURL(blob);
var voi = document.getElementById('voi');
var au = document.createElement('audio');
var div = document.createElement('div'); au.controls = true;
au.src = url;
voi.appendChild(div);
div.appendChild(au);
div.style = "float:left;clear:both;";
voi.scrollTop = voi.scrollHeight;//使滚动条一直在底部
openPage(reVal.voicetotext);
} }

借鉴https://segmentfault.com/a/1190000011563430

关于wesocket大文件通讯的切片实现方法的更多相关文章

  1. 【转】Linux 中清空或删除大文件内容的五种方法(truncate 命令清空文件)

    原文: http://www.jb51.net/article/100462.htm truncate -s 0 access.log -------------------------------- ...

  2. js实现大文件分片上传的方法

    借助js的Blob对象FormData对象可以实现大文件分片上传的功能,关于Blob和FormData的具体使用方法可以到如下地址去查看FormData 对象的使用Blob 对象的使用以下是实现代码, ...

  3. sharepoint 2013 资源管理器copy大文件到本地失败解决方法

    Error 0x800700DF: The file size exceeds the limit allowed and cannot be saved 中文错误信息是:文件大小超出同意范围.不能被 ...

  4. [译]在Linux中清空或删除大文件内容的5种方法

    原文来源: https://www.tecmint.com/empty-delete-file-content-linux/ 有时,在处理Linux终端中的文件时,您可能希望清除文件的内容,而无需使用 ...

  5. Linux下清空或删除大文件内容的2种方法

    在Linux终端下处理文件时,有时候我们想要直接清空文件的内容时但又不用使用任何Linux命令行编辑器,去打开这些文件.那如何才能达到这个目的呢? 1.通过重定向到NULL来清空文件内容 清空或者让一 ...

  6. Linux 下清空或删除大文件内容的 5 种方法

    在 Linux 终端下处理文件时,有时我们想直接清空文件的内容但又不必使用任何 Linux 命令行编辑器 去打开这些文件.那怎样才能达到这个目的呢?在这篇文章中,我们将介绍几种借助一些实用的命令来清空 ...

  7. 文件/大文件上传功能实现(JS+PHP)全过程

    文件/大文件上传功能实现(JS+PHP) 参考博文:掘金-橙红年代 前端大文件上传 路漫漫 其修远 PHP + JS 实现大文件分割上传 本文是学习文件上传后的学习总结文章,从无到有实现文件上传功能, ...

  8. 使用kbmmw 的REST 服务实现上传大文件

    我们在使用kbmmw的REST 服务时,经常会下载和上传大文件.例如100M以上的.kbmmw的rest服务中 提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理.这些对于文 ...

  9. Linux系统查找清理磁盘大文件

    本文主要介绍Linux系统磁盘使用空间不足时,如何查找大文件并进行清理的方法. 使用df-h检查一台服务器磁盘使用空间,发现磁盘已经使用了100%,其中/dev/mapper/vg_iavp-lv_r ...

随机推荐

  1. 第八模块:算法&设计模式、企业应用 第1章 常用算法&设计模式学习

    第八模块:算法&设计模式.企业应用 第1章 常用算法&设计模式学习

  2. MD5接口解密操作_接口签名校验

    很多HTTP接口在传参时,需要先对接口的参数进行数据签名加密如以下POST接口 http://localhost:8080/pinter/com/userInfo 参数为{"phoneNum ...

  3. 查看python中包的文档

    核心命令:python -m pydoc 查询某包:python -m pydoc 包名 示例: C:\Users\xxx>python -m pydoc pydoc - the Python ...

  4. LeetCode 145 ——二叉树的后序遍历

    1. 题目 2. 解答 2.1. 递归法 定义一个存放树中数据的向量 data,从根节点开始,如果节点不为空,那么 递归得到其左子树的数据向量 temp,将 temp 合并到 data 中去 递归得到 ...

  5. 简单构建基于RDF和SPARQL的KBQA(知识图谱问答系统)

    本文主要通过python实例讲解基于RDF和SPARQL的KBQA系统的构建.该项目可在python2和python3上运行通过. 注:KBQA即是我们通常所说的基于知识图谱的问答系统.这里简单构建的 ...

  6. SIG蓝牙mesh笔记3_网络结构

    目录 3. Mesh Networking 3.1 Bearers 承载层 3.2 Network Layer 网络层 3.2.3 Address validity 地址有效性 3.2.4 Netwo ...

  7. Windows环境下的TensorFlow安装过程

    安装环境 Windows8.1 python3.5.x(TensorFlow only supports version 3.5.x of Python on Windows) pip 9.0.1 t ...

  8. lintcode-163-不同的二叉查找树

    163-不同的二叉查找树 给出 n,问由 1...n 为节点组成的不同的二叉查找树有多少种? 样例 给出n = 3,有5种不同形态的二叉查找树: 标签 卡特兰数 动态规划 思路 参考博客http:// ...

  9. java 字符串—数字常用处理

    // 判断一个字符串是否都为数字 public boolean isDigit(String strNum) { return strNum.matches("[0-9]{1,}" ...

  10. [STL] vector基本用法

    vector的数据安排以及操作方式,与array非常相似.两者的唯一区别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能改变.vector是动态空间,随着元素的加入,它的内部机制会自行扩 ...