/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- * Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ package org.mozilla.geckoview.test import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import org.hamcrest.Matchers import org.json.JSONObject import org.junit.Assume.assumeThat import org.junit.Test import org.junit.runner.RunWith import org.mozilla.geckoview.GeckoSession import org.mozilla.geckoview.GeckoSession.MediaDelegate import org.mozilla.geckoview.GeckoSession.PermissionDelegate import org.mozilla.geckoview.test.rule.GeckoSessionTestRule @RunWith(AndroidJUnit4::class) @MediumTest @Suppress("DEPRECATION") class MediaDelegateTest : BaseSessionTest() { private fun requestRecordingPermission(allowAudio: Boolean, allowCamera: Boolean) { mainSession.delegateDuringNextWait(object : PermissionDelegate { @GeckoSessionTestRule.AssertCalled(count = 1) override fun onMediaPermissionRequest( session: GeckoSession, uri: String, video: Array?, audio: Array?, callback: GeckoSession.PermissionDelegate.MediaCallback, ) { if (!(allowAudio || allowCamera)) { callback.reject() return } var audioDevice: GeckoSession.PermissionDelegate.MediaSource? = null var videoDevice: GeckoSession.PermissionDelegate.MediaSource? = null if (allowAudio) { audioDevice = audio!![0] } if (allowCamera) { videoDevice = video!![0] } if (videoDevice != null || audioDevice != null) { callback.grant(videoDevice, audioDevice) } } override fun onAndroidPermissionsRequest( session: GeckoSession, permissions: Array?, callback: GeckoSession.PermissionDelegate.Callback, ) { callback.grant() } }) mainSession.delegateDuringNextWait(object : MediaDelegate { @GeckoSessionTestRule.AssertCalled(count = 1) override fun onRecordingStatusChanged( session: GeckoSession, devices: Array, ) { var audioActive = false var cameraActive = false for (device in devices) { if (device.type == org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice.Type.MICROPHONE) { audioActive = device.status != org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice.Status.INACTIVE } if (device.type == org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice.Type.CAMERA) { cameraActive = device.status != org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice.Status.INACTIVE } } assertThat( "Camera is ${if (allowCamera) { "active" } else { "inactive" }}", cameraActive, Matchers.equalTo(allowCamera), ) assertThat( "Audio is ${if (allowAudio) { "active" } else { "inactive" }}", audioActive, Matchers.equalTo(allowAudio), ) } }) var code: String? if (allowAudio && allowCamera) { code = """this.stream = window.navigator.mediaDevices.getUserMedia({ video: { width: 320, height: 240, frameRate: 10 }, audio: true });""" } else if (allowAudio) { code = """this.stream = window.navigator.mediaDevices.getUserMedia({ audio: true, });""" } else if (allowCamera) { code = """this.stream = window.navigator.mediaDevices.getUserMedia({ video: { width: 320, height: 240, frameRate: 10 }, });""" } else { return } // Stop the stream and check active flag and id val isActive = mainSession.waitForJS( """$code this.stream.then(stream => { if (!stream.active || stream.id == '') { return false; } return true; }) """.trimMargin(), ) as Boolean assertThat( "Stream should be active and id should not be empty.", isActive, Matchers.equalTo(true), ) } @Test fun testDeviceRecordingEventAudio() { // disable test on debug Bug 1555656 assumeThat(sessionRule.env.isDebugBuild, Matchers.equalTo(false)) mainSession.loadTestPath(HELLO_HTML_PATH) mainSession.waitForPageStop() val devices = mainSession.waitForJS( "window.navigator.mediaDevices.enumerateDevices()", ).asJSList() val audioDevice = devices.find { map -> map.getString("kind") == "audioinput" } if (audioDevice != null) { requestRecordingPermission(allowAudio = true, allowCamera = false) } } @Test fun testDeviceRecordingEventVideo() { // TODO: needs bug 1700243 assumeThat(sessionRule.env.isIsolatedProcess, Matchers.equalTo(false)) mainSession.loadTestPath(HELLO_HTML_PATH) mainSession.waitForPageStop() val devices = mainSession.waitForJS( "window.navigator.mediaDevices.enumerateDevices()", ).asJSList() val videoDevice = devices.find { map -> map.getString("kind") == "videoinput" } if (videoDevice != null) { requestRecordingPermission(allowAudio = false, allowCamera = true) } } @Test fun testDeviceRecordingEventAudioAndVideo() { // disabled test on debug builds Bug 1554189 assumeThat(sessionRule.env.isDebugBuild, Matchers.equalTo(false)) mainSession.loadTestPath(HELLO_HTML_PATH) mainSession.waitForPageStop() val devices = mainSession.waitForJS( "window.navigator.mediaDevices.enumerateDevices()", ).asJSList() val audioDevice = devices.find { map -> map.getString("kind") == "audioinput" } val videoDevice = devices.find { map -> map.getString("kind") == "videoinput" } if (audioDevice != null && videoDevice != null) { requestRecordingPermission(allowAudio = true, allowCamera = true) } } }