关于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. Unity Android设备的输入

    Unity Android设备的输入 1依据屏幕位置输入 有的时候也许是为了整个有些风格的干净,减少屏幕上的UI图标,以至于摒弃了虚拟按键这种常用的输入方式.为了替代虚拟按键的输入方式而选择了依据点击 ...

  2. JavaScript 字符串 & Math & Date

    字符串 字符串就是零个或多个排在一起的字符,放在单引号或双引号之中. 'abc' "abc" 单引号字符串的内部,可以使用双引号.双引号字符串的内部,可以使用单引号. 'key=& ...

  3. 【第三章】Shell 变量的数值计算

    一.算数运算符 shell中常见的算术运算符: shell中常见的算术命令: 1. 整数运算 方法一:expr  expr命令就既可以用于整数运算,也可以用于相关字符串长度.匹配等的运算处理: exp ...

  4. 关闭Tomcat进程 一条语句(必看)

    写在开始 MAC系统下进行JAVA研发,经常遇到的一个问题就是杀死异常Tomcat 通常都是用两条指令,先查询出Tomcat占用的进程,再kill掉该进程, 其实有一种联合语句的方式可以一条语句直接关 ...

  5. Python3 数据类型-元组

    Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 实例1(Python3.0+): tu ...

  6. fragment的介绍与使用

    稍稍摘录一段Fragment.java中的说明文档. /** * A Fragment is a piece of an application's user interface or behavio ...

  7. C语言中的字符串分割函数

    char *strtok(char *s, const char *delim); 分解字符串为一组字符串.s为要分解的字符串,delim为分隔符字符串. 从s开头开始的一个个被分割的串.当没有被分割 ...

  8. Thunder团队第三周 - Scrum会议7

    Scrum会议7 小组名称:Thunder 项目名称:i阅app Scrum Master:胡佑蓉 工作照片: 邹双黛在照相,所以图片中没有该同学. 参会成员: 王航:http://www.cnblo ...

  9. 20172330 2017-2018-1 《Java程序设计》第七周学习总结

    学号 2017-2018-1 <程序设计与数据结构>第七周学习总结 教材学习内容总结 这一章主要是对继承的学习: 继承是组织和创建类的基本技术,概念简单但影响重大,决定着面向对象软件的设计 ...

  10. sql 至少含有

    查询Score表中至少有5名学生选修的并以3开头的课程的平均分数: select avg(degree),cnofrom scorewhere cno like '3%'group by cnohav ...