Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/frontend/StarVoice.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-07-14 22:47:49 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-07-14 22:47:49 +1000
commit73c5a17746312415335098cb70e83e933b597565 (patch)
treeb6739f534347fe6fafa75402b3d24353bb6c0eac /source/frontend/StarVoice.cpp
parent52ba6fa7f78269fb69bb3addb297b6a8d0a779fd (diff)
Move Opus encoding off-thread because of SDL
SDL gives its audio threads a very small stack size and it was making Opus fuck up
Diffstat (limited to 'source/frontend/StarVoice.cpp')
-rw-r--r--source/frontend/StarVoice.cpp127
1 files changed, 83 insertions, 44 deletions
diff --git a/source/frontend/StarVoice.cpp b/source/frontend/StarVoice.cpp
index dc97070..29fcb9e 100644
--- a/source/frontend/StarVoice.cpp
+++ b/source/frontend/StarVoice.cpp
@@ -140,10 +140,22 @@ Voice::Voice(ApplicationControllerPtr appController) : m_encoder(nullptr, opus_e
m_channelMode = VoiceChannelMode::Mono;
m_applicationController = appController;
+ m_stopThread = false;
+ m_thread = Thread::invoke("Voice::thread", mem_fn(&Voice::thread), this);
+
s_singleton = this;
}
Voice::~Voice() {
+ m_stopThread = true;
+
+ {
+ MutexLocker locker(m_threadMutex);
+ m_threadCond.broadcast();
+ }
+
+ m_thread.finish();
+
save();
closeDevice();
@@ -232,14 +244,18 @@ void Voice::readAudioData(uint8_t* stream, int len) {
if (m_inputMode == VoiceInputMode::VoiceActivity) {
if (decibels > m_threshold)
m_lastThresholdTime = now;
- active = now - m_lastThresholdTime < 50;
+ active = now - m_lastThresholdTime < 50;
}
+ bool added = false;
+
+ MutexLocker captureLock(m_captureMutex);
if (active) {
m_capturedChunksFrames += sampleCount / m_deviceChannels;
auto data = (opus_int16*)malloc(len);
memcpy(data, stream, len);
m_capturedChunks.emplace(data, sampleCount); // takes ownership
+ added = true;
}
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 +264,8 @@ void Voice::readAudioData(uint8_t* stream, int len) {
m_capturedChunksFrames = 0;
}
- ByteArray encoded(VOICE_MAX_PACKET_SIZE, 0);
- size_t frameSamples = VOICE_FRAME_SIZE * (size_t)m_deviceChannels;
- while (m_capturedChunksFrames >= VOICE_FRAME_SIZE) {
- std::vector<opus_int16> samples;
- samples.reserve(frameSamples);
- size_t samplesLeft = frameSamples;
- while (samplesLeft && !m_capturedChunks.empty()) {
- auto& front = m_capturedChunks.front();
- if (front.exhausted())
- m_capturedChunks.pop();
- else
- samplesLeft -= front.takeSamples(samples, samplesLeft);
- }
- m_capturedChunksFrames -= VOICE_FRAME_SIZE;
-
- if (m_inputVolume != 1.0f) {
- for (size_t i = 0; i != samples.size(); ++i)
- samples[i] *= m_inputVolume;
- }
-
- if (int encodedSize = opus_encode(m_encoder.get(), samples.data(), VOICE_FRAME_SIZE, (unsigned char*)encoded.ptr(), encoded.size())) {
- if (encodedSize == 1)
- continue;
-
- encoded.resize(encodedSize);
-
- {
- MutexLocker lock(m_captureMutex);
- m_encodedChunks.emplace_back(move(encoded)); // reset takes ownership of data buffer
- m_encodedChunksLength += encodedSize;
-
- encoded = ByteArray(VOICE_MAX_PACKET_SIZE, 0);
- }
-
- Logger::info("Voice: encoded Opus chunk {} bytes big", encodedSize);
- }
- else if (encodedSize < 0)
- Logger::error("Voice: Opus encode error {}", opus_strerror(encodedSize));
-
- }
+ if (added)
+ m_threadCond.signal();
}
void Voice::mix(int16_t* buffer, size_t frameCount, unsigned channels) {
@@ -368,15 +346,17 @@ void Voice::setDeviceName(Maybe<String> deviceName) {
int Voice::send(DataStreamBuffer& out, size_t budget) {
out.setByteOrder(ByteOrder::LittleEndian);
out.write<uint16_t>(VOICE_VERSION);
- MutexLocker captureLock(m_captureMutex);
- if (m_capturedChunks.empty())
+ MutexLocker encodeLock(m_encodeMutex);
+
+ if (m_encodedChunks.empty())
return 0;
std::vector<ByteArray> encodedChunks = move(m_encodedChunks);
size_t encodedChunksLength = m_encodedChunksLength;
m_encodedChunksLength = 0;
- captureLock.unlock();
+
+ encodeLock.unlock();
for (auto& chunk : encodedChunks) {
out.write<uint32_t>(chunk.size());
@@ -518,4 +498,63 @@ bool Voice::playSpeaker(SpeakerPtr const& speaker, int channels) {
return true;
}
+void Voice::thread() {
+ while (true) {
+ MutexLocker locker(m_threadMutex);
+
+ m_threadCond.wait(m_threadMutex);
+ if (m_stopThread)
+ return;
+
+ {
+ MutexLocker locker(m_captureMutex);
+ ByteArray encoded(VOICE_MAX_PACKET_SIZE, 0);
+ size_t frameSamples = VOICE_FRAME_SIZE * (size_t)m_deviceChannels;
+ while (m_capturedChunksFrames >= VOICE_FRAME_SIZE) {
+ std::vector<opus_int16> samples;
+ samples.reserve(frameSamples);
+ size_t samplesLeft = frameSamples;
+ while (samplesLeft && !m_capturedChunks.empty()) {
+ auto& front = m_capturedChunks.front();
+ if (front.exhausted())
+ m_capturedChunks.pop();
+ else
+ samplesLeft -= front.takeSamples(samples, samplesLeft);
+ }
+ m_capturedChunksFrames -= VOICE_FRAME_SIZE;
+
+ if (m_inputVolume != 1.0f) {
+ for (size_t i = 0; i != samples.size(); ++i)
+ samples[i] *= m_inputVolume;
+ }
+
+ if (int encodedSize = opus_encode(m_encoder.get(), samples.data(), VOICE_FRAME_SIZE, (unsigned char*)encoded.ptr(), encoded.size())) {
+ if (encodedSize == 1)
+ continue;
+
+ encoded.resize(encodedSize);
+
+ {
+ MutexLocker lock(m_encodeMutex);
+ m_encodedChunks.emplace_back(move(encoded)); // reset takes ownership of data buffer
+ m_encodedChunksLength += encodedSize;
+
+ encoded = ByteArray(VOICE_MAX_PACKET_SIZE, 0);
+ }
+
+ Logger::info("Voice: encoded Opus chunk {} bytes big", encodedSize);
+ }
+ else if (encodedSize < 0)
+ Logger::error("Voice: Opus encode error {}", opus_strerror(encodedSize));
+ }
+ }
+
+ continue;
+
+ locker.unlock();
+ Thread::yield();
+ }
+ return;
+}
+
} \ No newline at end of file