1) 사용 플러그인 및 설정
Tarcopy.uprojectEOSVoiceChat,EOSVoiceChatPTT,OnlineSubsystemEOS플러그인 활성화
Config/DefaultEngine.iniEOSVoiceChat활성화- PTT 기본값은 토글용으로 사용하기 위해
bAlwaysTransmitByDefault=false로 설정
[EOSVoiceChat]
bEnabled=true
[/Script/EOSVoiceChatPTT.UEOSVoiceChatSubsystem]
bEnableVoiceLobby=true
VoiceLobbyIdPrefix=VOICE
VoiceLobbyBucketId=voice
VoiceLobbyMaxMembers=16
bAlwaysTransmitByDefault=false
2) 핵심 서브시스템 구조
보이스 채팅은 UGameInstanceSubsystem 기반인 UEOSVoiceChatSubsystem에서 처리.
- 파일:
Plugins/EOSVoiceChatPTT/Source/EOSVoiceChatPTT/Public/UEOSVoiceChatSubsystem.h - 주요 기능
- EOS Voice Chat 초기화/접속/로그인
- Lobby RTC 우선 접속 및 fallback 채널
- V 키 토글 동작
- 음성 표시(아이콘)용 브로드캐스트
UCLASS(Config=Engine)
class EOSVOICECHATPTT_API UEOSVoiceChatSubsystem : public UGameInstanceSubsystem
{
UFUNCTION(BlueprintCallable)
void ToggleMute(bool bMute);
UFUNCTION(BlueprintCallable)
void SetPTTEnabled(bool bEnabled);
UFUNCTION(BlueprintCallable)
void SetAlwaysTransmit(bool bEnabled);
UFUNCTION(BlueprintCallable)
void JoinChannel(const FString& ChannelName);
UFUNCTION(BlueprintCallable)
void LeaveChannel();
UFUNCTION(BlueprintCallable)
bool IsVoiceIndicatorActive() const;
UPROPERTY(BlueprintAssignable)
FOnVoiceTransmitStateChanged OnVoiceTransmitStateChanged;
};
3) 초기화 및 로그인 흐름
Initialize()에서 config 로드 후InitializeVoiceChat()실행HandleVoiceChatInitialized()→HandleVoiceChatConnected()→EnsureConnectLogin()- Dedicated Server에서는
EnsureConnectLogin()이 즉시 return 되어 EOS Connect 로그인 시도 자체를 하지 않음
void UEOSVoiceChatSubsystem::EnsureConnectLogin()
{
if (!VoiceChat || !VoiceChat->IsInitialized() || !VoiceChat->IsConnected()) return;
if (IsRunningDedicatedServer()) return;
...
}
EOS Connect 로그인은 DeviceId 방식으로 수행됨.
- 같은 PC에서 서버/클라를 동시에 켤 때 동일 PUID가 생성되어 RTC가 충돌할 수 있음 → 서버에서는 로그인 스킵
4) 채널/Lobby 접속 흐름
JoinChannel()은 다음 순서로 시도함.
1) Voice Lobby (Lobby RTC) 우선
2) 세션 Lobby RTC
3) Manual RTC (설정되어 있으면)
4) EOS VoiceChat 일반 채널 join
if (bEnableVoiceLobby && bPreferLobbyRtc)
{
if (ActiveLobbyId.IsEmpty()) { EnsureVoiceLobby(); ... }
if (TryUseLobbyRtc(ActiveLobbyId)) { ... }
}
...
ActiveRoomName = Sanitized;
ChannelMode = EEOSVoiceChannelMode::VoiceChat;
VoiceChatUser->JoinChannel(...);
Lobby ID 생성
- 서버 주소를 기반으로 CRC32 해시 →
VOICE_xxxxxxxx형태
const uint32 Hash = FCrc::StrCrc32(*ServerKey);
const FString Base = FString::Printf(TEXT("%s_%08X"), *VoiceLobbyIdPrefix, Hash);
5) 맵 전환 시 처리
- Redwood(자동 조인 맵) 이외 맵으로 이동하면
- Lobby RTC 채널 leave
- Lobby 상태 강제 리셋
- PTT/AlwaysTransmit 상태 리셋
if (ChannelMode == EEOSVoiceChannelMode::LobbyRtc || ChannelMode == EEOSVoiceChannelMode::LobbyRtcSdk)
{
LeaveChannel();
}
LeaveVoiceLobby();
if (bVoiceLobbyInFlight)
{
bVoiceLobbyInFlight = false;
VoiceLobbyIdOverride.Reset();
ActiveLobbyId.Reset();
}
bPTTEnabled = bEnablePTTByDefault;
bAlwaysTransmit = bAlwaysTransmitByDefault;
bIsPTTActive = false;
UpdateRTCSending(false);
UpdateVoiceIndicatorFromState();
6) PTT → 토글 동작 변경
토글 방식 입력은 Enhanced Input을 우선 사용하고, 실패 시 Legacy 바인딩을 사용함.
중복 호출 방지를 위해 Enhanced가 성공하면 Legacy는 바인딩하지 않음.
void UEOSVoiceChatSubsystem::OnPTTPressed()
{
if (bAlwaysTransmit) return;
if (!bPTTEnabled || bMuted) return;
bIsPTTActive = !bIsPTTActive;
UpdateRTCSending(bIsPTTActive);
UpdateVoiceIndicatorFromState();
}
void UEOSVoiceChatSubsystem::OnPTTReleased()
{
// 토글 모드에서는 처리 없음
}
7) 음성 전송 상태 표시 (UI)
음성 상태 변화는 서브시스템에서 브로드캐스트 됨.
OnVoiceTransmitStateChanged(bool bIsActive)
void UEOSVoiceChatSubsystem::UpdateVoiceIndicatorFromState()
{
const bool bActive = IsVoiceIndicatorActive();
if (bVoiceIndicatorActive == bActive) return;
bVoiceIndicatorActive = bActive;
OnVoiceTransmitStateChanged.Broadcast(bVoiceIndicatorActive);
}
UI는 UUISubsystem에서 ShowUI/HideUI로 제어.
EUIType::VoiceIndicator를DA_UIConfig에 등록해야 함
void UUISubsystem::HandleVoiceTransmitStateChanged(bool bIsActive)
{
if (bIsActive) ShowUI(EUIType::VoiceIndicator);
else HideUI(EUIType::VoiceIndicator);
}
8) Lobby 퇴장 안정화
LeaveVoiceLobby()는 EOS 핸들이 없거나 ActiveLobbyId가 비어 있어도 상태를 리셋하도록 수정되어, 다음 접속에서 막히는 문제를 방지.
if (!EOSLobbyHandle || !LocalProductUserId || ActiveLobbyId.IsEmpty())
{
ActiveLobbyId.Reset();
VoiceLobbyIdOverride.Reset();
bVoiceLobbyInFlight = false;
return;
}'Unreal' 카테고리의 다른 글
| 오브젝트 풀링 (Object Pooling) (0) | 2026.01.09 |
|---|---|
| Voxel Terrain (0) | 2026.01.06 |
| EOS 보이스 인터페이스 (0) | 2025.12.26 |
| Unreal Engine 패키징 (0) | 2025.12.24 |
| Installed Engine vs Source Build Engine (0) | 2025.12.23 |
