Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #24 from fippo/replaceTrack
Browse files Browse the repository at this point in the history
add replaceTrack test
  • Loading branch information
henbos authored Mar 1, 2018
2 parents 1951157 + c04d347 commit 63a46f7
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/replaceTrack/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
button {
margin: 0 20px 0 0;
width: 83px;
}

button#hangupButton {
margin: 0;
}

video {
height: 225px;
margin: 0 0 20px 0;
vertical-align: top;
width: calc(50% - 12px);
}

video#localVideo {
margin: 0 20px 20px 0;
}

@media screen and (max-width: 400px) {
button {
width: 83px;
}

button {
margin: 0 11px 10px 0;
}


video {
height: 90px;
margin: 0 0 10px 0;
width: calc(50% - 7px);
}
video#localVideo {
margin: 0 10px 20px 0;
}

}
34 changes: 34 additions & 0 deletions src/replaceTrack/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<!--
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
-->
<html>
<head>
<title>ReplaceTrack</title>
<link rel="stylesheet" href="css/main.css" />
</head>

<body>

<div id="container">
<video id="localVideo" autoplay muted></video>
<video id="remoteVideo" autoplay></video>

<div>
<button id="startButton">Start</button>
<button id="callButton">Call</button>
<button id="restartButton">Restart video with replaceTrack</button>
<button id="muteButton" disabled>toggle audio with replaceTrack</button>
<button id="hangupButton">Hang Up</button>
</div>

</div>

<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
291 changes: 291 additions & 0 deletions src/replaceTrack/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
'use strict';

function trace(arg) {
var now = (window.performance.now() / 1000).toFixed(3);
console.log(now + ': ', arg);
}

var startButton = document.getElementById('startButton');
var callButton = document.getElementById('callButton');
var hangupButton = document.getElementById('hangupButton');
var restartButton = document.getElementById('restartButton');
var muteButton = document.querySelector('button#muteButton');
callButton.disabled = true;
hangupButton.disabled = true;
restartButton.disabled = true;
startButton.onclick = start;
callButton.onclick = call;
hangupButton.onclick = hangup;
restartButton.onclick = restartVideo;
muteButton.onclick = toggleMute;

var supportsReplaceTrack =('RTCRtpSender' in window &&
'replaceTrack' in RTCRtpSender.prototype);

var startTime;
var localVideo = document.getElementById('localVideo');
var remoteVideo = document.getElementById('remoteVideo');

localVideo.addEventListener('loadedmetadata', function() {
trace('Local video videoWidth: ' + this.videoWidth +
'px, videoHeight: ' + this.videoHeight + 'px');
});

remoteVideo.addEventListener('loadedmetadata', function() {
trace('Remote video videoWidth: ' + this.videoWidth +
'px, videoHeight: ' + this.videoHeight + 'px');
});

remoteVideo.onresize = function() {
trace('Remote video size changed to ' +
remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight);
// We'll use the first onsize callback as an indication that video has started
// playing out.
if (startTime) {
var elapsedTime = window.performance.now() - startTime;
trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
startTime = null;
}
};

var localStream;
var pc1;
var pc2;
var offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};

function getName(pc) {
return (pc === pc1) ? 'pc1' : 'pc2';
}

function getOtherPc(pc) {
return (pc === pc1) ? pc2 : pc1;
}

function gotStream(stream) {
trace('Received local stream');
localVideo.srcObject = stream;
localStream = stream;
callButton.disabled = false;
}

function start() {
trace('Requesting local stream');
startButton.disabled = true;
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
}

function call() {
callButton.disabled = true;
hangupButton.disabled = false;
restartButton.disabled = !supportsReplaceTrack;
muteButton.disabled = !supportsReplaceTrack;

startTime = window.performance.now();
var videoTracks = localStream.getVideoTracks();
var audioTracks = localStream.getAudioTracks();
if (videoTracks.length > 0) {
trace('Using video device: ' + videoTracks[0].label);
}
if (audioTracks.length > 0) {
trace('Using audio device: ' + audioTracks[0].label);
}
var servers = null;
pc1 = new RTCPeerConnection(servers);
trace('Created local peer connection object pc1');
pc1.onicecandidate = function(e) {
onIceCandidate(pc1, e);
};
pc2 = new RTCPeerConnection(servers);
trace('Created remote peer connection object pc2');
pc2.onicecandidate = function(e) {
onIceCandidate(pc2, e);
};
pc1.oniceconnectionstatechange = function(e) {
onIceStateChange(pc1, e);
};
pc2.oniceconnectionstatechange = function(e) {
onIceStateChange(pc2, e);
};
pc2.ontrack = gotRemoteStream;

localStream.getTracks().forEach(
function(track) {
pc1.addTrack(
track,
localStream
);
}
);
trace('Added local stream to pc1');

trace('pc1 createOffer start');
pc1.createOffer(
offerOptions
).then(
onCreateOfferSuccess,
onCreateSessionDescriptionError
);
}

function onCreateSessionDescriptionError(error) {
trace('Failed to create session description: ' + error.toString());
}

function onCreateOfferSuccess(desc) {
trace('Offer from pc1\n' + desc.sdp);
trace('pc1 setLocalDescription start');
pc1.setLocalDescription(desc).then(
function() {
onSetLocalSuccess(pc1);
},
onSetSessionDescriptionError
);
trace('pc2 setRemoteDescription start');
pc2.setRemoteDescription(desc).then(
function() {
onSetRemoteSuccess(pc2);
},
onSetSessionDescriptionError
);
trace('pc2 createAnswer start');
// Since the 'remote' side has no media stream we need
// to pass in the right constraints in order for it to
// accept the incoming offer of audio and video.
pc2.createAnswer().then(
onCreateAnswerSuccess,
onCreateSessionDescriptionError
);
}

function onSetLocalSuccess(pc) {
trace(getName(pc) + ' setLocalDescription complete');
}

function onSetRemoteSuccess(pc) {
trace(getName(pc) + ' setRemoteDescription complete');
}

function onSetSessionDescriptionError(error) {
trace('Failed to set session description: ' + error.toString());
}

function gotRemoteStream(e) {
if (remoteVideo.srcObject !== e.streams[0]) {
remoteVideo.srcObject = e.streams[0];
trace('pc2 received remote stream');
}
}

function onCreateAnswerSuccess(desc) {
trace('Answer from pc2:\n' + desc.sdp);
trace('pc2 setLocalDescription start');
pc2.setLocalDescription(desc).then(
function() {
onSetLocalSuccess(pc2);
},
onSetSessionDescriptionError
);
trace('pc1 setRemoteDescription start');
pc1.setRemoteDescription(desc).then(
function() {
onSetRemoteSuccess(pc1);
},
onSetSessionDescriptionError
);
}

function onIceCandidate(pc, event) {
getOtherPc(pc).addIceCandidate(event.candidate)
.then(
function() {
onAddIceCandidateSuccess(pc);
},
function(err) {
onAddIceCandidateError(pc, err);
}
);
trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ?
event.candidate.candidate : '(null)'));
}

function onAddIceCandidateSuccess(pc) {
trace(getName(pc) + ' addIceCandidate success');
}

function onAddIceCandidateError(pc, error) {
trace(getName(pc) + ' failed to add ICE Candidate: ' + error.toString());
}

function onIceStateChange(pc, event) {
if (pc) {
trace(getName(pc) + ' ICE state: ' + pc.iceConnectionState);
console.log('ICE state change event: ', event);
}
}

function hangup() {
trace('Ending call');
pc1.close();
pc2.close();
pc1 = null;
pc2 = null;
hangupButton.disabled = true;
callButton.disabled = false;
}

// Stops and restarts the video with replaceTrack.
function restartVideo() {
localStream.getVideoTracks()[0].stop();
localStream.removeTrack(localStream.getVideoTracks()[0]);
window.setTimeout(function() {
navigator.mediaDevices.getUserMedia({video: true})
.then(function(stream) {
localStream.addTrack(stream.getVideoTracks()[0]);
var sender = pc1.getSenders().find(function(s) {
return s.track && s.track.kind === 'video';
});
return sender.replaceTrack(stream.getVideoTracks()[0]);
})
.then(function() {
console.log('Replaced video track');
})
.catch(function(err) {
console.error(err);
});
}, 5000);
}

// Toggles audio mute with replaceTrack(null/track)
function toggleMute() {
var sender = pc1.getSenders()[0];
var p;
if (!sender.track) {
trace('re-adding audio track');
p = sender.replaceTrack(localStream.getAudioTracks()[0]);
} else {
trace('replacing audio track with null');
p = sender.replaceTrack(null);
}
p.then(function() {
console.log('replaced track');
}).catch(function(err) {
console.error('during replaceTrack', err);
});
}

0 comments on commit 63a46f7

Please sign in to comment.