2013-12-18 41 views
5

Jak omówiono w artykule previous question, zbudowałem prototyp (za pomocą interfejsu API MVC, NAudio i NAudio.Lame), który przesyła na żywo dźwięk niskiej jakości po konwersji na format mp3. Źródłem strumienia jest PCM: 8K, 16-bit, mono i korzystam z tagu dźwiękowego html5.HTML5 <audio> zły wybór na transmisję na żywo?

Na zarówno Chrome i IE11 jest 15-34 sekund opóźnienie (latency wysokiej) przed dźwięku z przeglądarki, która, jak mi powiedziano, jest nie do przyjęcia dla użytkowników końcowych. Idealnie opóźnienie to nie więcej niż 5 sekund. Opóźnienie występuje nawet w przypadku użycia atrybutu preload = "none" w moim znaczniku audio.

Przyjrzyjmy się bliżej problemowi, wygląda na to, że obie przeglądarki: nie rozpoczną odtwarzania dźwięku, dopóki nie otrzymają ~ 32K danych dźwiękowych. Mając to na uwadze, mogę wpływać na opóźnienie, zmieniając ustawienie bitrate Lame'a MP3. Jeśli jednak zmniejszę opóźnienie (przesyłając więcej danych do przeglądarki o tę samą długość dźwięku), wprowadzę później przerwy audio.

Przykłady:

  • Jeśli za pomocą kodowania V0 lame za opóźnienie wynosi prawie 34 sekund co wymaga prawie 0.5 MB źródła dźwięku.
  • Jeśli używam kodowania Lame ABR_32, mogę zmniejszyć opóźnienie do 10-15 sekund, ale będę doświadczać przerw i przerw w sesji odsłuchowej.

Pytania:

  1. Wszelkie pomysły jak mogę zminimalizować opóźnienie rozruchu (latencji)?
  2. Czy powinienem dalej badać różne "presety" Lame'a w nadziei na wybranie "właściwego"?
  3. Czy to możliwe, że MP3 to , a nie najlepszy format na transmisję na żywo?
  4. Czy przejście na pomoc Ogg/Vorbis (lub Ogg/OPUS)?
  5. Czy potrzebujemy, aby porzucić znacznik dźwiękowy HTML5 i użyć Flasha lub apletu Java?

Dzięki.

Odpowiedz

4

Nie można zmniejszyć opóźnienia, ponieważ nie masz wpływu na kod przeglądarki i rozmiar bufora. Specyfikacja HTML5 nie wymusza żadnego ograniczenia, więc nie widzę powodu, dla którego miałaby się poprawić.

Można jednak zaimplementować rozwiązanie za pomocą interfejsu API webaudio (jest to dość proste), w którym samemu obsługuje się przesyłanie strumieniowe.

Jeśli możesz podzielić porcję MP3 w ustalonym rozmiarze (aby każdy rozmiar porcji MP3 był znany wcześniej lub przynajmniej w chwili odbioru), możesz transmitować na żywo w 20 liniach kodu. Rozmiar porcji będzie twoim opóźnieniem.

Kluczem jest użycie AudioContext :: decodeAudioData.

// Fix up prefixing 
window.AudioContext = window.AudioContext || window.webkitAudioContext; 
var context = new AudioContext(); 
var offset = 0; 
var byteOffset = 0; 
var minDecodeSize = 16384; // This is your chunk size 

var request = new XMLHttpRequest(); 
request.onprogress = function(evt) 
{ 
    if (request.response) 
    { 
     var size = request.response.length - byteOffset; 
     if (size < minDecodeSize) return; 
     // In Chrome, XHR stream mode gives text, not ArrayBuffer. 
     // If in Firefox, you can get an ArrayBuffer as is 
     var buf; 
     if (request.response instanceof ArrayBuffer) 
      buf = request.response; 
     else 
     { 
      ab = new ArrayBuffer(size); 
      buf = new Uint8Array(ab); 
      for (var i = 0; i < size; i++) 
       buf[i] = request.response.charCodeAt(i + byteOffset) & 0xff; 
     } 
     byteOffset = request.response.length; 
     context.decodeAudioData(ab, function(buffer) { 
      playSound(buffer); 
     }, onError); 
    } 
}; 
request.open('GET', url, true); 
request.responseType = expectedType; // 'stream' in chrome, 'moz-chunked-arraybuffer' in firefox, 'ms-stream' in IE 
request.overrideMimeType('text/plain; charset=x-user-defined'); 
request.send(null); 

function playSound(buffer) { 
    var source = context.createBufferSource(); // creates a sound source 
    source.buffer = buffer;     // tell the source which sound to play 
    source.connect(context.destination);  // connect the source to the context's destination (the speakers) 
    source.start(offset);       // play the source now 
              // note: on older systems, may have to use deprecated noteOn(time); 
    offset += buffer.duration; 
}