| <!doctype html> | |
| <meta charset=utf-8> | |
| <!-- This file contains a test that waits for 2 seconds. --> | |
| <meta name="timeout" content="long"> | |
| <title>captureTimestamp attribute in RTCRtpSynchronizationSource</title> | |
| <div><video id="remote" width="124" height="124" autoplay></video></div> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="/webrtc/RTCPeerConnection-helper.js"></script> | |
| <script src="/webrtc/RTCStats-helper.js"></script> | |
| <script src="/webrtc-extensions/RTCRtpSynchronizationSource-helper.js"></script> | |
| <script> | |
| 'use strict'; | |
| function listenForCaptureTimestamp(t, receiver) { | |
| return new Promise((resolve) => { | |
| function listen() { | |
| const ssrcs = receiver.getSynchronizationSources(); | |
| assert_true(ssrcs != undefined); | |
| if (ssrcs.length > 0) { | |
| assert_equals(ssrcs.length, 1); | |
| if (ssrcs[0].captureTimestamp != undefined) { | |
| resolve(ssrcs[0].captureTimestamp); | |
| return true; | |
| } | |
| } | |
| return false; | |
| }; | |
| t.step_wait(listen, 'No abs-capture-time capture time header extension.'); | |
| }); | |
| } | |
| // Passes if `getSynchronizationSources()` contains `captureTimestamp` if and | |
| // only if expected. | |
| for (const kind of ['audio', 'video']) { | |
| promise_test(async t => { | |
| const [caller, callee] = await initiateSingleTrackCall( | |
| t, /* caps= */{[kind]: true}, /* absCaptureTimeOffered= */false, | |
| /* absCaptureTimeAnswered= */false); | |
| const receiver = callee.getReceivers()[0]; | |
| for (const ssrc of await listenForSSRCs(t, receiver)) { | |
| assert_equals(typeof ssrc.captureTimestamp, 'undefined'); | |
| } | |
| }, '[' + kind + '] getSynchronizationSources() should not contain ' + | |
| 'captureTimestamp if absolute capture time RTP header extension is not ' + | |
| 'offered'); | |
| promise_test(async t => { | |
| const [caller, callee] = await initiateSingleTrackCall( | |
| t, /* caps= */{[kind]: true}, /* absCaptureTimeOffered= */false, | |
| /* absCaptureTimeAnswered= */false); | |
| const receiver = callee.getReceivers()[0]; | |
| for (const ssrc of await listenForSSRCs(t, receiver)) { | |
| assert_equals(typeof ssrc.captureTimestamp, 'undefined'); | |
| } | |
| }, '[' + kind + '] getSynchronizationSources() should not contain ' + | |
| 'captureTimestamp if absolute capture time RTP header extension is ' + | |
| 'offered, but not answered'); | |
| promise_test(async t => { | |
| const [caller, callee] = await initiateSingleTrackCall( | |
| t, /* caps= */{[kind]: true}, /* absCaptureTimeOffered= */true, | |
| /* absCaptureTimeAnswered= */true); | |
| const receiver = callee.getReceivers()[0]; | |
| await listenForCaptureTimestamp(t, receiver); | |
| }, '[' + kind + '] getSynchronizationSources() should contain ' + | |
| 'captureTimestamp if absolute capture time RTP header extension is ' + | |
| 'negotiated'); | |
| } | |
| // Passes if `captureTimestamp` for audio and video are comparable, which is | |
| // expected since the test creates a local peer connection between `caller` and | |
| // `callee`. | |
| promise_test(async t => { | |
| const [caller, callee] = await initiateSingleTrackCall( | |
| t, /* caps= */{audio: true, video: true}, | |
| /* absCaptureTimeOffered= */true, /* absCaptureTimeAnswered= */true); | |
| const receivers = callee.getReceivers(); | |
| assert_equals(receivers.length, 2); | |
| let captureTimestamps = [undefined, undefined]; | |
| const t0 = performance.now(); | |
| for (let i = 0; i < 2; ++i) { | |
| captureTimestamps[i] = await listenForCaptureTimestamp(t, receivers[i]); | |
| } | |
| const t1 = performance.now(); | |
| assert_less_than(Math.abs(captureTimestamps[0] - captureTimestamps[1]), | |
| t1 - t0); | |
| }, 'Audio and video RTCRtpSynchronizationSource.captureTimestamp are ' + | |
| 'comparable'); | |
| </script> |