diff --git a/source/base/StarMixer.cpp b/source/base/StarMixer.cpp index 7b8e338..c38d17e 100644 --- a/source/base/StarMixer.cpp +++ b/source/base/StarMixer.cpp @@ -349,7 +349,7 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount, ExtraMixFunction extraMi } if (extraMixFunction) - extraMixFunction(outBuffer, bufferSize, channels); + extraMixFunction(outBuffer, frameCount, channels); { MutexLocker locker(m_effectsMutex); diff --git a/source/extern/CMakeLists.txt b/source/extern/CMakeLists.txt index 5ea7420..f2e670c 100644 --- a/source/extern/CMakeLists.txt +++ b/source/extern/CMakeLists.txt @@ -3,6 +3,7 @@ SET (OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF) SET (OPUS_X86_MAY_HAVE_AVX OFF) SET (OPUS_X86_MAY_HAVE_SSE4_1 OFF) SET (OPUS_STACK_PROTECTOR OFF) +SET (OPUS_ENABLE_FLOAT_API ON) ADD_SUBDIRECTORY (opus) INCLUDE_DIRECTORIES ( diff --git a/source/frontend/StarVoice.cpp b/source/frontend/StarVoice.cpp index fcfaa35..9acbc47 100644 --- a/source/frontend/StarVoice.cpp +++ b/source/frontend/StarVoice.cpp @@ -145,6 +145,7 @@ Voice::Voice(ApplicationControllerPtr appController) : m_encoder(nullptr, opus_e Voice::~Voice() { save(); + closeDevice(); s_singleton = nullptr; } @@ -162,8 +163,8 @@ void Voice::loadJson(Json const& config) { m_threshold = config.getFloat("threshold", m_threshold); m_inputVolume = config.getFloat("inputVolume", m_inputVolume); m_outputVolume = config.getFloat("outputVolume", m_outputVolume); - m_inputMode = VoiceInputModeNames.getLeft(config.getString("inputMode", "pushToTalk")); - m_channelMode = VoiceChannelModeNames.getLeft(config.getString("channelMode", "mono")); + m_inputMode = VoiceInputModeNames.getLeft(config.getString("inputMode", "PushToTalk")); + m_channelMode = VoiceChannelModeNames.getLeft(config.getString("channelMode", "Mono")); } @@ -239,7 +240,7 @@ void Voice::readAudioData(uint8_t* stream, int len) { m_capturedChunksFrames += samples / m_deviceChannels; auto data = (opus_int16*)malloc(len); memcpy(data, stream, len); - m_capturedChunks.emplace(data, samples); + m_capturedChunks.emplace(data, samples); // takes ownership } else { // Clear out any residual data so they don't manifest at the start of the next encode, whenever that is while (!m_capturedChunks.empty()) @@ -248,46 +249,47 @@ void Voice::readAudioData(uint8_t* stream, int len) { m_capturedChunksFrames = 0; } - std::vector takenSamples; while (m_capturedChunksFrames >= VOICE_FRAME_SIZE) { - takenSamples.clear(); size_t samplesToTake = VOICE_FRAME_SIZE * (size_t)m_deviceChannels; + std::vector takenSamples; takenSamples.reserve(samplesToTake); while (!m_capturedChunks.empty()) { auto& front = m_capturedChunks.front(); if (front.exhausted()) m_capturedChunks.pop(); - else if ((samplesToTake -= front.takeSamples(takenSamples, samplesToTake)) == 0) - break; + else { + samplesToTake -= front.takeSamples(takenSamples, samplesToTake); + if (samplesToTake == 0) + break; + } } m_capturedChunksFrames -= VOICE_FRAME_SIZE; - ByteArray encodedData(VOICE_MAX_PACKET_SIZE, 0); float vol = m_inputVolume; if (m_inputVolume != 1.0f) { for (size_t i = 0; i != takenSamples.size(); ++i) takenSamples[i] *= m_inputVolume; } - - - if (opus_int32 size = opus_encode(m_encoder.get(), takenSamples.data(), VOICE_FRAME_SIZE, (unsigned char*)encodedData.ptr(), VOICE_MAX_PACKET_SIZE)) { - if (size == 1) - continue; - - encodedData.resize(size); + ByteArray encodedData(VOICE_MAX_FRAME_SIZE, 0); + opus_int32 encodedSize = opus_encode(m_encoder.get(), takenSamples.data(), VOICE_FRAME_SIZE, (unsigned char*)encodedData.ptr(), encodedData.size()); + if (encodedSize == 1) + continue; + else if (encodedSize < 0) + Logger::error("Voice: Opus encode error {}", opus_strerror(encodedSize)); + else { + encodedData.resize(encodedSize); MutexLocker lock(m_captureMutex); m_encodedChunks.emplace_back(move(encodedData)); // reset takes ownership of data buffer - m_encodedChunksLength += size; - Logger::info("Voice: encoded Opus chunk {} bytes big", size); - } - else if (size < 0) { - Logger::error("Voice: Opus encode error {}", opus_strerror(size)); + m_encodedChunksLength += encodedSize; + Logger::info("Voice: encoded Opus chunk {} bytes big", encodedSize); } + } } -void Voice::mix(int16_t* buffer, size_t samples, unsigned channels) { +void Voice::mix(int16_t* buffer, size_t frameCount, unsigned channels) { + size_t samples = frameCount * channels; static std::vector finalMixBuffer{}; static std::vector voiceMixBuffer{}; finalMixBuffer.resize(samples); @@ -326,7 +328,7 @@ void Voice::mix(int16_t* buffer, size_t samples, unsigned channels) { float vol = m_outputVolume; for (size_t i = 0; i != samples; ++i) - finBuf[i] = (int16_t)std::clamp(mixBuf[i] * vol, INT16_MIN, INT16_MAX); + finBuf[i] = (int16_t)clamp(mixBuf[i] * vol, INT16_MIN, INT16_MAX); SDL_MixAudioFormat((Uint8*)buffer, (Uint8*)finBuf, AUDIO_S16, samples * sizeof(int16_t), SDL_MIX_MAXVOLUME); } @@ -344,7 +346,7 @@ void Voice::update(PositionalAttenuationFunction positionalAttenuationFunction) } } - if (Time::monotonicMilliseconds() > m_nextSaveTime) { + if (m_nextSaveTime && Time::monotonicMilliseconds() > m_nextSaveTime) { m_nextSaveTime = 0; save(); } @@ -365,7 +367,7 @@ int Voice::send(DataStreamBuffer& out, size_t budget) { out.write(VOICE_VERSION); MutexLocker captureLock(m_captureMutex); - if (!m_encoder || m_capturedChunks.empty()) + if (m_capturedChunks.empty()) return 0; std::vector encodedChunks = move(m_encodedChunks); @@ -420,6 +422,8 @@ bool Voice::receive(SpeakerPtr speaker, std::string_view view) { throw VoiceException(strf("Decoder error: {}", opus_strerror(samples)), false); } + Logger::info("Voice: decoded Opus chunk {} bytes big", opusLength); + static auto getCVT = [](int channels) -> SDL_AudioCVT { SDL_AudioCVT cvt; SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, channels, VOICE_SAMPLE_RATE, AUDIO_S16, 2, 44100); @@ -478,8 +482,6 @@ void Voice::resetEncoder() { void Voice::openDevice() { closeDevice(); - - m_applicationController->openAudioInputDevice( m_deviceName ? m_deviceName->utf8Ptr() : nullptr, VOICE_SAMPLE_RATE, diff --git a/source/frontend/StarVoice.hpp b/source/frontend/StarVoice.hpp index e7ecd80..8b003e2 100644 --- a/source/frontend/StarVoice.hpp +++ b/source/frontend/StarVoice.hpp @@ -42,7 +42,7 @@ struct VoiceAudioChunk { } inline size_t takeSamples(std::vector& out, size_t count) { - size_t toRead = std::min(count, remaining); + size_t toRead = min(count, remaining); int16_t* start = data.get() + offset; out.insert(out.end(), start, start + toRead); offset += toRead; @@ -133,9 +133,7 @@ public: // Must be called every frame with input state, expires after 1s. void setInput(bool input = true); - inline int encoderChannels() const { - return m_channelMode == VoiceChannelMode::Mono ? 1 : 2; - } + inline int encoderChannels() const { return (int)m_channelMode; } private: static Voice* s_singleton;