Positional channel configuration
Configure positional channels for spatial audio in 3D environments.
Read time 2 minutesLast updated 2 days ago
If a game has joined a positional channel, it must frequently update the Vivox SDK with the position and orientation of the user in the 3D space that is associated with that channel. The client does this by calling the
ChannelSession::Set3DPositionChannelSessionChannelType::PositionalAudioStateTextState- The positive X-axis is to the avatar's right.
- The positive Y-axis runs from the avatar's feet upward through their head.
- The positive Z-axis runs from the avatar's chest out through their back.
You can set the position of the avatar's mouth independently of the avatar's ears. These are respectively referred to as the speaker position and the listener position, and they share coordinates in most scenarios. Because the positions are independent, this allows for effects like an "audio zoom," where a character who is using something like a shotgun microphone could be configured to hear voice as though they were closer to the target, but they are still only speaking to those immediately around them. In addition to position, the listener can also have its orientation set to accurately render audio panning. However, the speaker cannot have its orientation set; spoken voices are treated as omni-directional audio “point sources” and are unaffected by the speaker’s orientation.
After you set up and join a positional channel with any configured 3D properties, you then report your actor's position and orientation to the Vivox SDK.
The following code displays an example of how to set a user's position in a positional channel:
This code displays methods for limiting the number of 3D positional updates that are sent. For example, a time tracking technique is used in thevoid UMyClass::Tick(float DeltaTime){ AActor MyPlayerCharacter; /* . . . */ float PositionalUpdateRate = 0.2f; // Send position and orientation update every 0.2 seconds. static float NextUpdateTime = UGameplayStatics::GetRealTimeSeconds(GetWorld()) + PositionalUpdateRate; if (UGameplayStatics::GetRealTimeSeconds(GetWorld()) > NextUpdateTime) { NextUpdateTime += PositionalUpdateRate; Update3DPosition(MyPlayerCharacter); } /* . . . */}void UMyClass::Update3DPosition(AActor *Actor){ // Sample method GetPositionalChannel returns the valid positional channel the player is in ChannelId PositionalChannel = GetPositionalChannel(); // Update cached 3D position and orientation. m_cachedPosition.SetValue(Actor->GetActorLocation()); m_cachedForwardVector.SetValue(Actor->GetActorForwardVector()); m_cachedUpVector.SetValue(Actor->GetActorUpVector()); // Return If there's no change from cached values. if (!Get3DValuesAreDirty()) { return; } // Send new position and orientation to current positional channel MyLoginSession.GetChannelSession(PositionalChannel).Set3DPosition( m_cachedPosition.GetValue(), m_cachedPosition.GetValue(), m_cachedForwardVector.GetValue(), m_cachedUpVector.GetValue() ); Clear3DValuesAreDirty();}
Tick()Update3DPosition()CachedPropertyIChannelSession::Set3DPosition