关于wesocket大文件通讯的切片实现方法
关于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大文件通讯的切片实现方法的更多相关文章
- 【转】Linux 中清空或删除大文件内容的五种方法(truncate 命令清空文件)
原文: http://www.jb51.net/article/100462.htm truncate -s 0 access.log -------------------------------- ...
- js实现大文件分片上传的方法
借助js的Blob对象FormData对象可以实现大文件分片上传的功能,关于Blob和FormData的具体使用方法可以到如下地址去查看FormData 对象的使用Blob 对象的使用以下是实现代码, ...
- sharepoint 2013 资源管理器copy大文件到本地失败解决方法
Error 0x800700DF: The file size exceeds the limit allowed and cannot be saved 中文错误信息是:文件大小超出同意范围.不能被 ...
- [译]在Linux中清空或删除大文件内容的5种方法
原文来源: https://www.tecmint.com/empty-delete-file-content-linux/ 有时,在处理Linux终端中的文件时,您可能希望清除文件的内容,而无需使用 ...
- Linux下清空或删除大文件内容的2种方法
在Linux终端下处理文件时,有时候我们想要直接清空文件的内容时但又不用使用任何Linux命令行编辑器,去打开这些文件.那如何才能达到这个目的呢? 1.通过重定向到NULL来清空文件内容 清空或者让一 ...
- Linux 下清空或删除大文件内容的 5 种方法
在 Linux 终端下处理文件时,有时我们想直接清空文件的内容但又不必使用任何 Linux 命令行编辑器 去打开这些文件.那怎样才能达到这个目的呢?在这篇文章中,我们将介绍几种借助一些实用的命令来清空 ...
- 文件/大文件上传功能实现(JS+PHP)全过程
文件/大文件上传功能实现(JS+PHP) 参考博文:掘金-橙红年代 前端大文件上传 路漫漫 其修远 PHP + JS 实现大文件分割上传 本文是学习文件上传后的学习总结文章,从无到有实现文件上传功能, ...
- 使用kbmmw 的REST 服务实现上传大文件
我们在使用kbmmw的REST 服务时,经常会下载和上传大文件.例如100M以上的.kbmmw的rest服务中 提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理.这些对于文 ...
- Linux系统查找清理磁盘大文件
本文主要介绍Linux系统磁盘使用空间不足时,如何查找大文件并进行清理的方法. 使用df-h检查一台服务器磁盘使用空间,发现磁盘已经使用了100%,其中/dev/mapper/vg_iavp-lv_r ...
随机推荐
- mysql新手进阶01
生活不止眼前的苟且,还有诗和远方. 请根据给出的数据库表结构来回答相应问题: DEPT (DEPTNO INT, DNAME VARCHAR(14),LOC VARCHAR(13)); EMP (EM ...
- CSS 之 选择器
CSS的常见选择器 一.简单选择器 Simple Selectors 选择器 含义 * 通用元素选择器,匹配任何元素 E 标签选择器,匹配所有使用E标签的元素 .info class选择器,匹配所有c ...
- IMX6移植htop
top命令查看CPU利用率并不是很方便,因此打算移植htop到imx6上,主要包括以下几个步骤: - 资源下载 htop 下载http://hisham.hm/htop/releases/1.0.1/ ...
- 从hive导入到oracle(Hcatalog)
1.使用catalog的情况下: sqoop export --table tableName2 \ #oracle表 --connect jdbc:oracle:thin:@127.0.0.1:15 ...
- 十:HDFS Short-Circuit Local Reads 短路本地读取
当client请求数据时,datanode会读取数据然后通过TCP协议发送给client.short-circuit绕过了datanode直接读取数据.short-circuit的前提是client和 ...
- MFC常用数据类型
下面这些是和Win32程序共同使用的数据类型BOOL:布尔值,取值为TRUE or FALSEBSTR:32-bit 字符指针BYTE:8-bit整数,未带正负号COLORREF:32-bit数值,代 ...
- java中对象和对象的引用
1.何谓对象? 在Java中有一句比较流行的话,叫做“万物皆对象”,这是Java语言设计之初的理念之一.要理解什么是对象,需要跟类一起结合起来理解.下面这段话引自<Java编程思想>中的一 ...
- javaIO--文件操作类
文件操作类主要是使用File类的各种方法对文件和目录进行操作.包括文件名.文件长度.最后修改时间和是否只读等,提供获得当前文件的路径名.判断文件是否存在.创建.删除文件和目录等一系列的操作方法. 下面 ...
- Java中I/O流之数据流
Java 中的数据流: 对于某问题:将一个 long 类型的数据写到文件中,有办法吗? 转字符串 → 通过 getbytes() 写进去,费劲,而且在此过程中 long 类型的数需要不断地转换. ...
- LintCode-371.用递归打印数字
用递归打印数字 用递归的方法找到从1到最大的N位整数. 注意事项 用下面这种方式去递归其实很容易: recursion(i) { if i > largest number: return re ...