add voice chat

This commit is contained in:
2025-05-08 20:19:51 -05:00
parent b8fba92ea7
commit 2182abc714
6 changed files with 401 additions and 0 deletions

View File

@@ -295,4 +295,51 @@
''; '';
}; };
ChatClientVoice = pkgs.stdenvNoCC.mkDerivation {
name = "ChatClientVoice";
src = ./.;
imgui = inputs.imgui;
nativeBuildInputs = with pkgs; [
clang
];
buildInputs = with pkgs; [
gamenetworkingsockets
sdl3
glew
];
buildPhase = ''
clang++ \
modules/examples/ChatClientVoice/src/*.cpp \
modules/ClientModule/src/*.cpp \
-I ${pkgs.gamenetworkingsockets}/include/GameNetworkingSockets \
-lGameNetworkingSockets \
-DCHATCLIENTVOICE_DYNAMIC \
modules/WindowModule/src/*.cpp \
modules/ImguiModule/src/*.cpp \
$imgui/backends/imgui_impl_glfw.cpp \
$imgui/backends/imgui_impl_opengl3.cpp \
$imgui/misc/cpp/*.cpp \
$imgui/*.cpp \
-DRENDERER=1 \
-DWINDOW=2 \
-fpic -shared \
-I src -I include -I $imgui -I . \
-lGL -lSDL3 -lGLEW \
-Wall \
-o $name
'';
installPhase = ''
mkdir -p $out/bin
cp $name $out/bin
'';
};
} }

View File

@@ -1,12 +1,20 @@
#ifndef AUDIO_H #ifndef AUDIO_H
#define AUDIO_H #define AUDIO_H
#include <SDL3/SDL.h>
#include <SDL3/SDL_audio.h> #include <SDL3/SDL_audio.h>
namespace Archimedes { namespace Archimedes {
class Audio { class Audio {
public:
Audio() {}
~Audio() {}
}; };
} }

View File

@@ -0,0 +1,219 @@
#include "modules/ImguiModule/src/ImguiModule.h"
#include "modules/ClientModule/src/ClientModule.h"
#include "ChatClientVoice.h"
ChatClientVoice::ChatClientVoice(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChatClientVoice";
ClientModule* cm = new ClientModule(a, h);
deps[*cm] = cm;
cm->shouldHandleEvents(ClientModule::CMEventEnum::ConnectionStatusChanged | ClientModule::CMEventEnum::DataSent);
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
ChatClientVoice::~ChatClientVoice() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
if(buf)
delete [] buf;
}
}
void ChatClientVoice::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for ChatClientVoice!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
if(!cm) {
std::cout << "No ClientModule for ChatClientVoice!\n";
std::abort();
}
if(!SDL_Init(SDL_INIT_AUDIO)) {
std::cout << "Audio init failed!\n";
std::abort();
}
mic = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, NULL, NULL, NULL);
SDL_GetAudioStreamFormat(mic, &spec, NULL);
speaker = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
buf = new unsigned char[len];
}
void ChatClientVoice::run() {
static ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
if(!cm) {
std::cout << "No ClientModule for ChatClientVoice!\n";
std::abort();
}
if(open) {
static std::string s, addr = "127.0.0.1:9932";
ImGui::Begin("ChatClientVoice Module", &open);
ImGui::InputText("Server Address: ", &addr);
if(cm->isRunning() && cm->isConnected()) {
if(ImGui::Button("Disconnect") && cm->isRunning()) {
cm->stopClient();
}
} else {
if(ImGui::Button("Connect") && !cm->isRunning()) {
static SteamNetworkingIPAddr serverAddr;
serverAddr.ParseString(addr.c_str());
cm->startClient(serverAddr);
}
}
ImGui::Text("%s", messages.c_str());
ImGui::InputText("Message: ", &s);
ImGui::SameLine();
if(ImGui::Button("send")) {
cm->sendReliable(s.c_str(), (uint32) s.length());
}
static float micVol = 1.0f;
static float speakerVol = 1.0f;
static bool micTest = false;
ImGui::SliderFloat("Mic Volume", &micVol, 0.0f, 1.0f);
ImGui::SliderFloat("Speaker Volume", &speakerVol, 0.0f, 1.0f);
ImGui::Checkbox("Mic test", &micTest);
if(!SDL_AudioStreamDevicePaused(mic)) {
SDL_SetAudioStreamGain(mic, micVol);
} else if(micTest) {
SDL_ResumeAudioStreamDevice(mic);
SDL_SetAudioStreamGain(mic, micVol);
} else if(!cm->isConnected()) {
SDL_PauseAudioStreamDevice(mic);
}
if(!SDL_AudioStreamDevicePaused(speaker)) {
SDL_SetAudioStreamGain(speaker, speakerVol);
} else if(micTest) {
SDL_ResumeAudioStreamDevice(speaker);
SDL_SetAudioStreamGain(speaker, speakerVol);
} else if(!cm->isConnected()) {
SDL_PauseAudioStreamDevice(speaker);
}
if(micTest) {
static int avail = 0;
avail = SDL_min(len, SDL_GetAudioStreamAvailable(mic));
avail = SDL_GetAudioStreamData(mic, buf, avail);
SDL_PutAudioStreamData(speaker, buf, avail);
} else {
// if not testing, send to server.
}
ImGui::End();
} else {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(*cm));
}
}
bool ChatClientVoice::onEvent(const Archimedes::Event& event) {
unsigned int type = app->getEventType(event);
/*if(type == app->getEventType("DataSentEvent")) {
//we did this?
return true;
} else */
if(type == app->getEventType(Archimedes::DataRecievedEvent())) {
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize);
std::cerr << "Client Recieved: " << s << std::endl;
messages += "\n\n" + s;
return true;
} else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
switch(e.info->m_info.m_eState) {
case k_ESteamNetworkingConnectionState_None:
// NOTE: We will get callbacks here when we destroy connections. You can ignore these.
break;
case k_ESteamNetworkingConnectionState_ClosedByPeer:
case k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
{
SDL_PauseAudioStreamDevice(mic);
SDL_PauseAudioStreamDevice(speaker);
break;
}
case k_ESteamNetworkingConnectionState_Connecting:
{
break;
}
case k_ESteamNetworkingConnectionState_Connected:
//OnConnect
SDL_ResumeAudioStreamDevice(mic);
SDL_ResumeAudioStreamDevice(speaker);
break;
default:
// Silences -Wswitch
break;
}
return false;
}
return false;
}

View File

@@ -0,0 +1,37 @@
#include "Archimedes.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_audio.h>
class ChatClientVoice : public Archimedes::Module {
public:
ChatClientVoice(Archimedes::App* a, void* h);
ChatClientVoice() { name = "ChatClientVoice"; }
~ChatClientVoice();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event&) override;
private:
std::string messages = "";
bool open = true;
SDL_AudioSpec spec;
SDL_AudioStream *mic, *speaker;
const int len = 1024;
unsigned char* buf;
};
#ifdef CHATCLIENTVOICE_DYNAMIC
#define MODULE_TYPE ChatClientVoice
#include "endModule.h"
#endif

View File

@@ -0,0 +1,56 @@
#include "ChatServerVoice.h"
void ChatServerVoice::onLoad() {
ServerModule* sm = (ServerModule*) moduleInstances[ServerModule()];
sm->startServer(9932);
}
//void ChatServerVoice::run() {}
bool ChatServerVoice::onEvent(const Archimedes::Event& event) {
unsigned int type = app->getEventType(event);
/*if(type == app->getEventType("DataSentEvent")) {
//we did this?
return true;
} else */
if(type == app->getEventType(Archimedes::DataRecievedEvent())) {
static ServerModule* sm; { sm = (ServerModule*) moduleInstances[ServerModule()]; }
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize);
if(s == "/quit") {
sm->disconnectClient(e.msg->m_conn);
} else if(s == "/shutdown") {
sm->stopServer();
app->end();
}
std::cerr << "Server Recieved: " << s << std::endl;
for(auto& it : sm->getClients()) {
if(it.first != e.msg->m_conn)
sm->sendReliable(it.first, s.c_str(), s.length());
else
sm->sendReliable(e.msg->m_conn, "\nMessage sent\n", strlen("\nMessage sent\n"));
}
return true;
} /*else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
//Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
return false;
}*/
return false;
}

View File

@@ -0,0 +1,34 @@
#include "Archimedes.h"
#include "modules/ServerModule/src/ServerModule.h"
class ChatServerVoice : public Archimedes::Module {
public:
ChatServerVoice(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChatServerVoice";
ServerModule* sm = new ServerModule(a, h);
deps[*sm] = sm;
sm->shouldHandleEvents(ServerModule::SMEventEnum::ConnectionStatusChanged | ServerModule::SMEventEnum::DataSent);
}
ChatServerVoice() { name = "ChatServerVoice"; }
~ChatServerVoice() {
if(app) {}
}
void onLoad();
//void run();
bool onEvent(const Archimedes::Event&);
};
#ifdef CHATSERVERVOICE_DYNAMIC
#define MODULE_TYPE ChatServerVoice
#include "endModule.h"
#endif