#ifndef STAR_VOICE_HPP #define STAR_VOICE_HPP #include "StarJson.hpp" #include "StarBiMap.hpp" #include "StarException.hpp" #include "StarGameTypes.hpp" #include "StarMaybe.hpp" #include "StarApplicationController.hpp" struct OpusDecoder; typedef std::unique_ptr OpusDecoderPtr; struct OpusEncoder; typedef std::unique_ptr OpusEncoderPtr; namespace Star { STAR_EXCEPTION(VoiceException, StarException); enum class VoiceInputMode : uint8_t { VoiceActivity, PushToTalk }; extern EnumMap const VoiceInputModeNames; enum class VoiceChannelMode: uint8_t { Mono = 1, Stereo = 2 }; extern EnumMap const VoiceChannelModeNames; STAR_CLASS(Voice); STAR_CLASS(ApplicationController); class Voice { public: // Individual speakers are represented by their connection ID. typedef ConnectionId SpeakerId; struct Speaker { SpeakerId speakerId = 0; EntityId entityId = 0; Vec2F position = Vec2F(); String name = "Unnamed"; OpusDecoderPtr decoderMono; OpusDecoderPtr decoderStereo; atomic active = false; atomic currentLoudness = 0.0f; atomic> channelVolumes = Array::filled(1.0f); Speaker(SpeakerId speakerId); }; typedef std::shared_ptr SpeakerPtr; // Get pointer to the singleton Voice instance, if it exists. Otherwise, // returns nullptr. static Voice* singletonPtr(); // Gets reference to Voice singleton, throws VoiceException if root // is not initialized. static Voice& singleton(); Voice(ApplicationControllerPtr appController); ~Voice(); Voice(Voice const&) = delete; Voice& operator=(Voice const&) = delete; void load(Json const& config); Json save() const; // Sets the local speaker ID and returns the local speaker. Must be called upon loading into a world. SpeakerPtr setLocalSpeaker(SpeakerId speakerId); SpeakerPtr speaker(SpeakerId speakerId); // Called to mix voice audio with the game. void mix(int16_t* buffer, size_t frames, unsigned channels); typedef function PositionalAttenuationFunction; void update(PositionalAttenuationFunction positionalAttenuationFunction = {}); inline int encoderChannels() const { return m_channelMode == VoiceChannelMode::Mono ? 1 : 2; } private: static Voice* s_singleton; static OpusDecoder* createDecoder(int channels); static OpusEncoder* createEncoder(int channels); void resetEncoder(); void openDevice(); void closeDevice(); SpeakerId m_speakerId = 0; SpeakerPtr m_clientSpeaker; HashMap m_speakers; HashSet m_activeSpeakers; OpusEncoderPtr m_encoder; bool m_deviceOpen = false; Maybe m_deviceName; VoiceInputMode m_inputMode; VoiceChannelMode m_channelMode; ApplicationControllerPtr m_applicationController; }; } #endif