The OpenXR Space Sharing API enables a user to share their XR Scene with their guest players, creating a shared playspace. By sharing their space, the app benefits from shared scene understanding and shared coordinates among all the players. Scene Understanding allows the placement of virtual content that adapts to the geometry and semantics of the user’s environment. For example, a game can adapt its content to the size of the walls and location of furniture so the players can have a shared MR experience. See Space Sharing Overview to learn more about Scene Understanding use cases, and how to utilize it for a mixed reality experience.
Space Sharing uses the same extensions and APIs that enable Group Sharing of Spatial Anchors. It enhances the functions in the existing extensions by allowing sharing rooms - XrSpace with RoomLayout component. Similar to sharing Spatial Anchors to Groups, the following extensions are needed to use Space Sharing
XR_META_spatial_entity_sharing
XR_META_spatial_entity_group_sharing
XR_FB_spatial_entity_query
A host device can use xrShareSpacesMETA in the XR_META_spatial_entity_sharing extension to share rooms to a group. This is done by providing a list of XrSpace with RoomLayout component in its input struct XrShareSpacesInfoMETA, and an UUID of a group. Guest devices can use the xrQuerySpacesFB API in the XR_FB_spatial_entity_query extension to query the shared rooms with a Group UUID filter. Upon receiving the results of the shared room, guest devices can then fetch all the scene data in the shared rooms, such as the walls, floor, ceiling, and furniture.
To understand room (aka Scene Model) in OpenXR, and the API to query them, see OpenXR Scene API Reference.
As the host, sharing the room to others is not available via xrShareSpacesFB, more details can be found in User Sharing API. User Sharing API is where apps can share spatial entities with specific Oculus User IDs.
As a guest querying for a room shared by the host is not available via discovery API
Prerequisites
Meta Quest 2 or later headset running OS v74 or later
In the headset, go to Settings > System > Software Update.
Check the version.
If the version is not v74 or higher, update the software to the latest available version
Setup and Implementation
Follow the instructions here to set up your project for OpenXR.
To get started with Space Sharing, you will need to set up your app for required Meta Quest permissions, and then follow the Space Sharing flow in your implementation.
Setup
Declare permission to the Android manifest
Add extension headers
Enable extensions
Implementation
Acquire function pointers
Host app query rooms, shares them to a group and sends group UUID to guests
Guest app gets the group UUID and query the shared room by group UUID
Declare permission in the Android manifest
You can find the general specifications for your app’s AndroidManifest.xml file in Android Manifest Settings in the native development guide. Space Sharing requires three Android permissions to work.
Space Sharing requires three Android permissions to work. Add the permissions to your app’s AndroidManifest.xml:
To use the extension APIs, you must create an OpenXR instance and session. For details on creating OpenXR instances, read Creating Instances and Sessions.
A typical Space Sharing flow requires the following steps between a host device and guest devices:
The host device uses xrQuerySpacesFB API to query one or more rooms using the xrLayoutComponent filter. If no room is found, the app can use the xrRequestSceneCaptureFB API to start Scene capture.
The host device sets the Sharable Component on the room (xrSpace) found with a xrRoomLayoutFB component and uses xrShareSpacesMETA API to share the rooms to a group.
The host sends the group’s UUID to the guest devices via an app managed networking.
Upon receiving the group’s UUID, guest devices use xrQuerySpacesFB API with a group UUID filter to retrieve the Shared Rooms and their Scene data
In the following code example, the app is implemented in the ovrApp class, similar to a struct defined in the XRSamples\XRSpatialAnchor sample app.
The Host Query Rooms
Before sharing a room, the host first needs to query a captured room. See Scene Model/Spatial Entity Query for information about querying spatial entities. The following code example uses the RoomLayout component filter and xrQuerySpacesFB API to query the room.
XrSpaceStorageLocationFilterInfoFB storageLocationFilterInfo = {
XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, nullptr, XR_SPACE_STORAGE_LOCATION_LOCAL_FB};
// Build a room layout component filter to query XrSpace of type room only
XrSpaceComponentFilterInfoFB componentFilterInfo = {
XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB, &storageLocationFilterInfo, componentType};
// Build a query info struct with the room layout filter
XrSpaceQueryInfoFB queryInfo = {
XR_TYPE_SPACE_QUERY_INFO_FB,
nullptr,
XR_SPACE_QUERY_ACTION_LOAD_FB,
MAX_PERSISTENT_SPACES,
0,
(XrSpaceFilterInfoBaseHeaderFB*)&componentFilterInfo,
nullptr};
XrAsyncRequestIdFB requestId;
// call query API to get the room
OXR(app.FunPtrs.xrQuerySpacesFB(
app.Session, (XrSpaceQueryInfoBaseHeaderFB*)&queryInfo, &requestId));
The Host polls events to get the shared room
Set up OpenXR events handling and poll events to handle the XrEventDataSpaceQueryResultsAvailableFB event and use xrRetrieveSpaceQueryResultsFB API to retrieve the room. Since we are only querying rooms using the RoomLayout component filter above, we will only receive room XrSpace in the results.
void ovrApp::HandleXrEvents() {
XrEventDataBuffer eventDataBuffer = {}
// Poll for events
for (;;) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = NULL;
XrResult r;
OXR(r = xrPollEvent(instance, &eventDataBuffer));
if (r != XR_SUCCESS) {
break;
}
switch (baseEventHeader->type) {
case XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB: {
const auto resultsAvailable =
(XrEventDataSpaceQueryResultsAvailableFB*)baseEventHeader;
XrResult res = XR_SUCCESS;
XrSpaceQueryResultsFB queryResults{XR_TYPE_SPACE_QUERY_RESULTS_FB};
queryResults.resultCapacityInput = 0;
queryResults.resultCountOutput = 0;
queryResults.results = nullptr;
// First call to get the resultCountOutput
res = FunPtrs.xrRetrieveSpaceQueryResultsFB(Session, resultsAvailable->requestId, &queryResults);
if (res != XR_SUCCESS) {
break;
}
// Second call to get the results data
std::vector<XrSpaceQueryResultFB> results(queryResults.resultCountOutput);
queryResults.resultCapacityInput = results.size();
queryResults.resultCountOutput = 0;
queryResults.results = results.data();
res = FunPtrs.xrRetrieveSpaceQueryResultsFB(
Session, resultsAvailable->requestId, &queryResults);
if (res != XR_SUCCESS) {
break;
}
for (uint32_t i = 0; i < queryResults.resultCountOutput; ++i) {
auto& result = results[i];
// result.space is the room, enable shareale component
SetSharebleComponent(result.space);
}
}
Host sets Sharable Component on the room space
After we get the XrSpace representing the room, we need to set its Sharable Component so that it can be shared to other users
After we set the Sharable Component to the room using the example code above, we can use xrShareSpacesMETA API to share it to a group. Note that xrShareSpacesMETA is also used to share Spatial Anchors (see details in Shared Spatial Anchors). We can use the same function to share one room or multiple rooms. The following example shares a vector of rooms to a group:
XrAsyncRequestIdFB ShareSpaces(
ovrApp& app,
const std::vector<XrSpace>& spaces) {
for (const XrSpace space : spaces) {
if (!app.IsComponentEnabled(space, XR_SPACE_COMPONENT_TYPE_ Shareble_FB)) {
return kInvalidRequestId;
}
}
XrUuidEXT groupuuid = GenerateRandomGroupUUID();
XrShareSpacesRecipientGroupsMETA recipientGroupInfo = {
XR_TYPE_SHARE_SPACES_RECIPIENT_GROUPS_META, nullptr};
recipientGroupInfo.groupCount = 1;
recipientGroupInfo.groups = &groupuuid;
XrShareSpacesInfoMETA info = {XR_TYPE_SHARE_SPACES_INFO_META};
info.spaceCount = spaces.size();
info.spaces = const_cast<XrSpace*>(spaces.data());
info.recipientInfo = (const XrShareSpacesRecipientBaseHeaderMETA*)&recipientGroupInfo;
XrAsyncRequestIdFB shareRequestId;
XrResult r;
OXR(r = app.FunPtrs.xrShareSpacesMETA(app.Session, &info, &shareRequestId));
if (r == XR_SUCCESS) {
return shareRequestId;
} else {
return kInvalidRequestId;
}
}
XrUuidEXT GenerateRandomGroupUUID() {
XrUuidEXT groupuuid;
// Seed the random number generator with the current time, rand()
srand((unsigned int)time(nullptr));
for (uint8_t i = 0; i < XR_UUID_SIZE; i++) {
groupuuid.data[i] = rand();
}
return groupuuid;
}
To share the room and all the scene anchors in it, we only need to share the XrSpace representing the room. We do not need to call the Share API on each individual Scene Anchor. Calling xrShareSpacesMETA on individual Scene Anchors will result in an error of XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB.
The Host sends the group UUID to guest devices
After the Host successfully shares the room to the group via the xrShareSpacesMETA API, it can send the group UUID to guest devices via app managed networking. It is up to the app to choose the network library suitable to send the group UUID to guest devices. The app can also use the Colocation Discovery OpenXR API to do so.
The Guest Query the Shared Room
When a guest device receives the group UUID the host shared via the app managed networking, it can use the xrQuerySpacesFB API with a group UUID filter to get the Shared Room. Note that the first time a guest calls xrQuerySpacesFB, the API will trigger a network call to download the Shared Room and the Scene Anchors from the cloud, which can have networking latency. A second call on the same group UUID will get a faster response because it reads from the disk cache.
A Enhanced Spatial Service (ESS) permission dialog may pop-up if the permission has not been granted before. If the permission is not granted, the call will fail. After the user accepts the permission, call xrQuerySpacesFB again to get the results.
QuerySpaceByGroupUuid(ovrApp& app, XrUuidEXT groupUuid) {
// Specify the locationFilter to query from CLOUD
XrSpaceStorageLocationFilterInfoFB locationFilterInfo = {
XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, nullptr, XR_SPACE_STORAGE_LOCATION_CLOUD_FB};
// Specify the group UUID in the group UUID filter
XrSpaceGroupUuidFilterInfoMETA filterInfo = {XR_TYPE_SPACE_GROUP_UUID_FILTER_INFO_META};
filterInfo.groupUuid = groupUuid;
filterInfo.next = &locationFilterInfo;
// Construct the query info struct
XrSpaceQueryInfoFB info = {
XR_TYPE_SPACE_QUERY_INFO_FB,
nullptr,
XR_SPACE_QUERY_ACTION_LOAD_FB,
MAX_PERSISTENT_SPACES,
0,
(XrSpaceFilterInfoBaseHeaderFB*)&filterInfo,
nullptr};
XrAsyncRequestIdFB requestId;
XrResult r;
OXR(r = app.FunPtrs.xrQuerySpacesFB(
app.Session, (XrSpaceQueryInfoBaseHeaderFB*)&info, &requestId));
return true;
}
Shared Rooms cannot be retrieved using the xrDiscoverSpacesMETA. They can only be retrieved using the xrQuerySpacesFB with a group UUID filter.
After the Shared Room is retrieved, the app can use xrGetSpaceContainerFB to get the space container associated with the room, retrieve all the UUIDs of Scene Anchors in the room from the space container, and use xrQuerySpacesFB with a UUID filter again to get all the shared Scene Anchors in the room.
Troubleshooting
Space Sharing uses the common API and error codes with Shared Spatial Anchors. Many troubleshooting techniques for Shared Spatial Anchors also apply to Space Sharing.
Ensuring Enhanced Spatial Services is enabled
The device setting ‘Enhanced Spatial Services’ must be enabled for Space Sharing to work. Users can find it under Settings > Privacy > Device Permissions > Spatial Data. Your app can detect when this setting is disabled and inform users to turn it on. Your app will receive the error code XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB upon sharing rooms when this setting is disabled. Your app should check for this error and inform users that enabling Enhanced Spatial Services is required for Space Sharing to work. For all sharing errors and troubleshooting, refer to Shared Spatial Anchors Troubleshooting.
Known Issues
The automatic prompting for the Enhanced Spatial Services permission does not work reliably in some versions of the OS. Please ensure all users enable this permission manually ahead of running the sample.