我正在浏览器中开发一个项目,该项目从服务器接收多部分响应。
响应的第一部分是一些 JSON 元数据
响应的第二部分是一个二进制 MP3 文件。
我需要一种方法从多部分响应中提取 MP3 文件并在 HTML 5 音频元素中播放它。
有人遇到过这种情况或类似的情况吗?
最佳答案
我最终解决了我的问题。我正在向将来需要这样做的任何人提供该问题和我的解决方案。
背景信息:
当我发出这个 ajax 请求时,我使用的是 AngularJS,但是 jquery ajax 和常规 xhr 的想法是相同的。
代码:
//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");
});
})
概述:
您需要接受纯二进制数据(ArrayBuffer)形式的响应。大多数库都会将其作为字符串提供给您,这对于正常请求来说很酷,但对于二进制数据来说却很糟糕。
然后您逐步浏览数据以找到多部分边界。
然后你们在边界处 split 。
获取已知的边界索引是二进制数据
然后从 ArrayBuffer 中检索原始二进制文件。
就我而言,我将该二进制文件发送到扬声器中,但是如果它是图像,您可以构建一个 blob,从 FileReader 获取一个 url,然后将其设置为图像源。
关于Javascript 二进制字符串转 MP3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31574033/