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:
none
betyder 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.metadata
betyder 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.auto
innebä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:
kind
anger 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.
src
srclang
ä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.