| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>RTCPeerConnection Insertable Streams - Video</title> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src=/resources/testdriver.js></script> | |
| <script src=/resources/testdriver-vendor.js></script> | |
| <script src='../mediacapture-streams/permission-helper.js'></script> | |
| <script src="../webrtc/RTCPeerConnection-helper.js"></script> | |
| <script src="./RTCPeerConnection-insertable-streams.js"></script> | |
| </head> | |
| <body> | |
| <script> | |
| async function testVideoFlow(t, negotiationFunction) { | |
| const caller = new RTCPeerConnection({encodedInsertableStreams:true}); | |
| t.add_cleanup(() => caller.close()); | |
| const callee = new RTCPeerConnection({encodedInsertableStreams:true}); | |
| t.add_cleanup(() => callee.close()); | |
| await setMediaPermission("granted", ["camera"]); | |
| const stream = await navigator.mediaDevices.getUserMedia({video:true}); | |
| const videoTrack = stream.getVideoTracks()[0]; | |
| t.add_cleanup(() => videoTrack.stop()); | |
| const videoSender = caller.addTrack(videoTrack) | |
| const senderStreams = videoSender.createEncodedStreams(); | |
| const senderReader = senderStreams.readable.getReader(); | |
| const senderWriter = senderStreams.writable.getWriter(); | |
| const frameInfos = []; | |
| const numFramesPassthrough = 5; | |
| const numFramesReplaceData = 5; | |
| const numFramesModifyData = 5; | |
| const numFramesToSend = numFramesPassthrough + numFramesReplaceData + numFramesModifyData; | |
| const ontrackPromise = new Promise(resolve => { | |
| callee.ontrack = t.step_func(() => { | |
| const videoReceiver = callee.getReceivers().find(r => r.track.kind === 'video'); | |
| assert_not_equals(videoReceiver, undefined); | |
| const receiverStreams = | |
| videoReceiver.createEncodedStreams(); | |
| const receiverReader = receiverStreams.readable.getReader(); | |
| const receiverWriter = receiverStreams.writable.getWriter(); | |
| const maxFramesToReceive = numFramesToSend; | |
| let numVerifiedFrames = 0; | |
| for (let i = 0; i < maxFramesToReceive; i++) { | |
| receiverReader.read().then(t.step_func(result => { | |
| verifyNonstandardAdditionalDataIfPresent(result.value); | |
| if (frameInfos[numVerifiedFrames] && | |
| areFrameInfosEqual(result.value, frameInfos[numVerifiedFrames])) { | |
| numVerifiedFrames++; | |
| } else { | |
| // Receiving unexpected frames is an indication that | |
| // frames are not passed correctly between sender and receiver. | |
| assert_unreached("Incorrect frame received"); | |
| } | |
| if (numVerifiedFrames == numFramesToSend) | |
| resolve(); | |
| })); | |
| } | |
| }); | |
| }); | |
| exchangeIceCandidates(caller, callee); | |
| await negotiationFunction(caller, callee); | |
| // Pass frames as they come from the encoder. | |
| for (let i = 0; i < numFramesPassthrough; i++) { | |
| const result = await senderReader.read(); | |
| const metadata = result.value.getMetadata(); | |
| assert_true(containsVideoMetadata(metadata)); | |
| verifyNonstandardAdditionalDataIfPresent(result.value); | |
| frameInfos.push({ | |
| timestamp: result.value.timestamp, | |
| type: result.value.type, | |
| data: result.value.data, | |
| metadata: metadata, | |
| getMetadata() { return this.metadata; } | |
| }); | |
| senderWriter.write(result.value); | |
| } | |
| // Replace frame data with arbitrary buffers. | |
| for (let i = 0; i < numFramesReplaceData; i++) { | |
| const result = await senderReader.read(); | |
| const metadata = result.value.getMetadata(); | |
| assert_true(containsVideoMetadata(metadata)); | |
| const buffer = new ArrayBuffer(100); | |
| const int8View = new Int8Array(buffer); | |
| int8View.fill(i); | |
| result.value.data = buffer; | |
| frameInfos.push({ | |
| timestamp: result.value.timestamp, | |
| type: result.value.type, | |
| data: result.value.data, | |
| metadata: metadata, | |
| getMetadata() { return this.metadata; } | |
| }); | |
| senderWriter.write(result.value); | |
| } | |
| // Modify frame data. | |
| for (let i = 0; i < numFramesReplaceData; i++) { | |
| const result = await senderReader.read(); | |
| const metadata = result.value.getMetadata(); | |
| assert_true(containsVideoMetadata(metadata)); | |
| const int8View = new Int8Array(result.value.data); | |
| int8View.fill(i); | |
| frameInfos.push({ | |
| timestamp: result.value.timestamp, | |
| type: result.value.type, | |
| data: result.value.data, | |
| metadata: metadata, | |
| getMetadata() { return this.metadata; } | |
| }); | |
| senderWriter.write(result.value); | |
| } | |
| return ontrackPromise; | |
| } | |
| promise_test(async t => { | |
| return testVideoFlow(t, exchangeOfferAnswer); | |
| }, 'Frames flow correctly using insertable streams'); | |
| promise_test(async t => { | |
| return testVideoFlow(t, exchangeOfferAnswerReverse); | |
| }, 'Frames flow correctly using insertable streams when receiver starts negotiation'); | |
| </script> | |
| </body> | |
| </html> |