<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test passing capture device IDs to getUserMedia</title>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script>
    let deviceIds = [];

    if (window.testRunner)
        testRunner.setUserMediaPermission(true);

    promise_test(async (test) => {
        const devices = await navigator.mediaDevices.enumerateDevices();
        assert_true(devices.length <= 2, "before getting permission, at most 1 camera and 1 microphone are exposed");
        devices.forEach((device) => {
            assert_true(device.deviceId.length == 0 , "device.deviceId is empty before permission to capture");
        });
    }, "Device IDs should be empty initially");

    promise_test((test) => {
        return navigator.mediaDevices.getUserMedia({ audio:true, video:true })
            .then((stream) => {
                return navigator.mediaDevices.enumerateDevices();
            }).then(devices => {
                devices.forEach((device) => {
                    if (device.kind == "audiooutput")
                        return;
                    let kind = device.kind == "audioinput" ? "audio" : "video";
                    deviceIds.push({ type: kind, id : device.deviceId});
                });
            });
    }, "Collect device IDs");

    let constraints = { };

    promise_test((test) => {
        deviceIds.forEach((info) => {
            constraints[info.type] = { deviceId: { exact: info.id } };
        });
    
        var audioTrack, videoTrack;
        return navigator.mediaDevices.getUserMedia(constraints)
            .then((stream) => {
                assert_equals(stream.getAudioTracks().length, 1, "correct number of audio tracks");
                assert_equals(stream.getVideoTracks().length, 1, "correct number of audio tracks");

                videoTrack = stream.getVideoTracks()[0];
                audioTrack = stream.getAudioTracks()[0];
                return navigator.mediaDevices.enumerateDevices();
            }).then(devices => {
                var ids = devices.map(device => device.deviceId);
                assert_true(ids.indexOf(videoTrack.getSettings().deviceId) !== -1 , "deviceId for video track should be respected");
                assert_true(ids.indexOf(audioTrack.getSettings().deviceId) !== -1 , "deviceId for audio track should be respected");
                assert_equals(audioTrack.getSettings().groupId, videoTrack.getSettings().groupId, "groupId should match");
            })

    }, "Pass device IDs as exact constraints");
    
    promise_test((test) => {
        deviceIds.forEach((info) => {
            constraints[info.type] = { deviceId: info.id };
        });
    
        return navigator.mediaDevices.getUserMedia(constraints)
            .then((stream) => {
                assert_equals(stream.getAudioTracks().length, 1, "correct number of audio tracks");
                assert_equals(stream.getVideoTracks().length, 1, "correct number of video tracks");
            })

    }, "Pass device IDs as optional constraints");

    promise_test(async (test) => {
        await navigator.mediaDevices.getUserMedia({ audio: {deviceId: {exact: ""}}});
        await navigator.mediaDevices.getUserMedia({ video: {deviceId: {exact: [""]}}});
        await navigator.mediaDevices.getUserMedia({ audio: {deviceId: {exact: undefined}}});

        await navigator.mediaDevices.getUserMedia({ audio: {deviceId: {exact: null}}}).then(assert_unreached, () => { });
        await navigator.mediaDevices.getUserMedia({ audio: {deviceId: {exact: "test"}}}).then(assert_unreached, () => { });
    }, "Exact device IDs with special values: empty string, null, undefined");

    promise_test(async (test) => {
        await navigator.mediaDevices.getUserMedia({video: true});
        const devices  = await navigator.mediaDevices.enumerateDevices();
        for (let device of devices) {
            if (device.kind === "audioinput") {
                const stream = await navigator.mediaDevices.getUserMedia({audio: {deviceId: device.deviceId}});
                assert_equals(stream.getAudioTracks()[0].getSettings().deviceId, device.deviceId, "Matching audio device id");
            } else if (device.kind === "videoinput") {
                const stream = await navigator.mediaDevices.getUserMedia({video: {deviceId: device.deviceId}});
                assert_equals(stream.getVideoTracks()[0].getSettings().deviceId, device.deviceId, "Matching video device id");
            }
        }
    }, "Ideal deviceId constraints");

    </script>
</head>
<body>
</body>
</html>
