Javascript二进制字符串到MP3

时间:2015-07-22 21:09:49

标签: javascript angularjs server mp3 multipart

我在浏览器中处理一个项目,该项目从服务器接收多部分响应。

响应的第一部分是一些JSON元数据

响应的第二部分是二进制MP3文件。

我需要一种从多部分响应中提取该MP3文件并在HTML 5音频元素中播放的方法。

有没有人遇到这个或类似的东西?

1 个答案:

答案 0 :(得分:1)

我最终解决了我的问题。我为将来需要这样做的人提供了问题和解决方案。

背景信息:

我在制作这个ajax请求时使用AngularJS,但对于jquery ajax和常规xhr这个想法都是一样的。

<强>代码:

&#13;
&#13;
//creating a form object and assigning everything
//to it is so that XHR can automatically
//generate proper multipart formatting
var form  = new FormData();
var data = {};

data['messageHeader'] = {};

var jsonData = JSON.stringify(data);
var jsonBlob = new Blob([jsonData],{type: "application/json"});

//assign json metadata blob and audio blob to the form
form.append("request", jsonData);
form.append("audio",response); //Response is the audio blob

//make the post request
//Notes:
//content-type set to undefined so angular can auto assign type
//transformRequest: angular.identity allows for angular to create multipart
//response: arraybuffer so untouched binary data can be received
$http({method:"POST",
  url: endpoint + path,
  headers: {
    'Authorization': 'Bearer ' + $cookies.get('token'),
    'Content-Type': undefined
  },
  transformRequest: angular.identity,
  data: form,
  responseType: "arraybuffer"
  })
  .success(function(data){
    //data: ArrayBuffer of multipart response
    //toss ArrayBuffer into Uint8Array
    //lets you iterate over the bytes
    var audioArray = new Uint8Array(data);
  
    //toss a UTF-8 version of the response into
    //a variable. Used to extract metadata
    var holder = "";
    for (var i = 0; i < audioArray.length; i++){
      holder += String.fromCharCode(audioArray[i]);
    }

    //get the boundary from the string. Eg contents of first line
    var boundary = holder.substr(0, holder.indexOf("\n"));
    //break response into array at each boundary string
    var temp = holder.split(boundary);
    var parts = [];
    //loop through array to remove empty parts
    for (var i = 0; i < temp.length; i++){
      if (temp[i] != ""){
          parts.push(temp[i]);
        }
    }

    //PARSE FIRST PART
    //get index of first squiggly, indicator of start of JSON
    var jsonStart = parts[0].indexOf('{');
    //string to JSON on { index to end of part substring
    var JSONResponse = JSON.parse(parts[0].substring(jsonStart));

    //PARSE SECOND PART
    var audioStart = holder.indexOf('mpeg') + 8;
    //get an ArrayBuffer from UInt8Buffer from the audio
    //start point to the end of the array
    var audio = audioArray.buffer.slice(audioStart);

    //hand off audio to AudioContext for automatic decoding
    audio_context.decodeAudioData(audio, function(buffer) {
      var audioBuffer = buffer;
      //create a sound source
      var source = audio_context.createBufferSource();
      //attach audioBuffer to sound source
      source.buffer = audioBuffer;
      //wire source to speakers
      source.connect(audio_context.destination);
       //on audio completion, re-enable mic button
      source.onended = function() {
        console.log("ended");
        $scope.$apply(function(){
          $scope.playing = false;
        });		
      }
      //start playing audio
      source.start(0);

      }, function (){
        //callback for when there is an error
        console.log("error decoding audio");
      });
    })
&#13;
&#13;
&#13;

<强>概述:

您需要接受响应为纯二进制数据(ArrayBuffer)。大多数库都会将它作为字符串提供给您,这对于正常请求来说很酷,但对于二进制数据却很糟糕。

然后逐步浏览数据以查找多部分边界。

然后你在边界处分开。

获取您知道的边界索引是二进制数据

然后从ArrayBuffer中检索原始二进制文件。

在我的情况下,我将该二进制文件发送到扬声器,但是如果它是一个图像,您可以构建一个blob,从FileReader获取一个URL,然后将其设置为图像的源。