How to play audio byte array (not file!) with Java

2019-03-19 15:47发布

For mostly security reasons, I'm not allowed to store a WAV file on the server to be accessed by a browser. What I have is a byte array contains audio data (the data portion of a WAV file I believe) on the sever, and I want it to be played on a browser through JavaScript (or Applet but JS preferred), I can use JSON-PRC to send the whole byte[] over, or I can open a socket to stream it over, but in either case I don't know who to play the byte[] within the browser?

4条回答
地球回转人心会变
2楼-- · 2019-03-19 15:57

The following code will play the sine wave at 0.5 and 2.0. Call the function play_buffersource() in your button or anywhere you want.

Tested using Chrome with Web Audio flag enabled. For your case, all that you need to do is just to shuffle your audio bytes to the buf.

<script type="text/javascript">
const kSampleRate = 44100; // Other sample rates might not work depending on the your browser's AudioContext
const kNumSamples = 16834;
const kFrequency  = 440;
const kPI_2       = Math.PI * 2;

function play_buffersource() {
    if (!window.AudioContext) {
        if (!window.webkitAudioContext) {
            alert("Your browser sucks because it does NOT support any AudioContext!");
            return;
        }
        window.AudioContext = window.webkitAudioContext;
    }

    var ctx = new AudioContext();

    var buffer = ctx.createBuffer(1, kNumSamples, kSampleRate);
    var buf    = buffer.getChannelData(0);
    for (i = 0; i < kNumSamples; ++i) {
        buf[i] = Math.sin(kFrequency * kPI_2 * i / kSampleRate);
    }

    var node = ctx.createBufferSource(0);
    node.buffer = buffer;
    node.connect(ctx.destination);
    node.noteOn(ctx.currentTime + 0.5);

    node = ctx.createBufferSource(0);
    node.buffer = buffer;
    node.connect(ctx.destination);
    node.noteOn(ctx.currentTime + 2.0);
}
</script>

References:

If you need to resample the audio, you can use a JavaScript resampler: https://github.com/grantgalitz/XAudioJS

If you need to decode the base64 data, there are a lot of JavaScript base64 decoder: https://github.com/carlo/jquery-base64

查看更多
太酷不给撩
3楼-- · 2019-03-19 15:59

If you have the bytes on the server then I would suggest that you create some kind of handler on the server that will stream the bytes to the response as a wav file. This "file" would only be in memory on the server and not on disk. Then the browser can just handle it like a normal wav file. More details on the server stack would be needed to give more information on how this could be done in your environment.

查看更多
Root(大扎)
4楼-- · 2019-03-19 16:15

I suspect you can achieve this with HTML5 Audio API easily enough:

https://developer.mozilla.org/en/Introducing_the_Audio_API_Extension

This library might come in handy too, though I'm not sure if it reflects the latest browser behaviours:

https://github.com/jussi-kalliokoski/audiolib.js

查看更多
Viruses.
5楼-- · 2019-03-19 16:16

I accomplished this via the following code. I pass in a byte array containing the data from the wav file to the function playByteArray. My solution is similar to Peter Lee's, but I could not get his to work in my case (the output was garbled) whereas this solution works well for me. I verified that it works in Firefox and Chrome.

window.onload = init;
var context;    // Audio context
var buf;        // Audio buffer

function init() {
    if (!window.AudioContext) {
    if (!window.webkitAudioContext) {
        alert("Your browser does not support any AudioContext and cannot play back this audio.");
        return;
    }
        window.AudioContext = window.webkitAudioContext;
    }

    context = new AudioContext();
}

function playByteArray(byteArray) {

    var arrayBuffer = new ArrayBuffer(byteArray.length);
    var bufferView = new Uint8Array(arrayBuffer);
    for (i = 0; i < byteArray.length; i++) {
      bufferView[i] = byteArray[i];
    }

    context.decodeAudioData(arrayBuffer, function(buffer) {
        buf = buffer;
        play();
    });
}

// Play the loaded file
function play() {
    // Create a source node from the buffer
    var source = context.createBufferSource();
    source.buffer = buf;
    // Connect to the final output node (the speakers)
    source.connect(context.destination);
    // Play immediately
    source.start(0);
}
查看更多
登录 后发表回答