Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ We actively welcome contributions! Whether you're fixing a bug, optimizing perfo
#### 📱 Android App
1. **Prerequisites:** Install the latest **Android Studio**.
2. **Import:** Open the `android/` directory as a project.
3. **Build:** Let Gradle sync and download dependencies.
3. **Build:** Let Gradle sync and download dependencies, then build the release APK:
```cmd
cd android
gradlew.bat clean assembleRelease
```
* *Core Dependency:* [RootEncoder](https://github.com/pedroSG94/RootEncoder) (handles RTSP/RTP packets).
4. **Run:** Connect a physical Android device (emulators often lack necessary encoder hardware) and run the `app` module.

Expand Down Expand Up @@ -175,6 +179,13 @@ We actively welcome contributions! Whether you're fixing a bug, optimizing perfo
regsvr32 softcam.dll
```

#### 📦 Building the distributable package
Run `package.bat` from the repository root after building the Windows client into `dist/`.
The packaging script runs Gradle's `:app:copyApk` task, which builds the Android
release from the current source tree before copying it into `dist/apk/`. It removes
the previous destination APK first and stops if the build does not recreate it,
preventing an old APK from being shipped with a newer desktop client.

### 📬 Submitting a Pull Request
1. Fork the project.
2. Create your feature branch (`git checkout -b feature/AmazingFeature`).
Expand All @@ -200,6 +211,27 @@ If the Android app cannot connect to the Windows client:
* Open a terminal in the VCamdroid folder and run: `adb shell ping -c 4 <PC_IP_ADDRESS>`
* If you see "100% packet loss" or "unreachable," your PC's firewall or router settings (AP Isolation) are blocking the connection.

### Phone connects but the device and video do not appear
The TCP connection on port `6969` is only the first pairing step. The Android app
must next send its `DeviceDescriptor`; only then can the Windows client list the
device. Select the phone in the Windows source list to request streaming and open
the RTSP video on port `8554`.

If `vcamdroid.log` contains `Device connected` but the device never appears:
1. Make sure the desktop client and Android APK came from the same release package.
2. When building from source, run `package.bat` instead of reusing an APK from an
older `dist/` directory.
3. Reinstall the packaged APK with `scripts\install_apk.bat`. If ADB reports
`INSTALL_FAILED_UPDATE_INCOMPATIBLE`, uninstall the existing
`com.darusc.vcamdroid` package first; this removes its local app data.
4. Pair again, select the listed phone as the source, and verify that streaming
starts and live video appears in the desktop client.

The QR dialog remaining visible by itself does not prove that pairing failed; use
the device list, video preview, and logs as the success criteria. See
[Device registration troubleshooting](docs/troubleshooting-device-registration.md)
for the complete diagnostic flow.

### USB Connection not working
If the app does not detect your phone:
1. **Check ADB Devices:**
Expand Down
5 changes: 3 additions & 2 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ android {
}

tasks.register<Copy>("copyApk") {
from("release/")
into("../../dist/apk")
dependsOn("assembleRelease")
from(layout.buildDirectory.file("outputs/apk/release/app-release.apk"))
into(rootProject.file("../dist/apk"))
}

dependencies {
Expand Down
124 changes: 124 additions & 0 deletions docs/troubleshooting-device-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Device registration and video troubleshooting

This guide covers the failure mode where the Android camera opens and the phone
reaches the Windows client, but no device or video appears in the desktop app.

## Pairing sequence

A successful Wi-Fi pairing has five separate gates:

1. The QR code gives the Android client the Windows host and control port (`6969`).
2. Android opens the TCP control connection.
3. Android sends a `DeviceDescriptor` containing the device name, RTSP URL,
camera resolutions, and supported filters.
4. Windows registers the descriptor and adds the phone to the source list.
5. The user selects the phone in that source list; Windows then sends the stream
options and opens the RTSP stream (normally on port `8554`).

A TCP connection alone is not enough. If gate 2 succeeds but gate 3 fails, the
server can log `Device connected` while the device list and video remain empty.
The QR dialog may also remain visible, so the device list, logs, and live preview
are the reliable success criteria.

## Confirmed failure mode: mismatched release artifacts

The Android and Windows clients must use the same protocol version. A package
containing a current desktop executable and an older APK can connect on port
`6969`, but the old Android client may not send the `DeviceDescriptor` expected
by Windows. Without that descriptor, Windows cannot register the device or
request the RTSP stream.

Historically, the Gradle `copyApk` task copied from `android/app/release/`, a
manually populated location, and did not depend on `assembleRelease`.
`package.bat` then reused the contents of `dist/` without building Android. This
allowed a stale APK to be distributed with a newer desktop client.

The packaging flow now prevents that combination:

- `:app:copyApk` depends on `assembleRelease`.
- It copies the exact Gradle output from
`android/app/build/outputs/apk/release/app-release.apk`.
- `package.bat` removes the previous destination APK, invokes that task, and stops
if the Android build does not recreate the APK.

## Diagnosis

### 1. Confirm ADB access (USB)

```cmd
adb devices -l
```

The device state must be `device`, not `unauthorized` or `offline`.

### 2. Confirm the Windows control listener

```cmd
netstat -ano | findstr :6969
```

The desktop client should have a `LISTENING` socket on port `6969`.

### 3. Check both sides of the protocol

- Windows: inspect `vcamdroid.log` beside `VCamdroid.exe`.
- Android: use the in-app log screen when available, or collect Logcat:

```cmd
adb logcat | findstr /i VCamdroid
```

If Windows logs `Device connected` but never lists the phone, reinstall an APK
built from the same source/release as the desktop client before changing network
or firewall settings.

### 4. Handle Android signature mismatch

The installer first uses `adb install -r` to preserve app data. If ADB reports:

```text
INSTALL_FAILED_UPDATE_INCOMPATIBLE
```

the installed package was signed with a different key. Back up anything needed,
then uninstall `com.darusc.vcamdroid` and install the packaged APK again. Android
removes the application's local data during uninstall.

## Build and package a matching release

From the repository root on Windows:

```cmd
android\gradlew.bat -p android clean :app:copyApk
package.bat
```

`package.bat` expects the Windows release files to already exist in `dist/`. The
resulting Android package is:

```text
VCamdroid\apk\app-release.apk
```

To verify artifact identity, compare the SHA-256 values:

```cmd
certutil -hashfile android\app\build\outputs\apk\release\app-release.apk SHA256
certutil -hashfile dist\apk\app-release.apk SHA256
certutil -hashfile VCamdroid\apk\app-release.apk SHA256
```

All three hashes must match.

## End-to-end success criteria

After installing the packaged APK and pairing again, verify all of the following:

- the phone reaches the control server on port `6969`;
- the phone appears in the Windows device list;
- the phone is selected in the Windows source list;
- Windows requests streaming after that selection;
- the RTSP stream is reachable (normally port `8554`);
- live camera video appears in the desktop preview.

Treat the test as failed if only the TCP connection or camera preview works.
25 changes: 24 additions & 1 deletion install_apk.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
@echo off
setlocal
echo Installing VCamdroid apk to android device

..\adb\adb.exe install -r ..\apk\app-release.apk
set "ADB=%~dp0..\adb\adb.exe"
set "APK=%~dp0..\apk\app-release.apk"

if not exist "%ADB%" (
echo [ERROR] adb.exe was not found at: %ADB%
exit /b 1
)

if not exist "%APK%" (
echo [ERROR] Android APK was not found at: %APK%
exit /b 1
)

"%ADB%" install -r "%APK%"
if errorlevel 1 (
echo [ERROR] APK installation failed.
echo If adb reported INSTALL_FAILED_UPDATE_INCOMPATIBLE, uninstall the old
echo com.darusc.vcamdroid package first. This removes its local app data.
exit /b 1
)

echo [SUCCESS] VCamdroid Android client installed.
exit /b 0
100 changes: 89 additions & 11 deletions package.bat
Original file line number Diff line number Diff line change
@@ -1,66 +1,144 @@
@echo off
setlocal enabledelayedexpansion
setlocal
pushd "%~dp0"

:: --- Configuration ---
set "SOURCE_DIST=dist"
set "SOURCE_ADB=windows\adb"
set "OUTPUT_DIR=VCamdroid"
set "GRADLE_WRAPPER=android\gradlew.bat"
set "ANDROID_APK=%SOURCE_DIST%\apk\app-release.apk"
set "WINDOWS_APP=%SOURCE_DIST%\VCamdroid.exe"

:: List of scripts to copy (located in the current root dir)
set "SCRIPTS_TO_COPY=install.bat install_apk.bat uninstall.bat"

echo [INFO] Starting Package Build...

:: 1. Clean previous build
:: 1. Verify the Windows release exists before Android creates dist/apk
if not exist "%WINDOWS_APP%" (
echo [ERROR] Windows release not found at: %WINDOWS_APP%
goto :Error
)

:: 2. Build and copy the Android client from the current source tree
if not exist "%GRADLE_WRAPPER%" (
echo [ERROR] Gradle wrapper not found at: %GRADLE_WRAPPER%
goto :Error
)

if not exist "%SOURCE_ADB%\adb.exe" (
echo [ERROR] ADB executable not found at: %SOURCE_ADB%\adb.exe
goto :Error
)

for %%f in (%SCRIPTS_TO_COPY%) do (
if not exist "%%f" (
echo [ERROR] Required script not found: %%f
goto :Error
)
)

if exist "%ANDROID_APK%" (
echo [INFO] Removing previous Android APK...
del /f /q "%ANDROID_APK%"
if exist "%ANDROID_APK%" (
echo [ERROR] Could not remove the previous APK at: %ANDROID_APK%
goto :Error
)
)

echo [INFO] Building current Android release...
call "%GRADLE_WRAPPER%" -p android :app:copyApk --console=plain
if errorlevel 1 (
echo [ERROR] Android release build failed.
goto :Error
)

if not exist "%ANDROID_APK%" (
echo [ERROR] Android APK was not created at: %ANDROID_APK%
goto :Error
)

:: 3. Clean previous build
if exist "%OUTPUT_DIR%" (
echo [INFO] Cleaning old output directory...
rmdir /s /q "%OUTPUT_DIR%"
if exist "%OUTPUT_DIR%" (
echo [ERROR] Could not clean output directory: %OUTPUT_DIR%
goto :Error
)
)

:: 2. Create new directory structure
:: 4. Create new directory structure
echo [INFO] Creating directory structure...
mkdir "%OUTPUT_DIR%"
mkdir "%OUTPUT_DIR%\scripts"
mkdir "%OUTPUT_DIR%\adb"
if not exist "%OUTPUT_DIR%\scripts" (
echo [ERROR] Could not create scripts directory.
goto :Error
)
if not exist "%OUTPUT_DIR%\adb" (
echo [ERROR] Could not create ADB directory.
goto :Error
)

:: 3. Copy App Executables (contents of /dist -> /vcamdroid)
:: 5. Copy App Executables (contents of /dist -> /vcamdroid)
if exist "%SOURCE_DIST%" (
echo [INFO] Copying application executables...
xcopy /s /e /y /q "%SOURCE_DIST%\*" "%OUTPUT_DIR%\"
if errorlevel 1 goto :Error
) else (
echo [ERROR] Dist folder not found at: %SOURCE_DIST%
goto :Error
)

:: 4. Copy ADB folder (/windows/adb -> /vcamdroid/adb)
:: 6. Copy ADB folder (/windows/adb -> /vcamdroid/adb)
if exist "%SOURCE_ADB%" (
echo [INFO] Copying ADB binaries...
xcopy /s /e /y /q "%SOURCE_ADB%\*" "%OUTPUT_DIR%\adb\"
if errorlevel 1 goto :Error
) else (
echo [ERROR] ADB folder not found at: %SOURCE_ADB%
goto :Error
)

:: 5. Copy Batch Scripts (root -> /vcamdroid/scripts/)
:: 7. Copy Batch Scripts (root -> /vcamdroid/scripts/)
echo [INFO] Copying batch scripts...
for %%f in (%SCRIPTS_TO_COPY%) do (
if exist "%%f" (
copy /y "%%f" "%OUTPUT_DIR%\scripts\%%f" >nul
echo - Copied %%f
) else (
echo [WARNING] Script not found: %%f
copy /y "%%f" "%OUTPUT_DIR%\scripts\%%f" >nul
if errorlevel 1 (
echo [ERROR] Failed to copy script: %%f
goto :Error
)
echo - Copied %%f
)

if not exist "%OUTPUT_DIR%\VCamdroid.exe" (
echo [ERROR] Packaged Windows executable is missing.
goto :Error
)
if not exist "%OUTPUT_DIR%\apk\app-release.apk" (
echo [ERROR] Packaged Android APK is missing.
goto :Error
)
if not exist "%OUTPUT_DIR%\adb\adb.exe" (
echo [ERROR] Packaged ADB executable is missing.
goto :Error
)

echo.
echo ===================================================
echo [SUCCESS] Package created successfully in: %OUTPUT_DIR%
echo ===================================================
popd
pause
exit /b 0

:Error
echo.
echo [FAIL] An error occurred during packaging.
popd
pause
exit /b 1