Event Reference#
All omni.kit.collaboration.presence_layer events are global events that can be observed using the
carb::eventdispatcher::IEventDispatcher
. These events are dispatched when spatial awareness data changes
in collaborative live sessions, including bound camera changes, user selections, and follow mode state.
Since all events exist in a global namespace, Presence Layer event descriptors are composed as the following string:
omni.kit.collaboration.presence_layer:<event name>
The string <event name>
is listed below for each event type.
For ease of generating the event names for use with carb::eventdispatcher::IEventDispatcher
, there exist
constants in both Python that can be used directly via the omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType
enum.
The omni.kit.collaboration.presence_layer.get_presence_layer_event_payload()
helper function will take
an event (for either Events 1.0 or 2.0) and produce a omni.kit.collaboration.presence_layer.PresenceLayerEventPayload
instance that can be used to access the payload data in a Pythonic fashion.
Warning
Presence Layer events have a global name, but typically listeners care about a specific layer.
Therefore it is very important to specify a filter
when observing an event, otherwise your observer
will be called for all layers. The omni.kit.usd.layers.Layers.get_event_key()
Python helper
function exists to provide easy means to filter these events.
Note
Historically (Events 1.0), most Presence Layer events were pushed to the omni.kit.usd.layers event stream for a
particular layer and subscribing to those events required retrieving the event stream from the desired Layer.
With Events 2.0, these Presence Layer events are pushed to the message queue owned by a particular layer, but subscribing
to the events can be done through the global carb.eventdispatcher
Event Dispatcher.
Events#
The following events are dispatched for collaborative spatial awareness features:
Local Follow Mode Changed#
Sent when the local user enters or quits follow mode to other peer users.
Python Constant:
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType.LOCAL_FOLLOW_MODE_CHANGED
String event name:
omni.kit.collaboration.presence_layer:local_follow_mode
Note
This event is dispatched directly when the condition changes, not queued to the omni.kit.usd.layers message queue.
Arguments:
context
(uintptr) - The UsdContext handle representing the Layer, typically used as a filter parameter. Accessible viaomni.kit.usd.layers.Layers.get_event_key()
oromni.usd.UsdContext.get_event_key()
.
This event is triggered when:
The local user starts following another user
The local user stops following another user
Follow mode is toggled on/off
Bound Camera Changed#
Sent when a peer user switches their bound camera or when the user that is being followed switches their bound camera.
Python Constant:
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType.BOUND_CAMERA_CHANGED
String event name:
omni.kit.collaboration.presence_layer:bound_camera
Arguments:
payload
(list[string]) - List of user IDs whose bound camera changed.context
(uintptr) - The UsdContext handle representing the Layer, typically used as a filter parameter. Accessible viaomni.kit.usd.layers.Layers.get_event_key()
oromni.usd.UsdContext.get_event_key()
.
This event is triggered when:
A user binds to a different camera in the scene
A user switches from one camera to another
Camera binding is removed or reset
Selections Changed#
Sent when a peer user changes their object selections in the scene.
Python Constant:
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType.SELECTIONS_CHANGED
String event name:
omni.kit.collaboration.presence_layer:selections
Arguments:
payload
(list[string]) - List of user IDs whose selections changed.context
(uintptr) - The UsdContext handle representing the Layer, typically used as a filter parameter. Accessible viaomni.kit.usd.layers.Layers.get_event_key()
oromni.usd.UsdContext.get_event_key()
.
This event is triggered when:
A user selects or deselects objects in the scene
Selection set is modified (added to or removed from)
Selection is cleared completely
Bound Camera Properties Changed#
Sent when the bound camera of a peer user is a builtin camera and its properties have been modified.
Python Constant:
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType.BOUND_CAMERA_PROPERTIES_CHANGED
String event name:
omni.kit.collaboration.presence_layer:bound_camera_properties
Arguments:
payload
(dict[user_id(string), list[property names(string)]]) - A mapping of user IDs to the list of properties that were changed.context
(uintptr) - The UsdContext handle representing the Layer, typically used as a filter parameter. Accessible viaomni.kit.usd.layers.Layers.get_event_key()
oromni.usd.UsdContext.get_event_key()
.
This event is triggered when:
Camera position, rotation, or scale changes
Camera focal length, aperture, or other optical properties change
Any other camera-specific attributes are modified
Use omni.kit.collaboration.presence_layer.PresenceLayerEventPayload.get_changed_camera_properties()
to retrieve the specific properties that changed for each user.
Bound Camera Resynced#
Sent when the bound camera of a peer user is resynced. This is equivalent to a prim resync in USD.
Python Constant:
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType.BOUND_CAMERA_RESYNCED
String event name:
omni.kit.collaboration.presence_layer:bound_camera_resynced
Arguments:
payload
(list[string]) - List of user IDs whose bound camera was resynced.context
(uintptr) - The UsdContext handle representing the Layer, typically used as a filter parameter. Accessible viaomni.kit.usd.layers.Layers.get_event_key()
oromni.usd.UsdContext.get_event_key()
.
This event is triggered when:
The camera prim is resynced in the USD stage
Camera hierarchy or structure changes require resynchronization
Camera references are updated or reloaded
Usage Examples#
Python Example - Basic Event Observation#
import carb.eventdispatcher
import omni.kit.collaboration.presence_layer as pl
import omni.kit.usd.layers as layers
def on_presence_layer_event(event):
payload = pl.get_presence_layer_event_payload(event)
if not payload or not payload.event_type:
return
print(f"Presence Layer Event: {payload.event_type}")
print(f"Affected users: {list(payload.changed_user_ids)}")
# Subscribe to presence layer events
subscription = carb.eventdispatcher.get_eventdispatcher().observe_event(
observer_name="My Presence Layer Observer",
event_name=pl.PresenceLayerGlobalEventType.BOUND_CAMERA_CHANGED,
on_event=on_presence_layer_event,
filter=layers.get_layers(_usd_context)
)
Python Example - Comprehensive Event Monitoring#
import carb.eventdispatcher
import omni.kit.collaboration.presence_layer as pl
class PresenceLayerMonitor:
def __init__(self, usd_context):
self._usd_context = usd_context
self._subscriptions = []
self._setup_event_subscriptions()
def _setup_event_subscriptions(self):
"""Setup subscriptions for all presence layer events."""
event_handlers = [
(pl.PresenceLayerGlobalEventType.LOCAL_FOLLOW_MODE_CHANGED, self._on_follow_mode_changed),
(pl.PresenceLayerGlobalEventType.BOUND_CAMERA_CHANGED, self._on_camera_changed),
(pl.PresenceLayerGlobalEventType.SELECTIONS_CHANGED, self._on_selections_changed),
(pl.PresenceLayerGlobalEventType.BOUND_CAMERA_PROPERTIES_CHANGED, self._on_camera_properties_changed),
(pl.PresenceLayerGlobalEventType.BOUND_CAMERA_RESYNCED, self._on_camera_resynced),
]
for event_name, handler in event_handlers:
subscription = carb.eventdispatcher.get_eventdispatcher().observe_event(
observer_name=f"PresenceLayerMonitor:{event_name}",
event_name=event_name,
on_event=handler,
filter=self._usd_context.get_event_key()
)
self._subscriptions.append(subscription)
def _on_follow_mode_changed(self, event):
payload = pl.get_presence_layer_event_payload(event)
user_ids = list(payload.changed_user_ids)
print(f"Follow mode changed for users: {user_ids}")
def _on_camera_changed(self, event):
payload = pl.get_presence_layer_event_payload(event)
user_ids = list(payload.changed_user_ids)
print(f"Bound camera changed for users: {user_ids}")
def _on_selections_changed(self, event):
payload = pl.get_presence_layer_event_payload(event)
user_ids = list(payload.changed_user_ids)
print(f"Selections changed for users: {user_ids}")
def _on_camera_properties_changed(self, event):
payload = pl.get_presence_layer_event_payload(event)
for user_id in payload.changed_user_ids:
changed_props = payload.get_changed_camera_properties(user_id)
print(f"Camera properties changed for user {user_id}: {changed_props}")
def _on_camera_resynced(self, event):
payload = pl.get_presence_layer_event_payload(event)
user_ids = list(payload.changed_user_ids)
print(f"Camera resynced for users: {user_ids}")
def cleanup(self):
"""Clean up event subscriptions."""
for subscription in self._subscriptions:
subscription.reset()
self._subscriptions.clear()
# Usage
monitor = PresenceLayerMonitor()
# ... do work ...
monitor.cleanup() # Important to clean up when done
Python Example - Follow Mode Management#
import carb.eventdispatcher
import omni.kit.collaboration.presence_layer as pl
import omni.usd
class FollowModeManager:
def __init__(self):
self.usd_context = omni.usd.get_context()
self.presence_layer = pl.get_presence_layer_interface(self.usd_context)
self.following_user = None
# Subscribe to follow mode events
self.subscription = carb.eventdispatcher.get_eventdispatcher().observe_event(
observer_name="FollowModeManager",
event_name=pl.PresenceLayerGlobalEventType.LOCAL_FOLLOW_MODE_CHANGED,
on_event=self._on_follow_mode_changed,
filter=self.usd_context.get_event_key()
)
def start_following(self, user_id: str):
"""Start following a specific user."""
if self.following_user != user_id:
self.presence_layer.enter_follow_mode(user_id)
print(f"Started following user: {user_id}")
def stop_following(self):
"""Stop following any user."""
if self.following_user:
self.presence_layer.quit_follow_mode()
print(f"Stopped following user: {self.following_user}")
def _on_follow_mode_changed(self, event):
payload = pl.get_presence_layer_event_payload(event)
# Update local state based on follow mode change
# The specific logic depends on your application needs
print(f"Follow mode state updated for users: {list(payload.changed_user_ids)}")
def cleanup(self):
"""Clean up resources."""
if self.subscription:
self.subscription = None
Event Payload Helper#
The PresenceLayerEventPayload
class provides convenient access to event data:
def on_presence_event(event):
payload = pl.get_presence_layer_event_payload(event)
if not payload or not payload.event_type:
return
# Check event type
if payload.event_type == pl.PresenceLayerEventType.BOUND_CAMERA_PROPERTIES_CHANGED:
# Special handling for camera properties
for user_id in payload.changed_user_ids:
changed_props = payload.get_changed_camera_properties(user_id)
print(f"User {user_id} changed camera properties: {changed_props}")
elif payload.event_type == pl.PresenceLayerEventType.SELECTIONS_CHANGED:
# Handle selection changes
user_ids = list(payload.changed_user_ids)
print(f"Selection changed for users: {user_ids}")
# Get all affected users for any event type
all_users = list(payload.changed_user_ids)
print(f"Event affects users: {all_users}")
Integration with Live Sessions#
Presence Layer events are tightly integrated with the USD Layers live session system. Here’s how to work with them in the context of live sessions:
import omni.usd
import omni.kit.usd.layers as layers
import omni.kit.collaboration.presence_layer as pl
# Get the current USD context and layers interface
usd_context = omni.usd.get_context()
layers_interface = layers.get_layers(usd_context)
# Check if we're in a live session
live_syncing = layers_interface.get_live_syncing()
if live_syncing.is_in_live_session():
# Get presence layer interface
presence_layer = pl.get_presence_layer_interface(usd_context)
# Subscribe to presence layer events
subscription = carb.eventdispatcher.get_eventdispatcher().observe_event(
observer_name="Live Session Presence Monitor",
event_name=pl.PresenceLayerGlobalEventType.BOUND_CAMERA_CHANGED,
on_event=lambda event: handle_camera_change(event),
filter=layers_interface.get_event_key()
)
# Broadcast local camera to other users
camera_path = "/World/Camera"
presence_layer.broadcast_local_bound_camera(camera_path)
Legacy Events#
Previously, Presence Layer used Events 1.0 through the omni.kit.collaboration.presence_layer.PresenceLayerEventType
enum.
While still supported for backward compatibility, it is recommended to use the Events 2.0 system with
omni.kit.collaboration.presence_layer.PresenceLayerGlobalEventType
.
Converting from Legacy Events#
Old approach (Events 1.0):
import carb.events
import omni.kit.collaboration.presence_layer as pl
def _on_layers_event(event: carb.events.IEvent):
payload = pl.get_presence_layer_event_payload(event)
if payload.event_type == pl.PresenceLayerEventType.SELECTIONS_CHANGED:
# Handle event...
pass
# Subscribe through layers event stream (deprecated)
layers_interface = layers.get_layers(usd_context)
subscription = layers_interface.get_event_stream().create_subscription_to_pop(
_on_layers_event, name="My Presence Subscription"
)
New approach (Events 2.0):
import carb.eventdispatcher
import omni.kit.collaboration.presence_layer as pl
def on_selections_changed(event: carb.eventdispatcher.Event):
payload = pl.get_presence_layer_event_payload(event)
# Handle event...
pass
# Subscribe directly to global events
subscription = carb.eventdispatcher.get_eventdispatcher().observe_event(
observer_name="My Presence Observer",
event_name=pl.PresenceLayerGlobalEventType.SELECTIONS_CHANGED,
on_event=on_selections_changed,
filter=usd_context.get_event_key() # only desire the events for the given layer
)