context-time-monotonic-on-setsinkid.https.html (3655B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>currentTime and getOutputTimestamp().contextTime after setSinkId</title> 5 <meta name="flags" content="--use-fake-device-for-media-stream"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 </head> 9 <body> 10 <script> 11 promise_test(async t => { 12 // A timeout for waiting for the audio context to transition to a new state. 13 const TRANSITION_TIMEOUT = 250; 14 15 const context = new AudioContext(); 16 t.add_cleanup(() => context.close()); 17 await context.resume(); 18 19 // Let it run for a bit to ensure time values are advancing. 20 await new Promise(resolve => t.step_timeout(resolve, TRANSITION_TIMEOUT)); 21 22 const initialCurrentTime = context.currentTime; 23 const initialContextTime = context.getOutputTimestamp().contextTime; 24 assert_true( 25 initialCurrentTime > 0, 26 'Pre-check: currentTime should be > 0 after running for a while'); 27 assert_true( 28 initialContextTime > 0, 29 'Pre-check: contextTime should be > 0 after running for a while'); 30 31 const devices = await navigator.mediaDevices.enumerateDevices(); 32 const audioOutputDevices = devices.filter(d => d.kind === 'audiooutput'); 33 if (audioOutputDevices.length < 2) { 34 // This test requires at least two audio output devices. 35 assert_unreached( 36 'Not enough audio output devices to run this test. Need at least 2.'); 37 } 38 39 // Find a device that is not the current one. 40 const newDeviceId = 41 audioOutputDevices.find(d => d.deviceId !== context.sinkId)?.deviceId; 42 if (!newDeviceId) { 43 assert_unreached('Could not find a different device to switch to.'); 44 } 45 46 // Capture timestamps just before the switch. 47 const timeBeforeSetSinkId = context.currentTime; 48 const contextTimeBeforeSetSinkId = context.getOutputTimestamp().contextTime; 49 50 await context.setSinkId(newDeviceId); 51 52 // Capture timestamps immediately after the switch. 53 const timeAfterSetSinkId = context.currentTime; 54 const contextTimeAfterSetSinkId = context.getOutputTimestamp().contextTime; 55 56 // The time should not go backwards for either currentTime or contextTime. 57 assert_true( 58 timeAfterSetSinkId >= timeBeforeSetSinkId, 59 `currentTime should not go backwards after setSinkId. Before: ${ 60 timeBeforeSetSinkId}, after: ${timeAfterSetSinkId}`); 61 assert_true( 62 contextTimeAfterSetSinkId >= contextTimeBeforeSetSinkId, 63 `contextTime should not go backwards after setSinkId. Before: ${ 64 contextTimeBeforeSetSinkId}, after: ${contextTimeAfterSetSinkId}`); 65 66 // The time should not jump too far ahead. A small delta is expected for the 67 // device change while the context is running. 68 assert_true( 69 timeAfterSetSinkId - timeBeforeSetSinkId < 1, 70 `setSinkId took too long or currentTime jumped. Before: ${ 71 timeBeforeSetSinkId}, after: ${timeAfterSetSinkId}`); 72 73 // Let it run for a bit more to ensure it's still advancing. 74 await new Promise(resolve => t.step_timeout(resolve, TRANSITION_TIMEOUT)); 75 76 const finalCurrentTime = context.currentTime; 77 const finalContextTime = context.getOutputTimestamp().contextTime; 78 assert_true( 79 finalCurrentTime > timeAfterSetSinkId, 80 `currentTime should increase after setSinkId. After switch: ${ 81 timeAfterSetSinkId}, final: ${finalCurrentTime}`); 82 assert_true( 83 finalContextTime > contextTimeAfterSetSinkId, 84 `contextTime should increase after setSinkId. After switch: ${ 85 contextTimeAfterSetSinkId}, final: ${finalContextTime}`); 86 }, 'currentTime and getOutputTimestamp().contextTime should not reset after ' + 87 'setSinkId'); 88 </script> 89 </body> 90 </html>