Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
V
VRClassroom
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Danny Pires
VRClassroom
Commits
2a1309bc
Commit
2a1309bc
authored
Apr 11, 2021
by
Danny Pires
💬
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'third-sprint' into 'master'
Voice chat plugin added See merge request
!13
parents
e098a689
c6fcad33
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
659 additions
and
2 deletions
+659
-2
DefaultEngine.ini
src/Config/DefaultEngine.ini
+11
-2
DefaultGame.ini
src/Config/DefaultGame.ini
+6
-0
At_LocalAttenaution.uasset
src/Content/Campus/Blueprints/At_LocalAttenaution.uasset
+0
-0
SC_CSoundClass.uasset
src/Content/Campus/Blueprints/SC_CSoundClass.uasset
+0
-0
MotionControllerPawn.uasset
...t/VirtualRealityBP/Blueprints/MotionControllerPawn.uasset
+0
-0
EasyVoiceChat.uplugin
src/Plugins/EasyVoiceChat/EasyVoiceChat.uplugin
+33
-0
Icon128.png
src/Plugins/EasyVoiceChat/Resources/Icon128.png
+0
-0
EasyVoiceChat.Build.cs
...EasyVoiceChat/Source/EasyVoiceChat/EasyVoiceChat.Build.cs
+55
-0
EasyVoiceChat.cpp
...yVoiceChat/Source/EasyVoiceChat/Private/EasyVoiceChat.cpp
+20
-0
VoiceFunctionLibrary.cpp
...hat/Source/EasyVoiceChat/Private/VoiceFunctionLibrary.cpp
+52
-0
VoipAudioComponent.cpp
...eChat/Source/EasyVoiceChat/Private/VoipAudioComponent.cpp
+101
-0
VoipManagerComponent.cpp
...hat/Source/EasyVoiceChat/Private/VoipManagerComponent.cpp
+181
-0
EasyVoiceChat.h
...EasyVoiceChat/Source/EasyVoiceChat/Public/EasyVoiceChat.h
+15
-0
VoiceFunctionLibrary.h
...ceChat/Source/EasyVoiceChat/Public/VoiceFunctionLibrary.h
+18
-0
VoipAudioComponent.h
...oiceChat/Source/EasyVoiceChat/Public/VoipAudioComponent.h
+49
-0
VoipManagerComponent.h
...ceChat/Source/EasyVoiceChat/Public/VoipManagerComponent.h
+113
-0
VRClassroom.uproject
src/VRClassroom.uproject
+5
-0
No files found.
src/Config/DefaultEngine.ini
View file @
2a1309bc
...
...
@@ -7,8 +7,13 @@ GameName=VRClassroom
[Voice]
bEnabled
=
true
[OnlineSubsystem]
bHasVoiceEnabled
=
true
[/Script/OnlineSubsystemUtils.IpNetDriver]
MaxClientRate
=
50000
MaxInternetClientRate
=
50000
[/Script/Engine.Player]
ConfiguredInternetSpeed
=
500000
ConfiguredLanSpeed
=
500000
[HTTP]
HttpTimeout
=
300
...
...
@@ -370,3 +375,7 @@ net.MaxRepArraySize=65535
[/Script/OculusHMD.OculusHMDRuntimeSettings]
bRequiresSystemKeyboard
=
True
[/Script/Engine.AudioSettings]
MaximumConcurrentStreams
=
5
VoiPSoundClass
=
/Game/Campus/Blueprints/SC_CSoundClass.SC_CSoundClass
src/Config/DefaultGame.ini
View file @
2a1309bc
...
...
@@ -12,6 +12,12 @@ SupportContact=""
CopyrightNotice
=
Copyright 2020 Testy
ProjectDisplayedTitle
=
NSLOCTEXT("[/Script/EngineSettings]", "837C4DE649564002BDAE8187B61096E6", "{GameName}")
[/Script/Engine.GameNetworkManager]
TotalNetBandwidth
=
600000
MaxDynamicBandwidth
=
80000
MinDynamicBandwidth
=
4000
[/Script/Engine.GameSession]
bRequiresPushToTalk
=
false
...
...
src/Content/Campus/Blueprints/At_LocalAttenaution.uasset
0 → 100644
View file @
2a1309bc
File added
src/Content/Campus/Blueprints/SC_CSoundClass.uasset
0 → 100644
View file @
2a1309bc
File added
src/Content/VirtualRealityBP/Blueprints/MotionControllerPawn.uasset
View file @
2a1309bc
No preview for this file type
src/Plugins/EasyVoiceChat/EasyVoiceChat.uplugin
0 → 100644
View file @
2a1309bc
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.2",
"FriendlyName": "Easy Voice Chat",
"Description": "Easy to integrate VOIP using blueprints.",
"Category": "Voice",
"CreatedBy": "313 Studios",
"CreatedByURL": "https://313-studios.com",
"DocsURL": "https://313-studios.com/wp-content/uploads/2019/08/VoiceChatDocumentation.pdf",
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/b204a1777cb34ff88bcc32bd9296c412",
"SupportURL": "support@313-studios.com",
"EngineVersion": "4.25.4",
"CanContainContent": false,
"Installed": true,
"Modules": [
{
"Name": "EasyVoiceChat",
"Type": "Runtime",
"LoadingPhase": "Default",
"WhitelistPlatforms": [
"Win32",
"Win64"
]
}
],
"Plugins": [
{
"Name": "OnlineSubsystemUtils",
"Enabled": true
}
]
}
\ No newline at end of file
src/Plugins/EasyVoiceChat/Resources/Icon128.png
0 → 100644
View file @
2a1309bc
22 KB
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/EasyVoiceChat.Build.cs
0 → 100644
View file @
2a1309bc
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using
UnrealBuildTool
;
public
class
EasyVoiceChat
:
ModuleRules
{
public
EasyVoiceChat
(
ReadOnlyTargetRules
Target
)
:
base
(
Target
)
{
PCHUsage
=
ModuleRules
.
PCHUsageMode
.
UseExplicitOrSharedPCHs
;
PublicIncludePaths
.
AddRange
(
new
string
[]
{
// ... add public include paths required here ...
}
);
PrivateIncludePaths
.
AddRange
(
new
string
[]
{
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames
.
AddRange
(
new
string
[]
{
"Core"
,
"CoreUObject"
,
"Engine"
,
"Voice"
,
"OnlineSubsystemUtils"
,
"AudioMixer"
,
"SignalProcessing"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames
.
AddRange
(
new
string
[]
{
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames
.
AddRange
(
new
string
[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Private/EasyVoiceChat.cpp
0 → 100644
View file @
2a1309bc
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "EasyVoiceChat.h"
#define LOCTEXT_NAMESPACE "FEasyVoiceChatModule"
void
FEasyVoiceChatModule
::
StartupModule
()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}
void
FEasyVoiceChatModule
::
ShutdownModule
()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE
(
FEasyVoiceChatModule
,
EasyVoiceChat
)
\ No newline at end of file
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Private/VoiceFunctionLibrary.cpp
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#include "VoiceFunctionLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/GameStateBase.h"
#include "GameFramework/PlayerState.h"
#include "Kismet/KismetMathLibrary.h"
TArray
<
APawn
*>
UVoiceFunctionLibrary
::
GetAllPawnsFromState
(
UObject
*
WorldContextObject
,
APawn
*
CurrentPlayer
,
float
Distance
)
{
AGameStateBase
*
GameState
=
UGameplayStatics
::
GetGameState
(
WorldContextObject
);
const
bool
bUseDistance
=
Distance
>
0.
f
;
FVector
PlayerLocation
;
if
(
CurrentPlayer
)
{
PlayerLocation
=
CurrentPlayer
->
GetActorLocation
();
}
APawn
*
Pawn
;
TArray
<
APawn
*>
PawnArray
;
if
(
GameState
)
{
for
(
APlayerState
*
State
:
GameState
->
PlayerArray
)
{
Pawn
=
State
->
GetPawn
();
if
(
Pawn
)
{
if
(
bUseDistance
)
{
// if using distance filtering, only add pawns that are below the user defined distance
if
(
UKismetMathLibrary
::
Vector_Distance
(
Pawn
->
GetActorLocation
(),
PlayerLocation
)
<=
Distance
)
{
PawnArray
.
Add
(
Pawn
);
}
}
else
{
PawnArray
.
Add
(
Pawn
);
}
}
}
}
return
PawnArray
;
}
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Private/VoipAudioComponent.cpp
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#include "VoipAudioComponent.h"
#include "Net/VoiceConfig.h"
#include "Voice/Public/Voice.h"
UVoipAudioComponent
::
UVoipAudioComponent
()
{
PrimaryComponentTick
.
bCanEverTick
=
true
;
PrimaryComponentTick
.
bStartWithTickEnabled
=
true
;
}
void
UVoipAudioComponent
::
BeginPlay
()
{
Super
::
BeginPlay
();
VoiceDecoder
=
FVoiceModule
::
Get
().
CreateVoiceDecoder
();
OpenPacketStream
(
UVOIPStatics
::
GetVoiceSampleRate
(),
UVOIPStatics
::
GetNumBufferedPackets
(),
UVOIPStatics
::
GetBufferingDelay
());
ResetBuffer
(
UVOIPStatics
::
GetVoiceSampleRate
(),
UVOIPStatics
::
GetBufferingDelay
());
Initialize
(
UVOIPStatics
::
GetVoiceSampleRate
());
//Start();
bVoiceStarted
=
true
;
}
void
UVoipAudioComponent
::
TickComponent
(
float
DeltaTime
,
ELevelTick
TickType
,
FActorComponentTickFunction
*
ThisTickFunction
)
{
Super
::
TickComponent
(
DeltaTime
,
TickType
,
ThisTickFunction
);
if
(
IsIdling
()
&&
IsActive
())
{
// Stop when we're idle to free up for other streaming audio sources
// this tells the synth to stop on the render thread, must use bVoiceGenerating to make sure it has stopped
Stop
();
SetActive
(
false
);
UncompressedVoiceData
.
Empty
();
}
}
void
UVoipAudioComponent
::
PlayVoiceData
(
const
TArray
<
uint8
>&
CompressedVoiceData
)
{
if
(
!
bVoiceStarted
)
{
return
;
}
if
(
!
IsPlaying
()
||
!
IsActive
())
{
if
(
bVoiceGenerating
)
{
// if the synth is still generating voice, then don't try to restart voice
// this will give errors, and cause a packet buffer overflow
return
;
}
ResetBuffer
(
UVOIPStatics
::
GetVoiceSampleRate
(),
UVOIPStatics
::
GetBufferingDelay
());
Start
();
}
const
int32
NumCompressedBytes
=
CompressedVoiceData
.
Num
();
if
(
VoiceDecoder
.
IsValid
())
{
uint32
BytesWritten
=
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
();
UncompressedVoiceData
.
Empty
(
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
());
UncompressedVoiceData
.
AddUninitialized
(
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
());
// Decompress the data
VoiceDecoder
->
Decode
(
CompressedVoiceData
.
GetData
(),
NumCompressedBytes
,
UncompressedVoiceData
.
GetData
(),
BytesWritten
);
// If there is no data, return
if
(
BytesWritten
<=
0
)
{
return
;
}
// submit the array to the synth component for playback
SubmitPacket
((
float
*
)
UncompressedVoiceData
.
GetData
(),
BytesWritten
,
UVOIPStatics
::
GetVoiceSampleRate
(),
EVoipStreamDataFormat
::
Int16
);
}
}
void
UVoipAudioComponent
::
OnEndGenerate
()
{
Super
::
OnEndGenerate
();
bVoiceGenerating
=
false
;
}
void
UVoipAudioComponent
::
OnBeginGenerate
()
{
Super
::
OnBeginGenerate
();
bVoiceGenerating
=
true
;
}
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Private/VoipManagerComponent.cpp
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#include "VoipManagerComponent.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/PlayerState.h"
#include "Voice/Public/VoiceModule.h"
#include "Voice/Public/Interfaces/VoiceCodec.h"
#include "Engine/Player.h"
#define MAX_VOICE_REMAINDER_SIZE 1 * 1024
UVoipManagerComponent
::
UVoipManagerComponent
()
{
PrimaryComponentTick
.
bCanEverTick
=
true
;
PrimaryComponentTick
.
bStartWithTickEnabled
=
true
;
}
// Called every frame
void
UVoipManagerComponent
::
TickComponent
(
float
DeltaTime
,
ELevelTick
TickType
,
FActorComponentTickFunction
*
ThisTickFunction
)
{
Super
::
TickComponent
(
DeltaTime
,
TickType
,
ThisTickFunction
);
if
(
!
VoiceCapture
.
IsValid
()
||
!
VoiceEncoder
.
IsValid
())
{
return
;
}
// Empty the voice buffers
DecompressedVoiceBuffer
.
Empty
(
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
());
CompressedVoiceBuffer
.
Empty
(
UVOIPStatics
::
GetMaxCompressedVoiceDataSize
());
uint32
NewVoiceDataBytes
=
0
;
EVoiceCaptureState
::
Type
VoiceResult
=
VoiceCapture
->
GetCaptureState
(
NewVoiceDataBytes
);
if
(
!
bVoiceActive
&&
NewVoiceDataBytes
==
0
)
{
// No capture data present, stop processing
return
;
}
uint32
TotalVoiceBytes
=
NewVoiceDataBytes
+
VoiceRemainderSize
;
if
(
TotalVoiceBytes
>
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
())
{
TotalVoiceBytes
=
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
();
}
DecompressedVoiceBuffer
.
AddUninitialized
(
TotalVoiceBytes
);
// If there's still audio left from a previous ReadLocalData call that didn't get output, copy that first into the decompressed voice buffer
if
(
VoiceRemainderSize
>
0
)
{
FMemory
::
Memcpy
(
DecompressedVoiceBuffer
.
GetData
(),
VoiceRemainder
.
GetData
(),
VoiceRemainderSize
);
}
// Get new uncompressed data
uint8
*
RemainingDecompressedBufferPtr
=
DecompressedVoiceBuffer
.
GetData
()
+
VoiceRemainderSize
;
uint32
ByteWritten
=
0
;
VoiceResult
=
VoiceCapture
->
GetVoiceData
(
DecompressedVoiceBuffer
.
GetData
()
+
VoiceRemainderSize
,
NewVoiceDataBytes
,
ByteWritten
);
TotalVoiceBytes
=
ByteWritten
+
VoiceRemainderSize
;
if
((
VoiceResult
==
EVoiceCaptureState
::
Ok
||
VoiceResult
==
EVoiceCaptureState
::
NoData
)
&&
TotalVoiceBytes
>
0
)
{
// Prepare the encoded buffer (e.g. opus)
CompressedBytesAvailable
=
UVOIPStatics
::
GetMaxCompressedVoiceDataSize
();
CompressedVoiceBuffer
.
AddUninitialized
(
UVOIPStatics
::
GetMaxCompressedVoiceDataSize
());
check
(((
uint32
)
CompressedVoiceBuffer
.
Num
())
<=
UVOIPStatics
::
GetMaxCompressedVoiceDataSize
());
// Run the uncompressed audio through the opus decoder, note that it may not encode all data, which results in some remaining data
VoiceRemainderSize
=
VoiceEncoder
->
Encode
(
DecompressedVoiceBuffer
.
GetData
(),
TotalVoiceBytes
,
CompressedVoiceBuffer
.
GetData
(),
CompressedBytesAvailable
);
// Save off any unencoded remainder
if
(
VoiceRemainderSize
>
0
)
{
if
(
VoiceRemainderSize
>
MAX_VOICE_REMAINDER_SIZE
)
{
VoiceRemainderSize
=
MAX_VOICE_REMAINDER_SIZE
;
}
VoiceRemainder
.
AddUninitialized
(
MAX_VOICE_REMAINDER_SIZE
);
FMemory
::
Memcpy
(
VoiceRemainder
.
GetData
(),
DecompressedVoiceBuffer
.
GetData
()
+
(
TotalVoiceBytes
-
VoiceRemainderSize
),
VoiceRemainderSize
);
}
}
if
(
VoiceResult
!=
EVoiceCaptureState
::
Ok
||
TotalVoiceBytes
==
0
)
{
if
(
bVoiceActive
)
{
// get the current time in seconds
const
double
CurTime
=
FPlatformTime
::
Seconds
();
// Work out the time since this player last talked
double
TimeSince
=
CurTime
-
LastSeen
;
if
(
TimeSince
>=
StopTalkingThreshold
)
{
// Notify blueprints that we've stopped talking
OnPlayerStopTalking
();
PlayerStopTalking
.
Broadcast
();
bVoiceActive
=
false
;
}
}
}
// Pass the data to blueprints if there is voice data
if
(
CompressedBytesAvailable
>
0
)
{
// update the last seen time, used for the talking threshold
LastSeen
=
FPlatformTime
::
Seconds
();
if
(
!
bVoiceActive
)
{
OnPlayerStartTalking
();
PlayerTalking
.
Broadcast
();
bVoiceActive
=
true
;
}
// copy the encoded values into a new array, which only has encoded bytes in
// This prevents copying the entire array, which has lots of unused space and will just saturate the actor channel
OutCompressedVoiceBuffer
.
Empty
(
CompressedBytesAvailable
);
OutCompressedVoiceBuffer
.
AddUninitialized
(
CompressedBytesAvailable
);
FMemory
::
Memcpy
(
OutCompressedVoiceBuffer
.
GetData
(),
CompressedVoiceBuffer
.
GetData
(),
CompressedBytesAvailable
);
const
float
MicLevel
=
VoiceCapture
.
Get
()
->
GetCurrentAmplitude
();
VoiceGenerated
.
Broadcast
(
OutCompressedVoiceBuffer
,
MicLevel
);
OnVoiceGeneratedBP
(
OutCompressedVoiceBuffer
,
MicLevel
);
}
}
bool
UVoipManagerComponent
::
InitVoice
(
AController
*
Controller
)
{
if
(
Controller
)
{
FVoiceModule
&
VoiceModule
=
FVoiceModule
::
Get
();
APlayerController
*
PlayerController
=
Cast
<
APlayerController
>
(
Controller
);
if
(
!
PlayerController
)
{
return
false
;
}
if
(
Controller
->
GetNetOwningPlayer
())
{
Controller
->
GetNetOwningPlayer
()
->
ConsoleCommand
(
"voice.playback.ShouldResync 0"
);
if
(
bAutoSetConsoleVariables
)
{
Controller
->
GetNetOwningPlayer
()
->
ConsoleCommand
(
"voice.SilenceDetectionThreshold "
+
FString
::
SanitizeFloat
(
SilenceDetectionThreshold
));
Controller
->
GetNetOwningPlayer
()
->
ConsoleCommand
(
"voice.MicNoiseGateThreshold "
+
FString
::
SanitizeFloat
(
NoiseGateThreshold
));
Controller
->
GetNetOwningPlayer
()
->
ConsoleCommand
(
"voice.JitterBufferDelay "
+
FString
::
SanitizeFloat
(
VoiceBufferDelay
));
}
}
// Only create voice capture on local clients
if
(
VoiceModule
.
IsVoiceEnabled
()
&&
Controller
->
IsLocalController
())
{
VoiceCapture
=
FVoiceModule
::
Get
().
CreateVoiceCapture
(
FString
(),
UVOIPStatics
::
GetVoiceSampleRate
(),
UVOIPStatics
::
GetVoiceNumChannels
());
VoiceEncoder
=
FVoiceModule
::
Get
().
CreateVoiceEncoder
();
VoiceDecoder
=
FVoiceModule
::
Get
().
CreateVoiceDecoder
();
bool
bSuccess
=
VoiceCapture
.
IsValid
()
&&
VoiceEncoder
.
IsValid
();
if
(
bSuccess
)
{
VoiceCapture
->
Start
();
CompressedVoiceBuffer
.
Empty
(
UVOIPStatics
::
GetMaxCompressedVoiceDataSize
());
DecompressedVoiceBuffer
.
Empty
(
UVOIPStatics
::
GetMaxUncompressedVoiceDataSizePerChannel
());
return
true
;
}
}
}
return
false
;
}
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Public/EasyVoiceChat.h
0 → 100644
View file @
2a1309bc
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class
FEasyVoiceChatModule
:
public
IModuleInterface
{
public
:
/** IModuleInterface implementation */
virtual
void
StartupModule
()
override
;
virtual
void
ShutdownModule
()
override
;
};
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Public/VoiceFunctionLibrary.h
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "VoiceFunctionLibrary.generated.h"
UCLASS
()
class
EASYVOICECHAT_API
UVoiceFunctionLibrary
:
public
UBlueprintFunctionLibrary
{
GENERATED_BODY
()
/* Get player pawns from the game state. Optionally filter by a distance from the current player */
UFUNCTION
(
BlueprintPure
,
Category
=
"Voice"
,
meta
=
(
WorldContext
=
"WorldContextObject"
))
static
TArray
<
APawn
*>
GetAllPawnsFromState
(
UObject
*
WorldContextObject
,
APawn
*
CurrentPlayer
,
float
Distance
=
0
.
f
);
};
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Public/VoipAudioComponent.h
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "OnlineSubsystemUtils/Public/VoipListenerSynthComponent.h"
#include "VoipAudioComponent.generated.h"
/**
Decodes and plays compressed voice data passed over the network
*/
UCLASS
(
Blueprintable
,
ClassGroup
=
(
Custom
),
meta
=
(
BlueprintSpawnableComponent
))
class
EASYVOICECHAT_API
UVoipAudioComponent
:
public
UVoipListenerSynthComponent
{
GENERATED_BODY
()
public
:
UVoipAudioComponent
();
virtual
void
BeginPlay
()
override
;
// Called every frame
virtual
void
TickComponent
(
float
DeltaTime
,
ELevelTick
TickType
,
FActorComponentTickFunction
*
ThisTickFunction
)
override
;
/* Plays compressed voice data */
UFUNCTION
(
BlueprintCallable
,
Category
=
"Voip Audio"
)
void
PlayVoiceData
(
const
TArray
<
uint8
>
&
CompressedVoiceData
);
protected
:
virtual
void
OnEndGenerate
()
override
;
virtual
void
OnBeginGenerate
()
override
;
private
:
/* Voice buffer used by this audio component */
TArray
<
uint8
>
UncompressedVoiceData
;
/* Voice decoder interface */
TSharedPtr
<
class
IVoiceDecoder
>
VoiceDecoder
;
/* Component is active when the audio component is registered */
bool
bVoiceStarted
=
false
;
/* Used to check if the audio is being generated on the audio render thread */
bool
bVoiceGenerating
=
false
;
};
src/Plugins/EasyVoiceChat/Source/EasyVoiceChat/Public/VoipManagerComponent.h
0 → 100644
View file @
2a1309bc
// Copyright 2019 313 Studios. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "VoipManagerComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams
(
FVoiceGenerated
,
const
TArray
<
uint8
>&
,
VoiceData
,
const
float
,
MicLevel
);
DECLARE_DYNAMIC_MULTICAST_DELEGATE
(
FPlayerStartTalking
);
DECLARE_DYNAMIC_MULTICAST_DELEGATE
(
FPlayerStopTalking
);
class
AController
;
/*
Generates voice data and sends it to blueprints for processing
*/
UCLASS
(
Blueprintable
,
ClassGroup
=
(
Custom
),
meta
=
(
BlueprintSpawnableComponent
)
)
class
EASYVOICECHAT_API
UVoipManagerComponent
:
public
UActorComponent
{
GENERATED_BODY
()
public
:
UVoipManagerComponent
();
// Called every frame
virtual
void
TickComponent
(
float
DeltaTime
,
ELevelTick
TickType
,
FActorComponentTickFunction
*
ThisTickFunction
)
override
;
/* Call this to start the voice capture. Ensures voice only starts on a local player machine
@return true if capture started successfully
*/
UFUNCTION
(
BlueprintCallable
,
Category
=
"Voip Manager"
)
bool
InitVoice
(
AController
*
Controller
);
/* Called when voice data is generated, passes an array of compressed voice data to blueprints. Use on inherited components */
UFUNCTION
(
BlueprintImplementableEvent
,
Category
=
"Voip Manager"
)
void
OnVoiceGeneratedBP
(
const
TArray
<
uint8
>
&
VoiceBuffer
,
const
float
MicLevel
);
/* Called on the client when the player starts talking */
UFUNCTION
(
BlueprintImplementableEvent
,
BlueprintCosmetic
,
Category
=
"Voip Manager"
)
void
OnPlayerStartTalking
();
/* Called on the client when the player stops talking */
UFUNCTION
(
BlueprintImplementableEvent
,
BlueprintCosmetic
,
Category
=
"Voip Manager"
)
void
OnPlayerStopTalking
();
/* Delegate called when voice is generated */
UPROPERTY
(
BlueprintAssignable
,
Category
=
"VOIP"
)
FVoiceGenerated
VoiceGenerated
;
/* Called when the player starts talking */
UPROPERTY
(
BlueprintAssignable
,
Category
=
"VOIP"
)
FPlayerStartTalking
PlayerTalking
;
/* Called when the player stops talking */
UPROPERTY
(
BlueprintAssignable
,
Category
=
"VOIP"
)
FPlayerStopTalking
PlayerStopTalking
;
private
:
/* Capture interfaces */
TSharedPtr
<
class
IVoiceCapture
>
VoiceCapture
;
TSharedPtr
<
class
IVoiceEncoder
>
VoiceEncoder
;
TSharedPtr
<
class
IVoiceDecoder
>
VoiceDecoder
;
/* Voice buffers */
TArray
<
uint8
>
DecompressedVoiceBuffer
;
TArray
<
uint8
>
CompressedVoiceBuffer
;
/* Internally used buffer which is adjusted to the size of the encoded, and is passed to blueprints */
TArray
<
uint8
>
OutCompressedVoiceBuffer
;
/* Used internally for recieving voice data */
TArray
<
uint8
>
DecodedVoiceBuffer
;
/* Remainder of voice data carried over if the encode buffer has leftovers */
TArray
<
uint8
>
VoiceRemainder
;
/* The size of the remaining voice buffer */
uint32
VoiceRemainderSize
;
/* The size of the compressed voice buffer */
uint32
CompressedBytesAvailable
;
/* The time in seconds this voip was last transmitted */
float
LastSeen
=
0
.
0
f
;
/* The threshold in which Stop Talking event will be called after transmission to compensate for buffering */
UPROPERTY
(
EditDefaultsOnly
,
Category
=
"VOIP"
)
float
StopTalkingThreshold
=
1
.
0
f
;
/* Whether to automatically set the below console variables. Disable if you want to change these variables globally, instead of per component */
UPROPERTY
(
EditDefaultsOnly
,
Category
=
"VOIP"
)
bool
bAutoSetConsoleVariables
=
true
;
/* Transmits silence when below this threshold. When set to the same value as Noise Gate Threshold it has no effect */
UPROPERTY
(
EditDefaultsOnly
,
Category
=
"VOIP"
,
meta
=
(
ClampMin
=
0
,
ClampMax
=
1
))
float
SilenceDetectionThreshold
=
0
.
01
f
;
/* Stops transmitting audio when it falls below this value. Decrease if the voice cuts in and out */
UPROPERTY
(
EditDefaultsOnly
,
Category
=
"VOIP"
,
meta
=
(
ClampMin
=
0
,
ClampMax
=
1
))
float
NoiseGateThreshold
=
0
.
01
f
;
/* The amount of time that the voice playback components have to buffer the audio being played back
Decrease if you want to reduce latency
Increase if you experience underruns (audio stuttering or cutting out prematurely) */
UPROPERTY
(
EditDefaultsOnly
,
Category
=
"VOIP"
)
float
VoiceBufferDelay
=
0
.
5
f
;
/* Set to true whenever the player is talking */
bool
bVoiceActive
;
};
src/VRClassroom.uproject
View file @
2a1309bc
...
...
@@ -49,6 +49,11 @@
{
"Name": "OculusAvatar",
"Enabled": true
},
{
"Name": "EasyVoiceChat",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/b204a1777cb34ff88bcc32bd9296c412"
}
],
"TargetPlatforms": [
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment