From 3f24145e949cf9dce30155fc6edbb9b0bbbc1afb Mon Sep 17 00:00:00 2001 From: sssnake Date: Tue, 31 Mar 2026 03:25:19 -0700 Subject: [PATCH] Initial release: Miracast Enabler KernelSU module v1.0.0 Enables Wi-Fi Display (Miracast) on Pixel phones where Google disabled it in software. Uses fabricated overlays, system properties, and sysconfig XML. Includes WebUI for KernelSU manager. Tested hardware: Pixel 10 Pro Fold (rango), Tensor G5, BCM4390. --- build.sh | 111 ++++ customize.sh | 118 ++++ miracast-enabler-v1.0.0.zip | Bin 0 -> 12910 bytes module.prop | 6 + overlay/AndroidManifest.xml | 11 + overlay/build/compiled.zip | Bin 0 -> 540 bytes overlay/res/values/config.xml | 8 + post-fs-data.sh | 21 + pull-aapt2.sh | 44 ++ service.sh | 174 ++++++ system.prop | 11 + system/etc/permissions/miracast-enabler.xml | 6 + system/etc/sysconfig/miracast-enabler.xml | 6 + webroot/index.html | 643 ++++++++++++++++++++ 14 files changed, 1159 insertions(+) create mode 100755 build.sh create mode 100644 customize.sh create mode 100644 miracast-enabler-v1.0.0.zip create mode 100644 module.prop create mode 100644 overlay/AndroidManifest.xml create mode 100644 overlay/build/compiled.zip create mode 100644 overlay/res/values/config.xml create mode 100644 post-fs-data.sh create mode 100755 pull-aapt2.sh create mode 100644 service.sh create mode 100644 system.prop create mode 100644 system/etc/permissions/miracast-enabler.xml create mode 100644 system/etc/sysconfig/miracast-enabler.xml create mode 100644 webroot/index.html diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..2e0a9ad --- /dev/null +++ b/build.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# Build Miracast Enabler KernelSU/Magisk module zip +# +# The module uses fabricated overlays at runtime (no APK needed). +# If you have a local aapt2 binary (e.g. pulled from the phone), +# set AAPT2=/path/to/aapt2 and FRAMEWORK_RES=/path/to/framework-res.apk +# to also build an RRO APK as a fallback for pre-Android 12 devices. +set -e + +cd "$(dirname "$0")" + +MODULE_ZIP="miracast-enabler-v1.0.0.zip" + +echo "=== Miracast Enabler Build ===" +echo "" + +# Optional: build RRO APK if tools are available +AAPT2="${AAPT2:-tools/aapt2}" +FRAMEWORK_RES="${FRAMEWORK_RES:-tools/framework-res.apk}" + +if [ -x "$AAPT2" ] && [ -f "$FRAMEWORK_RES" ]; then + echo "[1/3] Building RRO overlay APK..." + + OVERLAY_DIR="overlay" + rm -rf "$OVERLAY_DIR/build" + mkdir -p "$OVERLAY_DIR/build" + + "$AAPT2" compile \ + --dir "$OVERLAY_DIR/res" \ + -o "$OVERLAY_DIR/build/compiled.zip" + + "$AAPT2" link \ + --manifest "$OVERLAY_DIR/AndroidManifest.xml" \ + -I "$FRAMEWORK_RES" \ + -o "$OVERLAY_DIR/build/MiracastEnablerOverlay.apk" \ + "$OVERLAY_DIR/build/compiled.zip" + + # Sign if possible + KEYSTORE="build-key.jks" + KEY_ALIAS="miracast" + KEY_PASS="miracast-build" + + if ! [ -f "$KEYSTORE" ] && command -v keytool >/dev/null 2>&1; then + keytool -genkeypair \ + -keystore "$KEYSTORE" \ + -alias "$KEY_ALIAS" \ + -keyalg RSA -keysize 2048 -validity 10000 \ + -storepass "$KEY_PASS" -keypass "$KEY_PASS" \ + -dname "CN=Miracast Enabler,O=Module,C=US" + fi + + if [ -f "$KEYSTORE" ]; then + if command -v apksigner >/dev/null 2>&1; then + apksigner sign \ + --ks "$KEYSTORE" --ks-key-alias "$KEY_ALIAS" \ + --ks-pass "pass:$KEY_PASS" --key-pass "pass:$KEY_PASS" \ + --out "$OVERLAY_DIR/MiracastEnablerOverlay.apk" \ + "$OVERLAY_DIR/build/MiracastEnablerOverlay.apk" + elif command -v jarsigner >/dev/null 2>&1; then + cp "$OVERLAY_DIR/build/MiracastEnablerOverlay.apk" "$OVERLAY_DIR/MiracastEnablerOverlay.apk" + jarsigner -keystore "$KEYSTORE" \ + -storepass "$KEY_PASS" -keypass "$KEY_PASS" \ + "$OVERLAY_DIR/MiracastEnablerOverlay.apk" "$KEY_ALIAS" + else + cp "$OVERLAY_DIR/build/MiracastEnablerOverlay.apk" "$OVERLAY_DIR/MiracastEnablerOverlay.apk" + fi + else + cp "$OVERLAY_DIR/build/MiracastEnablerOverlay.apk" "$OVERLAY_DIR/MiracastEnablerOverlay.apk" + fi + + mkdir -p system/vendor/overlay + cp "$OVERLAY_DIR/MiracastEnablerOverlay.apk" system/vendor/overlay/ + echo " RRO APK built: $(du -h system/vendor/overlay/MiracastEnablerOverlay.apk | cut -f1)" + rm -rf "$OVERLAY_DIR/build" +else + echo "[1/3] Skipping RRO APK (no local aapt2 or framework-res.apk)" + echo " Module will use fabricated overlays on Android 12+" + echo " To build APK: pull aapt2 from phone with ./pull-aapt2.sh" + rm -rf system/vendor/overlay +fi + +echo "[2/3] Packaging module..." +rm -f "$MODULE_ZIP" + +# Build file list +FILES=( + module.prop + customize.sh + post-fs-data.sh + service.sh + system.prop + system/ + webroot/ +) + +# Include overlay source for on-device build fallback +FILES+=(overlay/AndroidManifest.xml overlay/res/) + +# Include pre-built APK if it exists +if [ -f "system/vendor/overlay/MiracastEnablerOverlay.apk" ]; then + FILES+=(system/vendor/overlay/MiracastEnablerOverlay.apk) +fi + +zip -r9 "$MODULE_ZIP" "${FILES[@]}" \ + -x "overlay/build/*" "*.git*" "build.sh" "build-key.jks" \ + "pull-aapt2.sh" "tools/*" "README*" + +echo "[3/3] Done" +echo "" +echo "=== $MODULE_ZIP ($(du -h "$MODULE_ZIP" | cut -f1)) ===" +echo "Flash via KernelSU or Magisk manager" diff --git a/customize.sh b/customize.sh new file mode 100644 index 0000000..6ca0c5a --- /dev/null +++ b/customize.sh @@ -0,0 +1,118 @@ +#!/system/bin/sh +# Miracast Enabler - Installation Script + +SKIPUNZIP=0 + +ui_print "================================================" +ui_print " Miracast Enabler v1.0.0" +ui_print "================================================" +ui_print "" + +# Detect device +DEVICE=$(getprop ro.product.device) +MODEL=$(getprop ro.product.model) +SOC=$(getprop ro.soc.model) +ANDROID=$(getprop ro.build.version.release) +API=$(getprop ro.build.version.sdk) + +ui_print "- Device: $MODEL ($DEVICE)" +ui_print "- SoC: $SOC" +ui_print "- Android: $ANDROID (API $API)" +ui_print "" + +# Pixel detection +case "$DEVICE" in + rango|comet|cometl|caiman|komodo|tokay|blazer|husky|shiba|felix|tangorpro|lynx|panther|cheetah|oriole|raven|bluejay) + ui_print "- Pixel device detected" + ;; + *) + ui_print "! Non-Pixel device — module may still work" + ;; +esac + +# Foldable messaging +case "$DEVICE" in + rango|comet|cometl|felix) + ui_print "- Foldable detected: inner display is default Miracast source" + ui_print "- Change display source via WebUI in KernelSU manager" + ;; +esac +ui_print "" + +# --- Build RRO APK on-device as fallback for pre-Android 12 --- +# Android 12+ uses fabricated overlays (no APK needed) +# Pre-Android 12 needs a real RRO APK, built right here on the phone +if [ "$API" -lt 31 ]; then + ui_print "- Android < 12: building RRO overlay APK on-device..." + + AAPT2=$(which aapt2 2>/dev/null) + if [ -z "$AAPT2" ]; then + # aapt2 is typically in the build-tools or framework + for candidate in \ + /system/bin/aapt2 \ + /system/xbin/aapt2 \ + /data/adb/aapt2; do + if [ -x "$candidate" ]; then + AAPT2="$candidate" + break + fi + done + fi + + if [ -n "$AAPT2" ] && [ -x "$AAPT2" ]; then + ui_print "- Found aapt2: $AAPT2" + OVERLAY_BUILD="$MODPATH/overlay_build" + mkdir -p "$OVERLAY_BUILD" + + # Compile resources + "$AAPT2" compile \ + --dir "$MODPATH/overlay/res" \ + -o "$OVERLAY_BUILD/compiled.zip" 2>/dev/null + + if [ $? -eq 0 ]; then + # Link into APK + "$AAPT2" link \ + --manifest "$MODPATH/overlay/AndroidManifest.xml" \ + -I /system/framework/framework-res.apk \ + -o "$OVERLAY_BUILD/overlay.apk" \ + "$OVERLAY_BUILD/compiled.zip" 2>/dev/null + + if [ $? -eq 0 ]; then + mkdir -p "$MODPATH/system/vendor/overlay" + cp "$OVERLAY_BUILD/overlay.apk" "$MODPATH/system/vendor/overlay/MiracastEnablerOverlay.apk" + chmod 644 "$MODPATH/system/vendor/overlay/MiracastEnablerOverlay.apk" + ui_print "- RRO overlay APK built and installed" + else + ui_print "! aapt2 link failed — overlay APK not built" + fi + else + ui_print "! aapt2 compile failed — overlay APK not built" + fi + rm -rf "$OVERLAY_BUILD" + else + ui_print "! aapt2 not found on device" + ui_print "! Pre-Android 12 will rely on system properties only" + fi +else + ui_print "- Android 12+: will use fabricated overlays (no APK needed)" +fi + +ui_print "" +ui_print "- Setting permissions..." + +set_perm_recursive $MODPATH 0 0 0755 0644 +set_perm $MODPATH/post-fs-data.sh 0 0 0755 +set_perm $MODPATH/service.sh 0 0 0755 +set_perm_recursive $MODPATH/system/etc 0 0 0755 0644 + +if [ -f "$MODPATH/system/vendor/overlay/MiracastEnablerOverlay.apk" ]; then + set_perm "$MODPATH/system/vendor/overlay/MiracastEnablerOverlay.apk" 0 0 0644 +fi + +ui_print "" +ui_print "- Installation complete!" +ui_print "- Reboot to activate Miracast" +ui_print "- After reboot: Settings > Connected devices >" +ui_print " Connection preferences > Cast" +ui_print "- WebUI available in KernelSU manager" +ui_print "" diff --git a/miracast-enabler-v1.0.0.zip b/miracast-enabler-v1.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..a23e3780d419060ec67edf7cbdbafc729fbe170c GIT binary patch literal 12910 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 IdH(PJ0r_L(A^-pY literal 0 HcmV?d00001 diff --git a/module.prop b/module.prop new file mode 100644 index 0000000..319c080 --- /dev/null +++ b/module.prop @@ -0,0 +1,6 @@ +id=miracast-enabler +name=Miracast Enabler +version=v1.0.0 +versionCode=1 +author=snake +description=Enables Miracast (Wi-Fi Display) on Pixel phones and other devices where it is disabled by default diff --git a/overlay/AndroidManifest.xml b/overlay/AndroidManifest.xml new file mode 100644 index 0000000..7dca89d --- /dev/null +++ b/overlay/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/overlay/build/compiled.zip b/overlay/build/compiled.zip new file mode 100644 index 0000000000000000000000000000000000000000..ac819982cf28dee0960180bc50aa81f59f06a45c GIT binary patch literal 540 zcmZ`$%}xR_5N-jHthZh?M3RagzywfE>WS6GY($ccl5iwtw~LKsyJ-vP#V7EcjAviO zgNd(T_XjmGPSehpnXmI@X1qbM1ajL0Z!hog83K^pZ4+G*zMyL2izsBXHj&D2hn#5J z_C|&QlAD;!fpulM5bOfi#0qJ~JSKOr#>N*jT&syCm7F|wBvqYEr<3bE%sBw)6IMSU zDousp)d1~exe1NPl+!T_nZs0U{#OeKbR7$zo>i_uRH&5DQ9mW&F>75iobzyF$RzQJ z(oM`FtnVleC7IKekoWb{S)m83Pv|gLS^d<%UBt1FT6t1v>T4RDFT#*YmFiv_T{qX= zL?<@qVuj;16E~cjVaIhYye2kk!@W@O7HwcM!6K!?d$EU4;P8o>+@CNXE)ByZl;jhsf_|HPU!A3bDLUa1YzorZQ E0+|kk;Q#;t literal 0 HcmV?d00001 diff --git a/overlay/res/values/config.xml b/overlay/res/values/config.xml new file mode 100644 index 0000000..34715bd --- /dev/null +++ b/overlay/res/values/config.xml @@ -0,0 +1,8 @@ + + + + true + + + true + diff --git a/post-fs-data.sh b/post-fs-data.sh new file mode 100644 index 0000000..e6b0f22 --- /dev/null +++ b/post-fs-data.sh @@ -0,0 +1,21 @@ +#!/system/bin/sh +# Miracast Enabler - post-fs-data +# Runs early in boot before most services start + +MODDIR=${0%/*} + +# Core Wi-Fi Display props +resetprop persist.debug.wfd.enable 1 +resetprop persist.sys.wfd.virtual 0 + +# HDCP — disable by default for maximum compatibility +resetprop persist.sys.wfd.nohdcp 1 +resetprop wlan.wfd.hdcp disable + +# Tensor / Pixel: force GPU composition for virtual displays +# HWC on Tensor chips does not correctly handle virtual display layers, +# which causes black screen or green artifacts during Miracast +resetprop debug.sf.enable_hwc_vds 0 + +# Wi-Fi Direct concurrency — needed on Pixel to allow P2P alongside STA +resetprop wifi.direct.interface p2p-dev-wlan0 diff --git a/pull-aapt2.sh b/pull-aapt2.sh new file mode 100755 index 0000000..57b8779 --- /dev/null +++ b/pull-aapt2.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Pull aapt2 from a connected Android device for local builds +# Usage: ./pull-aapt2.sh +set -e + +DEST="tools/aapt2" + +if ! adb get-state >/dev/null 2>&1; then + echo "ERROR: No device connected via ADB" + exit 1 +fi + +echo "Searching for aapt2 on device..." + +# Find aapt2 binary on the device +DEVICE_PATH=$(adb shell "find /system /vendor /apex -name 'aapt2' -type f 2>/dev/null" | tr -d '\r' | head -1) + +if [ -z "$DEVICE_PATH" ]; then + echo "aapt2 not found as standalone binary, checking APEX modules..." + # On newer Android, build tools live inside APEX + DEVICE_PATH=$(adb shell "find /apex/com.android.sdkext /apex/com.android.art -name 'aapt2' 2>/dev/null" | tr -d '\r' | head -1) +fi + +if [ -z "$DEVICE_PATH" ]; then + echo "aapt2 not found on device." + echo "Trying framework-res.apk instead (for on-device overlay builds)..." + DEVICE_PATH="/system/framework/framework-res.apk" + DEST="tools/framework-res.apk" +fi + +echo "Pulling: $DEVICE_PATH" +mkdir -p "$(dirname "$DEST")" +adb pull "$DEVICE_PATH" "$DEST" + +if [ -f "$DEST" ]; then + chmod +x "$DEST" 2>/dev/null + echo "Saved to: $DEST" + file "$DEST" + + if [[ "$DEST" == *aapt2 ]]; then + VERSION=$("./$DEST" version 2>&1 || true) + echo "Version: $VERSION" + fi +fi diff --git a/service.sh b/service.sh new file mode 100644 index 0000000..2324e53 --- /dev/null +++ b/service.sh @@ -0,0 +1,174 @@ +#!/system/bin/sh +# Miracast Enabler - late service +# Runs after boot is completed + +MODDIR=${0%/*} +LOGFILE="$MODDIR/miracast.log" + +mlog() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOGFILE" + log -t MiracastEnabler "$1" +} + +# Truncate log on each boot +echo "" > "$LOGFILE" +mlog "Waiting for boot..." + +# Wait for boot to complete +while [ "$(getprop sys.boot_completed)" != "1" ]; do + sleep 1 +done +sleep 3 + +mlog "Boot complete, applying Miracast configuration" + +# --- Core WFD properties --- +# Some vendors reset these during boot, so re-apply +resetprop persist.debug.wfd.enable 1 +resetprop persist.sys.wfd.virtual 0 +resetprop persist.sys.wfd.nohdcp 1 +resetprop wlan.wfd.hdcp disable + +# Tensor / Pixel: force GPU composition for virtual display surfaces +# PowerVR (G5) and Mali (G4 and earlier) HWC implementations don't +# handle virtual display layers for Miracast, causing black/green frames +resetprop debug.sf.enable_hwc_vds 0 + +# Wi-Fi Direct concurrency — needed on Pixel to allow P2P alongside STA +resetprop wifi.direct.interface p2p-dev-wlan0 + +# --- Device detection --- +DEVICE=$(getprop ro.product.device) +SOC=$(getprop ro.soc.model) +PLATFORM=$(getprop ro.board.platform) +API=$(getprop ro.build.version.sdk) +GPU=$(getprop ro.hardware.egl) + +mlog "Device=$DEVICE SoC=$SOC Platform=$PLATFORM API=$API GPU=$GPU" + +# --- Tensor SoC family tweaks --- +case "$SOC" in + Tensor*) + # High GO intent so Pixel acts as Group Owner in P2P negotiation + # This ensures the Pixel controls the channel and timing + resetprop wifi.direct.go_intent 15 + mlog "Tensor SoC: set P2P GO intent=15" + ;; +esac + +# --- Pixel 10 Pro Fold (rango) — Tensor G5, Broadcom BCM4390 --- +# Confirmed: codename=rango, platform=laguna, gpu=powervr, wifi=bcmdhd4390 +# Display IDs: 0 (inner), 3 (outer) +# Wi-Fi features include WFD_R2 — hardware fully supports Miracast +case "$DEVICE" in + rango) + mlog "Pixel 10 Pro Fold (rango) detected" + + # Inner display (ID 0) as default Miracast source + if [ -z "$(getprop persist.sys.wfd.display_id)" ]; then + resetprop persist.sys.wfd.display_id 0 + fi + # Default 1080p30 — the inner panel is 2076x2152 which is too wide + # for most Miracast receivers; 1080p is the safe maximum + if [ -z "$(getprop persist.sys.wfd.resolution)" ]; then + resetprop persist.sys.wfd.resolution 7 + fi + + # Tensor G5 / laguna platform: PowerVR GPU composition + resetprop debug.sf.enable_hwc_vds 0 + + # BCM4390 Wi-Fi: P2P supplicant already supports VHT and DFS + # channels (p2p_go_vht=1, p2p_dfs_chan_enable=1 in vendor config) + # but 6GHz is disabled for P2P (p2p_6ghz_disable=1), which is fine + # since most Miracast receivers don't support 6GHz + + # Force single-channel concurrency to prevent the BCM4390 from + # splitting STA and P2P across bands which can cause latency spikes + resetprop persist.vendor.wifi.wfd.scc 1 + + mlog "rango: inner display=0, outer display=3, wifi=BCM4390, gpu=PowerVR" + ;; +esac + +# --- Pixel 9 Pro Fold (comet/cometl) — Tensor G4 --- +case "$DEVICE" in + comet|cometl) + mlog "Pixel 9 Pro Fold detected" + if [ -z "$(getprop persist.sys.wfd.display_id)" ]; then + resetprop persist.sys.wfd.display_id 0 + fi + if [ -z "$(getprop persist.sys.wfd.resolution)" ]; then + resetprop persist.sys.wfd.resolution 7 + fi + ;; +esac + +# --- Original Pixel Fold (felix) — Tensor G2 --- +case "$DEVICE" in + felix) + mlog "Pixel Fold (1st gen) detected" + if [ -z "$(getprop persist.sys.wfd.display_id)" ]; then + resetprop persist.sys.wfd.display_id 0 + fi + if [ -z "$(getprop persist.sys.wfd.resolution)" ]; then + resetprop persist.sys.wfd.resolution 7 + fi + ;; +esac + +# --- Pixel 9 series (non-fold) — Tensor G4 --- +case "$DEVICE" in + caiman|komodo|tokay|blazer) + mlog "Pixel 9 series detected ($DEVICE)" + # No foldable display concerns, standard single display + ;; +esac + +# --- Pixel 10 series (non-fold) --- +# Platform "laguna" is Tensor G5; other Pixel 10 variants share it +case "$PLATFORM" in + laguna) + if [ "$DEVICE" != "rango" ]; then + mlog "Tensor G5 device ($DEVICE) on laguna platform" + resetprop debug.sf.enable_hwc_vds 0 + resetprop persist.vendor.wifi.wfd.scc 1 + fi + ;; +esac + +# --- Fabricated overlay (Android 12+, API 31+) --- +# Primary method to flip config_enableWifiDisplay in the framework +# No APK compilation needed — fabricated overlays are created at runtime +# Requires root, which KernelSU provides +if [ "$API" -ge 31 ]; then + mlog "API $API >= 31, creating fabricated overlays" + + # TYPE_INT_BOOLEAN = 0x12, true = 0xFFFFFFFF + cmd overlay fabricate --target android --name MiracastEnablerWifiDisplay \ + android:bool/config_enableWifiDisplay 0x12 0xFFFFFFFF 2>/dev/null + RET1=$? + + cmd overlay fabricate --target android --name MiracastEnablerProtectedBuffers \ + android:bool/config_wifiDisplaySupportsProtectedBuffers 0x12 0xFFFFFFFF 2>/dev/null + RET2=$? + + # Enable the fabricated overlays + cmd overlay enable --user current com.android.shell:MiracastEnablerWifiDisplay 2>/dev/null + cmd overlay enable --user current com.android.shell:MiracastEnablerProtectedBuffers 2>/dev/null + + # Verify and log + WFD_STATE=$(cmd overlay list 2>/dev/null | grep MiracastEnabler) + mlog "Fabricate WifiDisplay ret=$RET1, ProtectedBuffers ret=$RET2" + mlog "Overlay state: $WFD_STATE" +else + mlog "API $API < 31, fabricated overlays not available" + mlog "Relying on system properties and sysconfig XML only" +fi + +# --- Fallback: enable pre-installed RRO APK if present --- +if [ -f "$MODDIR/system/vendor/overlay/MiracastEnablerOverlay.apk" ]; then + cmd overlay enable --user current com.miracast.enabler.overlay 2>/dev/null + mlog "Enabled RRO APK overlay" +fi + +mlog "Miracast enabler service complete" diff --git a/system.prop b/system.prop new file mode 100644 index 0000000..a7eeaaa --- /dev/null +++ b/system.prop @@ -0,0 +1,11 @@ +# Core Miracast / Wi-Fi Display +persist.debug.wfd.enable=1 +persist.sys.wfd.virtual=0 +persist.sys.wfd.nohdcp=1 +wlan.wfd.hdcp=disable + +# Tensor / Pixel: GPU composition for virtual displays +debug.sf.enable_hwc_vds=0 + +# Wi-Fi Direct concurrency +wifi.direct.interface=p2p-dev-wlan0 diff --git a/system/etc/permissions/miracast-enabler.xml b/system/etc/permissions/miracast-enabler.xml new file mode 100644 index 0000000..70f3dcc --- /dev/null +++ b/system/etc/permissions/miracast-enabler.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/system/etc/sysconfig/miracast-enabler.xml b/system/etc/sysconfig/miracast-enabler.xml new file mode 100644 index 0000000..9ff33d2 --- /dev/null +++ b/system/etc/sysconfig/miracast-enabler.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/webroot/index.html b/webroot/index.html new file mode 100644 index 0000000..016b422 --- /dev/null +++ b/webroot/index.html @@ -0,0 +1,643 @@ + + + + + + Miracast Enabler + + + +
+

Miracast Enabler

+
v1.0.0
+
+ +
+
+ Reading device state... +
+ + +
+
Miracast
+ +
+
+
Wi-Fi Display
+
Master toggle for Miracast
+
+ +
+ +
+
+
Disable HDCP
+
Skip DRM handshake (fixes many receivers)
+
+ +
+ +
+
+
Virtual Display
+
Use virtual display instead of overlay
+
+ +
+
+ + +
+
Quality
+ +
+
+
Max Resolution
+
Caps output resolution for stability
+
+ +
+ +
+
+
WLAN HDCP
+
Wi-Fi level HDCP control
+
+ +
+
+ + +
+
Pixel / Tensor Tweaks
+ +
+
+
Force P2P Concurrency
+
Allow Wi-Fi Direct alongside station mode
+
+ +
+ +
+
+
Force Display Composition
+
Use GPU composition for wireless display
+
+ +
+ +
+
+
Fold Display Source
+
Which display to mirror on foldables
+
+ +
+
+ + +
+
Framework Overlay
+ +
+
+
config_enableWifiDisplay
+
Framework feature flag (fabricated overlay)
+
+ +
+ +
+
+
config_wifiDisplaySupportsProtectedBuffers
+
Allow DRM content over wireless display
+
+ +
+ +
+
+
Overlay Status
+
Checking...
+
+ +
+
+ + +
+
Device Info
+
+
+
Device
+
+
+
+
SoC
+
+
+
+
Android
+
+
+
+
Wi-Fi Chip
+
+
+
+
+ + +
+
Log
+
Initializing...
+
+ + +
+
+ + + +