Getting Voice Chat Working - Device owned by another user

Hello all,

For several days I’m trying to get voice chat working. I have read all topics and documentation about voice chat but unable to get it working.

I’ve used both OnlineSubsystemSteam and OnlineSubsystemNull. These are firing “Device is currently owned by another user” error when I try to talk.

Thus, I’ve modified code to return true in following function and still I can’t hear voices. Voice packets in “net stat” is always “0”. I’ve tried in different comptuers through lan as well as in UE 4 editor.

FORCEINLINE bool IsOwningUser(uint32 UserIndex)
	{
		return UserIndex >= 0 && UserIndex < MAX_SPLITSCREEN_TALKERS && OwningUserIndex == UserIndex;		
	}

After these experiments I decided to take a look to ShooterGame example. It is giving “device is currently owned by another user” error too.

In some UE powered game’s Steam discussions people are telling it’s solved by closing Skype or applications that may use microphone. But in this case these aren’t worked for me.

You can find detailed error log (Manual trigger):

Cmd: ToggleSpeaking true
LogVoiceEncode:Error: StartLocalVoiceProcessing(): Device is currently owned by another user
LogVoice: StartLocalProcessing(0) returned 0x80004005
LogVoice: Starting networked voice for user: 0
Cmd: OnRelease ToggleSpeaking false
Cmd: ToggleSpeaking false
LogVoiceEncode:Error: StopLocalVoiceProcessing: Ignoring stop request for non-owning user
LogVoice: StopLocalVoiceProcessing(0) returned 0x80004005
LogVoice: Stopping networked voice for user: 0

What I’ve done to get it working so far:

Engine.ini

[Core.Log]
LogNet=verbose
LogOnline=verbose
LogVoice=verbose


[OnlineSubsystem] 
DefaultPlatformService=Null
bHasVoiceEnabled=true

[Voice] 
bEnabled=true

Game.ini (I’ve tried both true and false in ShooterGame example since it has an implemented trigger)

[/Script/Engine.GameSession]
bRequiresPushToTalk=false

EDIT: This is the debug output (isowninguser return set to true - shooter game example):


What I am asking for is:

1.What is the reason behind “Device is currently owned by another user” error ?

2.Is there some steps or implementation details I am missing ?

Bumping post.

Hey Lacridot, don’t know if this issue still concerns you, but I’ve just looked at this stuff as well so I figured I’d add some notes here. This started happening for me converting to 4.9 from 4.7 and there are a few changes in the codebase which are causing these error messages.

Short Answer:
In VoiceInterfaceImpl.cpp, find FOnlineVoiceImpl::RegisterLocalTalker. Comment out the if (0) { and closing } surrounding the call to VoiceEngine->StartLocalVoiceProcessing to get voice processing to start right away. Alternately, you can create your online session in a setup map and then change maps. APlayerController will try to start voice processing in PostLogin in the next map.

Details:
The error message is generated in FVoiceEngineImpl::StartLocalVoiceProcessing. The owner of the the voice engine is not set until FVoiceEngineImpl::RegisterLocalTalker is called, but unreal now calls StartLocalVoiceProcessing twice before ever calling RegisterLocalTalker. The first time is in the AGameMode::PostLogin codepath, and the second is in FOnlineVoiceImpl::RegisterLocalTalker which is reached through FOnlineSessionNull::CreateSession. FVoiceEngineImpl::StartLocalVoiceProcessing will generate the ownership error because the owner of the recording device is -1. The error is actually misleading. The device is owned by nobody, not another local user or program.

Two changes that happened somewhere between 4.7 and 4.9 made these error messages appear. First:

void FOnlineVoiceImpl::StartNetworkedVoice(uint8 LocalUserNum)
{
	// Validate the range of the entry
	if (LocalUserNum >= 0 && LocalUserNum < MaxLocalTalkers)
	{
		LocalTalkers[LocalUserNum].bHasNetworkedVoice = true;
		if (VoiceEngine.IsValid())
		{
			uint32 Return = VoiceEngine->StartLocalVoiceProcessing(LocalUserNum);
			UE_LOG(LogVoice, Log, TEXT("StartLocalProcessing(%d) returned 0x%08X"), LocalUserNum, Return);
		}
		UE_LOG(LogVoice, Log, TEXT("Starting networked voice for user: %d"), LocalUserNum);
	}
	else
	{
		UE_LOG(LogVoice, Log, TEXT("Invalid user specified in StartNetworkedVoice(%d)"),
			(uint32)LocalUserNum);
	}
}

This function did not previously call VoiceEngine->StartLocalVoiceProcessing(LocalUserNum) but now it does. At this point in the code when opening the first map, no local talkers have been added in the voice engine so we get our error message. (Sorry if its a bit hard to read, I don’t know how to markup my code to have line numbers here).

The other thing to note is this method:

bool FOnlineVoiceImpl::RegisterLocalTalker(uint32 LocalUserNum) 
{
	uint32 Return = E_FAIL;
	if (LocalUserNum >= 0 && LocalUserNum < (uint32)MaxLocalTalkers)
	{
		// Get at the local talker's cached data
		FLocalTalker& Talker = LocalTalkers[LocalUserNum];
		// Make local user capable of sending voice data
		StartNetworkedVoice(LocalUserNum);
		// Don't register talkers when voice is disabled
		if (VoiceEngine.IsValid())
		{
			if (Talker.bIsRegistered == false)
			{
				// Register the talker locally
				Return = VoiceEngine->RegisterLocalTalker(LocalUserNum);
				UE_LOG(LogVoice, Log, TEXT("RegisterLocalTalker(%d) returned 0x%08X"),	LocalUserNum, Return);
				if (Return == S_OK)
				{
					Talker.bIsRegistered = true;
					if (0)
					{	
						// If enabled, voice capture is continuous and "push to talk" merely sends packets
						// Kick off the processing mode
						Return = VoiceEngine->StartLocalVoiceProcessing(LocalUserNum);
						UE_LOG(LogVoice, Log, TEXT("StartLocalProcessing(%d) returned 0x%08X"), LocalUserNum, Return);
					}
				}
			}
			else
			{
				// Just say yes, we registered fine
				Return = S_OK;
			}
			
			// @todo ONLINE - update mute list?
		}
		else
		{
			// Not properly logged in, so skip voice for them
			Talker.bIsRegistered = false;
		}
	}
	else
	{
		UE_LOG(LogVoice, Log, TEXT("Invalid user specified in RegisterLocalTalker(%d)"), LocalUserNum);
	}
	return Return == S_OK;
}

Notice the suspicious-looking if (0). This, too, did not exist in 4.7. The code inside this block just always executed. The second error message is generated in this method when it tries to call StartNetworkedVoice right before actually calling VoiceEngine->RegisterLocalTalker, which is what sets the ownership of the voice device. The if (0) is causing voice to not be sent until a map change occurs. I have no idea why this was done, but if you remove that if check (or change maps after beginning the session) your voice should come back. The two errors generated before that seem to be pretty much harmless.

Hey jmassey, I need help with voice chat development. Do you have time/interest to work on that project on a contract basis? Pls contact me on skype:

I also used to uncomment this in the source code, but the way around this is to actually call starttalking() from playercontroller the first time you want the player to start talking.

Other way is setting PushToTalk to false in DefaultEngine.ini
[/Script/Engine.GameSession]
bRequiresPushToTalk=false

It’s currently not exposed to blueprint but you can make the function “blueprintcallable” when using ue4 from github.

i am having same problem in 4.15

was not it solved on engine side?

v 4.18.1, I got the same issue in the Shooter Game.

This is breaking some of our functional testing right now as this generates an “error” which causes the test to register a failure.

RegisterLocalTalker simply hasn’t been set up yet.
I’m probably going to modify this to not generate an error IF it’s an Invalid_index, but I’d appreciate knowing what the correct fix is.