2016-08-04 8 views
19

मैं एक क्रॉस-प्लेटफार्म वेब ऐप बना रहा हूं जहां सर्वर पर ऑडियो ऑन-द-फ्लाई उत्पन्न होता है और ब्राउज़र क्लाइंट पर स्ट्रीम किया जाता है, शायद एचटीएमएल 5 ऑडियो तत्व के माध्यम से। ब्राउज़र पर, मेरे पास जावास्क्रिप्ट-संचालित एनिमेशन होंगे जो निश्चित रूप से खेले गए ऑडियो के साथ समन्वयित होना चाहिए। "सटीक" का अर्थ है कि ऑडियो और एनीमेशन एक-दूसरे के दूसरे भाग में होना चाहिए, और उम्मीद है कि 250ms के भीतर (होंठ-सिंकिंग सोचें)। विभिन्न कारणों से, मैं सर्वर पर ऑडियो और एनीमेशन नहीं कर सकता और परिणामी वीडियो लाइव स्ट्रीम कर सकता हूं।एचटीएमएल 5 ऑडियो स्ट्रीमिंग: ठीक से विलंबता मापें?

आदर्श रूप से, सर्वर पर ऑडियो पीढ़ी और ब्राउज़र पर ऑडियो प्लेबैक के बीच बहुत कम या कोई विलंबता नहीं होगी, लेकिन मेरी समझ यह है कि विलंबता को नियंत्रित करना मुश्किल होगा और शायद 3-7 दूसरी श्रेणी में (ब्राउज़र -, पर्यावरण-, नेटवर्क- और चंद्रमा-निर्भर चरण)। मैं इसे संभाल सकता हूं, हालांकि, अगर मैं सही विलंब पर वास्तविक विलंबता को माप सकता हूं ताकि मेरा ब्राउज़र जावास्क्रिप्ट जानता हो कि उचित एनिमेटेड फ्रेम कब प्रस्तुत किया जाए।

तो, मुझे स्ट्रीमिंग सर्वर (आइसकास्ट?) में अपने हैंडिंग ऑडियो के बीच विलंबता को सटीक रूप से मापने की आवश्यकता है, और स्पीकर को होस्ट करने वाले कंप्यूटर पर स्पीकर से बाहर आने वाला ऑडियो। कुछ ब्लू-स्काई संभावनाएं:

  • जोड़ें मेटाडाटा ऑडियो स्ट्रीम के लिए, और खेल ऑडियो (मैं समझता हूँ कि इस मानक ऑडियो तत्व का उपयोग संभव नहीं है)

  • का संक्षिप्त अवधि के जोड़े से उसे पार्स ऑडियो के लिए शुद्ध चुप्पी, और फिर उन्हें ब्राउज़र पर पता लगाने (ऑडियो तत्वों वास्तविक ऑडियो नमूने उपज कर सकते हैं?)

  • क्वेरी सर्वर और विभिन्न बफर के रूप में ब्राउज़र गहराई

  • जावास्क्रिप्ट में स्ट्रीम किए गए ऑडियो को डीकोड करें और फिर मेटाडेटा

कोई विचार यह है कि मैं यह कैसे कर सकता हूं?

+1

मुझे नहीं लगता कि वहाँ अंतर को मापने के लिए एक रास्ता है, तो मैं आमतौर पर धारा ग्राहक का विश्लेषण WebAudioAPI का उपयोग कर ब्राउज़र में पक्ष। उस तकनीक का उपयोग करके आप एनीमेशन (उदाहरण के लिए तुल्यकारक) बना सकते हैं जो ब्राउज़र में खेले जाने वाले आइसकास्ट स्ट्रीम के साथ निकटता से संबंधित होगा। –

उत्तर

1

आपके लिए विलंबता को मापने के लिए कोई रास्ता नहीं है, लेकिन कोई भी ऑडियोइलेमेंट 'खेलना' जैसी घटनाएं उत्पन्न करता है अगर इसे अभी खेला जाता है (अक्सर रोक दिया जाता है), या स्ट्रीमिंग बंद होने पर 'रुका हुआ' या डेटा लोड होने पर 'प्रतीक्षा' होता है। तो आप क्या कर सकते हैं, इस घटना के आधार पर अपने वीडियो में हेरफेर करना है।

तो रुकने या प्रतीक्षा करने के दौरान खेलते समय खेलते हैं, फिर फिर से निकालकर वीडियो चलाते रहें।

लेकिन मुझे सलाह है कि आप अन्य घटनाओं की जांच करें जो आपके प्रवाह को प्रभावित कर सकती हैं (उदाहरण के लिए त्रुटि आपके लिए महत्वपूर्ण होगी)।

https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement

6

<audio> तत्व है, जो प्रति सेकंड तीन से चार बार गोली चलाई है timeupdate घटना का उपयोग, <audio> तत्व की .currentTime की जाँच करके मीडिया की स्ट्रीमिंग के दौरान सटीक एनिमेशन प्रदर्शन करने के लिए। जहां एनिमेशन या संक्रमण प्रति सेकंड कई बार शुरू या बंद किया जा सकता है।

तो ब्राउज़र पर उपलब्ध है, तो आप, ऑडियो संसाधन का अनुरोध करने के .then() वापसी response.body.getReader() जो संसाधन के एक ReadableStream रिटर्न पर fetch() उपयोग कर सकते हैं; एक नया MediaSource ऑब्जेक्ट बनाएं, MediaSource के <audio> या new Audio().srcobjectURL पर सेट करें; .read() परसे .mode"sequence" पर सेट किए गए पहले स्ट्रीम भाग को .read() पर अंकित करें। शेष हिस्सों को sourceBuffer पर sourceBufferupdateend ईवेंट पर संलग्न करें।

fetch() तो response.body.getReader() ब्राउज़र में उपलब्ध नहीं है, तब भी आप timeupdate या progress घटना <audio> तत्व की .currentTime जाँच, शुरू करने या मीडिया प्लेबैक स्ट्रीमिंग के लिए जरूरी दूसरे पर एनिमेशन या संक्रमण को रोकने के लिए उपयोग कर सकते हैं।

<audio> तत्व का उपयोग मीडिया चलाने के लिए करें जब स्ट्रीम ने MediaSource पर प्लेबैक के साथ आगे बढ़ने के लिए पर्याप्त बफर जमा किए हैं।

आप <audio> जहां एनीमेशन होने चाहिए की .currentTime करने के लिए इसी नंबर करने के लिए सेट गुण, और मूल्यों तत्व है जो सटीक एनिमेशन प्रदर्शन करने के लिए एनिमेटेड किया जाना चाहिए की css प्रॉपर्टी पर सेट के साथ एक वस्तु का उपयोग कर सकते हैं।

javascript पर, एनिमेशन प्रत्येक बीस दूसरी अवधि में होता है, 0 से शुरू होता है, और मीडिया प्लेबैक समाप्त होने तक हर साठ सेकंड में होता है।

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml">  
<head> 
    <meta charset="utf-8" /> 
    <title></title> 
    <style> 
    body { 
     width: 90vw; 
     height: 90vh; 
     background: #000; 
     transition: background 1s; 
    } 

    span { 
     font-family: Georgia; 
     font-size: 36px; 
     opacity: 0; 
    } 
    </style> 
</head> 

<body> 
    <audio controls></audio> 
    <br> 
    <span></span> 
    <script type="text/javascript"> 
    window.onload = function() { 
     var url = "/path/to/audio"; 
     // given 240 seconds total duration of audio 
     // 240/12 = 20 
     // properties correspond to `<audio>` `.currentTime`, 
     // values correspond to color to set at element 
     var colors = { 
     0: "red", 
     20: "blue", 
     40: "green", 
     60: "yellow", 
     80: "orange", 
     100: "purple", 
     120: "violet", 
     140: "brown", 
     160: "tan", 
     180: "gold", 
     200: "sienna", 
     220: "skyblue" 
     }; 
     var body = document.querySelector("body"); 
     var mediaSource = new MediaSource; 
     var audio = document.querySelector("audio"); 
     var span = document.querySelector("span"); 
     var color = window.getComputedStyle(body) 
        .getPropertyValue("background-color"); 
     //console.log(mediaSource.readyState); // closed 
     var mimecodec = "audio/mpeg"; 

     audio.oncanplay = function() { 
     this.play(); 
     } 

     audio.ontimeupdate = function() {   
     // 240/12 = 20 
     var curr = Math.round(this.currentTime); 

     if (colors.hasOwnProperty(curr)) { 
      // set `color` to `colors[curr]` 
      color = colors[curr] 
     } 
     // animate `<span>` every 60 seconds 
     if (curr % 60 === 0 && span.innerHTML === "") { 
      var t = curr/60; 
      span.innerHTML = t + " minute" + (t === 1 ? "" : "s") 
          + " of " + Math.round(this.duration)/60 
          + " minutes of audio"; 
      span.animate([{ 
       opacity: 0 
      }, { 
       opacity: 1 
      }, { 
       opacity: 0 
      }], { 
       duration: 2500, 
       iterations: 1 
      }) 
      .onfinish = function() { 
       span.innerHTML = "" 
      } 
     } 
     // change `background-color` of `body` every 20 seconds 
     body.style.backgroundColor = color; 
     console.log("current time:", curr 
        , "current background color:", color 
        , "duration:", this.duration); 
     } 
     // set `<audio>` `.src` to `mediaSource` 
     audio.src = URL.createObjectURL(mediaSource); 
     mediaSource.addEventListener("sourceopen", sourceOpen); 

     function sourceOpen(event) { 
     // if the media type is supported by `mediaSource` 
     // fetch resource, begin stream read, 
     // append stream to `sourceBuffer` 
     if (MediaSource.isTypeSupported(mimecodec)) { 
      var sourceBuffer = mediaSource.addSourceBuffer(mimecodec); 
      // set `sourceBuffer` `.mode` to `"sequence"` 
      sourceBuffer.mode = "sequence"; 

      fetch(url) 
      // return `ReadableStream` of `response` 
      .then(response => response.body.getReader()) 
      .then(reader => { 

      var processStream = (data) => { 
       if (data.done) { 
        return; 
       } 
       // append chunk of stream to `sourceBuffer` 
       sourceBuffer.appendBuffer(data.value); 
      } 
      // at `sourceBuffer` `updateend` call `reader.read()`, 
      // to read next chunk of stream, append chunk to 
      // `sourceBuffer` 
      sourceBuffer.addEventListener("updateend", function() { 
       reader.read().then(processStream); 
      }); 
      // start processing stream 
      reader.read().then(processStream); 
      // do stuff `reader` is closed, 
      // read of stream is complete 
      return reader.closed.then(() => { 
       // signal end of stream to `mediaSource` 
       mediaSource.endOfStream(); 
       return mediaSource.readyState; 
      }) 
      }) 
      // do stuff when `reader.closed`, `mediaSource` stream ended 
      .then(msg => console.log(msg)) 
     } 
     // if `mimecodec` is not supported by `MediaSource` 
     else { 
      alert(mimecodec + " not supported"); 
     } 
     }; 
    } 
    </script> 
</body> 
</html> 

plnkr http://plnkr.co/edit/fIm1Qp?p=preview

+0

@DanielGriscom यह भी देखें [मीडिया स्रोत एक्सटेंशन] (https://w3c.github.io/media-source/) – guest271314

0

क्या मैं पहली प्रक्रिया डेटा performance.now साथ एक टाइमस्टैम्प बनाने की है, की कोशिश करेंगे, और नए वेब रिकॉर्डर एपीआई के साथ एक ब्लॉब में यह रिकॉर्ड है।

वेब रिकॉर्डर उपयोगकर्ता को अपने ऑडियो कार्ड तक पहुंचने के लिए कहेंगे, यह आपके ऐप के लिए एक समस्या हो सकती है, लेकिन वास्तविक विलंबता प्राप्त करना अनिवार्य दिखता है।

जैसे ही यह किया गया, पीढ़ी और वास्तविक प्रतिपादन के बीच वास्तविक विलंबता को मापने के कई तरीके हैं। असल में, एक ध्वनि घटना।

आगे के संदर्भ और उदाहरण के लिए:

Recorder demo

https://github.com/mdn/web-dictaphone/

https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder_API/Using_the_MediaRecorder_API

संबंधित मुद्दे