uint32 FVoiceEngineSteam::StartLocalVoiceProcessing(uint32 LocalUserNum) { uint32 Return = E_FAIL; if (IsOwningUser(LocalUserNum)) { if (!bIsCapturing) { // Update the current recording state, if VOIP data was still being read VoiceCaptureUpdate(); if (!IsRecording()) { StartRecording(); } bIsCapturing = true; } Return = S_OK; } else { UE_LOG(LogVoiceEncode, Error, TEXT("StartLocalVoiceProcessing(): Device is currently owned by another user")); } return Return; }
uint32 FVoiceEngineSteam::StopLocalVoiceProcessing(uint32 LocalUserNum) { uint32 Return = E_FAIL; if (IsOwningUser(LocalUserNum)) { if (bIsCapturing) { bIsCapturing = false; bPendingFinalCapture = true; // Make a call to begin stopping the current VOIP recording session StopRecording(); // Now check/update the status of the recording session VoiceCaptureUpdate(); } Return = S_OK; } else { UE_LOG(LogVoiceEncode, Error, TEXT("StopLocalVoiceProcessing: Ignoring stop request for non-owning user")); } return Return; }
uint32 FVoiceEngineSteam::GetVoiceDataReadyFlags() const { // First check and update the internal state of VOIP recording VoiceCaptureUpdate(); if (OwningUserIndex != INVALID_INDEX && IsRecording()) { // Check if there is new data available via the Steam API if (AvailableVoiceResult == k_EVoiceResultOK && CompressedBytesAvailable > 0) { return 1 << OwningUserIndex; } } return 0; }
uint32 FVoiceEngineSteam::ReadLocalVoiceData(uint32 LocalUserNum, uint8* Data, uint32* Size) { check(*Size > 0); // Before doing anything, check/update the current recording state VoiceCaptureUpdate(); // Return data even if not capturing, if the final half-second of data from Steam is still pending if (IsOwningUser(LocalUserNum) && IsRecording()) { CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE); uint32 CompressedBytes = 0; EVoiceResult VoiceResult = SteamUserPtr->GetAvailableVoice(&CompressedBytes, NULL, 0); if (VoiceResult != k_EVoiceResultOK && VoiceResult != k_EVoiceResultNoData) { UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetAvailableVoice failure: VoiceResult: %s"), *SteamVoiceResult(VoiceResult)); return E_FAIL; } // This shouldn't happen, but just in case. if (CompressedBytes == 0) { UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: No Data: VoiceResult: %s"), *SteamVoiceResult(VoiceResult)); *Size = 0; return S_OK; } // Update the amount of data available for consumption (CompressedBytes can be more than AvailableWritten below) CompressedVoiceBuffer.AddUninitialized(CompressedBytes); uint32 AvailableWritten = 0; VoiceResult = SteamUserPtr->GetVoice(true, CompressedVoiceBuffer.GetData(), CompressedVoiceBuffer.Num(), &AvailableWritten, false, NULL, 0, NULL, 0); static double LastGetVoiceCallTime = 0.0; double CurTime = FPlatformTime::Seconds(); double TimeSinceLastCall = LastGetVoiceCallTime > 0 ? (CurTime - LastGetVoiceCallTime) : 0.0; LastGetVoiceCallTime = CurTime; UE_LOG(LogVoiceEncode, Log, TEXT("ReadLocalVoiceData: GetVoice: Result: %s, Available: %i, LastCall: %0.3f"), *SteamVoiceResult(VoiceResult), AvailableWritten, TimeSinceLastCall); if (VoiceResult != k_EVoiceResultOK) { UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetVoice failure: VoiceResult: %s"), *SteamVoiceResult(VoiceResult)); *Size = 0; CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE); return E_FAIL; } if (AvailableWritten > 0) { *Size = FMath::Min<int32>(*Size, AvailableWritten); FMemory::Memcpy(Data, CompressedVoiceBuffer.GetData(), *Size); UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: Size: %d"), *Size); return S_OK; } else { *Size = 0; } } return E_FAIL; }
uint32 FVoiceEngineImpl::ReadLocalVoiceData(uint32 LocalUserNum, uint8* Data, uint32* Size) { check(*Size > 0); // Before doing anything, check/update the current recording state VoiceCaptureUpdate(); // Return data even if not capturing, possibly have data during stopping if (IsOwningUser(LocalUserNum) && IsRecording()) { DecompressedVoiceBuffer.Empty(MAX_UNCOMPRESSED_VOICE_BUFFER_SIZE); CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE); uint32 NewVoiceDataBytes = 0; EVoiceCaptureState::Type VoiceResult = VoiceCapture->GetCaptureState(NewVoiceDataBytes); if (VoiceResult != EVoiceCaptureState::Ok && VoiceResult != EVoiceCaptureState::NoData) { UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetAvailableVoice failure: VoiceResult: %s"), EVoiceCaptureState::ToString(VoiceResult)); return E_FAIL; } if (NewVoiceDataBytes == 0) { UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: No Data: VoiceResult: %s"), EVoiceCaptureState::ToString(VoiceResult)); *Size = 0; return S_OK; } // Make space for new and any previously remaining data uint32 TotalVoiceBytes = NewVoiceDataBytes + PlayerVoiceData[LocalUserNum].VoiceRemainderSize; if (TotalVoiceBytes > MAX_UNCOMPRESSED_VOICE_BUFFER_SIZE) { UE_LOG(LogVoiceEncode, Warning, TEXT("Exceeded uncompressed voice buffer size, clamping")) TotalVoiceBytes = MAX_UNCOMPRESSED_VOICE_BUFFER_SIZE; } DecompressedVoiceBuffer.AddUninitialized(TotalVoiceBytes); if (PlayerVoiceData[LocalUserNum].VoiceRemainderSize > 0) { FMemory::Memcpy(DecompressedVoiceBuffer.GetData(), PlayerVoiceData[LocalUserNum].VoiceRemainder.GetData(), PlayerVoiceData[LocalUserNum].VoiceRemainderSize); } // Get new uncompressed data VoiceResult = VoiceCapture->GetVoiceData(DecompressedVoiceBuffer.GetData() + PlayerVoiceData[LocalUserNum].VoiceRemainderSize, NewVoiceDataBytes, NewVoiceDataBytes); TotalVoiceBytes = NewVoiceDataBytes + PlayerVoiceData[LocalUserNum].VoiceRemainderSize; if (VoiceResult == EVoiceCaptureState::Ok && TotalVoiceBytes > 0) { CompressedBytesAvailable = MAX_COMPRESSED_VOICE_BUFFER_SIZE; CompressedVoiceBuffer.AddUninitialized(MAX_COMPRESSED_VOICE_BUFFER_SIZE); PlayerVoiceData[LocalUserNum].VoiceRemainderSize = VoiceEncoder->Encode(DecompressedVoiceBuffer.GetData(), TotalVoiceBytes, CompressedVoiceBuffer.GetData(), CompressedBytesAvailable); // Save off any unencoded remainder if (PlayerVoiceData[LocalUserNum].VoiceRemainderSize > 0) { if (PlayerVoiceData[LocalUserNum].VoiceRemainderSize > MAX_VOICE_REMAINDER_SIZE) { UE_LOG(LogVoiceEncode, Warning, TEXT("Exceeded voice remainder buffer size, clamping")) PlayerVoiceData[LocalUserNum].VoiceRemainderSize = MAX_VOICE_REMAINDER_SIZE; } PlayerVoiceData[LocalUserNum].VoiceRemainder.AddUninitialized(MAX_VOICE_REMAINDER_SIZE); FMemory::Memcpy(PlayerVoiceData[LocalUserNum].VoiceRemainder.GetData(), DecompressedVoiceBuffer.GetData() + (TotalVoiceBytes - PlayerVoiceData[LocalUserNum].VoiceRemainderSize), PlayerVoiceData[LocalUserNum].VoiceRemainderSize); } static double LastGetVoiceCallTime = 0.0; double CurTime = FPlatformTime::Seconds(); double TimeSinceLastCall = LastGetVoiceCallTime > 0 ? (CurTime - LastGetVoiceCallTime) : 0.0; LastGetVoiceCallTime = CurTime; UE_LOG(LogVoiceEncode, Log, TEXT("ReadLocalVoiceData: GetVoice: Result: %s, Available: %i, LastCall: %0.3f"), EVoiceCaptureState::ToString(VoiceResult), CompressedBytesAvailable, TimeSinceLastCall); if (CompressedBytesAvailable > 0) { *Size = FMath::Min<int32>(*Size, CompressedBytesAvailable); FMemory::Memcpy(Data, CompressedVoiceBuffer.GetData(), *Size); UE_LOG(LogVoiceEncode, VeryVerbose, TEXT("ReadLocalVoiceData: Size: %d"), *Size); return S_OK; } else { *Size = 0; CompressedVoiceBuffer.Empty(MAX_COMPRESSED_VOICE_BUFFER_SIZE); UE_LOG(LogVoiceEncode, Warning, TEXT("ReadLocalVoiceData: GetVoice failure: VoiceResult: %s"), EVoiceCaptureState::ToString(VoiceResult)); return E_FAIL; } } } return E_FAIL; }