Use custom data channels to send custom data over an established remoting connection.
[!IMPORTANT] Custom data channels require a custom remote app and a custom player app. This allows communication between the two custom apps.
[!TIP] A simple ping-pong example can be found in the remote and player samples inside the Holographic Remoting samples github repository. Uncomment
#define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE
inside the OpenXrProgramm.cpp and SamplePlayerMain.h files to enable the sample code.
[!NOTE] The detailed specification can be found in the Holographic Remoting samples github repository.
A custom data channel is defined by the XrRemotingDataChannelMSFT
handle:
XrRemotingDataChannelMSFT m_userDataChannel;
After a connection is successfully established, new data channels can be created via the xrCreateRemotingDataChannelMSFT
function:
XrRemotingDataChannelCreateInfoMSFT channelInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_DATA_CHANNEL_CREATE_INFO_MSFT)};
channelInfo.channelId = 0;
channelInfo.channelPriority = XR_REMOTING_DATA_CHANNEL_PRIORITY_LOW_MSFT;
CHECK_XRCMD(m_extensions.xrCreateRemotingDataChannelMSFT(m_instance.Get(), m_systemId, &channelInfo, &m_userDataChannel));
Custom data channels can be created from the player and the remote application even if the runtimes are different.
If a data channel is created by the player side, the remote side is notified with the XrEventDataRemotingDataChannelCreatedMSFT
event structure:
XrEventDataBuffer eventData{};
while (pollEvent(eventData))
{
switch (eventData.type)
{
case XR_TYPE_EVENT_DATA_REMOTING_DATA_CHANNEL_CREATED_MSFT:
{
auto channelCreatedEventData = reinterpret_cast<const XrEventDataRemotingDataChannelCreatedMSFT*>(&eventData);
m_userDataChannel = channelCreatedEventData->channel;
break;
}
}
}
The initial XrRemotingDataChannelStatusMSFT
state after calling xrCreateRemotingDataChannelMSFT
is XR_REMOTING_DATA_CHANNEL_STATUS_OPEN_PENDING_MSFT
.
Once the data channel has been fully established, the channels state switches to
XR_REMOTING_DATA_CHANNEL_STATUS_OPENED_MSFT
.
The
XrEventDataRemotingDataChannelOpenedMSFT
event structure is placed in the event queue when the state of a previously created data channel switches from
XR_REMOTING_DATA_CHANNEL_STATUS_OPEN_PENDING_MSFT
to
XR_REMOTING_DATA_CHANNEL_STATUS_OPENED_MSFT
`.
The xrGetRemotingDataChannelStateMSFT
function can be used to query the data channel state:
XrRemotingDataChannelStateMSFT channelState{static_cast<XrStructureType>(XR_TYPE_REMOTING_DATA_CHANNEL_STATE_MSFT)};
CHECK_XRCMD(m_extensions.xrGetRemotingDataChannelStateMSFT(m_userDataChannel, &channelState));
If the channel is open the xrSendRemotingDataMSFT
function is used to send data to the player side:
if (channelState.connectionStatus == XR_REMOTING_DATA_CHANNEL_STATUS_OPENED_MSFT) {
// Only send the packet if the send queue is smaller than 1MiB
if (channelState.sendQueueSize >= 1 * 1024 * 1024) {
return;
}
uint8_t data[] = {1};
XrRemotingDataChannelSendDataInfoMSFT sendInfo{
static_cast<XrStructureType>(XR_TYPE_REMOTING_DATA_CHANNEL_SEND_DATA_INFO_MSFT)};
sendInfo.data = data;
sendInfo.size = sizeof(data);
sendInfo.guaranteedDelivery = true;
CHECK_XRCMD(m_extensions.xrSendRemotingDataMSFT(m_userDataChannel, &sendInfo));
}
[!NOTE] The data you send over a custom data channel shares the bandwidth with other data channels Holographic Remoting uses.
Every time data arrives via a data channel, an XrEventDataRemotingDataChannelDataReceivedMSFT
event structure is placed into the event queue.
Received packets can be retrieved with the xrRetrieveRemotingDataMSFT
function:
XrEventDataBuffer eventData{};
while (pollEvent(eventData))
{
switch (eventData.type)
{
case XR_TYPE_EVENT_DATA_REMOTING_DATA_CHANNEL_DATA_RECEIVED_MSFT:
{
auto dataReceivedEventData = reinterpret_cast<const XrEventDataRemotingDataChannelDataReceivedMSFT*>(&eventData);
std::vector<uint8_t> packet(dataReceivedEventData->size);
uint32_t dataBytesCount;
CHECK_XRCMD(m_extensions.xrRetrieveRemotingDataMSFT(dataReceivedEventData->channel,
dataReceivedEventData->packetId,
static_cast<uint32_t>(packet.size()),
&dataBytesCount,
packet.data()));
break;
}
}
}
You can destroy a data channel with xrDestroyRemotingDataChannelMSFT
:
CHECK_XRCMD(m_extensions.xrDestroyRemotingDataChannelMSFT(m_userDataChannel));
The XrRemotingDataChannelMSFT
handle is invalid after the xrDestroyRemotingDataChannelMSFT
call and the data channel handle must not be used afterwards.
The XrEventDataRemotingDataChannelClosedMSFT
will be placed in the event queue in case the player side closes or destroys the data channel.
The data channel state switches to XR_REMOTING_DATA_CHANNEL_STATUS_CLOSED_MSFT
.
For a closed data channel, the XrRemotingDataChannelMSFT
handle remains valid.