关于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. Jenkins构建完成后实现自动将war包部署到指定服务器

    首先我们需要确定我们的jenkins安装了:publish over ssh 插件,如果没有安装,到-->jenkins首页-->系统管理-->插件管理-->可选安装里面去搜 ...

  2. SecureCRT 注册

    http://download.csdn.net/download/xia2011214228/9952983 1.下载后解压到安装目录 2.输入自己要注册的:name company 后genera ...

  3. Python全栈 进阶(进阶内容都在这了)

    原文地址 https://yq.aliyun.com/articles/632754?spm=a2c4e.11155435.0.0.23eb3312feB6dG ................... ...

  4. 浙江天搜科技落棋人工智能,加速AI产业布局

    8月31日,2018年IFA大展在德国柏林正式开幕.IFA是全球三大消费电子展之一,在世界范围内久负盛名,被誉为“未来科技风向标”.在这个万众瞩目的展会上,号称“给智能世界铺上云的跑道,装上智能发动机 ...

  5. IntelliJ IDEA 2018 for MAC安装及破解

    ---------------------说在前面-------------------------- IntelliJ IDEA 2018 版本为2018.1.4 教程按照下载安装sdk.破解两部分 ...

  6. 有关WCSF的几点整理

    本文示例代码 一.CreateNew Attribute实现属性注入 Steps: 1/ aspx创建某个服务的属性. 2/ 为其添加[CreateNew] Attribute. 3/ 页面继承自Mi ...

  7. 衡量生活成本:消费者价格指数(CPI, Consumer Price Index)

    经济学家应该如何把经济中的许多价格加总成一个单一指数,从而能够衡量价格的总体水平呢?他们可以简单地计算所有产品与服务价格的平均值,但是这种方法的不足之处是把所有的产品与服务等同处理.由于人们购买的鸡比 ...

  8. PHP 签到,与时间获取,数组长度获取

    本文实例讲述了php实现签到功能的方法.分享给大家供大家参考,具体如下:首先我在数据库里建了两张表,一个是用户的积分表,一个是签到状态表,分来用来记录用户的积分数和先到状态 在用户签到状态表中我们有一 ...

  9. iOS- <项目笔记>项目配置常见文件

    项目常见文件 1.main.m * 里面有一个程序的入口:main函数 2.Prefix.pch文件 * pch文件中的内容能被项目中的其他任何文件共享\包含\访问 * 如果定义的内容只用在OC环境中 ...

  10. TCP系列27—窗口管理&流控—1、概述

    在前面的内容中我们依次介绍了TCP的连接建立和终止过程和TCP的各种重传方式.接着我们在这部分首先关注交互式应用TCP连接相关内容如延迟ACK.Nagle算法.Cork算法等,接着我们引入流控机制(f ...