GodotSteamKit Tutorials - Voice
By Gramps
This tutorial will cover the basics of using the Steam Voice custom node from the GodotSteamKit.
Usage
Once you have the GodotSteamKit installed, there will be a new node: SteamVoice which just a basic Node node. Make sure this is added to any scene you want voice chat to work in or your game's setting section if you want to test voice chat functionality with loopback.
Recording Voice
Just like in our regular Voice tutorial, you will probably want to offer both open mic and press-to-talk options with a toggle to switch between the two and, especially for in-game voice chat, attach these to action hotkeys. Borrowing the example from other tutorial:
var is_open_mic: bool = false
func _input(event: InputEvent) -> void:
if event.is_action_pressed("voice_toggle"):
is_open_mic = not is_open_mic
record_voice(steam_id, is_open_mic)
if event.is_action_pressed("voice_talk"):
record_voice(steam_id)
if event.is_action_released("voice_talk"):
record_voice(steam_id, false)
For our example, we create two new input actions: voice_toggle and voice_talk, as well as a new variable to keep track of whether the mic is on or not. Both will trigger the same record_voice() function in the Voice node which takes two parameters: steam_id and is_recording, the latter defaults to true.
You must pass the Steam ID of the local user to this function, though you could also just alter the node's script to always use your local user's Steam ID instead.
Sending The Voice Data
The node's script does require some minor alterations to send the voice data to other players unless you are just testing the voice audio using use_loopback. We will cover both RPCs and Steam Networking.
RPC
If you want to use RPCs, you can modify line 63 (where the comment is) to an RPC the process_voice_data().
func _get_voice_data() -> void:
var voice_data: Dictionary = Steam.getVoice()
if voice_data['result'] == Steam.VoiceResult.VOICE_RESULT_OK and voice_data['written'] > 0:
process_voice_data.rpc(voice_data['buffer'])
You will also want to add an @rpc line above the func process_voice_data(), starting at line 69:
@rpc("any_peer", "call_remote", "unreliable")
func process_voice_data(voice_data: PackedByteArray) -> void:
Steam Networking
Based on our Networking Message tutorial, you can modify line 63 (where the comment is) to a packet like:
func _get_voice_data() -> void:
var voice_data: Dictionary = Steam.getVoice()
if voice_data['result'] == Steam.VoiceResult.VOICE_RESULT_OK and voice_data['written'] > 0:
Networking.send_message(0, {"voice": voice_data['result']})
Your packet logic may vary but the above version sends the voice data to everyone and specifies the packet as 'voice'. On the receiving end, our networking script triggers a signal which connects to the process_voice_data() function in the next section.
Audio Testing
However, if you are using the node to do voice testing in your game's audio settings, there really isn't anything else you need to do except toggled use_loopback in the Inspector or pass true to it in your code.
Playing The Voice Data
Each of the above methods should connect to the node's process_voice_data(voice_data: PackedByteArray) function which will process the data and pass it to the internal AudioStreamPlayer.
And that is it.
Properties
SAMPLE_RATE
Set as the default sample rate. Steam Voice only uses a range of 11025 to 48000; do not set this outside of that range if you change it.
use_loopback
Whether the local player can hear themselves or not. This should not be used in-game.
use_optimal_sample_rate
Whether to use Steam's suggested optimal sample rate or not. This will set it to whatever getVoiceOptimalSampleRate() returns. For me, using the optimal rate made the voice sound high-pitched though.
Functions
process_voice_data
Process the voice buffer and play it out through the voice_playback stream. This must be the voice data buffer returned from getVoice().
record_voice
Record the voice of the local user. You must pass the local user's Steam ID.