Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to play audio byte array (not file!) with JavaScript in a browser

Tags:

web

streaming

wav

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?

like image 682
M_bay Avatar asked Nov 04 '11 21:11

M_bay


3 Answers

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:

  • http://epx.com.br/artigos/audioapi.php
  • https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html

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

like image 107
Peter Lee Avatar answered Nov 04 '22 16:11

Peter Lee


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);
}
like image 38
breakspirit Avatar answered Nov 04 '22 15:11

breakspirit


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.

like image 1
Mike Avatar answered Nov 04 '22 17:11

Mike