diff --git a/ExampleModules.nix b/ExampleModules.nix index eb52b08..28f7cb6 100644 --- a/ExampleModules.nix +++ b/ExampleModules.nix @@ -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 + ''; + + }; } diff --git a/include/utils/Audio/Audio.h b/include/utils/Audio/Audio.h index aef68ae..8747e91 100644 --- a/include/utils/Audio/Audio.h +++ b/include/utils/Audio/Audio.h @@ -1,12 +1,20 @@ #ifndef AUDIO_H #define AUDIO_H +#include #include namespace Archimedes { class Audio { + public: + + Audio() {} + + ~Audio() {} + + }; } diff --git a/modules/examples/ChatClientVoice/src/ChatClientVoice.cpp b/modules/examples/ChatClientVoice/src/ChatClientVoice.cpp new file mode 100644 index 0000000..df93fe1 --- /dev/null +++ b/modules/examples/ChatClientVoice/src/ChatClientVoice.cpp @@ -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; +} diff --git a/modules/examples/ChatClientVoice/src/ChatClientVoice.h b/modules/examples/ChatClientVoice/src/ChatClientVoice.h new file mode 100644 index 0000000..6cd6c59 --- /dev/null +++ b/modules/examples/ChatClientVoice/src/ChatClientVoice.h @@ -0,0 +1,37 @@ +#include "Archimedes.h" + + +#include +#include + +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 diff --git a/modules/examples/ChatServerVoice/src/ChatServerVoice.cpp b/modules/examples/ChatServerVoice/src/ChatServerVoice.cpp new file mode 100644 index 0000000..b107129 --- /dev/null +++ b/modules/examples/ChatServerVoice/src/ChatServerVoice.cpp @@ -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; +} diff --git a/modules/examples/ChatServerVoice/src/ChatServerVoice.h b/modules/examples/ChatServerVoice/src/ChatServerVoice.h new file mode 100644 index 0000000..820e533 --- /dev/null +++ b/modules/examples/ChatServerVoice/src/ChatServerVoice.h @@ -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