diff --git a/sepolicy.rule b/sepolicy.rule
index 7fbcd57..a6d3dea 100644
--- a/sepolicy.rule
+++ b/sepolicy.rule
@@ -1,4 +1,4 @@
# Only what's strictly needed. No broad "allow init ..." rules.
-allow virtual_camera_provider video_device:chr_file { read write ioctl open };
+allow virtual_camera_provider video_device:chr_file { read write ioctl open mmap };
allow virtual_camera_provider servicemanager:binder { call transfer };
allow cameraserver virtual_camera_provider:binder { call transfer };
diff --git a/service.sh b/service.sh
index 2515cdd..d030244 100755
--- a/service.sh
+++ b/service.sh
@@ -21,7 +21,24 @@ if ! lsmod 2>/dev/null | grep -q v4l2loopback; then
log "service: v4l2loopback loaded" || log "service: v4l2loopback load failed"
fi
-# Initial provider start if not running
+# Configure v4l2loopback for seamless loop transitions:
+# sustain_framerate=1 repeats the last written frame when the writer pauses
+# timeout=0 prevents kernel from injecting black timeout images
+sleep 2 # Wait for device nodes to appear
+if [ -c /dev/video0 ]; then
+ v4l2-ctl -d /dev/video0 -c sustain_framerate=1 >/dev/null 2>&1 || true
+ v4l2-ctl -d /dev/video0 -c timeout=0 >/dev/null 2>&1 || true
+ log "service: v4l2loopback configured (sustain_framerate=1, timeout=0)"
+fi
+
+# Start feeder FIRST so /dev/video0 has a format set before provider starts
+# This prevents mmap EACCES in V4L2 reader
+if [ -f "/data/local/tmp/virtualcam_config.json" ]; then
+ log "service: starting feeder before provider"
+ /system/bin/sh "$MODDIR/control.sh" start_feeder >/dev/null 2>&1
+fi
+
+# Now start provider (feeder already writing, so mmap will succeed)
if ! pgrep -f virtual_camera_provider >/dev/null 2>&1 && [ -x "$PROVIDER_DST" ]; then
log "service: starting provider"
nohup env LD_LIBRARY_PATH="$LIB_DST" "$PROVIDER_DST" \
@@ -69,6 +86,12 @@ while true; do
/dev/null 2>&1 &
fi
+ # Auto-start feeder if not running and config exists
+ if [ -z "$FEEDER_PID" ] && [ -f "/data/local/tmp/virtualcam_config.json" ]; then
+ log "service: auto-starting feeder"
+ /system/bin/sh "$MODDIR/control.sh" start_feeder >/dev/null 2>&1
+ fi
+
# Memory check: kill provider/feeder if RSS exceeds 512MB (safety limit)
for pid in $PROVIDER_PID $FEEDER_PID; do
[ -z "$pid" ] && continue
@@ -80,10 +103,15 @@ while true; do
done
# Check if stock HAL came back and kill it
- if pgrep -f camera-provider-2-7-google >/dev/null 2>&1; then
+ STOCK_PIDS=$(ps -A | grep -i "camera.provider" | grep -v "virtual_camera_provider" | awk '{print $1}')
+ if [ -n "$STOCK_PIDS" ]; then
+ for pid in $STOCK_PIDS; do
+ log "service: killing stock HAL PID $pid"
+ kill -9 "$pid" 2>/dev/null || true
+ done
+ # Try to stop the service via property if possible
setprop ctl.stop vendor.camera-provider-2-7-google 2>/dev/null || true
- kill -9 "$(pgrep -f camera-provider-2-7-google)" 2>/dev/null || true
- log "service: re-killed stock HAL"
+ setprop ctl.stop vendor.camera-provider-pixel 2>/dev/null || true
fi
sleep 10
diff --git a/system/etc/vintf/manifest/virtual_camera_manifest.xml b/system/etc/vintf/manifest/virtual_camera_manifest.xml
index 0bd6615..a3d4e13 100644
--- a/system/etc/vintf/manifest/virtual_camera_manifest.xml
+++ b/system/etc/vintf/manifest/virtual_camera_manifest.xml
@@ -2,7 +2,7 @@
android.hardware.camera.provider
- 1
+ 3
ICameraProvider/virtual/0
diff --git a/vendor/bin/virtual_camera_provider b/vendor/bin/virtual_camera_provider
index 418bf72..fc9e0f7 100755
Binary files a/vendor/bin/virtual_camera_provider and b/vendor/bin/virtual_camera_provider differ
diff --git a/vendor/etc/vintf/manifest/virtual_camera_manifest.xml b/vendor/etc/vintf/manifest/virtual_camera_manifest.xml
index 0bd6615..a3d4e13 100644
--- a/vendor/etc/vintf/manifest/virtual_camera_manifest.xml
+++ b/vendor/etc/vintf/manifest/virtual_camera_manifest.xml
@@ -2,7 +2,7 @@
android.hardware.camera.provider
- 1
+ 3
ICameraProvider/virtual/0