New To The Forum? Click Here To Read The How To Guide. -- Developers Click Here.

Cannot join an Oculus session: "Cannot map local player to unique net ID"

ginopelosoginopeloso Posts: 22
NerveGear
I'm trying to create and join an Oculus session. I already succeeded in creating a session by using the Null and the Steam subsystems, but the Oculus' one seems to be more complex.

Rather than using the Unreal's CreateSession and FindSessions blueprint functions I used the Oculus' CreateSession and FindMatchmakingSessions. These one are my Blueprint blocks for creating and searching/joining sessions.


The session is created and found correctly (the Oculus matchmaking pool named "ciao" is the one configured on my Oculus dashboard). My problem is the JoinSession function, which actually is the one provided by Unreal, because the Oculus sdk does not provide an equivalent method, so when I call it I receive a warning message "Cannot map local player to unique net ID".

How can I join a session by using blueprints? I'm also trying to create a Blueprint function library and writing the JoinSession with C++, but I don't know how to call the OnlineInterface::JoinSession method correctly. Does someone has an example of code on how to join an Oculus session?

Comments

  • JPonczekJPonczek Posts: 4
    NerveGear
    I'm having the same exact problem. Please help!
  • imperativityimperativity Posts: 1,435 Oculus Staff
    Hi,

    I am currently looking into this and will advise you on what information I find that is applicable to your situation.
  • aussieburgerVRaussieburgerVR Posts: 95
    Hiro Protagonist
    I'd also love to know, as will be tackling multiplayer with blueprints soon! ...
  • ginopelosoginopeloso Posts: 22
    NerveGear
    edited May 9
    I was able to join the matchmaking session by assigning the oculus id as UniqueNetId to the PlayerController (the title's warning message has disappeared when calling the Unreal's JoinSession function).

    Unlike what happens with the Null and the Steam subsystems, however, the voice is not replicated from side to side, so the abstraction still has something not working properly (the DefaultEngine.ini is configured like described here, and it actually works with the other aforementioned subsystems)...
  • brian_jewbrian_jew Posts: 61 Oculus Staff
    I was able to join the matchmaking session by assigning the oculus id as UniqueNetId to the PlayerController (the title's warning message has disappeared when calling the Unreal's JoinSession function).
    That sounds like the PlayerController doesn't automatically get the oculus UniqueNetId when it first initializes and instead is using the local player.
    Unlike what happens with the Null and the Steam subsystems, however, the voice is not replicated from side to side, so the abstraction still has something not working properly (the DefaultEngine.ini is configured like described here, and it actually works with the other aforementioned subsystems)...
    That's correct.  Right now unlike the other subsystems, Oculus' Voice Interface isn't hooked into the Session subsystem automatically yet (or in other words, joining a session doesn't automatically connect the voices to the other players).  It was kept that way for now to keep it simple, though I can see how this makes it more difficult to rely on blueprints to set this up.
  • xN31xN31 Posts: 10
    NerveGear
    @brian_jew : Is Oculus voice chat meant to use the UE4 default Opus codec or a specific one? I thought Oculus voice chat was based on the codec used in Facebook's voice calls, but using the command "online test voice" I see the initialisation of the Opus codec. Is this correct?

  • ginopelosoginopeloso Posts: 22
    NerveGear
    brian_jew said:
    That's correct.  Right now unlike the other subsystems, Oculus' Voice Interface isn't hooked into the Session subsystem automatically yet (or in other words, joining a session doesn't automatically connect the voices to the other players).  It was kept that way for now to keep it simple, though I can see how this makes it more difficult to rely on blueprints to set this up.
    Ok, so let's try to start a voice session "manually".
    On this page I read to call 
    Online::GetVoiceInterface()->RegisterRemoteTalker
    to connect to someone else, by passing a FUniqueNetIdOculus object. FUniqueNetIdOculus is declared inside OnlineSubsystemOculusTypes.h, which is private, so I cannot include it. How can I instantiate it?

    I tried to call RegisterRemoteTalker with a FUniqueNetIdString (which also extends FUniqueNetId) but the id it takes to register the remote talker is not the Oculus' one (with which the FUniqueNetIdString is created).

    Thanks for your clarification.
  • ginopelosoginopeloso Posts: 22
    NerveGear
    edited May 10
    Finally we got the voice working. Below is described what we tried to do, we think also this feature has the same problem related to the Oculus player id.

    First of all we tried to call RegisterRemoteTalker with the following code, by passing the oculus net id:
    bool UMyClass::RegisterRemoteTalker(FString PlayerId) {
        FUniqueNetIdString* uniqueNetId = new FUniqueNetIdString(PlayerId);
        return Online::GetVoiceInterface()->RegisterRemoteTalker(*uniqueNetId);
    }
    It returned true (success), but after some seconds it printed this warning log:
    LogVoice:Warning: RANDOM_NUMBER timed out
    where RANDOM_NUMBER is a number unrelated to the player id (I suspect it was the FUniqueNetIdString object address, it was different also whether the PlayerId was the same).

    Since we was unable to use the class FUniqueNetIdOculus class, we copied it from OnlineSubsystemOculusTypes.h to one of our files (it is a simple class).
    class FUniqueNetIdOculus : public FUniqueNetId {
    private:
        ovrID ID;
    
    protected:
        virtual bool Compare(const FUniqueNetId& Other) const
        {
            if (Other.GetSize() != sizeof(ovrID))
            {
                return false;
            }
    
            return ID == static_cast<const FUniqueNetIdOculus&>(Other).ID;
        }
    
    public:
        /** Default constructor */
        FUniqueNetIdOculus()
        {
            ID = 0;
        }
    
        FUniqueNetIdOculus(const ovrID& id)
        {
            ID = id;
        }
    
        FUniqueNetIdOculus(const FString& id)
        {
            ovrID_FromString(&ID, TCHAR_TO_ANSI(*id));
        }
    
        /**
        * Copy Constructor
        *
        * @param Src the id to copy
        */
        explicit FUniqueNetIdOculus(const FUniqueNetId& Src)
        {
            if (Src.GetSize() == sizeof(ovrID))
            {
                ID = static_cast<const FUniqueNetIdOculus&>(Src).ID;
            }
        }
    
        // IOnlinePlatformData
    
        virtual const uint8* GetBytes() const override
        {
            uint8* byteArray = static_cast<uint8*>(malloc(sizeof(uint8) * 4));
            check(byteArray);
    
            // convert from an unsigned long int to a 4-byte array
            byteArray[0] = static_cast<uint8>((ID >> 24) & 0xFF);
            byteArray[1] = static_cast<uint8>((ID >> 16) & 0xFF);
            byteArray[2] = static_cast<uint8>((ID >> 8) & 0XFF);
            byteArray[3] = static_cast<uint8>((ID & 0XFF));
    
            return byteArray;
        }
    
        virtual int32 GetSize() const override
        {
            return sizeof(ID);
        }
    
        virtual bool IsValid() const override
        {
            return ID != 0;
        }
    
        ovrID GetID() const
        {
            return ID;
        }
    
        virtual FString ToString() const override
        {
            return FString::Printf(TEXT("%llu"), ID);
        }
    
        virtual FString ToDebugString() const override
        {
            return FString::Printf(TEXT("ovrID: %llu"), ID);
        }
    
        /** Needed for TMap::GetTypeHash() */
        friend uint32 GetTypeHash(const FUniqueNetIdOculus& A)
        {
            return GetTypeHash((uint64)A.ID);
        }
    };
    This class uses the function ovrID_FromString, which is defined in OVR_Types.h and implemented in LibOVRPlatform64_1.lib. So we included the OVR_* header files in our project and added the file LibOVRPlatform64_1.lib to our Binaries.

    Then we modified the function RegisterRemoteTalker thus:
    bool UMyClass::RegisterRemoteTalker(FString PlayerId) {
        FUniqueNetIdOculus* uniqueNetId = new FUniqueNetIdOculus(PlayerId);
        return Online::GetVoiceInterface()->RegisterRemoteTalker(*uniqueNetId);
    }
    we call it the same way from Blueprint, by passing the same Oculus remote net id and now it is taking the right net id.

    Finally we are able to send and receive voice from side to side, but I imagine this isn't how the whole thing should work. May you investigate on it or suggest us how to do the same in a cleaner way?
  • aussieburgerVRaussieburgerVR Posts: 95
    Hiro Protagonist
    I was able to join the matchmaking session by assigning the oculus id as UniqueNetId to the PlayerController (the title's warning message has disappeared when calling the Unreal's JoinSession function).
    How was this done exactly? Would love to see your blueprint for that :)

    Would be a great help if blueprints also supported voice out of the box! hint for @brian_jew for a commonly required feature ;)
  • brian_jewbrian_jew Posts: 61 Oculus Staff
    Hey ginopeloso,

    That's a creative solution, but you are correct there is an easier and cleaner way through UE4.  FUniqueNetIdOculus isn't expose (by UE4 design.  FUniqueNetId class are suppose to be opaque), but if you do have the Oculus Id in a FString you can instea do this:

    bool UMyClass::RegisterRemoteTalker(FString PlayerId) {
        auto uniqueNetId = Online::GetIdentityInterface()->CreateUniquePlayerId(PlayerId);
        return Online::GetVoiceInterface()->RegisterRemoteTalker(*uniqueNetId);
    }
    That would create the FUniqueNetIdOculus but return it as a FUniqueNetId then plug that into the VoiceInterface.

    @aussieburgerVR, I hear you.  We're looking more into blueprints as we realize that there's plenty of great devs like yourself who are using it in there game.
  • brian_jewbrian_jew Posts: 61 Oculus Staff
    xN31 said:
    @brian_jew : Is Oculus voice chat meant to use the UE4 default Opus codec or a specific one? I thought Oculus voice chat was based on the codec used in Facebook's voice calls, but using the command "online test voice" I see the initialisation of the Opus codec. Is this correct?

    I'm not sure about the technical implementation on the voice chat implementation itself.  The unreal implementation takes PCM data and creates a UE4 AudioComponent to play
  • ginopelosoginopeloso Posts: 22
    NerveGear
    edited May 11
    I was able to join the matchmaking session by assigning the oculus id as UniqueNetId to the PlayerController (the title's warning message has disappeared when calling the Unreal's JoinSession function).
    How was this done exactly? Would love to see your blueprint for that :)

    Would be a great help if blueprints also supported voice out of the box! hint for @brian_jew for a commonly required feature ;)
    You should write it in C++, assign the net id by code and expose as Blueprint function (a UClass or, better, a BlueprintFunctionLibrary):

    void UMyClass::SetPlayerNetId(APlayerController* PlayerController, FString NetId) {
        FUniqueNetId* UniqueNetId = new FUniqueNetIdString(NetId);
        PlayerController->PlayerState->SetUniqueId(MakeShareable(UniqueNetId));
    }
  • JPonczekJPonczek Posts: 4
    NerveGear
    I was able to join the matchmaking session by assigning the oculus id as UniqueNetId to the PlayerController (the title's warning message has disappeared when calling the Unreal's JoinSession function).
    How was this done exactly? Would love to see your blueprint for that :)

    Would be a great help if blueprints also supported voice out of the box! hint for @brian_jew for a commonly required feature ;)
    You should write it in C++, assign the net id by code and expose as Blueprint function (a UClass or, better, a BlueprintFunctionLibrary):

    void UMyClass::SetPlayerNetId(APlayerController* PlayerController, FString NetId) {
        FUniqueNetId* UniqueNetId = new FUniqueNetIdString(NetId);
        PlayerController->PlayerState->SetUniqueId(MakeShareable(UniqueNetId));
    }

    I can't seem to find FUniqueNetIdString for some reason. The other classes are available, such as UniqueNetIdWrapper and UniqueNetIdRepl, but those don't seem to solve the problem of creating a UniqueNetId from a simple FString. Without it, I am unable to make a UniqueNetId that I can plug into the MakeShareable.
  • xN31xN31 Posts: 10
    NerveGear
    brian_jew said:
    xN31 said:
    @brian_jew : Is Oculus voice chat meant to use the UE4 default Opus codec or a specific one? I thought Oculus voice chat was based on the codec used in Facebook's voice calls, but using the command "online test voice" I see the initialisation of the Opus codec. Is this correct?

    I'm not sure about the technical implementation on the voice chat implementation itself.  The unreal implementation takes PCM data and creates a UE4 AudioComponent to play
    Thanks Brian, sounds interesting. A couple of questions:
    • How can I retrieve the generated AudioComponents (e.g. to spatialise the sound)
    • The voice quality is very good, but breaks quite often. Is there some setting to improve this? (e.g. is there a bandwidth limit setting causing voice packets to drop?)

  • xN31xN31 Posts: 10
    NerveGear
    edited May 17
    xN31 said:
    brian_jew said:
    xN31 said:
    @brian_jew : Is Oculus voice chat meant to use the UE4 default Opus codec or a specific one? I thought Oculus voice chat was based on the codec used in Facebook's voice calls, but using the command "online test voice" I see the initialisation of the Opus codec. Is this correct?

    I'm not sure about the technical implementation on the voice chat implementation itself.  The unreal implementation takes PCM data and creates a UE4 AudioComponent to play
    Thanks Brian, sounds interesting. A couple of questions:
    • How can I retrieve the generated AudioComponents (e.g. to spatialise the sound)
    • The voice quality is very good, but breaks quite often. Is there some setting to improve this? (e.g. is there a bandwidth limit setting causing voice packets to drop?)

    Brian, how is voice spatialisation achieved in toybox? the demo is built with UE4, isn't it?
  • JPonczekJPonczek Posts: 4
    NerveGear
    I cannot successfully get multiplayer working with Oculus. I am using mostly blueprint, except for setting the player's unique net ID, which is done through the C++ mentioned above by ginopeloso. After successfully joining the session with the Join Session node, the connection to the host is immediately lost. Here is the output log:

    PacketHandlerLog: Loaded PacketHandler component: Engine.EngineHandlerComponentFactory (StatelessConnectHandlerComponent)
    LogNet: Game client on port 7777, rate 10000
    LogNet: UPendingNetGame::InitNetDriver: Sending hello. [UNetConnection] RemoteAddr: 0.0.0.0:7777, Name: IpConnection_0, Driver: PendingNetDriver IpNetDriver_0, IsServer: NO, PC: NULL, Owner: NULL
    LogNet: Host name resolution failed with 48
    LogNet:Warning: Network Failure: PendingNetDriver[PendingConnectionFailure]: Your connection to the host has been lost.
    LogNet: NetworkFailure: PendingConnectionFailure, Error: 'Your connection to the host has been lost.'
    LogBlueprintUserMessages: [FPGameInstance_C_3] Pending Connection Failure
    LogNet: DestroyNamedNetDriver IpNetDriver_0 [PendingNetDriver]
    LogExit: PendingNetDriver IpNetDriver_0 shut down

    I've been racking my brain trying to figure out why this happens, to no avail. I even created a brand new first person project and tried again, but it still happens. There's barely any information about this error online, except that others have also gotten the error. Please help!
  • ginopelosoginopeloso Posts: 22
    NerveGear
    edited June 1
    Did you try to disable Windows Defender?
  • pieterdubpieterdub Posts: 8 Oculus Staff
    You could test using the OculusNetDriver rather than IpNetDriver:

    If you don't have the OculusNetDriver setup you can test it by adding this to defaultEngine.ini and then un-checking the LAN mode on CreateSession:
    [/Script/Engine.GameEngine]
    +NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="/Script/OnlineSubsystemOculus.OculusNetDriver",DriverClassNameFallback="/Script/OnlineSubsystemUtils.IpNetDriver")

    [/Script/OnlineSubsystemOculus.OculusNetDriver]
    NetConnectionClassName="/Script/OnlineSubsystemOculus.OculusNetConnection"

    Then in the log you should see the net connection try to use the OculusNetDriver rather than the IpNetDriver. Would be interested to see if that works.  Also, the server log might have some other info that could help?  Make sure to enable verbose logging for online and net in DefaultEngine.ini as well:
    [Core.Log]
    LogOnline=verbose
    LogNet=verbose

    Also, I am not sure that the Create Session node will properly initialize the server as a listen server.  When I load the map that will handle the matchmaking, I call openLevel <mapname>?listen to properly initialize the server as a listen server so when another machine calls join session, it will be ready for the connection.  That might not be an issue here but thought I would suggest as a test.


Sign In or Register to comment.