examples/video_stream/viewer/client/index.js
/**
 * play an audio using web API based from number of samples needed
 * */
play an audio using web API based from number of samples needed
play an audio using web API based from number of samples needed
function playFront(count) {
    let bufferTime = 0.5;
    if (audio_buffer.length == 0 || count == 0 || audioContext == null) {
        appendLog("audio buffer ran out of data...");
        if(audioContext.state === 'running') {
            audioContext.suspend();
            nextTime = 0;
        }
        return;
    }
    if (audioContext.state === 'suspended') {
        audioContext.resume();
    }
    if(audioContext.state != "running")
        return;
    let audio_ts = timestamp_cache[0];
    if(sourceList.length > 0)
        audio_ts = sourceList[0].timestamp;
    let videoGap = (videoTimeStamp) - (audio_ts);
    let gap = HighResolutionClock_milliseconds(videoGap) / 1000;
    if(gap >= bufferTime) {
        let audio_tolerance = BigInt(0);
        let timestamp = videoTimeStamp - audio_tolerance;
        let index = -1;
        for (let i = 0; i < timestamp_cache.length; i++) {
            if (timestamp_cache[i] >= timestamp) {
                index = i;
                break;
            }
        }
        if(index != -1) {
            audio_buffer = audio_buffer.slice(index);
            timestamp_cache = timestamp_cache.slice(index);
        }
    }
    if(audio_buffer.length < samplingRate) {
        appendLog("not enough sound audio buffer to play, length = " + audio_buffer.length +
            " expected = " + samplingRate);
    }
    let nowBuffering = audio_buffer.slice(0, count);
    audio_buffer = audio_buffer.slice(count);
    timestamp_cache = timestamp_cache.slice(count);
    var newBuffer = audioContext.createBuffer(1, nowBuffering.length, samplingRate);
    newBuffer.getChannelData(0).set(nowBuffering);
    var newSource = audioContext.createBufferSource();
    newSource.buffer = newBuffer;
    newSource.connect(audioContext.destination);
    if(nextTime == 0) {
        nextTime = audioContext.currentTime + bufferTime;
    }
    newSource.start(nextTime);
    sourceList.push({
        source: newSource,
        timestamp : audio_ts
    });
    newSource.onended = ()=>{
        for(let s = 0; s < sourceList.length; s++) {
            if(sourceList[s].source == newSource) {
                sourceList.splice(s,1);
                break;
            }
        }
    };
    nextTime += newSource.buffer.duration;
}
function playFront ( count ) { let bufferTime = 0.5 ; if ( audio_buffer . length == 0 || count == 0 || audioContext == null ) { appendLog ( "audio buffer ran out of data..." ) ; if ( audioContext . state === 'running' ) { audioContext . suspend ( ) ; nextTime = 0 ; } return ; } if ( audioContext . state === 'suspended' ) { audioContext . resume ( ) ; } if ( audioContext . state != "running" ) return ; let audio_ts = timestamp_cache [ 0 ] ; if ( sourceList . length > 0 ) audio_ts = sourceList [ 0 ] . timestamp ; let videoGap = ( videoTimeStamp ) - ( audio_ts ) ; let gap = HighResolutionClock_milliseconds ( videoGap ) / 1000 ; if ( gap >= bufferTime ) { let audio_tolerance = BigInt ( 0 ) ; let timestamp = videoTimeStamp - audio_tolerance ; let index = - 1 ; for ( let i = 0 ; i < timestamp_cache . length ; i ++ ) { if ( timestamp_cache [ i ] >= timestamp ) { index = i ; break ; } } if ( index != - 1 ) { audio_buffer = audio_buffer . slice ( index ) ; timestamp_cache = timestamp_cache . slice ( index ) ; } } if ( audio_buffer . length < samplingRate ) { appendLog ( "not enough sound audio buffer to play, length = " + audio_buffer . length + " expected = " + samplingRate ) ; } let nowBuffering = audio_buffer . slice ( 0 , count ) ; audio_buffer = audio_buffer . slice ( count ) ; timestamp_cache = timestamp_cache . slice ( count ) ; var newBuffer = audioContext . createBuffer ( 1 , nowBuffering . length , samplingRate ) ; newBuffer . getChannelData ( 0 ) . set ( nowBuffering ) ; var newSource = audioContext . createBufferSource ( ) ; newSource . buffer = newBuffer ; newSource . connect ( audioContext . destination ) ; if ( nextTime == 0 ) { nextTime = audioContext . currentTime + bufferTime ; } newSource . start ( nextTime ) ; sourceList . push ( { source : newSource , timestamp : audio_ts } ) ; newSource . onended = ( ) => { for ( let s = 0 ; s < sourceList . length ; s ++ ) { if ( sourceList [ s ] . source == newSource ) { sourceList . splice ( s , 1 ) ; break ; } } } ; nextTime += newSource . buffer . duration ; }
play an audio using web API based from number of samples needed
play an audio using web API based from number of samples needed
/**
     * we buffer/forced latency for half a second
     * 500 millisecond is deducted to timestamp passed by server because of audio clock time delay during audio start
     * */ /**
     * HTML audio adds a click sound at the end of each audio if it does not reach sampling rate (samples per second)
     * producing a choppy sound.
     * main  cause is frontend single thread limitation, the video processing thread is eating the CPU time of the audio decoding and
     * filling up data when returning to main thread
     * */ /***
         * we let the hardware audio clock run for some time before we start playing
         * video should also sync with this
         * */