#javascript #synchronization #html5-video #html5-audio
#javascript #синхронизация #html5-видео #html5-аудио
Вопрос:
У меня есть два медиа-элемента:
<audio id="aud"></audio>
<video id="vid"></video>
Я прикрепил к ним обоим URL-адреса мультимедиа.
Затем я загружаю и воспроизводю их, выполняя audio.load()
и video.load()
, а затем audio.play()
и video.play()
в прослушивателе
audio.load();
video.load();
video.addEventListener("canplay", () => {
video.play();
});
audio.addEventListener("canplay", () => {
audio.play();
});
Оба начинают загружаться, сначала загружается аудио, а загрузка видео занимает около 1-2 секунд.
Когда они действительно начнут воспроизводиться, зависит от того, когда событие «canplay» запускается каждым медиа-элементом. (который запускается после загрузки, выполняется как минимум для пары кадров)
что я хочу сделать, так это вызывать audio.play()
AND video.play()
вместе ТОЛЬКО тогда, когда canplay
для них обоих запускается событие «». Как я могу этого добиться?
обратите внимание, что мне нужно использовать как аудио, так и видеоэлемент, и я пытаюсь добиться близкой, но не идеальной синхронизации при запуске.
вкратце: чего я хочу добиться, так это:
audio.load();
video.load();
// when video can "canplay" and when audio can "canplay" ONLY then
video.play();
audio.play();
Комментарии:
1. Не загружайте их одно за другим. Запустите audio.load(); затем запустите video.load() при загрузке аудио. триггер воспроизводится для обоих после загрузки видео. : audio.load(); audio.addEventListener(«canplay», () => { video.load(); }); video.addEventListener(«canplay», () => { audio.play(); video.play(); });
2. Когда вы хотите дождаться завершения многих асинхронных действий, вы используете
Promise.all
: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /…3. @AntiqTech ваш ответ, похоже, намного меньше, чем у других, есть ли в нем возможный недостаток? или это только для МОЕГО варианта использования, который, кажется, подходит идеально?
4. Я просто перестроил ваш код. Единственный недостаток, о котором я могу думать, это то, что «audio.load();» может вызвать исключение или что событие «canplay» по какой-то причине никогда не запускается, что нарушает поток. Я могу добавить это в качестве ответа, если вы хотите проголосовать за него.
Ответ №1:
Используйте глобальные флаги:
let audCanPlay=false;
let vidCanPlay=false;
function audPlay() {
audCanPlay=true;
console.log("audCanPlay=true");
if(vidCanPlay) playBoth();
}
function vidPlay() {
vidCanPlay=true;
console.log("vidCanPlay=true");
if(audCanPlay) playBoth();
}
function playBoth() {
console.log("audio.play();");
console.log("video.play();");
}
/* commented for demonstration
audio.addEventListener("canplay", audPlay);
video.addEventListener("canplay", vidPlay);
audio.load();
video.load();
*/
<audio id="aud"></audio>
<button id="audBtn" onclick="audPlay()">Mimic Audio canplay</button>
<video id="vid"></video>
<button id="vidBtn" onclick="vidPlay()">Mimic Video canplay</button>
Я думаю, что лучше добавить прослушиватели событий перед вызовом методов загрузки.
Я думаю, что лучше сделать это таким образом, вместо того, чтобы ждать завершения одного / canplay и только затем вызывать второе = экономит время / быстрее.
Комментарии:
1. прослушиватели событий лучше использовать перед загрузкой asin? поскольку мы не должны очищать прослушиватель после запуска функции, я буду вызывать метод okay много раз во время воспроизведения..
2. Я не знаю, как работают аудио и видео. вероятно:
let audio=document.getElementById("aud")
и аналогично для видео, затем:addEventListener
s, затем:load
.3. Что такое «метод okay»?
4. В функции
playBoth
вы можете добавить в конце:audCanPlay=false; vidCanPlay=false;
, и:audio.removeEventListener("canplay", audPlay); video.removeEventListener("canplay", vidPlay);
, но вам придется добавлять слушателей снова всякий раз, когда вы меняете источники. Я не знаю,canplay
срабатывает ли более одного раза для каждого источника — если это не так = я не понимаю, зачем удалять слушателей — просто снимите флаги (установленные наfalse
).5. См. canplay (и canplaythrough ). И HTMLMediaElement .
Ответ №2:
canplay
На ум приходят обещания, разрешенные событиями и объединенные с Promise.all
ожиданием нескольких событий.
Однако то, насколько сложной она должна быть, также зависит от того, насколько общей она должна быть. Для простого случая ожидания готовности к воспроизведению ровно одного видео и одного аудио я бы использовал только одно обещание и считал события по мере их поступления.
Обратите внимание, что для перехвата событий в элементах, которые извлекают файлы, небезопасно устанавливать src
href
атрибуты or перед добавлением прослушивателей событий.
Концептуальный код (непроверенный) для добавления слушателей, установки источников и возврата обещания, когда оба будут готовы:
const loadAV = (video, vidSrc, audio, audioSrc, timeout) {
let resolve, reject;
const p = new Promise( (r,j) => { resolve = r, reject = j};
let count = 0;
let timer;
const listenCanPlay = () => {
if( count == 2) {
resolve();
unListen();
}
};
const unListen = () => {
video.removeEventListener("canplay", listenCanPlay);
audio.removeEventListener("canplay", listenCanPlay);
if( timeout) {
clearTimeout(timer);
}
};
if( timeout) {
timer = setTimeout( ()=> {
if( count < 2) {
unListen();
reject( new Error(`loadAV timed out after ${timeout} msec`)
}
}, timeout);
}
video.addEventListener("canplay", listenCanPlay);
audio.addEventListener("canplay", listenCanPlay);
video.src = vidSrc;
audio.src = audioSrc;
return p;
}
который затем будет вызываться как
loadAV( video, video_url, audio, audio_url, 15000)
.then(()=>{ video.play(); audio.play()})
.catch(err=> console.log(err));
Комментарии:
1. Привет, спасибо за замечательный ответ, хотя не могли бы вы, пожалуйста, проверить комментарий к моему вопросу от AntiqTech? В чем недостаток этого использования, оно кажется довольно маленьким для работы..
2. @shriyanskapoor хорошо, что все просто. Если загрузка ресурсов последовательно приемлема с точки зрения производительности, то загрузка их таким образом потребует меньше кода. Следует включить обработку условий ошибки, и разрешение воспроизведения другой видео- и звуковой дорожки после завершения первой пары снова начнет усложнять ситуацию. Всего наилучшего в ваших начинаниях.