
Kako napraviti <audio> koji radi u Safariju?
Da biste napravili audio HTML5 tag, koji može da pušta zapise u Chrome pretraživaču na primer dovoljno je da napišete.
<audio src=’/putanja/do/fajla.wav’></audio>
Problem sa ovakvim remote učitavanjem fajla je što ne možete da prikažete odmah koliko vaš audio zapis traje, kao i da preskočimo negde na sredinu zapisa. Postoji bug koji nas sprečava da to uradimo, ali postoji način da rešimo taj problem.
const audioWithDurationLoaded = new Promise<HTMLAudioElement>((resolve, reject) => {
audio.addEventListener("loadedmetadata", () => {
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=642012
if (audio.duration === Infinity) {
audio.currentTime = Number.MAX_SAFE_INTEGER;
audio.ontimeupdate = () => {
audio.ontimeupdate = null;
resolve(audio);
audio.currentTime = 0;
};
}
// Normal behavior
else {
resolve(audio);
}
});
audio.onerror = (event) => reject(event);
});
Audio u gornjem isečku predstavlja referencu na HTML5 audio element koji smo kreirali. Audio element pravimo dinamički: const audio = document.createElement("audio");
Ovim ćemo rešiti problem u ostalim pretraživačima, međutim, Safari i dalje neće puštati audio zapis koji se ne nalazi na istom serveru kao vaša aplikacija. Lokalni Blob fajl koji biste kreirali u vašoj klijentskoj aplikaciji biste mogli da pustite, ali remote fajlovi bi ostali neučitani zbog načina na koji Safari učitava fajlove i pravi pozive na server.
Postoji rešenje za ovaj problem, a to je da dinamički napravimo i <source>
element kojem ćemo proslediti url do našeg audio zapisa. Od izuzetne je važnost da odredite tip zapisa PRE nego što postavite url.
const audio = document.createElement("audio");
const source = document.createElement("source");
source.type = "audio/wav";
audio.appendChild(source);
Da bi smo ostavili mogućnost da naš player pušta i zapise sa drugog servera, kao i audio zapise koje pravimo u našoj aplikaciji, source moramo setovati na dva načina:
source.src =
typeof blob === "string" || blob instanceof String
? (blob as string)
: window.URL.createObjectURL(blob);
Na kraju nam ostaje samo da vratimo naš novi audio element koji funkcioniše u svim pretraživačima.
Ceo kod:
export const getBlobPlayer = async (
blob: String
): Promise<HTMLAudioElement> => {
const audio = document.createElement("audio");
const source = document.createElement("source");
source.type = "audio/wav";
audio.appendChild(source);
const audioWithDurationLoaded = new Promise<HTMLAudioElement>((resolve, reject) => {
audio.addEventListener("loadedmetadata", () => {
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=642012
if (audio.duration === Infinity) {
audio.currentTime = Number.MAX_SAFE_INTEGER;
audio.ontimeupdate = () => {
audio.ontimeupdate = null;
resolve(audio);
audio.currentTime = 0;
};
}
// Normal behavior
else {
resolve(audio);
}
});
audio.onerror = (event) => reject(event);
});
source.src =
typeof blob === "string" || blob instanceof String
? (blob as string)
: window.URL.createObjectURL(blob);
return audioWithDurationLoaded;
}
Ako imate predlog kako možemo optimizovati kod, pišite u komentarima.