Skip to main content
Version: 0.9.0 (next)

QAR Streaming C# API

Quaternar.Qaros is the .NET binding of the QAROS streaming C API. It targets netstandard2.0, netstandard2.1 and net8.0, loads the same native qar-streaming-c library, and is the C# surface Unity uses too.

  • Quaternar.Qaros (this reference) is the managed API: IDisposable handles, Result<T> return values, C# events and ...Async variants. Every public type is listed below.
  • Quaternar.Qaros.Mathematics holds Vector3, Vector3d, Quaternion and Pose, apart from the main namespace so they do not clash with the UnityEngine or System.Numerics types of the same names. Add using Quaternar.Qaros.Mathematics; where you use them.
  • Quaternar.Qaros.Interop is the internal P/Invoke layer the managed API is built on. It is not part of the public surface and is not documented here.

Concepts, threading rules and usage snippets live in the Developer Guide, next to the C examples.

Entry points​

  1. Library.Init loads the native library, once per process.
  2. Runtime.Create creates the runtime. Its Onboard joins a session for the first time and returns an OnboardSession; Rejoin returns to a session joined before.
  3. A Session exposes one control per area: Peers, GuiPanels, AppVolumes, RenderSenders and PrimarylessVideoSenders.
  4. Calls return a Result<T>: check IsSuccess, or use ValueOrThrow(). Failures carry a StatusCode.

Library and runtime​

Load the native library and create the runtime that onboards and rejoins sessions.

TypeKindDescription
LibraryclassProcess-wide library state. Library.Init comes first, before any other call of this API; then Runtime.Create, then Runtime.Onboard or Runtime.Rejoin for a Session.
LibraryOptionsclassArguments of Library.Init, which must run once per process before any other call. The defaults match qar_library_init_default().
LogSeverityenumMinimum severity the library logs; see LibraryOptions.LogSeverity.
RuntimeclassHosts the identity slots a process onboards with and produces its sessions. Create it after Library.Init; every Session comes from Runtime.Onboard or Runtime.Rejoin on it.
RuntimeOptionsclassArguments of Runtime.Create.
StructureclassBase of the extension structures chained onto an options object with its WithExtension method. The options are copied into native memory for the duration of the call that takes them.
StructureTypeenumNative structure type tag of a Structure. Each extension class sets its own in its constructor.

Onboarding and sessions​

Join a QAROS session for the first time, rejoin it later, invite devices and start target apps.

TypeKindDescription
ActionProgressstruct
ActionSeverityenum
ForgetOptionsclass
GpuDeviceIdTypeenumHow GraphicsDeviceId names the adapter.
GraphicsDeviceIdclassExtension: selects the graphics adapter the session's Vulkan and D3D11 devices, and with them every render sender's frame textures, are created on. Chain on OnboardOptions or RejoinOptions; absent, the library picks one. Windows accepts a LUID, other platforms a UUID. The C API currently supports NVIDIA adapters only.
OnboardCodeclassOnboarding mode extension behind OnboardOptions.UseCode; prefer that method.
OnboardHostclassThe hub to code-onboard against, behind OnboardOptions.WithHost; prefer that method.
OnboardingIdstructThe key of an identity slot, minted by the first Runtime.Onboard. It is the one thing an application persists: hand it back to Runtime.Rejoin on every start and to Runtime.Forget to unpair.
OnboardingInviteclassA one-time onboarding invite minted by the hub: everything another instance needs to onboard with OnboardOptions.UseInvite, or a code to hand out by OnboardingInvite.GetCode.
OnboardingMethodenumWhich onboarding path an onboarding invite carries. More may be added, so do not treat "not OnboardingMethod.Pake" as OnboardingMethod.Password.
OnboardInviteclassOnboarding mode extension behind OnboardOptions.UseInvite; prefer that method. The invite is borrowed, not owned.
OnboardOptionsclassOptions of Runtime.Onboard. Choose exactly one mode: OnboardOptions.UseCode or OnboardOptions.UseInvite; the last call wins.
OnboardPeerIdclassExtension: join the session under a caller-chosen peer id instead of a freshly minted one. Chain on OnboardOptions with OnboardOptions.WithPeerId. The id is persisted with the slot, so a later rejoin keeps it. A zero id is rejected with StatusCode.ArgumentNotSupported.
OnboardSessionstructWhat Runtime.Onboard produces. Persist OnboardSession.OnboardingId before anything else; the caller owns and disposes OnboardSession.Session.
RejoinOptionsclassOptions of Runtime.Rejoin.
RequestOnboardingCodesOptionsclassA request for a new set of one-time onboarding codes. Every request gets codes of its own; codes other callers hold and the hub's onboarding screen code stay valid.
RequestOnboardingInviteOptionsclass
SessionclassAn active session, the entry point to peers, GUI panels, app volumes and senders. Only Runtime.Onboard and Runtime.Rejoin produce one, and there is no getter for a "current" session: keep the instance.
SessionIdstructA session's 16-byte UUID. Compared by content; default(SessionId) equals SessionId.Default.
TargetAppConnectionStringclassBuilds the connection strings Session.InviteTargetApp accepts. A host is a hostname or an IP address; it must not be empty.

Peers and hands​

The peers in a session, their presentation and the hand-tracking data devices send.

TypeKindDescription
AppStateenumA peer's lifecycle state. A target app is ready to be rendered for only while it is AppState.Running.
DeviceHandsWithJointsstructThe newest hands sample a device sent. From RenderSender.GetLastHands every pose, radius and velocity in it is in the bound app volume's app content space (right-handed, +Y up, -Z forward, app units), like the view poses.
HandednessenumLeft or right: which hand made a gesture, and the handedness of the axes of a GeoAnchorFrame.
HandJointenumXR_EXT_hand_tracking joint indices; HandJointLocation.JointId carries one.
HandJointLocationstructOne XR_EXT_hand_tracking joint.
HandJointLocationFlagsenumBits of HandJointLocation.LocationFlags and HandJointVelocity.Flags.
HandJointsstructOne hand's tracking state: 26 joint locations and velocities indexed by HandJoint.
HandJointVelocitystructVelocity of one joint.
PeerControlclassThe peers of a session: every participant, devices and applications alike, this process included. Reached through Session.Peers.
PeerIdstructA peer's 16-byte UUID. Compared by content; default(PeerId) equals PeerId.Default.
PeerPresentationOptionsclassHow this peer presents itself to the others. Never a storage key. A property left null keeps its persisted value, or gets a generated default on the first onboard.
PeerSpecclassAn immutable snapshot of one peer, taken when it was read or delivered; safe to keep. It does not change: read a new one, or watch PeerControl.SubscribeUpdates.
PeerSpecUpdatedEventArgsclassOne peer update; PeerSpecUpdatedEventArgs.Peer is a snapshot, safe to keep.

App volumes​

The 3D volumes an application renders into, their gestures and world anchoring.

TypeKindDescription
AppScaleSensitivityModeenum
AppVolumeclassAn immutable snapshot of one app volume: the box in the room a remote 3D application renders into, and how the application's content sits inside it.
AppVolumeAxisFlagsenumBitmask of the axes a mapping rule lets a gesture translate along or rotate about; see AppVolumeGestureMappingRule.TranslationAxes and AppVolumeGestureMappingRule.RotationAxes.
AppVolumeControlclassThe session's app volumes: the boxes in the room that remote 3D applications render into. Reached through Session.AppVolumes.
AppVolumeControllerRayLineStyleenum
AppVolumeControllerRayStylestructHow the hand ray is drawn for gestures a mapping rule matches. The colour is RGBA, 0 to 255 per channel; AppVolumeControllerRayStyle.Default is a solid opaque white line.
AppVolumeEditingStatusstructWhether a peer holds the volume's editing lock (AppVolumeControl.StartEditing) to move or resize the box itself. A peer manipulating the app with a gesture is not editing it.
AppVolumeGestureConfigurationclassA gesture mode's mapping rules, in descending priority order, plus the peers whose gestures may move or scale the app.
AppVolumeGestureEventstructOne mapped gesture on an app volume, copied out of the native callback.
AppVolumeGestureEventArgsclass
AppVolumeGestureMappingRuleclassHow one gesture kind on an app volume is shaped and what it is applied to. Its priority is its position in AppVolumeGestureConfiguration.MappingRules, not a field.
AppVolumeGestureStateclassAn app volume's gesture modes and who is using them, read with the volume snapshot.
AppVolumeIdstructAn app volume's 16-byte UUID, derived from the volume's common name by AppVolumeControl.GetOrCreate. Compared by content; default(AppVolumeId) equals AppVolumeId.Default.
AppVolumeLifetimeStatusenum
AppVolumeOptionsclassArguments of AppVolumeControl.GetOrCreate. The defaults match qar_app_volume_init_default(): identity poses, a 1 m cube, app scale 1, no world anchor and the default gesture configuration.
AppVolumeSizestructAn app volume cuboid's extents in metres, centred on the volume's pose: it spans plus and minus half of each extent along app volume space X, Y and Z. Note the constructor order: width (X), length (Z), height (Y).
AppVolumeUpdatedEventArgsclassOne app volume update; AppVolumeUpdatedEventArgs.Volume is a snapshot, safe to keep.
AppWorldAnchorstructAn app volume's world anchor, if it has one.
GeoAnchorFramestructA local frame fully defined in world coordinates: its origin and unit axes in GeoAnchorFrame.WorldReferenceSystem (ECEF WGS84, metres, double precision), plus the handedness of those axes. Pins an app volume to the Earth.
GestureAppTransformMappingenumWhat the library applies a mapped gesture to by itself. Either way the gesture still reaches the volume's gesture subscribers; AppVolumeGestureEvent.WasMappedToAppTransform tells whether it was already applied.
GestureKindenumWhat a hand interaction with an app volume was recognised as.
GesturePhaseenum
WorldReferenceSystemenum

GUI panels​

Flat 2D panels placed in the room and the gestures users make on them.

TypeKindDescription
GuiPanelclassAn immutable snapshot of one GUI panel, safe to keep. Get a newer one from GuiPanelControl.SubscribeUpdates.
GuiPanelContentTypeenumWhat a GUI panel shows. Fixed at creation: GuiPanelControl.NavigateToUri on a stream panel fails with StatusCode.GuiPanelChangeNotPermitted.
GuiPanelControlclassThe session's GUI panels: shared 2D surfaces in the room showing a web page or a video stream. Reached through Session.GuiPanels.
GuiPanelGestureEventstructOne recognised gesture on a GUI panel, copied out of the native callback.
GuiPanelGestureEventArgsclass
GuiPanelGestureKindenumWhat a contact on a GUI panel was recognised as.
GuiPanelIdstructA GUI panel's 16-byte UUID, derived from the panel's common name by GuiPanelControl.GetOrCreate. Compared by content; default(GuiPanelId) equals GuiPanelId.Default.
GuiPanelOptionsclassArguments of GuiPanelControl.GetOrCreate.
GuiPanelPointstructA position on a GUI panel in panel-content-space pixels: origin top-left as the viewer sees it, +X right, +Y down.
GuiPanelSizestructA GUI panel's surface size in metres and the zoom of the content drawn on it. The surface spans panel-space X from -Width/2 to +Width/2 and hangs down from the pose to -Height.
GuiPanelStateenum
GuiPanelUpdatedEventArgsclassOne GUI panel update; GuiPanelUpdatedEventArgs.Panel is a snapshot, safe to keep.

Rendering​

Render senders stream frames for a target peer: frame begin/show, views, stream parameters per graphics API.

TypeKindDescription
DXGIKeyedMutexSyncstructThe keyed mutex of one shared D3D11 texture and the keys for its AcquireSync and ReleaseSync. Needed only when StreamParamsD3D11.AcquireKeyedMutexSync is false and the application drives the key chain itself.
FovstructField of view of one render view, in view space: angles in radians from the view's -Z axis, with OpenXR signs - left and down negative, right and up positive.
FrameLayoutenumHow the views of one video frame are packed into textures.
GraphicsAPIenumThe graphics backend a sender's frame textures live on. Every GPU value requires exactly the matching stream-parameter extension on the options; GraphicsAPI.Cpu takes none.
ImageSizestructAn image size in pixels.
NearFarstructNear and far clip distances along a view's -Z, in the units of the poses the view was rendered with: app units for a render sender. A near plane greater than the far plane declares reverse-Z.
OpenGlContextCallbacksstructRaw C function pointers overriding how the library binds an OpenGL context; see QarOpenGlContextCallbacks in types.h. Every one is optional and called on the library's internal graphics thread; zero uses the library's own platform implementation for that step.
PixelFormatenum
RenderFrameInfoclassPer-frame information from a successful begin-frame. Everything it hands out is in the bound app volume's app content space.
RenderFrameShowclassArguments of RenderSender.ShowFrame: the projection metadata the frame was rendered with. The defaults match qar_render_frame_show_default(): near 0.1, far 100, depth scale 1.
RenderFrameShowViewOverridesclassExtension of RenderFrameShow: the pose or field of view a view was really rendered with, when it differs from what RenderSender.BeginFrame handed out. RenderFrameShow.WithViewOverrides chains one.
RenderFrameViewstructOne view declared in RenderSenderOptions.FrameViews.
RenderFrameViewOverridestructThe pose and/or field of view one view was really rendered with, when it deviates from what RenderSender.BeginFrame handed out. Only the parts whose flag is set are used.
RenderSenderclassStreams the application's rendered frames to one target peer, displayed in the bound app volume. Create one per target with RenderSenderControl.Create.
RenderSenderControlclassCreates render senders and delivers render stream requests for a session; reached through Session.RenderSenders.
RenderSenderOptionsclassArguments of a render sender: one stream rendered for one target peer, displayed in one app volume. The defaults match qar_render_sender_init_default().
RenderStreamRequeststruct
RenderStreamRequestEventArgsclass
StreamIdstructA logical video stream's 16-byte UUID, generated by the library for each PrimarylessVideoSender (PrimarylessVideoSender.GetStreamId). Compared by content; default(StreamId) equals StreamId.Default.
StreamParamsD3D11classExtension: adopt the application's D3D11.1 device, so the sender's frame textures are shared D3D11 textures it renders into directly, with no CPU copy. Windows only.
StreamParamsOpenGlclassBase of the three OpenGL stream-parameter extensions. Pick the one matching the context the application owns; requires a library built with QAR_ENABLE_OPENGL.
StreamParamsOpenGlEglclassExtension: adopt an existing EGL context.
StreamParamsOpenGlGlxclassExtension: adopt an existing GLX context.
StreamParamsOpenGlWglclassExtension: adopt an existing WGL context.
StreamParamsVulkanclassExtension: adopt an existing Vulkan device. Requires a library built with QAR_ENABLE_VULKAN.
SyncFrameD3D11struct
TextureSizestructOne texture of a frame layout; width and height in pixels.

Video senders and frames​

Video streams without a primary render target, and the frame and texture types every sender hands out.

TypeKindDescription
PrimarylessVideoSenderclassApplication-owned video stream, such as GUI panel content, that exists before any receiver connects and is delivered to every receiver that requests its stream id.
PrimarylessVideoSenderControlclassCreates PrimarylessVideoSenders for a session; reached through Session.PrimarylessVideoSenders.
PrimarylessVideoSenderOptionsclassArguments of PrimarylessVideoSender: application-owned video, such as GUI panel content, under a library-generated StreamId. Unlike a render sender it answers no receiver request and may exist before any receiver connects.
VideoFrameCpustructA snapshot of a sender's CPU frame: its views and textures, in layout order. The pixel memory stays the sender's.
VideoFrameD3D11structA snapshot of a sender's D3D11 frame: its views, its shared textures and their keyed-mutex synchronization. The textures stay the sender's; render into them only inside a frame cycle. A render sender's frame is readable from creation, before the first begin-frame.
VideoFrameLayoutclassThe views of a video frame and the textures backing them.
VideoFrameOpenGlstructA snapshot of a sender's OpenGL frame: its views and textures. The textures stay the sender's; render into them only inside a frame cycle. A render sender's frame is readable from creation, before the first begin-frame.
VideoFrameViewstructWhere one view of a video frame lives: a pixel rectangle in one texture (and array layer). The end coordinates are exclusive and may be smaller than the start ones, which flips the view.
VideoFrameViewEyeenum
VideoFrameViewTypeenum
VideoFrameVulkanclassAccess to a sender-owned Vulkan frame. The library owns the native frame; this object is valid until the next GetVulkanFrame call on the same sender or the sender's disposal. Before showing a frame, write the layouts and queue families the images were left in and the synchronization objects with VideoFrameVulkan.SetTextureState and VideoFrameVulkan.SetSynchronization.
VideoTextureCpustructOne sender-owned CPU texture. The pixel memory is not copied: VideoTextureCpu.TextureData points into the sender.
VideoTextureD3D11struct
VideoTextureOpenGlstruct
VideoTextureVulkanstructOne sender-owned Vulkan image and the state it is in.

Results and errors​

Every call returns a Result<T> instead of throwing; these types carry the outcome.

TypeKindDescription
NativeCallExceptionclassA native failure turned into an exception on request, by Result<T>.ValueOrThrow or EnsureSuccess. NativeCallException.Result carries the status code.
Result<T>structA value or a failure. A native failure is returned, never thrown: check Result<T>.IsSuccess, or opt into an exception with Result<T>.ValueOrThrow or Result<T>.EnsureSuccess.
ResultInfostructThe outcome of a native call: a ResultInfo.StatusCode and a diagnostic message.
StatusCodeenumStatus codes the C API exposes (QarStatusCode), with the same values. Any internal code outside this set reaches callers as StatusCode.Unclassified.
UnitstructThe value of a Result<T> whose operation returns nothing.

Math and time​

Value types shared by every area.

TypeKindDescription
PosestructPosition plus orientation (x, y, z, w). A pose carries no space of its own: every member that holds one names the space it is in. The bindings convert no coordinates; each value is exactly what the native library produced.
QuaternionstructRotation quaternion, Hamilton convention, stored and constructed in x, y, z, w order (w last). default(Quaternion) is all zeros, not a rotation; use Quaternion.Identity.
TimePointstructWall-clock instant: nanoseconds since the Unix epoch (UTC). Instants stamped on different hosts are only as comparable as those hosts' clocks are synchronized. Converts to a UTC DateTime implicitly or with TimePoint.ToDateTime, truncated to its 100 ns tick.
Vector3structA 3D vector. It carries no space of its own; the member holding it names the space (see Pose).
Vector3dstructDouble-precision 3D vector, used for Earth-fixed world coordinates in GeoAnchorFrame.