Skip to main content

· One min read

Welcome to my blog! My name is Justin Lin, I'm a software engineer, and this is a place for me to just document things that I want to share. Often there might be projects, random thoughts, or instructional posts. I hope you enjoy!

If you are interested to contact me, feel free to reach out to me at

· 7 min read

In this blogpost, I'm going to be talking about my favorite setup using Immerese for Mac. B/c yes, I just love sharing my current virtual setup, b/c living in NYC, space is at a premium, and it amazes me of the future! I also am going to try to share my best strategies when using Immersed.

(Image of me floating around the Earth + chatting in the Immersed discord) immersedVR

High Level Settings Overview

Immersed Settings: Super-sampling: 0-2

Monitors: 2K resolution range, above 2048x1080, I think is best.

Retina quality: 0-2

Encode Quality: Medium/High

Virtual mouse: on

Additional Software:

BetterDisplay for virtual monitors

Alfred 4/5 for productivity shortcuts

First, Monitors!

(Which I think is a big part to the clarity of the Immersed setup.)

Ghost Plugs

When talking to the Immersed team, I found out that the resolution of the monitors you can spawn in Immeresed is at most, 1920x1080. This is due to them using a VM to represent the screens and it just has a cap to the resolution. While, I can go down a software solution to potentially create my own virtual monitors at a higher resolution, which then gets mirrored into Immersed, I found that I could just buy a 4K ghost plug. Which is essentially an HDMI plug that tricks your computer into thinking it has a 4K monitor, without having to actually display the image.

I think this is a cheap and great non-technical solution for every computer. I end up setting these displays to 2048x1080. Even though I can go to 4K, I find the text becomes too small. Also at a certain point, the resolution will exceed the resolution of the headset ability to display, and pass 2K the differences become minimal. Even though it can get sharper, I think 2048x1080 is a great place to be, for sharpness + clarity + text size. I however, no longer use this solution in favor of the one upcoming: BetterDisplay.

(Screen resolution setting of my ghost plug.) screenRes

BetterDisplay (Mac Only)

I recently found out about this solution on Mac, which lets you create dummy monitors software wise, with great configuration options from the Immersed discord. It allows you to create a dummy monitor of any resolution, and a license is only 15 dollars. So, now, instead of my 4K monitor ghostplug, I can create fake monitors in software at any ratios, for me I like a 20:9 ratio, at 2K again. The con to this is that there is additional software configuration, and not as easy as the ghostplug, but both are great options.

I still find that the best resolution range is in the 2K range.

(Better Display settings > Manage Dummy > Resize Dummy) BetterDisplay

(Better Display WideScreen) (The image is distorted due to Oculus capture, but its a 20:9 monitor) WideScreen

(The ranges of resolution options for Dummy Monitors) BetterDisplay

(There is a resize option that lets you set the aspect ratio, which I set to 20:9 / other configurations depending on my work) BetterDisplay

Immersed Virtual Monitors

The immersed virtual monitors, I find is usually set to a lower 1400x900 when it spawns. You should set this to the max of 1920x1080 if you chose to use them. Otherwise, I find that text is too blurry.

resImmersed

Overall feeling:

1920x1080, I feel is the minimum for a good quality monitor. But if possible I think that 2048x1080 / any monitors in the 2K range, to be the best resolution to work in, especially if you have alternative solutions outside of the Immersed built in additional monitors. Past 2K I find that the return is minimal.

It becomes better to focus on monitor configurations + display sizes and ratios, to get the best experience.

Note:

In the Menu > Settings > Monitors, there is a sidebar, look closely, use your controller to drag the scroll bar down. It does not work based off of joystick. You can save different monitor configurations! I find this helpful as I might have one monitor configuration with my wide screen in the middle + my normal macscreen on the side.

While I have another configuration with it in the background + my mac screen in the middle. I find this helpful for different workflows.

Second! Retina and Encoding Quality:

Retina Quality

Retina Quality: 0 - 5

When talking to the Immersed team, I asked them what is retina quality in the Immersed computer app setting. I was told that: "if your original resolution is 1920x1080, then 0 will render as 1920x1080 pixel and 10 will render as 3840x2160 for retina display."

Meaning that it basically doubles the amount of pixels that Immersed tries to bring into the headset. But due to the diminishing return, the sharpness increase after 5 is not much. In addition, with every step up, there is a large latency hit, meaning that it is better to set the base monitor at a higher resolution in the 2K range, and keep the retina quality closer to 0-5, to reduce latency.

Again, past 2K resolution, there is not much of a difference showing up in the headset for me, so better to optimize for latency past that point.

Encoding Quality

Encoding Quality: Medium - High.

For encoding quality, I was told: "Encoding quality really depends on contents. If there's lots of movement, higher setting will encode with better quality. It doesn't really affect for performance-wise, but it will increase data size that affect latency in slow network." B/c of this, while I could do "highest", I decided to just leave it between "medium" and "high", and I think this is good.

Third! Supersampling!

In the app, there is an option to set super sampling. To be honest, I am not 100% sure what this does, even after trying to browse the Discord, but I think a consensus is that this makes the text worst? So, I actually end up setting this between 0-2, which I think makes it more readable.

Fourth! Virtual mouse on.

Keeping virtual mouse on will heavily reduce input latency.

Fifth! Latency / Connection Speed setup:

(This section is if you are just chasing after the best low-latency possible, but might take a lot of playing around. Hopefully the above sections are enough.)

Wifi Direct

Currently, you can do Wifi Direct, an official Immersed solution. This can get your latency down.

Plugging Directly to Ethernet / Router

Also, as seen from another Discord user, you can also just directly plug into your ethernet if that is an option. Which is quite a low latency solution.

[was able to get latency down] to 3 milliseconds tonight by simply plugging my Macbook Pro into my router with an ethernet cable and turning off wifi.

Wired Connection (hacky / unsupported / unofficial)

caution

After further investigation,there is caveats to this solution, and is not a full wired solution, and only seems to be transmitting the initial connection (for more stable connection to computer) + input latency time.

I do not necessarily recommend this solution unless you want to chase down reducing input latency time + bit more technical, and you've tried the other settings and configurations already, and maybe play around a bit more yourself too.

B/c for me, I can't plug directly to my ethernet, due to when at work being in a corporate network, or at home, not having access to the ethernet port, I used a hacky method that someone found out in the DIscord community to allow connecting over a USB connection. - my blog post.

· 14 min read
caution

After further investigation this wired method is NOT as good as expected. It does not stream display over the wire.

As context, first lets talk about how the computer and headset talks to each other. The first is that the computer and headset goes and talks to a middle-man server. This middle-man server gets both computers to agree how to communicate directly to each other. They then connect. The computer is streaming its display to the oculus headset.

A big problem in latency for me was the time it took for me to move my real mouse to interact with my computer. There was a significant lag. As proof, when I spun my mouse in a circle, I would get latency that spike up to 50ms to 80ms. Where I then moved to a virtual mouse, and then there was still some lag. This wired method, basically only optimizes your this "virtual mouse". As the position of your virtual mouse in the oculus display, is sent straight to your computer.

Thus, I'd only recommend it if this is a bottleneck for you + if connecting to your computer and establishing an initial connection is a problem.

How to test, play a Youtube video. If the youtube video is playing at an okay speed for you, then streaming your computer display to your headset is not the bottleneck. If it is lagging for you significantly, this wired method will NOT help you.

If moving your virtual mouse / real mouse is lagging, and is hurting your workflow on where you are pointing / interacting with your computer, then this guide might help you create a more real time workflow.

Feel free to read this Discord message for more information as to the discovery that the wired connection 1ms response time is not as expected

Immersed

Recently, I've begun to work in VR, using an app called Immersed. And I have to say it is one of the most gorgeous thing ever. With very limited space, I am now able to work with as many monitors as I want, and have flexibility that I've never had before.

(Image of me floating around the Earth + chatting in the Immersed discord) immersedVR

What is the existing problem?

One of the big problems with Immersed when I first worked with it for several days was the latency + restriction to be on the same wifi network. (Not that it is their fault). Currently, all virtual workspace apps have a restriction to have to stream the display over the same wifi connection. This causes latency of 20ms-50ms depending on your wifi, and on some networks like corporate network this is not always viable.

The solution would be to use a wired connection, but unfortunately, there is no official SDK from Meta's side (to my knowledge) to allow this type of data streaming connection, and thus, why all solutions, even Meta's own Workplace Horizon app, is limited to wifi. Maybe as more investigations is done over time, there will be new official options that emerge in the future.

Existing Solutions / Supported

Currently you can use Wifi Direct, an official Immersed solution. Or also, as seen from another Discord user, you can also just directly plug into your ethernet if that is an option [was able to get latency down] to 3 milliseconds tonight by simply plugging my Macbook Pro into my router with an ethernet cable and turning off wifi.

Credit + Solution

As I interacted in the Immersed community, someone in it by Discord name, @OwariDa, figured out how to get a wired connection working! His blog post. His tutorial is great and has instructions for Window / Mac / Linux, but I just want to write a bit more organized about the Mac side of it and my own finding + following another Discord user's instructions README in the Discord server, @woodland, who was able to build ontop of OwariDa post. Please highly recommend, also refer to these other instructions if needbe.

But what I hope with this post is to build ontop of their instructions, maybe make it a tadbit easier to follow for mac, and add some of my own findings.

Benefits of a wired solution:

  • Should work on a corporate network (though have not yet tried)
  • Latency is very low
  • Stable connection to the laptop
  • Flexible to bring around to other wifi avaliable spots.

Con:

  • A lot of setup is needed / not as easy as just plugging into a router / wifi direct if an option.
  • Tethered to your computer
note

This approach is a hacky approach, not "officially" supported by the Immeresed team. So while the Immersed team can be helpful, they are not responsible nor can provide official support for this. Probably community support for those who are doing this currently is best.

End Results

By the end of it, the goal should be to use a wired connection to Immersed, and have a latency of 1m-5ms latency. This is a huge improvement over the 20ms-50ms that you get with wifi. msLatency

Devices this blog is targeted at:

Quest 2, Quest Pro, and Mac OS. Though Owarida blog post, goes over Pico4, and again, the other operating systems. I still hope maybe this article, can help give additional context to this process to those trying to get it working.

Notable Alternative

Gnirehtet project. As stated in owarida blog post, there is a different project that is able to establish a connection between your headset and computer. I'm guessing if you use this project, the only additional modification you would need to make is to change the desktop application to look at the local network (which will be part of the blog post) down below. But I couldn't get this to work personally.

How to get a wired connection working

Note, I highly recommend read this whole article first, as there are some gotchas! And I want you to be aware of it before following fully along.

Definitions

Agent - the Immersed Desktop application

Client - your headset

Prerequisites

  1. You must enable developer mode and enable USB debugging. For Quest devices, the steps are here Make sure that after you get a developer account, you also set your headset to developer mode.

  2. Install ADB - Guide how to do it

Additional Oculus Documentation if need-be:

mobile device setup adb

note

Run adb devices with your headset plugged in. If your device does not show up, there is still an issue, and you won't be able to run an adb command later in the guide.

  1. You might need a modified agent from the Immersed Discord community. Depending when you read this, this modified agent, might have already been released, when talking to the devs / Immersed community, but we will get into this later. Definitely check the Discord first, or if it been a while since this post has been written, it should have been released, and maybe even an official alternative to this method.

Edit: Seems like the beta-agent is public on the Discord as a message, so I'll put the link here if interested

Context

What are we about to do? (Note, this is from my own understanding and may not be technically correct.) But should still give you an idea.

When the client is booted up, it broadcasts packets on your wifi network. If these packets are received by the agent, then the agent will connect to the client. These packets are sent over WIFI / UDP connection. So what we need to do instead is, establish a TCP / wired connection to our computer. And then, when we click on connect to a computer, have it send these packets or request over the wire, and have the agent, respond back to the client over the wire vs trying to stream it back out over wifi. This is the gist of it. (BTW, IK that UDP/TCP are just protocols for communication and not necessarily wired/nonwired connection, just saying that these are the protocols being used in these instances since there is some important differentiation here).

Instructions

First goal: Force the agent to look for connections only on the computer.

The first step is to force the agent to look for connections only on the computer, or essentially only on your localhost. Immersed has a config file, where we can forceIPAddress, to tell the agent to only look for connections on the computer.

Step 1:

Quit both the agent and the client.

Step 2:

Using xCode, or software that would let you modify plist files, go to: ~/Library/Preferences/team.Immersed.plist

Do not use a direct text editor as it is unable to properly write the plist file.

Step 3:

Identify the data key of the file: plist

Ex of the data key for me (though I have played around with some values / redacted my client key here):

{"Analytics":"[]","Capture":"{\"EnableAppFrames\":\"1\",\"FPS\":\"80.000000\",\"FPSFor2\":\"80.000000\",\"FPSFor4\":\"45.000000\",\"SavedFrames\":[{\"Height\":\"900\",\"Index\":\"VD-2\",\"RefreshRate\":\"120.000000\",\"Width\":\"1440\",\"X\":\"4288\",\"Y\":\"76\"},{\"Height\":\"1200\",\"Index\":\"VD-0\",\"RefreshRate\":\"120.000000\",\"Width\":\"1920\",\"X\":\"808\",\"Y\":\"1117\"},{\"Height\":\"1117\",\"Index\":\"MainDisplay\",\"RefreshRate\":\"120.000000\",\"Width\":\"1728\",\"X\":\"0\",\"Y\":\"0\"},{\"Height\":\"1200\",\"Index\":\"VD-1\",\"RefreshRate\":\"120.000000\",\"Width\":\"1920\",\"X\":\"1728\",\"Y\":\"-83\"}]}","Client": [REDACTED],"EnableAudio":"0","Encode":{"Codec":"3","Encoder":"Auto","ForceBitrate":"0","GPU":{"LocalCaptureFPS":"60.000000","LocalMaxBitrate":"16000.000000","LocalMinBitrate":"4000.000000","RemoteCaptureFPS":"60.000000","RemoteMaxBitrate":"8000.000000","RemoteMinBitrate":"1000.000000"},"Quality":"0.700000"},"ForceIPAddress":"127.0.0.1","ForcePort":"0","ForceStreamPort":"0","Log":"{\"CurrentSuccessCount\":\"6\",\"EnableForceLog\":\"0\"}","SettingVersion":"1","WebRTC":"{}"}

Step 4:

Find the "ForceIPAddress" which should be of the value: “ForceIPAddress”: “” and change it to "ForceIPAddress":"127.0.0.1"

There is some caution I want to make here. Make sure that the quotes are in the proper place. The first time I did this, they were not. Second, you might need to retype the quotes. When I originally did this, I copied from owarida blogpost, where the quotes look like but I needed to manually type the quotes out so that they looked like ". If you type it with your own keyboard on the quotes, should be correct.

Step 5:

Lock the file. In order to do this, find the file in finder. You can type in the terminal open ~/Library/Preferences/ and use the search bar to search in the preferences folder for the team.Immersed.plist file. Then right click on the file and select "Get Info". Then check the box that says "Locked". lock

Second Goal [Optional depending on the time of reading this]

This is the most important step!!! When you are reading this, there are two alternatives to go down.

  1. Using a modified beta-agent that the Immersed Discord Team was able to provide me. Maybe this is something can ask, if can be provided to you if you chose to go down this route, or maybe it has already been released. As the mods / devs, were saying they hope to get a release soon (who knows when) to this modified agent.

But the current problem is that the current publicly released agent, even when we set the forcedIPAddress to localhost, it will still try to look for connections over wifi. So the modified agent by the Immersed team, when the forcedIPAddress is set, will not look for wifi connections, thus meaning, we can force it to only look for wired connections. So I first, highly recommend, maybe wait for a release of this modified agent, or maybe the Immersed team will be kind enough to provide it.

tip

Update: Has been posted in the Discord as a public message, so I am more comfortable to share here, this is the Discord message link Highly recommend using this modified agent and skipping the Section 2, and going to Section 3.

  1. If the agent has not been released, and you want to try to do it with the publicly avaliable agent, then we can just block all UDP packets that are being streamed over the network to our computer. Thus, if the agent is unable to find this packet, will use the localhost connection (wired connection).

Second Goal: Blocking all UDP packets (Optional Step if not the updated / modified agent)

BTW, this is a step that is only possible if you own the computer. I was trying to do this on my company computer, and I am for obvious reasons not allowed to modify the network configuration, so I used the modified client instead. Also, I found difficulties in getting this to work for my personal computer, so I ended up skipping this step, and was provided a modified agent through a beta-link by the Immersed team. But, this is still how I tried to do it following owarida's blogpost and woodland instructions.

B/c the agent is still going to be looking for UDP packets, we want to block all UDP packets coming onto the network coming towards our computer.

  1. Open Terminal.app and run the command: ifconfig
  2. Look for the en0 interface and copy the "broadcast" address from the command

For me, I was able to cmd + f for broadcast flag and found the following parts a bit under the en0 section (parts of the number I replaced with xxx)

 netmask 0xffffff00 broadcast xxx.xxx.0.255
  1. Copy that number: xxx.xxx.0.255 (whatever the number is for you)
  2. Open the following in a text editor /etc/pf.conf
  3. Add two line breaks after load anchor "com.apple" from "/etc/pf.anchors/com.apple"
  4. Type: block drop in proto udp from any to <BROADCAST ADDRESS YOU GOT>. Owardi command is a bit different, but both works, if you are following along with his instructions too. But feel free to use this command, or Owardi's blog post command. Woodland used this command above.
  5. Save the file, you might need to use sudo to save it / type in your computer password.
  6. Type in the command sudo pfctl -e to enable pf
  7. Type in the command sudo pfctl -f /etc/pf.conf to load the config we edited in pf.conf (If you ever want to delete this configuration in the future: just remove the line and run step 8 and 9 again).

Third Step: Opening a connection between the headset and the computer

Plug in your headset, allow in the headset for the computer to be able to talk to your headset if asked.

Then run using your ADB command: adb reverse tcp:21000 tcp:21000 && adb reverse --list

If you have your adb in a different file path, make sure to specify / cd to wherever it is. This is now opening a connection between our headset and computer. you need to do this every time you plug in your headset. I actually have a tool like Alfred4, which makes it easy for me to set up keybinds for things like this, but you can do it manually too.

You should see the result: UsbFfs tcp:21000 tcp:21000

Fourth Step: Run the Immersed Client

Go to the Immersive client, and run it. Sit at the choose computer screen.

Fifth step: Run the Immersed Agent.

  1. As it starts up, double check your plist, still has the forcedIPAddress set. (BTW, by locking this file, some of your preferences when using Immmersed might not be saved for next session, if you ever find a bug like that).

  2. Then, as the agent starts up, should say ready to connect, BUT, it should not automatically connect.

  3. If it automatically connects, something is wrong, and it is still picking up the UDP packets over wifi, if you got this far, and are not using the modified client, you might need to request it from the server.

  4. Now, on the client, click on the computer you want to connect to, and now it should connect to the agent.

  5. You might see latency saying it is 1-10ms, but should settle down between 1-5ms after.

  6. If you unplug the cable, the connection should crash, this is also a way to verify if it is working.

Running this in the future:

In the future, the only requisite is that you need to open the reverse connection with the adb command > then open the Immersed agent. From there, you can open the app before or after opening the agent, and click to connect to the computer.

B/c the goal is as always:

  1. Establish the wire connection, which locally connects your computer to headset
  2. Tell the computer to look only locally on that computer for that wired connection.
  3. As long as that is established, you can open your agent and client in any order.

Additional Configurations you can make now:

Check out my other post in this link