From 3fb8cc08fcf011e8520f5897daa81bf7ba5e356c Mon Sep 17 00:00:00 2001 From: zarik5 Date: Thu, 4 Jan 2024 19:10:52 +0800 Subject: [PATCH 1/4] Use ? instead of unwrap() --- alvr/dashboard/src/dashboard/components/setup_wizard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alvr/dashboard/src/dashboard/components/setup_wizard.rs b/alvr/dashboard/src/dashboard/components/setup_wizard.rs index b89c7bce5b..12211c072d 100644 --- a/alvr/dashboard/src/dashboard/components/setup_wizard.rs +++ b/alvr/dashboard/src/dashboard/components/setup_wizard.rs @@ -305,7 +305,7 @@ fn download_and_prepare_audio_script() -> alvr_common::anyhow::Result Date: Fri, 5 Jan 2024 15:00:11 +0500 Subject: [PATCH 2/4] Miscaleneous wiki, script updates (#1948) * Updated wiki with reformats, deleting older info, updating adb forwarder link; Updated flatpak audio script; Updated alvr screenshot in wiki; * Removed v11 section; Formatted audio-flatpak-setup.sh --- alvr/xtask/flatpak/audio-flatpak-setup.sh | 76 ++++++++++-------- wiki/ALVR-Checklist.md | 3 + ...lient-and-streamer-on-separate-networks.md | 26 +++--- wiki/ALVR-in-distrobox.md | 28 ++----- wiki/Building-From-Source.md | 55 ++++++++++--- ...uration-Information-and-Recommendations.md | 65 ++++++++------- wiki/Controller-latency.md | 3 - wiki/Fixed-Foveated-Rendering-(FFR).md | 10 ++- wiki/Flatpak.md | 1 - wiki/Hand-tracking-controller-bindings.md | 18 +++-- wiki/Installation-guide.md | 23 ++---- wiki/Linux-Support-development-progress.md | 11 +++ .../My-game-is-not-working-properly!-Help!.md | 5 -- wiki/Real-time-video-upscaling-experiments.md | 2 +- wiki/Roadmap.md | 12 +-- wiki/Troubleshooting.md | 14 +++- wiki/Use-ALVR-through-a-USB-connection.md | 34 ++++---- wiki/images/ALVRexe-no-clients.png | Bin 17042 -> 35808 bytes 18 files changed, 220 insertions(+), 166 deletions(-) diff --git a/alvr/xtask/flatpak/audio-flatpak-setup.sh b/alvr/xtask/flatpak/audio-flatpak-setup.sh index e5e6d7d1be..0d2f2324c4 100644 --- a/alvr/xtask/flatpak/audio-flatpak-setup.sh +++ b/alvr/xtask/flatpak/audio-flatpak-setup.sh @@ -1,9 +1,21 @@ #!/bin/bash -function get_alvr_playback_source_id() { +# Set either to 0 to prevent from creating audio or microphone sinks and instead you using own headset or microphone +USE_HEADSET_AUDIO=1 +USE_HEADSET_MIC=1 + +function get_playback_sink_input_id() { + get_playback_id sink-inputs 'Sink Input' "$1" +} + +function get_playback_source_output_id() { + get_playback_id source-outputs 'Source Output' "$1" +} + +function get_playback_id() { local last_node_name='' local last_node_id='' - pactl list $1 | while read -r line; do + pactl list "$1" | while read -r line; do node_id=$(echo "$line" | grep -oP "$2 #\K.+" | sed -e 's/^[ \t]*//') node_name=$(echo "$line" | grep -oP 'node.name = "\K[^"]+' | sed -e 's/^[ \t]*//') if [[ "$node_id" != '' ]] && [[ "$last_node_id" != "$node_id" ]]; then @@ -19,52 +31,52 @@ function get_alvr_playback_source_id() { done } -function get_sink_id() { +function get_sink_id_by_name() { local sink_name sink_name=$1 pactl list short sinks | grep "$sink_name" | cut -d$'\t' -f1 } function setup_mic() { - echo "Creating microphone sink & source and linking alvr playback to it" - # This sink is required so that it persistently auto-connects to alvr playback later - pactl load-module module-null-sink sink_name=ALVR-MIC-Sink media.class=Audio/Sink - # This source is required so that any app can use it as microphone - pactl load-module module-null-sink sink_name=ALVR-MIC-Source media.class=Audio/Source/Virtual - # We link them together - pw-link ALVR-MIC-Sink ALVR-MIC-Source - # And we assign playback of pipewire alsa playback to created alvr sink - pactl move-sink-input "$(get_alvr_playback_source_id sink-inputs 'Sink Input' 'ALSA plug-in [vrserver]')" "$(get_sink_id ALVR-MIC-Sink)" + if [[ $USE_HEADSET_MIC == 1 ]]; then + echo "Creating microphone sink & source and linking alvr playback to it" + # This sink is required so that it persistently auto-connects to alvr playback later + pactl load-module module-null-sink sink_name=ALVR-MIC-Sink media.class=Audio/Sink | tee -a /run/user/1000/alvr-audio + # This source is required so that any app can use it as microphone + pactl load-module module-null-sink sink_name=ALVR-MIC-Source media.class=Audio/Source/Virtual | tee -a /run/user/1000/alvr-audio + # We link them together + pw-link ALVR-MIC-Sink:monitor_FL ALVR-MIC-Source:input_FL + pw-link ALVR-MIC-Sink:monitor_FR ALVR-MIC-Source:input_FR + # And we assign playback of pipewire alsa playback to created alvr sink + pactl move-sink-input "$(get_playback_sink_input_id 'ALSA plug-in [vrserver]')" "$(get_sink_id_by_name ALVR-MIC-Sink)" + pactl set-default-source ALVR-MIC-Source + fi } -function setup_audio() { - echo "Setting up audio" - pactl load-module module-null-sink sink_name=ALVR-AUDIO-Sink media.class=Audio/Sink - pactl set-default-sink ALVR-AUDIO-Sink - pactl move-source-output "$(get_alvr_playback_source_id source-outputs 'Source Output' 'ALSA plug-in [vrserver]')" "$(get_sink_id ALVR-AUDIO-Sink)" +function unload_modules() { + echo "Unloading audio, microphone sink & source" + while read -r line; do + pactl unload-module "$line" + done <"/run/user/1000/alvr-audio" + >/run/user/1000/alvr-audio } -function unload_mic() { - echo "Unloading microphone sink & source" - pw-cli destroy ALVR-MIC-Sink - pw-cli destroy ALVR-MIC-Source -} - -function unload_sink() { - echo "Unloading audio sink" - pw-cli destroy ALVR-AUDIO-Sink +function setup_audio() { + if [[ $USE_HEADSET_AUDIO == 1 ]]; then + echo "Setting up audio" + pactl load-module module-null-sink sink_name=ALVR-AUDIO-Sink media.class=Audio/Sink | tee -a /run/user/1000/alvr-audio + pactl set-default-sink ALVR-AUDIO-Sink + pactl move-source-output "$(get_playback_source_output_id 'ALSA plug-in [vrserver]')" "$(get_sink_id_by_name ALVR-AUDIO-Sink)" + fi } case $ACTION in connect) - unload_sink - unload_mic - sleep 1 - setup_mic + unload_modules setup_audio + setup_mic ;; disconnect) - unload_mic - unload_sink + unload_modules ;; esac diff --git a/wiki/ALVR-Checklist.md b/wiki/ALVR-Checklist.md index 1f163f29ca..7e3b1a0faf 100644 --- a/wiki/ALVR-Checklist.md +++ b/wiki/ALVR-Checklist.md @@ -8,6 +8,7 @@ * [ ] A 5Ghz router/access point or my PC can create its own 5Ghz hotspot ## Network settings + * [ ] My PC has a wired connection to the router/access point * [ ] The access point is placed in sight of my designated playspace without any obstructions * [ ] I'm using the 5ghz antenna of the router/access point @@ -16,10 +17,12 @@ * [ ] The 5Ghz and 2.4Ghz parts of the access point have different SSIDs to prevent switching to 2.4ghz ## Software settings + * [ ] I have the latest Windows 10 updates * [ ] I have a recent version of SteamVR ## Troubleshooting + * [ ] The firewall settings where successfully applied with the setup of ALVR * [ ] I did not change the network settings since the installation of ALVR (Private/Public/Work) * [ ] I did not move the installation folder of ALVR since the setup diff --git a/wiki/ALVR-client-and-streamer-on-separate-networks.md b/wiki/ALVR-client-and-streamer-on-separate-networks.md index cc8e291bf0..b56d5f8112 100644 --- a/wiki/ALVR-client-and-streamer-on-separate-networks.md +++ b/wiki/ALVR-client-and-streamer-on-separate-networks.md @@ -5,6 +5,7 @@ Here are explained two methods to connect PC and headset remotely, port-forwarding and ZeroTier. The primary purpose of this is connecting the headset to a Cloud PC (like ShadowPC). ## Port-forwarding + Port-forwarding allows to connect devices that are behind different NATs, i.e. local networks. You need to have administrator access to your router. This method has the best streaming performance. **IMPORTANT**: ALVR does not use end-to-end encryption of the stream data. By using this method you need to be aware that the connection is vulnerable to "Man In The Middle" attacks. @@ -24,22 +25,27 @@ You can now use ALVR to connect to your remote PC. Comparing this to the port-forwarding method: Pros: + * Does not require access to the router interface. * You don't need to update the public IP often on the streamer. * The connection in encrypted. Cons: + * The streaming performance is worse. You may experience more glitches and loss of quality in the image and audio. ### Requirements + - [ZeroTier](https://www.zerotier.com/) for your PC - ZeroTier APK for your Quest (you can find it online) - SideQuest or some other method to install the ZeroTier APK onto your headset ### Installation + Use the "Install APK" function of SideQuest to install the ZeroTier APK to your Quest, and also download and install ZeroTier on your PC. After you've installed ZeroTier, follow Zerotier's official [Getting Started](https://zerotier.atlassian.net/wiki/spaces/SD/pages/8454145/Getting+Started+with+ZeroTier) guide to setup a network for ALVR. Join the network on both the Quest and the PC. On the Quest, make sure that the network is enabled by switching on the slider on the network in the list in the ZeroTier app (you may be prompted to allow ZeroTier to create a VPN connection). After both your PC and your Quest are connected to the same ZeroTier network, we'll need to manually add your quest to the ALVR dashboard. To do so, we'll need to find your Quest's ZeroTier IP. There are two ways to do this. + - Go the the ZeroTier network page, find your quest under "Members", and copy the managed IP from there - Or, in the ZeroTier app on your quest, click on the network you created. The IP is under the "Managed IPs" section at the bottom. @@ -50,6 +56,7 @@ Next, we'll need to add the Quest to the ALVR dashboard. On your headset, launch At this point, you should be ready to go. Have fun in VR! ### Troubleshooting + - If you can't get your Quest to connect to ALVR, and are stuck on the "Trust" screen, try to ping your Quest's managed IP address (the one we got earlier). If it says "no route to host" or something similar, your Quest can't see your PC. Try running through the steps above to make sure you didn't miss anything. ## Tailscale @@ -64,6 +71,7 @@ https://tailscale.com/ Its pros and cons are similar to ZeroTier, but it's self-hosted and open-source if you care about privacy, though instead you need some knowledge about networking and server deploying. ### Requirements + - Compile [n2n](https://github.com/ntop/n2n) from source - Or you can grab pre-built binaries from [here](https://github.com/lucktu/n2n) directly, compiled by lucktu. - Some Linux distribution may have n2n, but be sure you're using the same version. Since the source code is v3, the following steps will also use v3 in the example below. @@ -73,6 +81,7 @@ Its pros and cons are similar to ZeroTier, but it's self-hosted and open-source - SideQuest or some other method to install the hin2n APK onto your headset ### Installation + We're going to use n2n v3, and set the port of _supernode_ to `1234` as the example. You can change `1234` to any port, but below `1024` requires root. - Open port `1234` on your server's firewall (usually `iptables`, if you don't know what to do, ask Google). @@ -94,27 +103,14 @@ We're going to use n2n v3, and set the port of _supernode_ to `1234` as the exam - Once it's done, you're all set. ### Troubleshooting + - Make sure you can access to the supernode, your supernode should be run on a server with public IP, and you can ping it on your PC. - If your Quest cannot connect to ALVR dashboard, ping the IP you assigned to Quest in hin2n. If it fails, try redoing the setup steps. - If the edge binary or hin2n says the IP has already been assigned and not released by supernode, you can set IP address to another one in the same subnet like `192.168.100.123` to reassign a new IP to the device. - If you're playing over WAN, you may see more glitches, higher stream latency, or lagger response with TCP. Use adaptive bitrate and UDP may improve your experience. -# ALVR v11 and Below - -ALVR version Experimental v7 or newer is recommended for this configuration. - -This configuration is **NOT** supported in ALVR v12. The latest release to still support this is v11. - -To run ALVR client and ALVR streamer on separate networks (broadcast domains) the following things must be done: -1. UDP ports 9943 and 9944 of ALVR streamer must be accessible from Oculus Quest device (i.e. firewall openings must be made to allow Oculus Quest to connect to ALVR streamer UDP ports 9943 and 9944). -1. Oculus Quest must be connected to computer and command-line `adb shell am startservice -n "com.polygraphene.alvr/.ChangeSettings" --es "targetServers" "10.10.10.10"` must be run in Command Prompt to specify IP address of ALVR streamer (`10.10.10.10` must be substituted with IP address of ALVR streamer; the long line is a single command-line). -1. Next time when ALVR client will be started it should try to connect to the specified ALVR streamer. ALVR streamer should display the client in _Server_ tab (the same way local-network clients are displayed). - - -ALVR does **NOT** provide any kind of tunnel, NAT traversal etc. UDP ports 9943 and 9944 of ALVR streamer (VR gaming PC) must be accessible from ALVR client (Oculus Quest) otherwise this won't work. - - **Important notes on security!** + * ALVR protocol does not have any encryption or authentication (apart from ALVR client IP address shown in ALVR streamer and the requirement to click _Connect_ on ALVR streamer). * It is recommended to run ALVR via encrypted tunnel (VPN) over the internet. In case VPN is not an option, access to ALVR streamer (UDP ports 9943 and 9944) should be restricted by Windows Firewall (only connections from known IP addresses of ALVR clients should be allowed) and ALVR streamer should not be left running unattended. * **Warning!** SteamVR allows to control desktop from VR headset (i.e. a **malicious ALVR client could take over the PC**). diff --git a/wiki/ALVR-in-distrobox.md b/wiki/ALVR-in-distrobox.md index 145dbe0691..a8d3e2e5b6 100644 --- a/wiki/ALVR-in-distrobox.md +++ b/wiki/ALVR-in-distrobox.md @@ -21,7 +21,6 @@ For installing you only really need couple of dependencies on host: 3. `sed` (for removing color in logs) 4. `pipewire` for fully automatic microphone, `pulseaudio` for basic audio support (automatic microphone is unsupported with it) 5. For nvidia - `CUDA` (distrobox passes through it and driver as well into the container and CUDA contains NVENC encoder for streaming) -6. If you don't have `newgidmap` command available, you need to install `shadow-utils`. (packages ubuntu-like: `newuidmap`, arch-like: `shadow`, mint: `uidmap`) After you have installed required dependencies for your installation from above, open terminal in this repository folder and do: @@ -31,13 +30,9 @@ After you have installed required dependencies for your installation from above, In case if have errors during installation, please report the full log as-is (remove private info if you happen to have some) as an Issue. - But if you are just reinstalling it, please run `./uninstall.sh` first before trying to install again. - After full installation, you can use `./start-alvr.sh` to launch alvr automatically. Script also downloads related apk file to install to headset into `installation` folder for you. Use Sidequest or ADB to install it. - - **Experimental:** Prefixed installation is now available, which allows you to specify where to install relative to this folder. Use --prefix and --container-name to specify folder name and container name (you should specify both for this to work) ## Post-install ALVR & SteamVR Configuration @@ -49,21 +44,17 @@ After installing ALVR you may want to configure it and steamvr to run at best qu 2. **Preferred framerate:** If you know that you will have lower fps than usual (for instance, VRChat), run at lower fps. This is because when reprojection (this is what allows for smooth view despite being at low fps) goes lower than twice the amount of specified framerate - it fails to reproject and will look worse. So for example, you can run at 72hz if you know you're expecting low framerate, and 120hz if you are going to play something like Beat Saber, which is unlikely to run at low fps. -3. **Encoder preset:** Balanced - -4. **Game Audio & Microphone:** Set to pipewire as has been said in installation. ALVR uses default audio sink for audio, and doesn't care about volume (it's controlled only onboard audio on headset), and automatic audio scripts mutes default audio by default to prevent mirroring. As for microphone, every time ALVR is connected on headset, on connect script creates audio source named **ALVR-MIC-Source**, which can be used in game as default microphone, if you set it at least once. No need to un-set it back to default. And when headset disconnects it automatically clears audio source and restores back to previous microphone. +3. **Encoder preset:** Speed -5. **Bitrate:** Constant, bitrate: 350-450 mbps for h264 wireless/700 mbit-1 gbit cabled, 100-150 mbps for HEVC. +4. **Bitrate:** Constant, bitrate: 350-450 mbps for h264 wireless/700 mbit-1 gbit cabled, 100-150 mbps for HEVC (tested on Pico 4 ). -6. **Foveated rendering:** This highly depends on given headset, but generally default settings should be OK for Quest 2. For **pico neo 3** i would recommend setting center region width to 0.8 and height to 0.75, shifts to 0 and edge ratios can be set at 6-7, and for the same **pico neo 3** disable oculus foveation level and dynamic oculus foveation. +5. **Foveated rendering:** This highly depends on given headset, but generally default settings should be OK for Quest 2. For **pico neo 3** i would recommend setting center region width to 0.8 and height to 0.75, shifts to 0 and edge ratios can be set at 6-7, and for the same **pico neo 3** disable oculus foveation level and dynamic oculus foveation. -7. **Color correction:** Set sharpening to 1and if you like oversaturated image, bump saturation to 0.6. +6. **Color correction:** Set sharpening to 1and if you like oversaturated image, bump saturation to 0.6. -8. For **pico neo 3** left controller offsets (from top to bottom): Position -0.06, -0.03, -0.1; Rotation: 0, 3, 17. +7. For **pico neo 3** left controller offsets (from top to bottom): Position -0.06, -0.03, -0.1; Rotation: 0, 3, 17. -9. **Connection -> Stream Protocol:** TCP. This ensures that there would be no heavy artifacts if packet loss happens (until it's too severe), only slowdowns. - -10. **Linux async reprojection:** keep it off, it's not needed anymore and client does reprojection better +8. **Connection -> Stream Protocol:** TCP. This ensures that there would be no heavy artifacts if packet loss happens (until it's too severe), only slowdowns. ### AMD-specific configuration: @@ -95,12 +86,7 @@ Inside SteamVR you also may need to change settings to improve experience. Open ### Distrobox note: -* To enter container (for updating archlinux, installing additional software, and other reasons) you need to do the following: -1. `source ./setup-env.sh` - -2. `distrobox-enter arch-alvr` - -        This enters the container. Do note that `sudo` inside container doesn't have privliges to do anything as `root`, but that container has almost exactly the same rights as regular user, so deleting user files from that container **is** possible. +* Do note that `sudo` inside container doesn't have privliges to do anything as `root`, but that container has almost exactly the same rights as regular user, so deleting user files from that container **is** possible. * You can add your steam library from outside the container after alvr installation as for container, `/home/user` folder is the same as on your host, so you can add it from inside distrobox steam. diff --git a/wiki/Building-From-Source.md b/wiki/Building-From-Source.md index c490c23dd3..6210cc91b6 100644 --- a/wiki/Building-From-Source.md +++ b/wiki/Building-From-Source.md @@ -15,29 +15,39 @@ First you need to gather some additional resources in preparation for the build. If you are on Linux, install these additional packages: * **Arch** + ```bash sudo pacman -S clang curl nasm pkgconf yasm vulkan-headers libva-mesa-driver unzip ffmpeg ``` - * The [`alvr-git`](https://aur.archlinux.org/packages/alvr-git) [AUR package](https://wiki.archlinux.org/title/Arch_User_Repository) may also be used to do this automatically. + + * The [`alvr-git`](https://aur.archlinux.org/packages/alvr-git) [AUR package](https://wiki.archlinux.org/title/Arch_User_Repository) may also be used to do this automatically. + * **Gentoo** + * `media-video/ffmpeg >= 4.4 [encode libdrm vulkan vaapi]` * `sys-libs/libunwind` * `dev-lang/rust >= 1.72` * `media-video/pipewire [jacksdk]` + * **Nix(OS)** + * Use the `shell.nix` in `packaging/nix`. + * **Debian 12 / Ubuntu 20.04 / Pop!\_OS 20.04** + ```bash sudo apt install build-essential pkg-config libclang-dev libssl-dev libasound2-dev libjack-dev libgtk-3-dev libvulkan-dev libunwind-dev gcc-8 g++-8 yasm nasm curl libx264-dev libx265-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libdrm-dev libva-dev libvulkan-dev vulkan-headers ``` + * **Fedora** + ```bash sudo dnf groupinstall 'Development Tools' | For c++ and build tools sudo dnf install yasm libdrm-devel vulkan-headers pipewire-jack-audio-connection-kit-devel atk-devel gdk-pixbuf2-devel cairo-devel rust-gdk0.15-devel x264-devel vulkan-devel libunwind-devel clang openssl-devel alsa-lib-devel libva-devel - ``` - If you are using Nvidia, see [Fedora cuda installation](https://github.com/alvr-org/ALVR/wiki/Building-From-Source#fedora-cuda-installation) + If you are using Nvidia, see [Fedora cuda installation](https://github.com/alvr-org/ALVR/wiki/Building-From-Source#fedora-cuda-installation) + Move to the root directory of the project, then run this command (paying attention to the bullet points below): ```bash @@ -61,56 +71,77 @@ You can find the resulting package in `build/alvr_streamer_[your platform]` If you want to edit and rebuild the code, you can skip the `prepare-deps` command and run only the `build-streamer` command. ## Fedora CUDA installation + If you are here for CUDA installation on Fedora you're at the right place! Else continue down to [Client Building](https://github.com/alvr-org/ALVR/wiki/Building-From-Source#client-building) + ### 1. Install Nvidia drivers and Fedora CUDA driver + ```bash sudo dnf update -y ``` + (Reboot if you have a new kernel) + ```bash sudo dnf install akmod-nvidia sudo dnf install xorg-x11-drv-nvidia-cuda ``` + Wait until ```modinfo -F version nvidia``` doesn't report ```"ERROR: Module nvidia not found"``` anymore ### 2. Install Nvidia's CUDA + In the previous step, we installed Fedora's CUDA that doesn't work with ALVR, installing Nvidia's CUDA works and creates directories instead + ```bash sudo dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/fedora37/x86_64/cuda-fedora37.repo ``` + Change the Fedora version if you are on a different version. You should check if your version is supported by inspecting the repo + ```bash sudo dnf clean all sudo dnf module disable nvidia-driver sudo dnf -y install cuda export PATH=/usr/local/cuda-12.3/bin${PATH:+:${PATH}} ``` + If your cuda version is different, change it to the version that is installed. You can check installed versions by doing ```ls /usr/local/ | grep "cuda"``` in your terminal **Comments** + * Disabling the nvidia-driver doesn't disable Nvidia drivers but prevents nvidia dkms from installing over the akmod driver ### 3. Install gcc11 install with homebrew + Becuase cuda cannot be ran without a gcc version lower than or equal to gcc12, you will need to install a gcc version on homebrew. The fedora gcc11 package got removed so this is the only way sadly To install homebrew, run this command: + ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` + Then install gcc11 + ```bash brew install gcc@11 ``` + **Comments** + * If brew is not found in your path, run the following separately to add brew to your path: -```bash -test -d ~/.linuxbrew && eval "$(~/.linuxbrew/bin/brew shellenv)" -test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" -echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.bashrc -``` + + ```bash + test -d ~/.linuxbrew && eval "$(~/.linuxbrew/bin/brew shellenv)" + test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.bashrc + ``` ### 4. Modify dependencies.rs to use correct cuda path and gcc version + Because CURA installs as a symlink by default, we need to change the dependencies.rs to use the directory From the ALVR directory edit the ./alvr/xtask/src/dependencies.rs, and change two lines: + * Line 159, change ```cuda``` -> ```cuda-12.3``` (or whatever version you have) * Line 179, replace that line with ```--nvccflags=\"-ccbin /home/linuxbrew/.linuxbrew/bin/g++-11 -gencode arch=compute_52,code=sm_52 -O2\"``` (Change homebrew path if needed, default is used) @@ -121,6 +152,7 @@ You should be good to go! Refer to [Streamer Building](https://github.com/alvr-o ## 1. Installing necessary packages For the client you need install: + * [Android Studio](https://developer.android.com/studio) or the [sdkmanager](https://developer.android.com/studio/command-line/sdkmanager) * Android SDK Platform-Tools 29 (Android 10) * Latest Android NDK (currently v25.1.8937393) @@ -150,10 +182,12 @@ The three mentioned developer applications can be installed from upstream; altho For Debian, it requires to have the `non-free` repository to be enabled: * **Debian 12 / Ubuntu 22.10 / Pop!\_OS 22.10** + ```bash sudo apt install android-sdk-platform-tools-common sdkmanager google-android-ndk-r25b-installer ``` -## 2. Setting environment variables + + ## 2. Setting environment variables For Windows, set the environment variables: @@ -195,11 +229,13 @@ cargo xtask prepare-deps --platform android Before building the client, Android has to have us to agree to the licenses otherwise building the client will halt and fail. To accept the agreements, follow the instructions for your corresponding OS: * Windows: + ```shell cd "%ANDROID_SDK_ROOT%\tools\bin" sdkmanager.bat --licenses ``` * Linux: + ```bash cd ~/AndroidSDK sdkmanager --licenses @@ -214,6 +250,7 @@ cargo xtask build-client --release The built APK will be in `build/alvr_client_quest`. You can then use adb or SideQuest to install it to your headset. To build and run: + ```bash cd alvr/client_openxr cargo apk run diff --git a/wiki/Configuration-Information-and-Recommendations.md b/wiki/Configuration-Information-and-Recommendations.md index 2f6301a70d..bed16f3f19 100644 --- a/wiki/Configuration-Information-and-Recommendations.md +++ b/wiki/Configuration-Information-and-Recommendations.md @@ -1,6 +1,7 @@ # Information and Recommendations # PC + - A high-end PC is a requirement; ALVR is not a cheap alternative to a PCVR HMD - ALVR resolution configuration and SteamVR multi-sampling may be used to influence quality in favor of performance or vice-versa - Frequent dropped frames can cause a poor experience on ALVR; this can be verified using a tool such as [OVR Advanced Settings](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings) @@ -9,21 +10,24 @@ - A good starting point is 100% resolution and 30mbit- 200kb buffer settings. In this config it should be butter smooth with almost no lag or packet loss; packet loss seen at this point is likely a result of network issues # Network + - A wired connection from the PC to the network is **strongly recommended** - A modern mid to high-end router and / or access point supporting at least 802.11AC (ideally 802.11AX) with regularly updated firmware is recommended ## Wireless + ### General WiFi configuration best practices: + - Any device that can be wired should be; each wireless device slows down the overall wireless network - Devices should have the fewest obstructions and be as close to the access point or router as possible - Any other wireless networks (ex: a printer's default wireless network) should be disabled; each network slows others down - Any devices that do not need high speeds but support them (ex: a thermostat) should use 2.4Ghz; often middle and higher end access points and routers support methods to "force" clients to use 2.4Ghz, and some can even perform this automatically based on signal strength and connection speed - Only WiFi revisions which are necessary should be enabled; older standards such as 802.11B, 802.11G, and to a lesser extent, 802.11N, will slow down all clients - Devices that require high speeds should use: - - 5Ghz only - - The newest WiFi specifications (802.11AX, followed by 802.11AC) - - In most environments, the largest channel width possible (160MHz for 802.11AX, 80MHz in practice for 802.11AC) (**note: some vendors do not set this to the maximum by default**) - - The lowest utilization, followed by the lowest channel number (sub-frequency) possible + - 5Ghz only + - The newest WiFi specifications (802.11AX, followed by 802.11AC) + - In most environments, the largest channel width possible (160MHz for 802.11AX, 80MHz in practice for 802.11AC) (**note: some vendors do not set this to the maximum by default**) + - The lowest utilization, followed by the lowest channel number (sub-frequency) possible - **Manually selecting channels should only be done in places with extreme noise, or on older, lower quality, or ISP provided access points or routers** ; modern mid to high-end routers and access points should optimize their channels fairly well, and as a result of other routers and clients "channel hopping", static settings are often less optimal - If a specific WiFi channel range is absolutely necessary, use a WiFi scanning tool on a phone or PC to determine the least used channels; mid to high-end access points and routers may provide an interface for this as well, however, this sometimes causes a disconnect when scanning - **Manually selecting wifi signal strength should only be done in places with extreme noise**; modern routers and access points do this well, and it is a complex task @@ -31,16 +35,18 @@ - If you have a significant number of devices, some routers and access points support features such as airtime fairness, which help to limit the amount of airtime slower clients take, improving the performance of higher speed clients ### Things to keep in mind when configuring a wireless network and devices: + - All devices on the same frequency impact each other (**including other WiFi networks on the same channel**) because only one device can transmit or receive data at a time, meaning that: - - If one device utilizes WiFi heavily it will impact the latency and throughput of all other clients - - If a slow device is connected, it can still take a significant amount of "airtime" (time for that dedicated client to transmit / receive data to the access point or router), even though it does so at a slower rate than other clients - - Each connected device requires additional time, regardless of whether it is actively in use (and often devices send small amounts of data when idle for things such as NTP and DHCP) + - If one device utilizes WiFi heavily it will impact the latency and throughput of all other clients + - If a slow device is connected, it can still take a significant amount of "airtime" (time for that dedicated client to transmit / receive data to the access point or router), even though it does so at a slower rate than other clients + - Each connected device requires additional time, regardless of whether it is actively in use (and often devices send small amounts of data when idle for things such as NTP and DHCP) - WiFi is [half duplex](https://en.wikipedia.org/wiki/Duplex_(telecommunications)#Half_duplex) by nature of it being radio frequency, meaning data can only ever be transmitted **or** received on the same frequency, not both at the same time; twisted pair (copper ethernet cable) is full duplex - Wireless frequency bands (ex: 2.4Ghz, 5Ghz) have separate channels that can be statically assigned if needed, but **these are not mutually exclusive, meaning the channels overlap significantly and interfere with each other** - Different regions of the world support different channels (sub-frequencies); devices sold in these regions are generally locked to those channels (ex: in the US, 2.4Ghz channels 12 - 13 are low power only, and channel 14 is military and EMS use only) - Different wireless devices support different frequencies, standards, speeds, and features; using these to your advantage is key to getting best performance ## Routing / Switching / Firewalling / General Info + - Ideally client and streamer should live on the same logical (layer 2) network and subnet; this allows for no routing overhead, and the correct function of client discovery via mDNS - Twisted pair (normal copper ethernet cables) should never be run alongside power cables; this can cause signal noise and result in frame loss and lowered auto-negotiation speeds - High quality CAT5E or higher (ideally CAT6A or CAT7) cabling should be used for modern networks @@ -55,6 +61,7 @@ https://imaginevr.home.blog/author/imaginevrresearch/ Some points came from [FingrMastr](https://github.com/FingrMastr) # Linux + ## Encoder requirements ALVR uses FFmpeg for all encoders, so you will need to make sure the encoder of your choice works with FFmpeg. @@ -70,21 +77,21 @@ Trying display: wayland vainfo: VA-API version: 1.16 (libva 2.16.0) vainfo: Driver version: Mesa Gallium driver 23.0.0-devel for Radeon RX 7900 XTX (gfx1100, LLVM 16.0.0, DRM 3.49, 6.1.1-zen1-1-zen) vainfo: Supported profile and entrypoints - VAProfileH264ConstrainedBaseline: VAEntrypointVLD - VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice - VAProfileH264Main : VAEntrypointVLD - VAProfileH264Main : VAEntrypointEncSlice - VAProfileH264High : VAEntrypointVLD - VAProfileH264High : VAEntrypointEncSlice - VAProfileHEVCMain : VAEntrypointVLD - VAProfileHEVCMain : VAEntrypointEncSlice - VAProfileHEVCMain10 : VAEntrypointVLD - VAProfileHEVCMain10 : VAEntrypointEncSlice - VAProfileJPEGBaseline : VAEntrypointVLD - VAProfileVP9Profile0 : VAEntrypointVLD - VAProfileVP9Profile2 : VAEntrypointVLD - VAProfileAV1Profile0 : VAEntrypointVLD - VAProfileNone : VAEntrypointVideoProc + VAProfileH264ConstrainedBaseline: VAEntrypointVLD + VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice + VAProfileH264Main : VAEntrypointVLD + VAProfileH264Main : VAEntrypointEncSlice + VAProfileH264High : VAEntrypointVLD + VAProfileH264High : VAEntrypointEncSlice + VAProfileHEVCMain : VAEntrypointVLD + VAProfileHEVCMain : VAEntrypointEncSlice + VAProfileHEVCMain10 : VAEntrypointVLD + VAProfileHEVCMain10 : VAEntrypointEncSlice + VAProfileJPEGBaseline : VAEntrypointVLD + VAProfileVP9Profile0 : VAEntrypointVLD + VAProfileVP9Profile2 : VAEntrypointVLD + VAProfileAV1Profile0 : VAEntrypointVLD + VAProfileNone : VAEntrypointVideoProc ``` *VAProfileH264High, VAProfileHEVCMain, VAProfileHEVCMain10* encoders (VAEntrypointEncSlice) required. If you don't see those @@ -120,10 +127,12 @@ Software encoder is mainly used as a fallback and as such should work on all GPU Only H264 encoding is currently supported. ## Legacy Reprojection + SteamVR by default will still use async reprojection for all games, which can cause issues such as: - - Ghosting - - Jumpy framerate - - Jittery movement - - General unsmoothness -And all other sorts of issues. Turning on Legacy Reprojection in the per game video settings inside SteamVR will effectively disable -any reprojection making the experience far better. + +- Ghosting +- Jumpy framerate +- Jittery movement +- General unsmoothness + And all other sorts of issues. Turning on Legacy Reprojection in the per game video settings inside SteamVR will effectively disable + any reprojection making the experience far better. diff --git a/wiki/Controller-latency.md b/wiki/Controller-latency.md index 3be261e7fe..c65798ab20 100644 --- a/wiki/Controller-latency.md +++ b/wiki/Controller-latency.md @@ -14,6 +14,3 @@ You can change the 10ms offset for SteamVR in the "Other" tab of ALVR (Controlle The parameter defines how old the data that is fed into SteamVR is and controls the SteamVR pose prediction. Set it to 0 to disable all predictions The default is 0.01=10ms. Its the amount of time I needed to be able swing my sword in Skyrim without feeling weird. Its very possible that this value depends on the game/user, that's why it's exposed in the control panel, and you can change it on the fly - - - diff --git a/wiki/Fixed-Foveated-Rendering-(FFR).md b/wiki/Fixed-Foveated-Rendering-(FFR).md index cead101096..b7752144d8 100644 --- a/wiki/Fixed-Foveated-Rendering-(FFR).md +++ b/wiki/Fixed-Foveated-Rendering-(FFR).md @@ -1,5 +1,7 @@ # Fixed Foveated Rendering (FFR) + ## What is it, why do I need it + In short: The human eye can only see sharp in a very small area (the fovea). That's why we move our eyes constantly to get the feeling that our whole view is a sharp image. The idea of foveated rendering is, to only render the small portion of the screen where we look at at the highest resolution, and the other parts at a lower resolution. This would massively increase the performance without any noticeable visual impact. But it has one drawback: You need to track the movement of the eyes. While there are already headsets out there that have eyetracking, the quest does not have it. @@ -7,17 +9,20 @@ But it has one drawback: You need to track the movement of the eyes. While there That's why oculus is using Fixed Foveated rendering. There is some research that shows, that if you assume that the user looks at the center of the screen, some parts of the image are more important than others ([Oculus](https://developer.oculus.com/documentation/mobilesdk/latest/concepts/mobile-ffr/)). Many games on the Quest use this to improve rendering performance. ## FFR in ALVR + That's not how ALVR is using it :P We don't have any influence on how games get rendered, we only get the final rendered image that should be displayed. What ALVR normally does is: + - takes that image - encodes it as a video with the resolution you set at the video tab - transmits it to the Quest - displays the video With FFR: + - takes the image - projects the image, keeping the center area at the resolution you set at the video tab, reducing the resolution at the outer regions - encodes it as a video with the new, lower overall resolution @@ -26,6 +31,7 @@ With FFR: - displays the image There are two implementations of FFR by [zarik5](https://github.com/zarik5) + - warp: Uses a radial warping of the video where the center stays the same resolution and the outer regions get "squished" to reduce resolution - slices: Slices the image into parts (center, left/right, top/bottom) and encodes the outer slices with lower resolution. This method produces a much sharper image. @@ -36,11 +42,9 @@ Slicing will result in a noticeable border where the high res center ends. Increasing the foveation strength will result in visual artifacts with both methods ## Configuration + That depends on your perception. You should try different settings going from strength = 2 up to 5 for both methods. The higher you go, the more visual artifacts you will see at the edges of the screen. For the slice method, you can also set a center offset. This moves the high res center up or down to accommodate games that have more interaction in the upper or lower part of the screen. - - - [wikipedia](https://en.wikipedia.org/wiki/Foveated_rendering) diff --git a/wiki/Flatpak.md b/wiki/Flatpak.md index 4146aab53b..ec08c6bdbf 100644 --- a/wiki/Flatpak.md +++ b/wiki/Flatpak.md @@ -129,4 +129,3 @@ The support for other applications that are not launched via Steam is non-existe Various SteamVR utilities such as [WlxOverlay](https://github.com/galister/WlxOverlay) and [OpenVR-AdvancedSettings](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings) cannot run within the Flatpak sandbox due to their usage of AppImage. However, unpacking the supplied AppImage or building the utilities from source and running their binaries from within the sandbox similiarly to `alvr_dashboard` could work, but there is no guarantee that they will work properly. Some applications such as [Godot](https://godotengine.org) support OpenXR. However, unless they are launched within the Steam Flatpak sandbox, they will not work with the Steam Flatpak. See [here](https://github.com/flathub/com.valvesoftware.Steam/issues/1010) for more details. - diff --git a/wiki/Hand-tracking-controller-bindings.md b/wiki/Hand-tracking-controller-bindings.md index f375799154..d09ed0506b 100644 --- a/wiki/Hand-tracking-controller-bindings.md +++ b/wiki/Hand-tracking-controller-bindings.md @@ -6,15 +6,17 @@ Enabled state means that gestures won't be triggered, disabled would mean all ge Gestures --- -|Action|Handtracking pinch| -|-|-| -|Trigger|Pinch thumb and index| -|Joystick click|Curl thumb to palm| -|Grip|Curl middle, ring and little| -|Y/B|Pinch thumb and middle| -|X/A|Pinch thumb and ring| -|Menu button|Pinch thumb and little on left hand| + +| Action | Handtracking pinch | +| -------------- | ----------------------------------- | +| Trigger | Pinch thumb and index | +| Joystick click | Curl thumb to palm | +| Grip | Curl middle, ring and little | +| Y/B | Pinch thumb and middle | +| X/A | Pinch thumb and ring | +| Menu button | Pinch thumb and little on left hand | Joystick --- + Activation is done through curling all 4 fingers and touching top of hand with thumb diff --git a/wiki/Installation-guide.md b/wiki/Installation-guide.md index b2c3d8554f..7c24917a98 100644 --- a/wiki/Installation-guide.md +++ b/wiki/Installation-guide.md @@ -74,12 +74,12 @@ Notes: * Guide also contains fixes, tweaks, additional software like desktop overlay to help you run with steamvr better and workaround it's issues. -* It didn't have a *huge* feedback history yet, so if you happen to have issues, please report them into the said repository. +* It didn't have a *huge* feedback history yet, so if you happen to have issues, please report them into [the said](https://github.com/alvr-org/ALVR-Distrobox-Linux-Guide) repository. Installation: 1. `git clone https://github.com/alvr-org/ALVR-Distrobox-Linux-Guide.git` or download zip from https://github.com/alvr-org/ALVR-Distrobox-Linux-Guide, unpack it -somewhere in your home directory (steam doesn't like long paths) + somewhere in your home directory (steam doesn't like long paths) 1.1. If you want to use nightly (potentially unstable, but fresh) builds use [nightly](https://github.com/alvr-org/ALVR-Distrobox-Linux-Guide/tree/nightly) branch. @@ -92,9 +92,11 @@ somewhere in your home directory (steam doesn't like long paths) ### Other #### AppImage + You can get appimage for latest stable version from [here](https://github.com/alvr-org/ALVR/releases/latest). #### Flatpak + For Flatpak users, refer to the instructions [here](https://github.com/alvr-org/ALVR/wiki/Flatpak) #### Portable tar.gz @@ -106,19 +108,10 @@ For Flatpak users, refer to the instructions [here](https://github.com/alvr-org/ ### Automatic Audio & Microphone Setup -* Must be on v20+ - -* Enable Game Audio and Microphone in ALVR dashboard. - -* Select `pipewire` as the device +* Must be on v20.5.0+ -* Connect with headset and wait until streaming starts. +* Pipewire required -* Download [audio-setup.sh](https://github.com/alvr-org/ALVR-Distrobox-Linux-Guide/blob/main/audio-setup.sh) - script and place it in some safe place. - -* Make it executable (`chmod +x audio-setup.sh` or via your file manager through file properties) then put the - absolute path to the script in "On connect script" and "On disconnect script" settings, apply paths with enter - (Setting -> Scroll all the way to the bottom). +* Open installation -> Run setup wizard, skip to part with automatic audio setup -* Put headset to sleep and turn it back on, it should automatically create microphone and audio in your system and switch to them. +* Press the button to automatically download and set it diff --git a/wiki/Linux-Support-development-progress.md b/wiki/Linux-Support-development-progress.md index d6e0e44a39..898be240e6 100644 --- a/wiki/Linux-Support-development-progress.md +++ b/wiki/Linux-Support-development-progress.md @@ -1,12 +1,15 @@ **Warning:** This page is very outdated, see [Building From Source](https://github.com/alvr-org/ALVR/wiki/Building-From-Source) instead. ## 2022-01-04 + An experimental NVENC fork has successfully been created by [Toxblh](https://github.com/Toxblh), helping fix one of the larger bottlenecks on NVIDIA GPUs. [Pull Request here](https://github.com/alvr-org/ALVR/pull/906) ## 2021-05-18 + No special build steps are required for users who can acquire the correct ffmpeg version, read more [here](https://github.com/alvr-org/ALVR/wiki/Build-from-source#linux-experimental-build). ## 2021-04-22 + The PR in the last log was proceeded by [#604](https://github.com/alvr-org/ALVR/pull/604) and this new PR was merged into the main branch. Build instructions remain the same, but the `vrenv.sh` patching is no longer needed. ## 2021-04-01 @@ -14,12 +17,14 @@ The PR in the last log was proceeded by [#604](https://github.com/alvr-org/ALVR/ A [PR](https://github.com/alvr-org/ALVR/pull/569) has been made integrating Xytovl's vulkan layer into the main ALVR tree. It doesn't actually stream video yet but it provides a solid base for future work and is compatible with nVidia GPUs. After you've checked the PR's branch out and [built the streamer](https://github.com/alvr-org/ALVR/wiki/Build-from-source#build-streamer), you can build and install the Vulkan layer like this: + ``` cd alvr/server/cpp/tools/vulkan-layer mkdir build && cd build cmake .. make -j ``` + Add this line: `source "$(cat $XDG_RUNTIME_DIR/alvr_dir.txt | rev | cut -d'/' -f3- | rev)/alvr/server/cpp/tools/vulkan-layer/layer/vrenv.sh"` **before** the last one (`exec "$@"`) to `/path/to/your/SteamLibrary/steamapps/common/SteamVR/bin/vrenv.sh`. ## 2021-03-15 @@ -32,9 +37,11 @@ Work has started towards a new frame capturing method using a Vulkan debug layer An experimental branch is available at https://github.com/xytovl/ALVR/tree/linux-port-openvr with many limitations ### Adopted solution + We use SteamVR direct rendering mode on a fake screen, and capture the output of the screen. Current implementation only works for AMD (and probably Intel) open source drivers. ### Limitations + - audio streaming is not working - foveated encoding is not implemented - requires superuser access for setup @@ -45,9 +52,11 @@ We use SteamVR direct rendering mode on a fake screen, and capture the output of - only supports open source drivers ### Setup + See [build from source](Build-from-source) ## Usage + Run `build/alvr_streamer_linux/ALVR Dashboard` On first setup, SteamVR will probably show the VR display on your screen, with the configuration window. If you have dual screen, you can move the configuration window to a visible area (with Alt + drag on most desktop environments). @@ -59,6 +68,7 @@ On the headset, launch the application, then click trust on the configuration wi The headset says that the streamer will restart, but it will not. You must relaunch it manually. If you are here, once it is all restarted, you should be able to get the stream on the headset. + ## 2021-01-15 The development road has been defined, but we are not completely sure everything will work. @@ -75,6 +85,7 @@ The development road has been defined, but we are not completely sure everything We cannot find a way of obtaining the frames rendered by the VR game from SteamVR. The OpenVR API exposes methods to do this but they don't work on Linux (at least we were not able to make them work). The two methods to obtain frames with OpenVR are by implementing the interfaces `IVRVirtualDisplay` and `IVRDriverDirectModeComponent`. On Windows, ALVR uses `IVRDriverDirectModeComponent`. On Linux, `IVRVirtualDisplay` crashes on Nvidia GPUs and does nothing on AMD. Similarly `IVRDriverDirectModeComponent` does not work on Linux. We tried to get help from Valve through multiple channels but we were not successful. References: + * OpenVR driver header: https://github.com/ValveSoftware/openvr/blob/master/headers/openvr_driver.h * Main OpenVR issue tracker: https://github.com/ValveSoftware/openvr/issues * Virtual display sample issue tracker: https://github.com/ValveSoftware/virtual_display/issues diff --git a/wiki/My-game-is-not-working-properly!-Help!.md b/wiki/My-game-is-not-working-properly!-Help!.md index a9a4fcac62..843045eba8 100644 --- a/wiki/My-game-is-not-working-properly!-Help!.md +++ b/wiki/My-game-is-not-working-properly!-Help!.md @@ -13,8 +13,3 @@ In general, this is a rather bad practice as all relevant data can be accessed t Nonetheless, we want to play and support those games. Problem is, that we don't own all games. This is a Open Source without any funding. We can not buy any games just to fix a bug. In the case of Vivecraft, one user (thanks @Avencore) was generous to gift us a copy and the bug could be fixed. There are no guaranties! Neither on the time it will take nor if the bug will ever be fixed! Please contact us before buying anything. - - - - - diff --git a/wiki/Real-time-video-upscaling-experiments.md b/wiki/Real-time-video-upscaling-experiments.md index 82f6f7080b..e23034207c 100644 --- a/wiki/Real-time-video-upscaling-experiments.md +++ b/wiki/Real-time-video-upscaling-experiments.md @@ -16,7 +16,7 @@ This traditional upscaling method seems like a good step up from basic bilinear A GPL 2 implementation of a Lanczos shader can be found here: https://github.com/obsproject/obs-studio/blob/6943d9a973aa3dc935b39f99d06f4540ea79da61/libobs/data/lanczos_scale.effect -# Neural net image super resolution +# Neural net image super resolution I did some basic investigations on the feasibility of using AI upscalers to get even better results than traditional signal processing methods. diff --git a/wiki/Roadmap.md b/wiki/Roadmap.md index 38f6cf1f7d..09d3b816a5 100644 --- a/wiki/Roadmap.md +++ b/wiki/Roadmap.md @@ -9,13 +9,13 @@ Create a universal bridge between XR devices. ## What is coming next * Compositor rewrite - * **Purpose**: add Linux support for FFR and color correction, preparation for sliced encoding - * **Status**: FFE and color correction done on all platforms + * **Purpose**: add Linux support for FFR and color correction, preparation for sliced encoding + * **Status**: FFE and color correction done on all platforms * Encoder rewrite - * **Purpose**: support any OS and hardware with a single API, using [Vulkan video extensions](https://www.khronos.org/blog/an-introduction-to-vulkan-video) - * **Status**: blocked by adoption by AMD and Intel, landing of the feature on stable Nvidia drivers + * **Purpose**: support any OS and hardware with a single API, using [Vulkan video extensions](https://www.khronos.org/blog/an-introduction-to-vulkan-video) + * **Status**: blocked by adoption by AMD and Intel, landing of the feature on stable Nvidia drivers * Monado Driver - * **Purpose**: support other runtimes with the streamer - * **Status**: blocked on refactors + * **Purpose**: support other runtimes with the streamer + * **Status**: blocked on refactors Due to the low development capacity, no ETA can be provided. New releases will not have a regular cadence and they do not have scheduled features. diff --git a/wiki/Troubleshooting.md b/wiki/Troubleshooting.md index 40cf81530c..37ded21b0d 100644 --- a/wiki/Troubleshooting.md +++ b/wiki/Troubleshooting.md @@ -5,7 +5,7 @@ For ALVR 20.0.0 and later First off, please make sure to carefully read the [Installation guide](https://github.com/alvr-org/ALVR/wiki/Installation-guide) and [Usage](https://github.com/alvr-org/ALVR/wiki/Usage) pages. -The first thing to try is to delete the file `settings.json` located in the ALVR installation folder on the PC. This resets everything to default. If it doesn't work, try reinstalling ALVR. +The first thing to try is to delete the file `session.json` located in the ALVR installation folder on the PC. This resets everything to default. If it doesn't work, try reinstalling ALVR. Keep in mind that sometimes a restart of ALVR/SteamVR/PC/Headset will be enough to solve some problems. @@ -23,7 +23,9 @@ If you need more help, come to our [Discord](https://discord.gg/KbKk3UM) and ask Trouble starting ALVR === -`ALVR Dashboard.exe` needs a working graphics driver to be installed in order to work. +ALVR needs a working graphics driver to be installed in order to work. + +**On linux**, you also need to make sure you have `x264` for base software encoding to work and either `vaapi` on AMD or `cuda` on NVIDIA for hardware encoders to work. ALVR starts launching, but gets stuck on "ALVR is not responding..." === @@ -48,9 +50,11 @@ Failed to initialize CEncoder. --- ALVR currently needs a recent AMD or Nvidia GPU to run, since it utilizes hardware video encoding (see [requirements](https://github.com/alvr-org/ALVR#requirements)). If you get an error saying something like + ``` Failed to initialize CEncoder. All VideoEncoder are not available. VCE: AMF Error 1. g_AMFFactory.Init(), NVENC: NvEnc NvEncoderD3D11 failed. Code=1 NvEncoder::LoadNvEncApi : NVENC library file is not found. Please ensure NV driver is installed at c:\src\alvr\alvr_server\nvencoder.cpp:70 ``` + and you have up-to-date GPU drivers, then your graphics card isn't supported. If you're using a laptop with a powerful enough discrete GPU, you _might_ be able to get ALVR to work by forcing SteamVR to use it in either Windows settings, or the Nvidia control panel. If you have a compatible GPU, you're most likely seeing a different error after either `VCE:` or `NVENC:` than above. In that case, try using a different video codec in ALVR settings. You can also try lowering your video resolution setting. @@ -97,7 +101,11 @@ SteamVR says "headset not detected" ![SteamVR headset not detected](images/SteamVR-headset-not-detected.png) -This message means that the ALVR SteamVR driver isn't loading properly when SteamVR starts. Check that SteamVR isn't blocking ALVR (see SteamVR settings, enable advanced settings and check `Startup / Shutdown -> Manage Add-ons`). +This message means that the ALVR SteamVR driver isn't loading properly when SteamVR starts. + +On linux double-check if you have software and hardware encoders installed, without them driver won't load. + +Check that SteamVR isn't blocking ALVR (see SteamVR settings, enable advanced settings and check `Startup / Shutdown -> Manage Add-ons`). ![SteamVR add-ons](images/SteamVR-add-ons.png) diff --git a/wiki/Use-ALVR-through-a-USB-connection.md b/wiki/Use-ALVR-through-a-USB-connection.md index f4220505e2..fc0fa5c248 100644 --- a/wiki/Use-ALVR-through-a-USB-connection.md +++ b/wiki/Use-ALVR-through-a-USB-connection.md @@ -8,14 +8,14 @@ ### ALVR Streamer (PC): -* If your headset is detected, click "Trust." Click "Configure" and add the IP address `127.0.0.1`. Remove the other IP address. +* If your headset is detected, click "Trust." Click "Edit", "Add new" and change the IP address to `127.0.0.1`. * If your headset is not detected, click "Add client manually" and use the IP address `127.0.0.1`. Use the hostname displayed on your headset screen. * Turn off client discovery in Settings > Connection. * Switch the connection streaming protocol to TCP in Settings > Connection. ## Letting your PC communicate with your HMD -The Quest and Go HMDs are Android devices, therefore, we can use [Android Device Bridge](https://developer.android.com/studio/command-line/adb) commands to tell the HMDs to look for data over USB, as well as Wi-Fi, using port forwarding. +The Quest, Pico HMDs are Android devices, therefore, we can use [Android Device Bridge](https://developer.android.com/studio/command-line/adb) commands to tell the HMDs to look for data over USB, as well as Wi-Fi, using port forwarding. You can accomplish this with some pre-made applications/scripts (just below), or run the commands manually with [SideQuest](https://sidequestvr.com/setup-howto) @@ -25,32 +25,34 @@ If you haven't already, connect a USB cable from your PC to your headset. USB 2. The following programs serve to wrap and simplify the process of doing manual ADB commands, the first two will also automatically reconnect the headset if the USB connection is interrupted. -* [**ADBForwarder**](https://github.com/AtlasTheProto/ADBForwarder) - * Easy to use - * Downloads ADB for you - * Cross-platform (Windows & Linux with Mono) +* [**ADBForwarder (Recommended)**](https://github.com/alvr-org/ADBForwarder) + + * Easy to use + * Downloads ADB for you + * Cross-platform (Windows & Linux) * [**Python Script**](https://gist.github.com/Bad-At-Usernames/684784f42cbb69e22688a21173ec263d) - * Lightweight and simple - * Requires [Python 3](https://www.python.org/downloads/) and [PyWin32](https://pypi.org/project/pywin32/) - * Requires [ADB Platform Tools](https://developer.android.com/studio/releases/platform-tools) to be in the same directory as `main.py` - * Just extract `platform-tools` to your desktop and place `main.py` in that folder, should work when you run the script + + * Lightweight and simple + * Requires [Python 3](https://www.python.org/downloads/) and [PyWin32](https://pypi.org/project/pywin32/) + * Requires [ADB Platform Tools](https://developer.android.com/studio/releases/platform-tools) to be in the same directory as `main.py` + * Just extract `platform-tools` to your desktop and place `main.py` in that folder, should work when you run the script * [**Batch Script**](https://gist.github.com/AtlasTheProto/1f03c3aeac70c4af5b4f2fcd9b9273c0) - * Requires [ADB Platform Tools](https://developer.android.com/studio/releases/platform-tools), edit the path in line 2 to point to the directory where you extracted `platform-tools` - * Needs to be run every time you (re)connect your headset + + * Requires [ADB Platform Tools](https://developer.android.com/studio/releases/platform-tools), edit the path in line 2 to point to the directory where you extracted `platform-tools` + * Needs to be run every time you (re)connect your headset ### Option 2 - [SideQuest](https://sidequestvr.com/setup-howto): * Ensure SideQuest is running, and the headset has authorized the USB connection to the PC * Open the 'Run ADB Commands' menu in SideQuest (top-right, box with an arrow inside it) * Click 'Custom Command' and run these adb commands: - * `adb forward tcp:9943 tcp:9943` - * `adb forward tcp:9944 tcp:9944` - * These commands will need to be run every time you (re)connect your headset. + * `adb forward tcp:9943 tcp:9943` + * `adb forward tcp:9944 tcp:9944` + * These commands will need to be run every time you (re)connect your headset. * Keep SideQuest opened until you want to close the connection. - *** Once you are finished, the headset should now establish a connection over USB. diff --git a/wiki/images/ALVRexe-no-clients.png b/wiki/images/ALVRexe-no-clients.png index 21ec47c97832c4109f240978257c9d68524f7e6f..6daef18f03eb9443dcf29896960a89714cbf3942 100644 GIT binary patch literal 35808 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 literal 17042 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 From 3b4249da7292463ea2da55d124c483236370e9ae Mon Sep 17 00:00:00 2001 From: Riccardo Zaglia Date: Wed, 10 Jan 2024 14:43:53 +0800 Subject: [PATCH 3/4] docs: :memo: Update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 937326039b..19b4fb7f19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## v20.6.0 + +* Add tongue tracking for Quest Pro (by @zarik5) + * This is a breaking change in the protocol, but only affects Quest Pro users. + * Only VRCFT ALVR module v1.2.0 and up is supported +* Add Quest 3 emulation mode + icons for SteamVR HUD (by @Goodguy140 #1926) +* Add Type of Service (ToS) socket settings, tested only on Linux (by @Vixea #1946) +* Add software decoding option and fallback (by @20kdc #1933) +* Add Baseline encoding option for h264 (by @20kdc #1932) +* Fix ADB connection (by @The-personified-devil #1942) +* Fix rare bug preventing reconnections on wifi (by @zarik5) + ## v20.5.0 * Fix Vulkan layer GPU loading (by @nairaner #1847) From da30886c7d8836d23f71ea0ed66000a01b7c0a4c Mon Sep 17 00:00:00 2001 From: Riccardo Zaglia Date: Wed, 10 Jan 2024 17:25:44 +0800 Subject: [PATCH 4/4] fix(ci): :green_heart: Fix android CI --- .github/workflows/prepare-release.yml | 7 +++++-- .github/workflows/rust.yml | 9 ++++++++- wiki/Building-From-Source.md | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index cf09bb979e..a783b9e00a 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -232,11 +232,14 @@ jobs: - uses: actions/setup-java@v2 with: distribution: 'temurin' - java-version: '11' + java-version: '17' + - uses: android-actions/setup-android@v3 + with: + packages: 'platforms;android-29' - uses: nttld/setup-ndk@v1 id: setup-ndk with: - ndk-version: r25c + ndk-version: r26b - name: Build and package ALVR id: build diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a211e729dd..34244921ed 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -85,10 +85,17 @@ jobs: target: aarch64-linux-android override: true - uses: Swatinem/rust-cache@v1 + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + - uses: android-actions/setup-android@v3 + with: + packages: 'platforms;android-29' - uses: nttld/setup-ndk@v1 id: setup-ndk with: - ndk-version: r25c + ndk-version: r26b - name: Install deps uses: actions-rs/cargo@v1 diff --git a/wiki/Building-From-Source.md b/wiki/Building-From-Source.md index 6210cc91b6..63e01d374e 100644 --- a/wiki/Building-From-Source.md +++ b/wiki/Building-From-Source.md @@ -184,7 +184,7 @@ For Debian, it requires to have the `non-free` repository to be enabled: * **Debian 12 / Ubuntu 22.10 / Pop!\_OS 22.10** ```bash - sudo apt install android-sdk-platform-tools-common sdkmanager google-android-ndk-r25b-installer + sudo apt install android-sdk-platform-tools-common sdkmanager google-android-ndk-r26b-installer ``` ## 2. Setting environment variables