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.