• 关于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

  • 相关阅读:
    AFNetworking 2.0 -1016错误解决办法
    dispatch_once创建单例
    ASIHTTPRequest 1.x:断点续传
    iOS开源项目汇总
    NSSearchPathForDirectoriesInDomains
    开源中国iOS客户端学习——(一)Prefix.pch文件
    UITableView 滚动条
    隐藏UITableView的滚动条以及修改滚动条的颜色,UITableView 滚动到指定行 section
    收藏几个支持中文的PHP字符串截取函数
    Cookie和Session
  • 原文地址:https://www.cnblogs.com/mjbrian/p/9673270.html
Copyright © 2020-2023  润新知