osb/source/game/StarVoice.cpp

131 lines
3.4 KiB
C++
Raw Normal View History

2023-07-12 12:16:12 +00:00
#include "StarVoice.hpp"
2023-07-13 05:01:07 +00:00
#include "StarFormat.hpp"
#include "opus/include/opus.h"
#include "SDL.h"
2023-07-12 12:16:12 +00:00
namespace Star {
2023-07-13 05:01:07 +00:00
EnumMap<VoiceTriggerMode> const VoiceTriggerModeNames{
{VoiceTriggerMode::VoiceActivity, "VoiceActivity"},
{VoiceTriggerMode::PushToTalk, "PushToTalk"}
};
2023-07-12 12:16:12 +00:00
2023-07-13 05:01:07 +00:00
EnumMap<VoiceChannelMode> const VoiceChannelModeNames{
{VoiceChannelMode::Mono, "Mono"},
{VoiceChannelMode::Stereo, "Stereo"}
};
static SDL_AudioDeviceID sdlInputDevice = 0;
constexpr int VOICE_SAMPLE_RATE = 48000;
constexpr int VOICE_FRAME_SIZE = 960;
2023-07-12 12:16:12 +00:00
2023-07-13 05:01:07 +00:00
constexpr int VOICE_MAX_FRAME_SIZE = 6 * VOICE_FRAME_SIZE;
constexpr int VOICE_MAX_PACKET_SIZE = 3 * 1276;
constexpr uint16_t VOICE_VERSION = 1;
Voice::Speaker::Speaker(SpeakerId id)
: decoderMono (createDecoder(1), opus_decoder_destroy)
, decoderStereo(createDecoder(2), opus_decoder_destroy) {
speakerId = id;
2023-07-12 12:16:12 +00:00
}
Voice* Voice::s_singleton;
Voice* Voice::singletonPtr() {
return s_singleton;
}
Voice& Voice::singleton() {
if (!s_singleton)
throw VoiceException("Voice::singleton() called with no Voice instance available");
else
return *s_singleton;
}
2023-07-13 05:01:07 +00:00
Voice::Voice() : m_encoder(nullptr, opus_encoder_destroy) {
2023-07-12 12:16:12 +00:00
if (s_singleton)
throw VoiceException("Singleton Voice has been constructed twice");
2023-07-13 05:01:07 +00:00
m_clientSpeaker = make_shared<Speaker>(m_speakerId);
m_triggerMode = VoiceTriggerMode::PushToTalk;
m_channelMode = VoiceChannelMode::Mono;
resetEncoder();
2023-07-12 12:16:12 +00:00
s_singleton = this;
}
Voice::~Voice() {
s_singleton = nullptr;
}
2023-07-13 05:01:07 +00:00
void Voice::load(Json const& config) {
// do stuff
}
Json Voice::save() const {
return JsonObject{};
}
Voice::SpeakerPtr Voice::setLocalSpeaker(SpeakerId speakerId) {
if (m_speakers.contains(m_speakerId))
m_speakers.remove(m_speakerId);
m_clientSpeaker->speakerId = m_speakerId = speakerId;
return m_speakers.insert(m_speakerId, m_clientSpeaker).first->second;
}
Voice::SpeakerPtr Voice::speaker(SpeakerId speakerId) {
if (m_speakerId == speakerId)
return m_clientSpeaker;
else {
if (SpeakerPtr const* ptr = m_speakers.ptr(speakerId))
return *ptr;
else
return m_speakers.emplace(speakerId, make_shared<Speaker>(speakerId)).first->second;
}
}
void Voice::mix(int16_t* buffer, size_t frames, unsigned channels) {
}
void Voice::update(PositionalAttenuationFunction positionalAttenuationFunction) {
if (positionalAttenuationFunction) {
for (auto& entry : m_speakers) {
if (SpeakerPtr& speaker = entry.second) {
speaker->channelVolumes = {
positionalAttenuationFunction(0, speaker->position, 1.0f),
positionalAttenuationFunction(1, speaker->position, 1.0f)
};
}
}
}
}
OpusDecoder* Voice::createDecoder(int channels) {
int error;
OpusDecoder* decoder = opus_decoder_create(VOICE_SAMPLE_RATE, channels, &error);
if (error != OPUS_OK)
throw VoiceException::format("Could not create decoder: {}", opus_strerror(error));
else
return decoder;
}
OpusEncoder* Voice::createEncoder(int channels) {
int error;
OpusEncoder* encoder = opus_encoder_create(VOICE_SAMPLE_RATE, channels, OPUS_APPLICATION_AUDIO, &error);
if (error != OPUS_OK)
throw VoiceException::format("Could not create encoder: {}", opus_strerror(error));
else
return encoder;
}
void Voice::resetEncoder() {
int channels = encoderChannels();
m_encoder.reset(createEncoder(channels));
opus_encoder_ctl(m_encoder.get(), OPUS_SET_BITRATE(channels == 2 ? 50000 : 24000));
}
2023-07-12 12:16:12 +00:00
}