Please use the latest release when intergating in to your project > Releases.
Before importing VoyagerAPI.unitypackage your project must have the following packages installed for the test scenes to work.
| Package Name |
|---|
| com.unity.xr.interaction.toolkit |
| com.unity.ugui |
| com.unity.inputsystem |
To add them: Window, Package Manager, switch the top left dropdown to packages: Unity Registry, search by name.
For new projects, enable run in background in player settings, resolution.
Install XR Plug-in Management, otherwise the test scenes will run like a phone app.
User presence
Use the Oculus plug in provider in XR-Plugin management or this will be always true
Recentering
Any recenter API calls are no-op for Quest 3. https://forum.unity.com/threads/xr-recenter-not-working-in-oculus-quest-2.1129019/#post-7268662
To recenter, move the XROrigin (or similiar rig) appropriately like a teleport to compensate for the rotation and position of the headset (camera)
See VoyagerAPITest.OnVoyagerRecenter for an example
Disable system recenter from user presence by setting the origin tracking to stage mode.
- Set the Tracking Origin Mode to floor in your rig in the scene
- In project settings, XR Plugin Management. Oculus, Android settings: check the box "Enable TrackingOrigin Stage Mode"
Sleep
Increase the time before sleep in Settings, System, Power from 15 seconds up to 4hrs to reduce the number of disconnects.
Meta setup guide
If you choose to use the OVRCameraRig it means you have to re-implement recentering, see TeleportationProvider.Update
PSHS must be running to connect with PSM.
See the readme and download the latest release here: https://github.com/PositronicSoftware/Positronic-Standalone-Headset-Software
Class VoyagerDevice
Implements the network-connection and interface methods to the Voyager chair. Singleton.
Class VoyagerDeviceConfig
Defines the network-connection settings for interfacing with a Voyager chair. Use this to initialize the VoyagerDevice instance.
Class VoyagerDeviceUtils
Implements loading a VoyagerDeviceConfig object from a JSON config-file. For details, read the 'Device Settings Config' section below.
Scene VoyagerAPI/Scenes/Voyager API Test.unity Class VoyagerAPI/Scripts/VoyagerAPITest.cs
Scene Voyager API Example/Scenes/Voyager Demo.unity Class VoyagerAPI/Scripts/VoyagerManager.cs
Create a GameObject in your scene and call it VoyagerManager.
Now add the VoyagerManager and TimelineControl Components to this GameObject.
Start Modeallows you to initialize in the Voyager in different states based on project requirements.
If in single experience executable mode:
- Check the single experience executable checkbox.
Pathshould be set to your build executable path"C:\ExecutableName.exe"in the inspector.
In either mode single experience or player mode:
Timeline Controlcan be left null. It will be auto-set on Play if a TimelineControl component is detected.- You can optimize the VoyagerManager SendTime() frequency on memory-constrained platforms by setting
optimizeSendTime = truein the inspector. - VoyagerManager will load your PSM connection settings from a JSON Config file: See Device Settings Config.
VoyagerManager implements the following Keyboard commands for us to easily create Motion data and test your experience.
| Key | Command |
|---|---|
Spacebar |
Toggle Play-Pause |
Left-Right Arrows |
Skip Forward-Backward 10 Seconds |
Up-Down Arrows |
Skip Forward-Backward 30 Seconds |
R |
Recenter HMD Position + Orientation |
This component is required if your project is using 1 or more PlayableDirector to run the experience.
- Set the Timeline UI references to handle Scrubbing, Pause, Play, etc..
- Bind your Timeline UI buttons to VoyagerManager methods like
Play(), Pause(), PlayPause(), Mute(), NextTrack(), PrevTrack()etc.. - Use the
TrackSetupsArray to add your PlayableDirector reference(s) and their associated MotionProfile ( name of the Motion data file used by the Chair ).
VoyagerAPITest.cs and VoyagerManager.cs both have examples of using the API
var voyagerDevice = VoyagerDevice.Instance; // Init Singleton
if( voyagerDevice == null )
{
Debug.LogError("Failed to create VoyagerDevice Singleton.");
return;
}Once created, the instance must be initialized with the desired network-connection settings.
// Load config from file
VoyagerDeviceConfig config = VoyagerDeviceUtils.LoadDeviceConfigFile("Config", "InterfaceConfig.json");
// Initialize interface
VoyagerDevice.Init(config);
// Error: Not initialized
if( !VoyagerDevice.IsInitialized )
{
Debug.LogError("VoyagerDevice not initialized.");
return;
}You must wait for a connection to be established before following the sequence of calls in step 03
VoyagerDevice.OnClientConnected += OnConnected;
VoyagerDevice.OnClientDisconnected += OnDisconnected;
// If you are creating a player, this event fires when PSM sends a url
VoyagerDevice.OnContentChange += OnVoyagerContentChange;The following sequence of calls ensures that the newly created VoyagerDevice instance is linked with the Positronic Show Manager ( PSM ) that controls the chair.
private void OnConnected()
{
// Set the Content Params.
VoyagerDevice.SetContent("Application", "Windows", "Voyager VR Demo", "1.0");
// Media players should start in Stopped state.
// VoyagerDevice.Stop();
// If you are not making a player:
// Experience should start in Paused state
VoyagerDevice.Pause();
// Set the Content ID.
VoyagerDevice.LoadContent("C:/ExecutableName.exe");
// Notify PSM when loading is complete.
VoyagerDevice.Loaded(true);
// Set the initial Motion Profile track name.
VoyagerDevice.SetMotionProfile("TestProfile");
}
// If you are creating a player, respond to PSM events to change content. You can remove these calls from OnConnected.
private void OnVoyagerContentChange(string inUrl)
{
// Set the Content ID. Send back the same url as a confirmation to avoid errors
VoyagerDevice.LoadContent(inUrl);
// Notify PSM when loading is complete.
VoyagerDevice.Loaded(true);
// Set the initial Motion Profile track name.
VoyagerDevice.SetMotionProfile("TestProfile");
// Media Players should pause after changing content
VoyagerDevice.Pause();
}The VoyagerDevice has useful events that you can Bind to in order to control your experience. These events are triggered based on calls from Positronic Show Manager ( PSM ).
VoyagerDevice.OnPlayStateChange += OnVoyagerPlayStateChange;
VoyagerDevice.OnPlay += OnVoyagerPlay;
VoyagerDevice.OnPaused += OnVoyagerPaused;
VoyagerDevice.OnStopped += OnVoyagerStopped;
VoyagerDevice.OnMuteToggle += OnVoyagerToggleMute;
VoyagerDevice.OnRecenter += OnVoyagerRecenterHMD;
VoyagerDevice.OnMotionProfileChange += OnVoyagerMotionProfileChange;
VoyagerDevice.OnUserPresentToggle += OnVoyagerUserPresentToggle;switch( VoyagerDevice.PlayState )
{
case VoyagerDevicePlayState.Play:
{
experienceTime += Time.deltaTime;
VoyagerDevice.SendTimeSeconds(experienceTime);
break;
}
case VoyagerDevicePlayState.Pause:
{
VoyagerDevice.SendTimeSeconds(experienceTime);
break;
}
}For the Voyager Chair to accurately synchronize motion with the experience, you must frequently send the current Experience Time back to PSM. Think of this as the current playback-time of your experience i.e. When the experience is paused time will not increase.
Caveats:
- You must continue to send Experience Time back to PSM even if the Voyager state is Paused.
- If PSM stops receiving time data from the API for a certain duration it will cause errors.
For us to easily create Motion data for your experience, and test it, we require projects to support the following Keyboard commands.
| Key | Command |
|---|---|
Spacebar |
Toggle Play-Pause |
Right-Left Arrows |
Skip Forward-Backward 10 Seconds |
Up-Down Arrows |
Skip Forward-Backward 30 Seconds |
R |
Recenter HMD Position + Orientation |
Using a remote IP works with Quest 3, but it's for development purposes only and is not supported. You must also change the PSHS config file.
If you wish to load VoyagerDeviceConfig settings from a config-file, do the following:
-
Setup a folder in '/Assets/StreamingAssets/' directory, that will contain your config file(s).
-
Your config-file must contain valid JSON with the following structure:
{
"use": 1,
"comment": "Change the 'use' property above to select settings: 1-local, 2-development, 3-production",
"local":
{
"ipAddr": "127.0.0.1", "portNum": 61557, "onScreenLogs": true
},
"development":
{
"ipAddr": "127.0.0.1", "portNum": 61557, "onScreenLogs": true
},
"production":
{
"ipAddr": "127.0.0.1", "portNum": 61557, "onScreenLogs": true
}
}- Use the
VoyagerDeviceUtils::LoadDeviceConfigFile()method to load settings from your config.
// Name of directory that contains config file(s)
string configDir = "Config";
// Name of Device Config file to load
string fileName = "ExampleConfig.json";
// Load config from file
VoyagerDeviceConfig deviceConfig = VoyagerDeviceUtils.LoadDeviceConfigFile(configDir, fileName);
VoyagerDevice.Init(deviceConfig); // Initialize the interface w/ the config.LoadDeviceConfigFile() will look for config files in the following locations.
| Platform | Config Location |
|---|---|
| In-Editor | <ProjectDir>\Assets\StreamingAssets\<ConfigDir>\<FileName> |
| Windows Build | <BuildFolder>\<ProjectName>_Data\StreamingAssets\<ConfigDir>\<FileName> |
| Quest 3 Build | /storage/emulated/0/Android/data/<packagename>/files/<ConfigDir>/<FileName> |
In-Editor and Windows Builds
You can edit your config-file(s) without having to rebuild ( assuming you did step 2 ). This allows you to quickly test different network settings.
Quest 3 Builds
For Android, the config loading system will use the '/storage/emulated/0/Android/data/<packagename>/files/<ConfigDir>/...' path for your configs.
You can use the provided script BatchScripts/Push_DeviceConfig.bat to push your config file(s) to the Quest 3 through ADB. This allows you to test different network settings without having to re-deploy the app.
This batch file also sets permissions with adb shell chmod on the config folder and file, which was necessary in testing.
Working Quest 3 settings (other settings may work): API Target 29, write permission external (sdcard) Additional AndroidManifest.xml settings:
<application android:requestLegacyExternalStorage="true">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>See Assets/Plugins/Android/AndroidManifest.xml
See the Example Project for a working implementation of this in 'VoyagerAPITest.cs', in the
Start()method.
This project implements a simple demo scene that shows you how to use VoyagerDevice.
VoyagerAPITest.cs
Povides a working example of how to initialize a VoyagerDevice and how to reconnect/disconnect paused
Voyager API Test.unity
A simple test scene for the API, setup like a media player. UI buttons make API calls to the VoyagerDevice Instance. UI Tested with with mouse and gaze with Quest 3.
Use https://github.com/PositronicSoftware/PositronicTester for testing and select a real mp4 file as content.
Consider using PositronicTester before PSM because it doesn't check for haptics etc.
For PSM check content. Make sure vmedia,vmotion,-haptics,mp4 are in the correct path on the PC side.
Example by default: C:\Positron\Media\Scent of a Song\Scent of a Song.vmedia, etc
Recentering from PSM also pauses. This is intended.
Windows
Runtime logging from the API is written to the log file.
Quest 3
You can use our batch script Push_DeviceConfig.bat in BatchScripts/ to push a new JSON config file(s)
Log File Locations
See https://docs.unity3d.com/Manual/LogFiles.html
Copyright 2018 Positron Voyager, Inc. All Rights Reserved


