Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1032839",
title: "Replace video and audio (with WebAudio) tracks",
visible: true
});
function allLocalStreamsHaveSender(pc) {
return pc.getLocalStreams()
.every(s => s.getTracks() // Every local stream,
.some(t => pc.getSenders() // should have some track,
.some(sn => sn.track == t))) // that's being sent over |pc|.
}
function allRemoteStreamsHaveReceiver(pc) {
return pc.getRemoteStreams()
.every(s => s.getTracks() // Every remote stream,
.some(t => pc.getReceivers() // should have some track,
.some(sn => sn.track == t))) // that's being received over |pc|.
}
function replacetest(wrapper) {
var pc = wrapper._pc;
var oldSenderCount = pc.getSenders().length;
var sender = pc.getSenders().find(sn => sn.track.kind == "video");
var oldTrack = sender.track;
ok(sender, "We have a sender for video");
ok(allLocalStreamsHaveSender(pc),
"Shouldn't have any local streams without a corresponding sender");
ok(allRemoteStreamsHaveReceiver(pc),
"Shouldn't have any remote streams without a corresponding receiver");
var newTrack;
var audiotrack;
return getUserMedia({video:true, audio:true})
.then(newStream => {
window.grip = newStream;
newTrack = newStream.getVideoTracks()[0];
audiotrack = newStream.getAudioTracks()[0];
isnot(newTrack, sender.track, "replacing with a different track");
ok(!pc.getLocalStreams().some(s => s == newStream),
"from a different stream");
// Use wrapper function, since it updates expected tracks
return wrapper.senderReplaceTrack(sender, newTrack, newStream);
})
.then(() => {
is(pc.getSenders().length, oldSenderCount, "same sender count");
is(sender.track, newTrack, "sender.track has been replaced");
ok(!pc.getSenders().map(sn => sn.track).some(t => t == oldTrack),
"old track not among senders");
// Spec does not say we add this new track to any stream
ok(!pc.getLocalStreams().some(s => s.getTracks()
.some(t => t == sender.track)),
"track does not exist among pc's local streams");
return sender.replaceTrack(audiotrack)
.then(() => ok(false, "replacing with different kind should fail"),
e => is(e.name, "TypeError",
"replacing with different kind should fail"));
});
}
runNetworkTest(function () {
test = new PeerConnectionTest();
test.audioCtx = new AudioContext();
test.setMediaConstraints([{video: true, audio: true}], [{video: true}]);
test.chain.removeAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW");
// Test replaceTrack on pcRemote separately since it's video only.
test.chain.append([
function PC_REMOTE_VIDEOONLY_REPLACE_VIDEOTRACK(test) {
return replacetest(test.pcRemote);
},
function PC_LOCAL_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) {
return test.pcLocal.waitForMediaFlow();
}
]);
// Replace video twice on pcLocal to make sure it still works
// (does audio twice too, but hey)
test.chain.append([
function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_1(test) {
return replacetest(test.pcLocal);
},
function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_1(test) {
return test.pcRemote.waitForMediaFlow();
},
function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_2(test) {
return replacetest(test.pcLocal);
},
function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_2(test) {
return test.pcRemote.waitForMediaFlow();
}
]);
test.chain.append([
function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_WITHSAME(test) {
var pc = test.pcLocal._pc;
var sender = pc.getSenders().find(sn => sn.track.kind == "video");
ok(sender, "should still have a sender of video");
return sender.replaceTrack(sender.track)
.then(() => ok(true, "replacing with itself should succeed"));
},
function PC_REMOTE_NEW_SAME_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) {
return test.pcRemote.waitForMediaFlow();
}
]);
// Replace the gUM audio track on pcLocal with a WebAudio track.
test.chain.append([
function PC_LOCAL_AUDIOVIDEO_REPLACE_AUDIOTRACK_WEBAUDIO(test) {
var pc = test.pcLocal._pc;
var sender = pc.getSenders().find(sn => sn.track.kind == "audio");
ok(sender, "track has a sender");
var oldSenderCount = pc.getSenders().length;
var oldTrack = sender.track;
var sourceNode = test.audioCtx.createOscillator();
sourceNode.type = 'sine';
// We need a frequency not too close to the fake audio track (1kHz).
sourceNode.frequency.value = 2000;
sourceNode.start();
var destNode = test.audioCtx.createMediaStreamDestination();
sourceNode.connect(destNode);
var newTrack = destNode.stream.getAudioTracks()[0];
return test.pcLocal.senderReplaceTrack(
sender, newTrack, destNode.stream)
.then(() => {
is(pc.getSenders().length, oldSenderCount, "same sender count");
ok(!pc.getSenders().some(sn => sn.track == oldTrack),
"Replaced track should be removed from senders");
// TODO: Should PC remove local streams when there are no senders
// associated with it? getLocalStreams() isn't in the spec anymore,
// so I guess it is pretty arbitrary?
is(sender.track, newTrack, "sender.track has been replaced");
// Spec does not say we add this new track to any stream
ok(!pc.getLocalStreams().some(s => s.getTracks()
.some(t => t == sender.track)),
"track exists among pc's local streams");
});
}
]);
test.chain.append([
function PC_LOCAL_CHECK_WEBAUDIO_FLOW_PRESENT(test) {
return test.pcRemote.checkReceivingToneFrom(test.audioCtx, test.pcLocal);
}
]);
test.chain.append([
function PC_LOCAL_INVALID_ADD_VIDEOTRACKS(test) {
let videoTransceivers = test.pcLocal._pc.getTransceivers()
.filter(transceiver => {
return !transceiver.stopped &&
transceiver.receiver.track.kind == "video" &&
transceiver.sender.track;
});
ok(videoTransceivers.length,
"There is at least one non-stopped video transceiver with a track.");
videoTransceivers.forEach(transceiver => {
var stream = test.pcLocal._pc.getLocalStreams()[0];;
var track = transceiver.sender.track;
try {
test.pcLocal._pc.addTrack(track, stream);
ok(false, "addTrack existing track should fail");
} catch (e) {
is(e.name, "InvalidAccessError",
"addTrack existing track should fail");
}
});
}
]);
return test.run();
});
</script>
</pre>
</body>
</html>