简体   繁体   中英

Asynchronous recursive functions in javascript

I am trying to stream mp3 data from my server to the client side. I am doing this using Ajax. The server sends 50 kilobytes per request. I wrote two functions: one that gets the mp3 data and one that plays them. The first function takes the 50 kilobytes, decodes them and stores the decoded data in an array then it calls itself recursively. The second function starts playing as soon as the first element in the array is filled with data. The problem is that this works for the first 50kilobytes only then it fails. What I want to do is keep my get_buffer function running until the server tells it no more data to send, and keep my play() function playing data until there is no more elements in the array.

Here is my two functions:

function buffer_seg() {
    // starts a new request
    buff_req = new XMLHttpRequest();

    // Request attributes
    var method = 'GET';
    var url = '/buffer.php?request=buffer&offset=' + offset;
    var async = true;

    // set attributes
    buff_req.open(method, url, async);
    buff_req.responseType = 'arraybuffer';

    // keeps loading until something is recieved
    if (!loaded) {
        change_icon();
        buffering = true;

    }


    buff_req.onload = function() {
        segment = buff_req.response;

        // if the whole file was already buffered
        if (segment.byteLength == 4) {
            return true;
        } else if (segment.byteLength == 3) {
            return false;
        }
        // sets the new offset
        if (offset == -1) {
            offset = BUFFER_SIZE;
        } else {
            offset += BUFFER_SIZE;
        }
        //decodes mp3 data and adds it to the array
        audioContext.decodeAudioData(segment, function(decoded) {
            buffer.push(decoded);
            debugger;
            if (index == 0) {
                play();
            }

        });


    }
    buff_req.send();
    buff_seg();
}

Second function:

function play() {

    // checks if the end of buffer has been reached
    if (index == buffer.length) {
        loaded = false;
        change_icon();
        if (buffer_seg == false) {
            stop();
            change_icon();
            return false;
        }
    }
    loaded = true;
    change_icon();

    // new buffer source
    var src = audioContext.createBufferSource();

    src.buffer = buffer[index++];

    // connects 
    src.connect(audioContext.destination);

    src.start(time);
    time += src.buffer.duration;
    src.onended = function() {
        src.disconnect(audioContext.destination);
        play();
    }

}

The recursive call to buffer_seg is in the main body of buffer_seg , not in the callback, so it happens immediately - not, as you seem to intend, after a response is received. Second, this also means that the recursive call is unconditional when it should be based on whether the previous response indicated more data would be available. If this isn't just crashing your browser, I'm not sure why. It also means that chunks of streamed audio could be pushed into the buffer out of order.

So to start I'd look at moving the recursive call to the end of the onload handler, after the check for end of stream.

In the 2nd function, what do you intend if (buffer_seg == false) to do? This condition will never be met. Are you thinking this is a way to see the last return value from buffer_seg ? That's not how it works. Perhaps you should have a variable that both functions can see, which buffer_seg can set and play can test, or something like that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM