Spela ljud (och video) i webbläsaren
Jag kommer i detta inlägget skriva om audio-elementet som finns i HTML5. Jag kommer även skriva lite om video-elementet eftersom de är så väldigt lika varandra.
<audio> och <video>
<audio> och <video> används för att spela ljud och video i webbläsaren,
utan att behöva använda plug-in som t.ex. Flash, och är en del av
HTML5 Embedded content.
Både <audio> och <video> stödjs av alla moderna webbläsare, och ända
tillbaka till Internet Explorer 9.
<audio> och <video> kan ha ett src-attribut eller en eller flera
<source>-element.
<audio src="fil.mp3" controls></audio>
<audio controls>
<source src="fil.mp3" type="audio/mpeg"></source>
<source src="fil.wav" type="audio/wav"></source>
</audio>Attribut
<audio> och <video> har några gemensamma attribut. Dessa kan även användas
i JS API:et som egenskaper.
<audio src="fil.mp3" autoplay></audio>är samma som:
var audio = new Audio();
audio.autoplay = true;
audio.src = "fil.mp3";
audio.load();src
Address till filen som ska spelas. Behövs inte anges, utan man kan istället
använda <source> innanför <audio> eller <video>. Det går att ange vilka
delar som ska spelas med hjälp av
Media Fragments URI.
<!-- Spela filen fil.mp3 -->
<audio src="fil.mp3"></audio>
<!-- Spela 10 sekunder från 20 sekunder in i filen -->
<audio src="fil.mp3#t=20,30"></audio>
<!-- Spela de första 30 minuterna -->
<audio src="fil.mp3#t=,00:30:00"></audio>
<!-- Börja spela en timme in i filen -->
<audio src="fil.mp3#t=01:00:00"></audio>Det går att ange flera <source>, och då kommer webbläsaren välja den första
som den klarar av att spelar. Om webbläsaren inte kan spela någon av dem kommer
det som inte är <source> eller <track> visas.
<audio controls>
<source src="fil.mp3" type="video/mpeg">
<source src="fil.wav" type="video/wav">
<p>Din webbläsare kan inte spela filen.</p>
</audio>crossorigin
Kan vara “anonymous” eller “use-credentials” och om inget anges är default-läget “No CORS”. Läs mer hos W3C.
preload
preload används för att bestämma hur mycket som ska laddas ner innan
användaren börjar spela videon/ljudet, och även hur filen ska laddas ner.
Giltiga värden för preload är:
nonebetyder att inget ska laddas ner innan användaren har klickat på play. Den bestämmer inte hur filen ska laddas ner när användaren har klickat på play.metadatabetyder att metadata ska laddas ner, bl.a. längd. Oftast betyder det även att början av filen ska laddas ner. När användaren har klickat på play kommer filen laddas ner så långsamt som möjligt utan att behöva pausa för att buffra, för att spara bandbredd.autoinnebär att både metadata och hela filen kan laddas ner direkt, utan att användaren ska behöva klicka på play.
Tom sträng är samma som auto, men om preload saknas rekomenderas metadata
i specifikationen. Chrome och Safari följer rekommendationen, men Firefox
använder auto.
autoplay
autoplay är ett boolean attribut som används för att bestämma om spelaren
automatiskt ska börja spela.
<!-- Spela automatiskt -->
<audio src="fil.mp3" autoplay></audio>
<audio src="fil.mp3" autoplay=autoplay></audio>
<audio src="fil.mp3" autoplay=""></audio>
<!-- Spela INTE automatiskt -->
<audio src="fil.mp3"></audio>loop
Boolean attributet loop startar om videon eller ljudet när det har spelats.
muted
Boolean attributet muted stänger av ljudet för vidoen eller ljudet.
controls
Om videon eller ljudet har boolean attributet loop kommer webbläsarens egna
controller visas. Det ser lite olika ut i olika webbläsare.

<video>-specifika attribut
<video> har ett par egna attribut.
poster — Bild som vissas innan videon är nerladdad och tillgänglig.
width och height — Används för att ändra storleket på videon.
Egenskaper
Alla attribut går att använda som egenskaper i API:et, men det finns även egenskaper som bara går att komma åt med API:et. Mycket är inte implementerat i webbläsarna än, med dessa är de jag tycker är viktigast.
currentTime
currentTime reprensenterar nuvarande position i sekunder. Kan även användas
för att ändra position.
duration
duration reprensenterar längden på videon eller ljudklippet. Om det inte
finns någon video eller ljud är duration NaN, och om det streamas är värdet
Inf (infinity).
networkState
networkState reprensenterar <audio>/<video> nuvarande tillstånd.
- 0 = NETWORK_EMPTY
- 1 = NETWORK_IDLE
- 2 = NETWORK_LOADING
- 3 = NETWORK_NO_SOURCE
playbackRate
playbackRate reprensenterar uppspelningshastigheten och kan även användas för
att ändra hastigheten. Kan även vara ett negativt värde för att spela
baklänges.
readyState
readyState reprensenterar hur mycket av filen som har laddats ner.
- 0 = HAVE_NOTHING
- 1 = HAVE_METADATA
- 2 = HAVE_CURRENT_DATA
- 3 = HAVE_FUTURE_DATA
- 4 = HAVE_ENOUGH_DATA
volume
volume reprensenterar volymen, och är ett värde mellan 0.0 och 1.0. Kan även
användas för att ändra volymen.
buffered, played och seekable
buffered reprensenterar vilka delar av filen som har laddats, played vilka
delar av filen som har spelats av användaren och seekable vilka delar av filen
som är tillgängliga (oftast hela filen om den inte streamas). buffered, played
och seekable returnerar alla tre ett TimeRanges-objekt.
TimeRanges är ett objekt som har en egenskap och två funktioner:
lengthär antalet tids-intervall.start(index)är hur många sekunder in i filen intervallet börjar.end(index)är hur många sekunder in i filen intervallet slutar.
Intervallen sorteras efter tid, och intervallet överlappas aldrig och börjar aldrig där ett annat intervall slutar, intervallet slås istället ihop till ett enda intervall.
Metoder
<audio> och <video> har bara ett fåtal metoder och de är ganska
självförklarande, play(), pause() och load() (laddar om filen).
Metoden canPlayType() kontrollerar om webbläsaren har stöd för ett visst
video-/ljud-format.
var audio = new Audio();
audio.canPlayType('audio/mpeg;codecs="mp3"');canPlayType() returnerar en tom sträng om webbläsaren inte kan spela formatet,
“probably” om webbläsaren vet att den kan spela formatet, annars returneras
“maybe”.
Events
abort när webbläsaren avbryter hämtandet av filen innan den är helt
nerladdad, men inte pga error. Då är det istället error-eventet eller
stalled när webbläsaren försöker hämta filen, men inte lyckas.
canplay när webbläsaren kan börja spela videon/ljudet och canplaythrough
när webbläsaren kan spela utan att behöva stanna för att buffra. När
webbläsaren behöver vänta på att filen buffras används eventet waiting och
playing när filen börjar spelas igen (och även när filen börjar spelas igen
efter att ha varit pausad).
ended när videon eller ljudet är slut.
var mp3s = [
'http://sverigesradio.se/topsy/ljudfil/5182870.mp3',
'http://sverigesradio.se/topsy/ljudfil/5180916.mp3',
'http://sverigesradio.se/topsy/ljudfil/2103136.mp3',
'http://sverigesradio.se/topsy/ljudfil/1642156.mp3',
'http://sverigesradio.se/topsy/ljudfil/5149820.mp3'
];
var audio = new Audio();
audio.addEventListener('ended', function () {
audio.src = mp3s.pop();
audio.play();
});loadstart när webbläsaren börjar ladda ner fil, loadedmetadata när metadata
är nerladdat och slutligen loadeddata när nuvarande del av filen är nerladdad.
progress när webbläsaren laddar ner filen.
var audio = new Audio('http://...');
audio.addEventListener('progress', function () {
var buffered = audio.buffered.end(audio.buffered.length - 1);
console.log("Buffered: " + (buffered / audio.duration * 100) + "%");
});seeking när användaren ändrar position i videon eller ljudet, och seeked
när användaren är färdig med att ändra position.
timeupdate när nuvarande position i videon eller ljudet ändras.
var secsToStr = function (time) {
if (isNaN(time)) { return '00:00'; }
var hour = '';
var min = Math.round(time / 60);
var sec = Math.round(time % 60);
if (min > 59) {
hour = Math.round(min / 60) + ':';
min = Math.round(min % 60);
}
return hour + (min < 10 ? '0' + min : min) + ':' + (sec < 10 ? '0' + sec : sec);
};
var audio = new Audio('http://...');
audio.addEventListener('timeupdate', function () {
console.log("Current time: " + secsToStr(audio.currentTime));
});Andra event är play, pause, durationchange, ratechange (hastighet),
volumechange och suspend när webbläsaren har slutat hämta filen.
<track>
<track>
används för att lägga till text till <audio> och <video> på angivna
ställen. Elementet har attributen:
kindanger vilken typ av text-track.- “subtitles” — Transkription eller översättning av dialog.
- “captions” — Transkription eller översättning av dialog, ljudeffekter och andra relevanta ljud. Användbart för när det är svårt att höra ljudet.
- “descriptions”
- “chapters”
- “metadata” — Visas inte av webbläsaren.
srcsrclangär textens språk.labelär titel som används när webbläsaren listar tracks.defaultär ett boolean attribute.
<video src="film.mp4">
<track kind="subtitles" src="film.en.vtt" label="EN">
<track kind="subtitles" src="film.sv.vtt" label="SV">
</video>WebVTT
WebVTT är ett format för att skapa tidsinställda textspår som fungerar
tillsammans med <track>. En WebVTT-fil måset vara UTF-8.
WEBVTT
1
00:02:32.893 --> 00:02:36.328
Fel, gör det igen!
2
00:02:37.123 --> 00:02:42.324
Om du inte äter ditt kött, kan du inte ha någon pudding.
Hur kan du ha någon pudding om du inte äter ditt kött?
3
00:02:42.343 --> 00:02:44.738
Du! Ja, du bakom cyckelskjulet, stå stilla kompis!Det finns mycket mer man kan göra. Mozilla Developer Network har mer information. Och även HTML5Rocks.
Web Audio API
Jag började läsa om Web Audio API
först idag, men jag tänkte ändå skriva lite om det eftersom det är ett väldigt
intressant API som det går att göra väldigt mycket med. Medans <audio> bara
kan användas för att spela ljud. Om du ska spela flera eller samma ljud samtidigt
som du vill spela vid en exakt tidpunkt, som i ett spel, fungerar <audio>
inte lika bra, du kan istället använda Web Audio API. Web Audio API låter dig
även använda effekter, generera, manipulera och analysera ljud.
Jag har tyvärr inte använt Web Audio API i min applikation, men jag tänkte visa ett par exempel på vad man kan göra med det. Jag kommer inte gå igenom det lika noga som jag gjorde med Audio-elementet. Jag rekommenderar att du läser HTML5Rocks introduktion till Web Audio API.
Spela ljud
Här använder jag AJAX, men du kan även använda Audio som källa till din buffer, och då kan du streama ljudet istället för att ladda ner hela ljudet innan du kan spela det.
var context = new AudioContext();
var loadSound = function (url, callback) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.addEventListener('load', function () {
context.decodeAudioData(request.response, callback);
});
request.send();
};
var playSound = function (buffer) {
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.start(0);
};decodeAudioData avkodar ljuddatan i ArrayBuffer:en, och returnerar ett
Promise-objekt, men det går även att använda en success- och error-callback.
createBufferSource skapar en AudioBufferSourceNode och sen tilldelas den
buffer som ska spelas. AudioNode:en måste kopplas samman med en annan
AudioNode, i detta fallet AudioDestinationNode (högtalaren). Till sist spelar
ljudet från början.
Generera ljud
Det går även att generera en buffer från kod och använda i en Node.
var context = new AudioContext();
var whiteNoise = function () {
var length = 2 * context.sampleRate;
var buffer = context.createBuffer(1, length, context.sampleRate);
var bufferData = buffer.getChannelData(0);
for (var i = 0; i < length; i += 1) {
bufferData[i] = (2 * Math.random() - 1);
}
return buffer;
};sampleRate är antalet frames (?) per sekund, och därför är två ggr det
värdet två sekunder. Alla noder i samma context har samma hastighet. Sen skapas
en buffer och dess data hämtas med getChannelData() som
PCM i en array.
Analysera ljud
var context = new AudioContext();
var audio = new Audio('http://...');
var source = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
source.connect(analyser);
analyser.connect(context.destination);I exemplet ovan skapas en
AnalyserNode
mellan ljudet och högtalarna. Jag har tyvärr inte hunnit testa AnalyserNode
mer än en väldigt kort stund, men jag lyckades ändå skapa ett ganska snyggt
demo.