test_peerConnection_replaceTrack.html (7365B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 </head> 6 <body> 7 <pre id="test"> 8 <script type="application/javascript"> 9 createHTML({ 10 bug: "1032839", 11 title: "Replace video and audio (with WebAudio) tracks", 12 visible: true 13 }); 14 15 function allLocalStreamsHaveSender(pc) { 16 return pc.getLocalStreams() 17 .every(s => s.getTracks() // Every local stream, 18 .some(t => pc.getSenders() // should have some track, 19 .some(sn => sn.track == t))) // that's being sent over |pc|. 20 } 21 22 function allRemoteStreamsHaveReceiver(pc) { 23 return pc.getRemoteStreams() 24 .every(s => s.getTracks() // Every remote stream, 25 .some(t => pc.getReceivers() // should have some track, 26 .some(sn => sn.track == t))) // that's being received over |pc|. 27 } 28 29 function replacetest(wrapper) { 30 var pc = wrapper._pc; 31 var oldSenderCount = pc.getSenders().length; 32 var sender = pc.getSenders().find(sn => sn.track.kind == "video"); 33 var oldTrack = sender.track; 34 ok(sender, "We have a sender for video"); 35 ok(allLocalStreamsHaveSender(pc), 36 "Shouldn't have any local streams without a corresponding sender"); 37 ok(allRemoteStreamsHaveReceiver(pc), 38 "Shouldn't have any remote streams without a corresponding receiver"); 39 40 var newTrack; 41 var audiotrack; 42 return getUserMedia({video:true, audio:true}) 43 .then(newStream => { 44 window.grip = newStream; 45 newTrack = newStream.getVideoTracks()[0]; 46 audiotrack = newStream.getAudioTracks()[0]; 47 isnot(newTrack, sender.track, "replacing with a different track"); 48 ok(!pc.getLocalStreams().some(s => s == newStream), 49 "from a different stream"); 50 // Use wrapper function, since it updates expected tracks 51 return wrapper.senderReplaceTrack(sender, newTrack, newStream); 52 }) 53 .then(() => { 54 is(pc.getSenders().length, oldSenderCount, "same sender count"); 55 is(sender.track, newTrack, "sender.track has been replaced"); 56 ok(!pc.getSenders().map(sn => sn.track).some(t => t == oldTrack), 57 "old track not among senders"); 58 // Spec does not say we add this new track to any stream 59 ok(!pc.getLocalStreams().some(s => s.getTracks() 60 .some(t => t == sender.track)), 61 "track does not exist among pc's local streams"); 62 return sender.replaceTrack(audiotrack) 63 .then(() => ok(false, "replacing with different kind should fail"), 64 e => is(e.name, "TypeError", 65 "replacing with different kind should fail")); 66 }); 67 } 68 69 runNetworkTest(function () { 70 test = new PeerConnectionTest(); 71 test.audioCtx = new AudioContext(); 72 test.setMediaConstraints([{video: true, audio: true}], [{video: true}]); 73 test.chain.removeAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW"); 74 75 // Test replaceTrack on pcRemote separately since it's video only. 76 test.chain.append([ 77 function PC_REMOTE_VIDEOONLY_REPLACE_VIDEOTRACK(test) { 78 return replacetest(test.pcRemote); 79 }, 80 function PC_LOCAL_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) { 81 return test.pcLocal.waitForMediaFlow(); 82 } 83 ]); 84 85 // Replace video twice on pcLocal to make sure it still works 86 // (does audio twice too, but hey) 87 test.chain.append([ 88 function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_1(test) { 89 return replacetest(test.pcLocal); 90 }, 91 function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_1(test) { 92 return test.pcRemote.waitForMediaFlow(); 93 }, 94 function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_2(test) { 95 return replacetest(test.pcLocal); 96 }, 97 function PC_REMOTE_NEW_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW_2(test) { 98 return test.pcRemote.waitForMediaFlow(); 99 } 100 ]); 101 102 test.chain.append([ 103 function PC_LOCAL_AUDIOVIDEO_REPLACE_VIDEOTRACK_WITHSAME(test) { 104 var pc = test.pcLocal._pc; 105 var sender = pc.getSenders().find(sn => sn.track.kind == "video"); 106 ok(sender, "should still have a sender of video"); 107 return sender.replaceTrack(sender.track) 108 .then(() => ok(true, "replacing with itself should succeed")); 109 }, 110 function PC_REMOTE_NEW_SAME_VIDEOTRACK_WAIT_FOR_MEDIA_FLOW(test) { 111 return test.pcRemote.waitForMediaFlow(); 112 } 113 ]); 114 115 // Replace the gUM audio track on pcLocal with a WebAudio track. 116 test.chain.append([ 117 function PC_LOCAL_AUDIOVIDEO_REPLACE_AUDIOTRACK_WEBAUDIO(test) { 118 var pc = test.pcLocal._pc; 119 var sender = pc.getSenders().find(sn => sn.track.kind == "audio"); 120 ok(sender, "track has a sender"); 121 var oldSenderCount = pc.getSenders().length; 122 var oldTrack = sender.track; 123 124 var sourceNode = test.audioCtx.createOscillator(); 125 sourceNode.type = 'sine'; 126 // We need a frequency not too close to the fake audio track (1kHz). 127 sourceNode.frequency.value = 2000; 128 sourceNode.start(); 129 130 var destNode = test.audioCtx.createMediaStreamDestination(); 131 sourceNode.connect(destNode); 132 var newTrack = destNode.stream.getAudioTracks()[0]; 133 134 return test.pcLocal.senderReplaceTrack( 135 sender, newTrack, destNode.stream) 136 .then(() => { 137 is(pc.getSenders().length, oldSenderCount, "same sender count"); 138 ok(!pc.getSenders().some(sn => sn.track == oldTrack), 139 "Replaced track should be removed from senders"); 140 // TODO: Should PC remove local streams when there are no senders 141 // associated with it? getLocalStreams() isn't in the spec anymore, 142 // so I guess it is pretty arbitrary? 143 is(sender.track, newTrack, "sender.track has been replaced"); 144 // Spec does not say we add this new track to any stream 145 ok(!pc.getLocalStreams().some(s => s.getTracks() 146 .some(t => t == sender.track)), 147 "track exists among pc's local streams"); 148 }); 149 } 150 ]); 151 test.chain.append([ 152 function PC_LOCAL_CHECK_WEBAUDIO_FLOW_PRESENT(test) { 153 return test.pcRemote.checkReceivingToneFrom(test.audioCtx, test.pcLocal); 154 } 155 ]); 156 test.chain.append([ 157 function PC_LOCAL_INVALID_ADD_VIDEOTRACKS(test) { 158 let videoTransceivers = test.pcLocal._pc.getTransceivers() 159 .filter(transceiver => { 160 return !transceiver.stopped && 161 transceiver.receiver.track.kind == "video" && 162 transceiver.sender.track; 163 }); 164 165 ok(videoTransceivers.length, 166 "There is at least one non-stopped video transceiver with a track."); 167 168 videoTransceivers.forEach(transceiver => { 169 var stream = test.pcLocal._pc.getLocalStreams()[0];; 170 var track = transceiver.sender.track; 171 try { 172 test.pcLocal._pc.addTrack(track, stream); 173 ok(false, "addTrack existing track should fail"); 174 } catch (e) { 175 is(e.name, "InvalidAccessError", 176 "addTrack existing track should fail"); 177 } 178 }); 179 } 180 ]); 181 return test.run(); 182 }); 183 </script> 184 </pre> 185 </body> 186 </html>