2017-02-17 110 views
0

我想從我的服務器流到客戶端的MP3數據。我正在使用Ajax來做這件事。服務器每個請求發送50千字節。我寫了兩個函數:一個獲取mp3數據和一個播放它們。第一個函數需要50千字節,對它們進行解碼並將解碼數據存儲在一個數組中,然後遞歸地調用它自己。只要數組中的第一個元素填充數據,第二個函數就會開始播放。問題是,這隻適用於第一個50千字節,然後才失敗。我想要做的是保持我的get_buffer函數運行,直到服務器告訴它沒有更多的數據要發送,並保持我的play()函數播放數據,直到數組中沒有更多的元素。在javascript中的異步遞歸函數

這裏是我的兩個功能:

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(); 
} 

二級功能:

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(); 
    } 

} 

回答

0

buffer_seg的遞歸調用是在buffer_seg的主體,而不是在回調,所以它會立即發生 - 而不是像你打算的那樣,在收到答覆後。其次,這也意味着遞歸調用是無條件的,當它應該基於先前的響應是否指示更多的數據可用時。如果這不僅僅是瀏覽器崩潰,我不知道爲什麼。這也意味着大量的流式音頻可能會被無序地壓入緩衝區。

所以開始我會看看遞歸調用移動到onload處理程序的末尾,檢查流結束後。

在第二個函數中,你打算做什麼if (buffer_seg == false)?這種情況永遠不會得到滿足。您是否認爲這是查看buffer_seg的最後一個返回值的方法?這不是它的工作原理。也許你應該有一個變量,這兩個函數都可以看到,其中buffer_seg可以設置,play可以測試,或類似的東西。

+0

「offset」變量告訴服務器開始服務器發送mp3音頻的哪個字節。因此,如果將偏移量發送到文件末尾或文件結束後,服務器會回覆「已完成」。我檢查一下arraybuffer的大小是否等於4,而不是必須「完成」。然後它返回false。對不起,這是我的不好,它應該是(buffer_seg()== false)。當它到達數組的末尾時,它調用buffer_seg()函數來查看buffer_seg是否將緩衝新數據或返回false來指示EOF。謝謝你的回覆 –

+0

是的,我知道你打算抵消什麼。我不確定你爲什麼指出這一點;它不會改變您的代碼編寫過程中您的響應可能會失敗。另外,'(buffer_seg()== false)'不會更好,因爲調用'buffer_seg'永遠不會返回。無論如何,因爲你有'buffer_seg'自己調用,所以沒有'play'調用它的意思。 –

+0

是的,我同意你的觀點,我可以看到這可能導致腳本無法正常運行,我甚至已經糾正了一些這些問題。但是,對於如何編寫一個函數來保存流式數據並將其存儲在數組中以及讀取該數組並存儲它的另一個函數中,您是否有任何建議?或者任何想法如何緩衝MP3二進制數據,並在整個緩衝完成之前播放它? –