diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-07-13 19:12:55 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-07-13 19:12:55 +1000 |
commit | 28f4204b09b04280340ffbbeaccf86b96f377296 (patch) | |
tree | e2a166cc3ddd57460814631b7a8258ed0ee975ea /source/frontend/StarVoice.hpp | |
parent | c3bf7a3c87e61c56d48dd932f295c99d64d14a38 (diff) |
more Voice work
Diffstat (limited to 'source/frontend/StarVoice.hpp')
-rw-r--r-- | source/frontend/StarVoice.hpp | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/source/frontend/StarVoice.hpp b/source/frontend/StarVoice.hpp new file mode 100644 index 0000000..0d485db --- /dev/null +++ b/source/frontend/StarVoice.hpp @@ -0,0 +1,109 @@ +#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<OpusDecoder, void(*)(OpusDecoder*)> OpusDecoderPtr; +struct OpusEncoder; +typedef std::unique_ptr<OpusEncoder, void(*)(OpusEncoder*)> OpusEncoderPtr; + +namespace Star { + +STAR_EXCEPTION(VoiceException, StarException); + +enum class VoiceInputMode : uint8_t { VoiceActivity, PushToTalk }; +extern EnumMap<VoiceInputMode> const VoiceInputModeNames; + +enum class VoiceChannelMode: uint8_t { Mono = 1, Stereo = 2 }; +extern EnumMap<VoiceChannelMode> 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<bool> active = false; + atomic<float> currentLoudness = 0.0f; + atomic<Array<float, 2>> channelVolumes = Array<float, 2>::filled(1.0f); + + Speaker(SpeakerId speakerId); + }; + + typedef std::shared_ptr<Speaker> 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<float(unsigned, Vec2F, float)> 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<SpeakerId, SpeakerPtr> m_speakers; + + HashSet<SpeakerPtr> m_activeSpeakers; + + OpusEncoderPtr m_encoder; + + bool m_deviceOpen = false; + Maybe<String> m_deviceName; + VoiceInputMode m_inputMode; + VoiceChannelMode m_channelMode; + + ApplicationControllerPtr m_applicationController; +}; + +} + +#endif
\ No newline at end of file |