Reputation: 77
Let's say I would like to synchronize two videos and avoid echos. I meant that the two tracks should stay in sync as though playing a regular video file with audio.
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls=""></video><br>
<p>Current Time:<span id="aTime"></span></p><br>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls=""></video><br>
<p>Current Time:<span id="bTime"></span></p><br>
<button onclick="playM()">Play</button>
<button onclick="pauseM()">Pause</button>
<script>
var a = document.getElementById("A");
var b = document.getElementById("B");
function playM() {
a.play();
b.play();
}
function pauseM() {
a.pause();
b.pause();
}
a.ontimeupdate = function() {
document.getElementById("aTime").innerHTML = a.currentTime;
};
b.ontimeupdate = function() {
document.getElementById("bTime").innerHTML = b.currentTime;
};
a.onseeked = function() {
b.currentTime= a.currentTime;
};
b.onseeked = function() {
a.currentTime = b.currentTime;
};
</script>
Upvotes: 0
Views: 1111
Reputation: 43880
After some experimentation, I've discovered that the an offset of mere microseconds is great, but not really necessary for syncing videos. In Demo 2 we have video tag A and B. A has 4 eventListener()
and video B as the callback. play()
, pause()
, and seek
are synced between A and B with A being the "master" and B the "slave".
<!DOCTYPE html>
<html>
<head>
<style>
html {
font: 400 16px/1.5 Consolas
}
section {
display: flex;
justify-content: space-around;
width: 100%;
height: calc(100% - 160px);
}
button {
padding: 0;
border: 0;
}
</style>
</head>
<body>
<section>
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='240' height='135'></video>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='240' height='135'></video>
</section>
<script>
var A = document.getElementById("A");
var B = document.getElementById("B");
A.addEventListener("play", function() {
B.play();
});
A.addEventListener("pause", function() {
B.pause();
});
A.addEventListener("seeking", function() {
B.currentTime = A.currentTime;
});
A.addEventListener("seeked", function() {
B.currentTime = A.currentTime;
});
</script>
</body>
</html>
Promise
s which allows asynchronous operations but it's syntax is unintuitive and down right difficult. Fortunately async
and await
just got released in all major browsers* only a couple of months ago. All of the behavior and flow of Promise
s are in await
. Here's the basic syntax involved using 2 functions asynchronously:
async function functionName() {
var A = await functionA();
var B = await functionB();
var C = A + B;
return C;
}
References are at the bottom of post
/* For details on how this demo controls the <form>,
|| see HTMLFormControlsCollection in References
*/
var x = document.forms.ui.elements;
var playM = x.playM;
var pauseM = x.pauseM;
/* Register the buttons to the click event
|| callback is asyncCall()
|| Register a video tag to the ended event
|| callback is just an anonymous function to
|| display 'IDLE' message when the videos have ended
*/
/* Avoid the use of on event handlers, use event
|| listeners instead. For details on Event Listeners
|| see addEventListener() in References
*/
playM.addEventListener('click', asyncCall, false);
pauseM.addEventListener('click', asyncCall, false);
document.querySelector('video').addEventListener('ended', function(e) {
x.display.value = 'IDLE';
}, false);
/* This callback is an Async Function which uses a key
|| word called "await". await waits for a function
|| to start then moves on to the next await to
|| see when it's ready to start. The players are
|| playing asynchronously (i.e. congruently, i.e i.e. in
|| parallel). Normally JavaScript is synchronous because
|| the evaluation and execution of a function is the
|| only thing a browser would do, so everything else
|| had to wait their turn. That is called: "blocking".
|| While await is waiting, the browser is allowed to do
|| other processing. For details on async and await,
|| see References.
*/
async function asyncCall(e) {
var A = document.getElementById("A");
var B = document.getElementById("B");
var status;
/* if/if else condition to determin which button was
|| actually clicked. Use e.target to get the origin
|| of event (i.e. clicked button). For details on
|| Event.target, see References
*/
// if the button's #id is 'playM'...
if (e.target.id === 'playM') {
var mediaA = await mPlay(A);
x.outA.value = performance.now(mediaA);
var mediaB = await mPlay(B);
x.outB.value = performance.now(mediaB);
status = mPlay(B);
// otherwise if the button's #id is 'pauseM'...
} else if (e.target.id === 'pauseM') {
var mediaA = await mIdle(A);
x.outA.value = performance.now(mediaA);
var mediaB = await mIdle(B);
x.outB.value = performance.now(mediaB);
status = mIdle(B);
} else {
status = 'IDLE';
}
x.display.value = status;
return status;
}
// Simple function used in asyncCall() to play
function mPlay(ele) {
var state = 'PLAYING';
ele.play();
return state;
}
// Simple function used in asyncCall() to pause
function mIdle(ele) {
var state = 'IDLE';
ele.pause();
return state;
}
html {
font: 400 16px/1.5 Consolas
}
section {
display: flex;
justify-content: space-around;
width: 100%;
height: calc(100% - 160px);
}
button {
padding: 0;
border: 0;
}
#playM:before {
content: '▶';
font-size: 32px
}
#pauseM::before {
content: '⏸';
font-size: 32px;
}
<section>
<video id="A" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='160' height='90'></video>
<video id="B" src="http://media.w3.org/2010/05/sintel/trailer.webm" controls width='160' height='90'></video>
</section>
<form id='ui'>
<fieldset>
<legend>Asynchronous Playback</legend>
<button id='playM' type='button'></button>
<button id='pauseM' type='button'></button>
<output id='display'></output><br><br>
<label for='outA'>Source A: </label>
<output id='outA'></output><br><br>
<label for='outB'>Source B: </label>
<output id='outB'></output><br><br>
</fieldset>
</form>
Event.target
.addEventListener(
'event'
, function
, false
)
Upvotes: 2
Reputation: 1681
You can use plain JavaScript for this. A good starting point and reference would be W3C Schools. The currentTime
property with an oncuechange
function should get you started in checking changes in the timeline and seeking.
Although, I don't understand your restrictions (if any) so don't know why you wouldn't just use a video file with the audio and video already synced.
Upvotes: 1