Voice support is in very early alpha testing and is NOT fully functional yet.
Status: Connection and signaling work, but audio transmission requires additional WebRTC implementation using libraries like SIPSorcery.
The VoiceClient provides experimental support for connecting to Fluxer voice channels using LiveKit protocol. While basic connection is implemented, full audio streaming capabilities are not yet available.
Voice functionality requires additional NuGet packages (not included by default):
dotnet add package NAudio
dotnet add package Concentus # For Opus encoding
To connect to voice, you need to listen for the VOICE_STATE_UPDATE and VOICE_SERVER_UPDATE gateway events:
using Fluxer.Net;
using Fluxer.Net.Voice;
using Fluxer.Net.Gateway.Data;
using Serilog;
string? sessionId = null;
string? voiceToken = null;
string? endpoint = null;
ulong targetGuildId = YOUR_GUILD_ID;
ulong targetChannelId = YOUR_VOICE_CHANNEL_ID;
// Listen for voice state updates
gatewayClient.VoiceStateUpdate += (data) =>
{
if (data.UserId == YOUR_BOT_USER_ID && data.GuildId == targetGuildId)
{
sessionId = data.SessionId;
Log.Information("Voice state updated, session: {SessionId}", sessionId);
}
};
// Listen for voice server updates
gatewayClient.VoiceServerUpdate += (data) =>
{
if (data.GuildId == targetGuildId)
{
voiceToken = data.Token;
endpoint = data.Endpoint;
Log.Information("Voice server update: {Endpoint}", endpoint);
// We now have all required info to connect
if (sessionId != null && voiceToken != null && endpoint != null)
{
Task.Run(async () => await ConnectToVoice(
endpoint, targetGuildId, YOUR_BOT_USER_ID, sessionId, voiceToken));
}
}
};
Use the ApiClient to update your voice state and join a voice channel:
// Join a voice channel
await apiClient.UpdateVoiceState(targetGuildId, new()
{
ChannelId = targetChannelId,
SelfMute = false,
SelfDeaf = false
});
async Task ConnectToVoice(string endpoint, ulong guildId, ulong userId,
string sessionId, string token)
{
try
{
var voiceClient = new VoiceClient(
endpoint: endpoint,
guildId: guildId,
userId: userId,
sessionId: sessionId,
token: token,
logger: Log.Logger
);
voiceClient.OnReady += () =>
{
Log.Information("Voice client connected and ready!");
// Note: You can't actually send audio yet
};
voiceClient.OnError += (ex) =>
{
Log.Error(ex, "Voice client error");
};
await voiceClient.ConnectAsync();
Log.Information("Voice client connected to LiveKit server");
// Keep the voice connection alive
await Task.Delay(-1);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to connect to voice");
}
}
The AudioPlayer class exists but cannot currently send audio due to missing WebRTC implementation:
// This code exists but DOES NOT WORK yet
var audioPlayer = new AudioPlayer(voiceClient, Log.Logger);
audioPlayer.OnPlaybackFinished += () =>
{
Log.Information("Playback finished");
};
// This will NOT actually play audio - WebRTC implementation needed
await audioPlayer.PlayAsync("path/to/audio.mp3");
// Disconnect from voice channel
await voiceClient.DisconnectAsync();
// Or leave via API
await apiClient.UpdateVoiceState(guildId, new()
{
ChannelId = null // null = leave voice
});
using Fluxer.Net;
using Fluxer.Net.Voice;
using Fluxer.Net.Gateway.Data;
using Serilog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.CreateLogger();
const string token = "YOUR_TOKEN_HERE";
const ulong guildId = YOUR_GUILD_ID;
const ulong channelId = YOUR_VOICE_CHANNEL_ID;
ulong botUserId = 0;
var config = new FluxerConfig { Serilog = Log.Logger };
var api = new ApiClient(token, config);
var gateway = new GatewayClient(token, config);
string? sessionId = null;
string? voiceToken = null;
string? endpoint = null;
VoiceClient? voiceClient = null;
gateway.Ready += (data) =>
{
botUserId = data.User.Id;
Log.Information("Bot ready! User ID: {UserId}", botUserId);
};
gateway.VoiceStateUpdate += (data) =>
{
if (data.UserId == botUserId && data.GuildId == guildId)
{
sessionId = data.SessionId;
Log.Information("Got session ID: {SessionId}", sessionId);
TryConnectVoice();
}
};
gateway.VoiceServerUpdate += (data) =>
{
if (data.GuildId == guildId)
{
voiceToken = data.Token;
endpoint = data.Endpoint;
Log.Information("Got voice server: {Endpoint}", endpoint);
TryConnectVoice();
}
};
void TryConnectVoice()
{
if (sessionId != null && voiceToken != null && endpoint != null && botUserId != 0)
{
Task.Run(async () =>
{
voiceClient = new VoiceClient(endpoint, guildId, botUserId,
sessionId, voiceToken, Log.Logger);
voiceClient.OnReady += () =>
{
Log.Information("Voice connection established!");
};
voiceClient.OnError += (ex) =>
{
Log.Error(ex, "Voice error");
};
await voiceClient.ConnectAsync();
});
}
}
await gateway.ConnectAsync();
Log.Information("Connected to gateway");
// Wait a bit for READY event
await Task.Delay(3000);
// Request to join voice channel
Log.Information("Requesting to join voice channel...");
await api.UpdateVoiceState(guildId, new()
{
ChannelId = channelId,
SelfMute = false,
SelfDeaf = false
});
await Task.Delay(-1);
Fluxer BETA uses LiveKit for voice connections. LiveKit is a WebRTC-based platform that requires:
To complete voice support, the following would need to be implemented:
// 1. WebRTC peer connection using SIPSorcery or similar
// 2. DTLS handshake for encryption
// 3. SRTP encryption for audio packets
// 4. RTP packet construction and transmission
// 5. Opus encoding/decoding (partial - encoder exists)
// 6. Audio receiving and decoding
Voice support is planned for future releases but requires significant WebRTC infrastructure work. Contributions are welcome! If you're interested in implementing full voice support, please check the GitHub repository.
Estimated complexity: High - Requires deep understanding of WebRTC, encryption protocols, and real-time audio streaming.
For more information about voice-related events:
Voice-related API methods:
ApiClient.UpdateVoiceState() - Join or leave voice channelsApiClient.GetVoiceRegions() - Get available voice regionsSee the API Client Reference for more details.