包含全息远程处理和 OpenXR API 的自定义数据通道

使用自定义数据通道通过已建立的远程处理连接发送自定义数据。

重要

自定义数据通道需要自定义远程应用和自定义播放器应用。 这允许两个自定义应用之间的通信。

提示

可在全息远程处理示例 GitHub 存储库中的远程和播放器示例中找到简单的乒乓球示例。 在 OpenXrProgramm.cpp 和 SamplePlayerMain.h 文件中取消注释 #define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE 可启用示例代码。

注意

可在全息远程处理示例 github 存储库中找到详细的规范

创建自定义数据通道

自定义数据通道由 XrRemotingDataChannelMSFT 句柄定义:

XrRemotingDataChannelMSFT m_userDataChannel;

成功建立连接后,可以通过 xrCreateRemotingDataChannelMSFT 函数创建新的数据通道:

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));

即使运行时不同,也可以从播放器和远程应用程序创建自定义数据通道。 如果由播放器端创建了数据通道,将使用 XrEventDataRemotingDataChannelCreatedMSFT 事件结构通知远程端:

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;
        }
    }
}

调用 xrCreateRemotingDataChannelMSFT 后的初始 XrRemotingDataChannelStatusMSFT 状态为 XR_REMOTING_DATA_CHANNEL_STATUS_OPEN_PENDING_MSFT。 数据通道完全建立后,通道的状态将切换为 XR_REMOTING_DATA_CHANNEL_STATUS_OPENED_MSFT。 以前创建的数据通道的状态从 XrEventDataRemotingDataChannelOpenedMSFT 切换为 XR_REMOTING_DATA_CHANNEL_STATUS_OPEN_PENDING_MSFT 时,将在事件队列中放置 XR_REMOTING_DATA_CHANNEL_STATUS_OPENED_MSFT 事件结构。

获取通道状态

可以使用 xrGetRemotingDataChannelStateMSFT 函数查询数据通道状态:

XrRemotingDataChannelStateMSFT channelState{static_cast<XrStructureType>(XR_TYPE_REMOTING_DATA_CHANNEL_STATE_MSFT)};
CHECK_XRCMD(m_extensions.xrGetRemotingDataChannelStateMSFT(m_userDataChannel, &channelState));

发送数据

如果通道是打开的,使用 xrSendRemotingDataMSFT 函数将数据发送到播放器端:

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));
}

注意

通过自定义数据通道发送的数据与全息远程处理使用的其他数据通道共享带宽。

检索数据

每次数据通过数据通道到达时,都会在事件队列中放置 XrEventDataRemotingDataChannelDataReceivedMSFT 事件结构。 可以通过 xrRetrieveRemotingDataMSFT 函数检索接收到的数据包:

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;
        }
    }
}

销毁数据通道

可以使用 xrDestroyRemotingDataChannelMSFT 销毁数据通道:

CHECK_XRCMD(m_extensions.xrDestroyRemotingDataChannelMSFT(m_userDataChannel));

XrRemotingDataChannelMSFT 句柄在 xrDestroyRemotingDataChannelMSFT 调用后无效,其后不得使用该数据通道句柄。

如果播放器端关闭或销毁数据通道,则将 XrEventDataRemotingDataChannelClosedMSFT 放置在事件队列中。 数据通道状态切换为 XR_REMOTING_DATA_CHANNEL_STATUS_CLOSED_MSFT。 对于已关闭的数据通道,XrRemotingDataChannelMSFT 句柄仍有效。

另请参阅