| <!DOCTYPE html><!-- webkit-test-runner [ IPCTestingAPIEnabled=true ] --> |
| <html> |
| <head> |
| <script> |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| testRunner.waitUntilDone(); |
| testRunner.setUserMediaPermission(true); |
| } |
| |
| function done() { |
| document.body.textContent = "This test passes if it does not crash."; |
| if (window.testRunner) |
| testRunner.notifyDone(); |
| } |
| |
| function failTest(error) { |
| document.body.textContent = `Fail: ${error.message}`; |
| if (window.testRunner) |
| testRunner.notifyDone(); |
| } |
| |
| async function runTest() |
| { |
| if (!window.IPC) { |
| done(); |
| return; |
| } |
| |
| const { CoreIPC } = await import('./coreipc.js'); |
| |
| let stream; |
| try { |
| stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
| } catch (error) { |
| throw error; |
| } |
| |
| // Hardcoded ID chosen to be much larger than the WebProcess's |
| // RealtimeMediaSourceIdentifier monotonic counter could ever reach in a |
| // single layout-test session, avoiding collision with the id allocated |
| // for the getUserMedia() source above. |
| // |
| // WARNING: RealtimeMediaSourceIdentifier is a process-global monotonic |
| // counter (ObjectIdentifier::generate()) that is never reset across |
| // tests sharing a WebProcess (e.g. mac-wk2). A small hardcoded value |
| // like 100 will eventually collide with the id auto-allocated for the |
| // getUserMedia() source above once enough prior tests have advanced the |
| // counter, tripping ASSERT(!m_proxies.contains(id)) in |
| // UserMediaCaptureManagerProxy::createMediaSourceForCaptureDeviceWithConstraints |
| // and crashing the GPU process on debug bots. Any future IPC test that |
| // hardcodes a RealtimeMediaSourceIdentifier must pick a value well above |
| // any plausible counter (and below the UINT64_MAX hash-traits sentinel). |
| const sourceId = 0xFFFFFFFFn; |
| |
| const emptyConstraintMap = { |
| m_width: {}, m_height: {}, m_sampleRate: {}, m_sampleSize: {}, |
| m_aspectRatio: {}, m_frameRate: {}, m_volume: {}, |
| m_echoCancellation: {}, m_displaySurface: {}, m_logicalSurface: {}, |
| m_facingMode: {}, m_deviceId: {}, m_groupId: {}, m_whiteBalanceMode: {}, |
| m_zoom: {}, m_torch: {}, m_backgroundBlur: {}, m_powerEfficient: {} |
| }; |
| |
| let timer; |
| await new Promise((resolve, reject) => { |
| CoreIPC.GPU.UserMediaCaptureManagerProxy.CreateMediaSourceForCaptureDeviceWithConstraints(0, { |
| id: sourceId, |
| device: { |
| persistentId: '239c24b0-2b15-11e3-8224-0800200c9a66', |
| type: 2, |
| label: 'Mock audio device 1', |
| groupId: 'microphonegroup', |
| enabled: true, |
| isDefault: true, |
| isMockDevice: true, |
| isEphemeral: false |
| }, |
| hashSalts: { persistentDeviceSalt: 'a', ephemeralDeviceSalt: 'b' }, |
| constraints: { mandatoryConstraints: emptyConstraintMap, advancedConstraints: [], isValid: true }, |
| shouldUseGPUProcessRemoteFrames: false, |
| pageIdentifier: IPC.pageID |
| }, () => { |
| resolve(); |
| }); |
| |
| timer = setTimeout(() => reject(`Timed out waiting for CreateMediaSourceForCaptureDeviceWithConstraints`), 5000); |
| }); |
| clearTimeout(timer); |
| |
| CoreIPC.GPU.UserMediaCaptureManagerProxy.StartProducingData(0, { id: sourceId, pageIdentifier: IPC.pageID }); |
| |
| let count = 0; |
| const interval = setInterval(() => { |
| for (let i = 0; i < 10; i++) |
| CoreIPC.GPU.UserMediaCaptureManagerProxy.StartProducingData(0, { id: sourceId, pageIdentifier: IPC.pageID }); |
| if (++count > 20) { |
| clearInterval(interval); |
| stream.getTracks().forEach(t => t.stop()); |
| |
| // Tear down the GPU-side proxy we created via raw IPC so layout-test |
| // runs that share this WebProcess don't collide on the hardcoded sourceId. |
| CoreIPC.GPU.UserMediaCaptureManagerProxy.RemoveSource(0, { id: sourceId }); |
| done(); |
| } |
| }, 10); |
| } |
| |
| window.addEventListener('load', async event => { |
| runTest().catch((error) => { |
| failTest(error); |
| }); |
| }); |
| |
| </script> |
| </head> |
| <body> |
| </body> |
| </html> |