-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
webrtc: add setParameterOptions to sender.setParameters
adding a new RTCSetParameterOptions object which has a sequence of RTCEncodingOptions similar to WebCodecs VideoEncoderEncodeOptions https://w3c.github.io/webcodecs/#dictdef-videoencoderencodeoptions and its keyFrame flag. On the native side, this adds the request_key_frame flag to the RtpEncodingParameters. WebRTC CL: https://webrtc-review.googlesource.com/c/src/+/286741 Spec PRs: w3c/webrtc-pc#2885 w3c/webrtc-extensions#167 Chromestatus feature: https://chromestatus.com/feature/5161082937409536 BUG=chromium:1354101 Change-Id: I5bfe266eac5990b1921212babdee1af35edc4242
- Loading branch information
1 parent
d44d043
commit 9540005
Showing
1 changed file
with
94 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<!doctype html> | ||
<meta charset=utf-8> | ||
<meta name="timeout" content="long"> | ||
<title>RTCRtpSender.prototype.setParameters for generating keyFrames</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="RTCPeerConnection-helper.js"></script> | ||
<script> | ||
'use strict'; | ||
|
||
// https://w3c.github.io/webrtc-extensions/#rtcrtpsender-setparameters-keyframe | ||
|
||
async function waitForStats(t, pc, spatialLayer, minimumKeyFrames) { | ||
// return after 5 seconds. | ||
const startTime = performance.now(); | ||
while (true) { | ||
const report = await pc.getStats(); | ||
const stats = [...report.values()].find(({type, rid}) => type === 'outbound-rtp' && rid === spatialLayer); | ||
if (stats && stats.keyFramesEncoded >= minimumKeyFrames) { | ||
return stats; | ||
} | ||
await new Promise(r => t.step_timeout(r, 100)); | ||
if (performance.now() > startTime + 5000) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
promise_test(async t => { | ||
const pc1 = new RTCPeerConnection(); | ||
t.add_cleanup(() => pc1.close()); | ||
const pc2 = new RTCPeerConnection(); | ||
t.add_cleanup(() => pc2.close()); | ||
// Video must be small enough to reach a key frame of the right size immediately. | ||
const stream = await getNoiseStream({video: {width: 320, height: 160}}); | ||
t.add_cleanup(() => stream.getTracks().forEach(t => t.stop())); | ||
|
||
const sender = pc1.addTrack(stream.getTracks()[0], stream); | ||
exchangeIceCandidates(pc1, pc2); | ||
await exchangeOfferAnswer(pc1, pc2); | ||
|
||
const rid = undefined; | ||
const first_stats = await waitForStats(t, pc1, rid, 1); | ||
assert_true(!!first_stats); | ||
sender.setParameters(sender.getParameters(), { | ||
encodingOptions: [{keyFrame: true}], | ||
}); | ||
const second_stats = await waitForStats(t, pc1, rid, first_stats.keyFramesEncoded + 1); | ||
assert_true(!!second_stats); | ||
assert_greater_than(second_stats.keyFramesEncoded, first_stats.keyFramesEncoded); | ||
}, `setParameters() second argument can be used to trigger keyFrame generation`); | ||
|
||
promise_test(async t => { | ||
const pc1 = new RTCPeerConnection(); | ||
t.add_cleanup(() => pc1.close()); | ||
const pc2 = new RTCPeerConnection(); | ||
t.add_cleanup(() => pc2.close()); | ||
// Video must be small enough to reach a key frame of the right size immediately. | ||
const stream = await getNoiseStream({video: {width: 640, height: 360}}); | ||
t.add_cleanup(() => stream.getTracks().forEach(t => t.stop())); | ||
|
||
const {sender} = pc1.addTransceiver(stream.getTracks()[0], { | ||
streams: [stream], | ||
sendEncodings: [{rid: 0}, {rid: 1}], | ||
}); | ||
exchangeIceCandidates(pc1, pc2); | ||
await pc1.setLocalDescription(); | ||
await pc2.setRemoteDescription(pc1.localDescription); | ||
await pc2.setLocalDescription(); | ||
await pc1.setRemoteDescription({type: 'answer', sdp: pc2.localDescription.sdp + | ||
'a=rid:0 recv\r\n' + | ||
'a=rid:1 recv\r\n' + | ||
'a=simulcast:recv 0;1\r\n' | ||
}); | ||
|
||
const first_stats_l0 = await waitForStats(t, pc1, "0", 1); | ||
assert_true(!!first_stats_l0); | ||
const first_stats_l1 = await waitForStats(t, pc1, "1", 1); | ||
assert_true(!!first_stats_l1); | ||
|
||
// Generate a keyframe on the second layer. This may, depending on the encoder, force | ||
// a key frame on the first layer as well. | ||
sender.setParameters(sender.getParameters(), { | ||
encodingOptions: [{keyFrame: false}, {keyFrame: true}], | ||
}); | ||
const second_stats_l1 = await waitForStats(t, pc1, "1", first_stats_l1.keyFramesEncoded + 1); | ||
assert_true(!!second_stats_l1); | ||
assert_greater_than(second_stats_l1.keyFramesEncoded, first_stats_l1.keyFramesEncoded); | ||
|
||
const second_stats_l0 = await waitForStats(t, pc1, "0", first_stats_l0.keyFramesEncoded); | ||
assert_true(!!second_stats_l0); | ||
assert_greater_than_equal(second_stats_l0.keyFramesEncoded, first_stats_l0.keyFramesEncoded); | ||
}, `setParameters() second argument can be used to trigger keyFrame generation (simulcast)`); | ||
</script> |