stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
This commit is contained in:
1 parent
a3783b5f55
commit
38c9f229bc
1272 files changed
+968388
-1
No files matched your search
@@ -0,0 +1,243 @@
|
||||
#include "miniaudio.h"
|
||||
|
||||
#include "sound_manager.h"
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include "../../lib/debug_config.h"
|
||||
|
||||
SoundManager* SoundManager::instance() {
|
||||
static SoundManager s;
|
||||
return &s;
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager() {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: static destructor entered");
|
||||
shutdown();
|
||||
}
|
||||
|
||||
bool SoundManager::init() {
|
||||
if (m_initialized) return true;
|
||||
|
||||
ma_engine* engine = new ma_engine;
|
||||
ma_result result = ma_engine_init(NULL, engine);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("SoundManager: ma_engine_init failed (%d)", result);
|
||||
delete engine;
|
||||
return false;
|
||||
}
|
||||
m_engine = engine;
|
||||
m_context = ma_device_get_context(ma_engine_get_device(engine));
|
||||
m_initialized = true;
|
||||
qDebug("SoundManager: initialized (engine=%p, context=%p)", (void*)engine, (void*)m_context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundManager::shutdown() {
|
||||
if (!m_initialized) return;
|
||||
|
||||
stopCurrentPcm();
|
||||
|
||||
for (auto it = m_sounds.begin(); it != m_sounds.end(); ++it) {
|
||||
if (it->sound) { ma_sound_uninit(it->sound); delete it->sound; }
|
||||
if (it->decoder) { ma_decoder_uninit(it->decoder); delete it->decoder; }
|
||||
}
|
||||
m_sounds.clear();
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: before ma_engine_uninit engine=%p", (void*)m_engine);
|
||||
if (m_engine) { ma_engine_uninit(m_engine); delete m_engine; m_engine = nullptr; }
|
||||
if (m_currentPcmSound) { delete m_currentPcmSound; m_currentPcmSound = nullptr; }
|
||||
if (m_currentPcmBuffer) {
|
||||
ma_audio_buffer* buf = (ma_audio_buffer*)m_currentPcmBuffer;
|
||||
ma_audio_buffer_uninit(buf); delete buf; m_currentPcmBuffer = nullptr;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: after ma_engine_uninit");
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void SoundManager::setEnabled(bool enabled) { m_enabled = enabled; }
|
||||
|
||||
bool SoundManager::isEnabled() const { return m_enabled; }
|
||||
|
||||
void SoundManager::setVolume(float volume) {
|
||||
if (volume < 0.0f) volume = 0.0f;
|
||||
if (volume > 1.0f) volume = 1.0f;
|
||||
m_volume = volume;
|
||||
}
|
||||
|
||||
float SoundManager::volume() const { return m_volume; }
|
||||
|
||||
void SoundManager::setEvent(const QString& name, bool enabled, float volume) {
|
||||
if (volume < 0.0f) volume = 0.0f;
|
||||
if (volume > 1.0f) volume = 1.0f;
|
||||
EventSettings es;
|
||||
es.enabled = enabled;
|
||||
es.volume = volume;
|
||||
m_eventSettings[name] = es;
|
||||
qDebug("SoundManager: event '%s' enabled=%d vol=%.2f", qPrintable(name), enabled, volume);
|
||||
}
|
||||
|
||||
SoundManager::EventSettings SoundManager::eventSettings(const QString& name) const {
|
||||
return m_eventSettings.value(name);
|
||||
}
|
||||
|
||||
bool SoundManager::loadSound(const QString& name, const QString& filePath) {
|
||||
if (!m_initialized) {
|
||||
qWarning("SoundManager: not initialized, cannot load %s", qPrintable(name));
|
||||
return false;
|
||||
}
|
||||
if (m_sounds.contains(name)) {
|
||||
qWarning("SoundManager: sound '%s' already loaded", qPrintable(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile f(filePath);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
qWarning("SoundManager: cannot open %s", qPrintable(filePath));
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadedSound ls;
|
||||
ls.mp3Data = f.readAll();
|
||||
f.close();
|
||||
|
||||
ls.decoder = new ma_decoder;
|
||||
ma_decoder_config decConfig = ma_decoder_config_init_default();
|
||||
ma_result result = ma_decoder_init_memory(ls.mp3Data.constData(), ls.mp3Data.size(),
|
||||
&decConfig, ls.decoder);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("SoundManager: ma_decoder_init_memory failed for %s (%d)", qPrintable(name), result);
|
||||
delete ls.decoder;
|
||||
return false;
|
||||
}
|
||||
|
||||
ls.sound = new ma_sound;
|
||||
result = ma_sound_init_from_data_source(m_engine, (ma_data_source*)&ls.decoder->ds,
|
||||
0, NULL, ls.sound);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("SoundManager: sound init failed for %s (%d)", qPrintable(name), result);
|
||||
ma_decoder_uninit(ls.decoder); delete ls.decoder;
|
||||
delete ls.sound;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sounds.insert(name, ls);
|
||||
qDebug("SoundManager: loaded '%s' from %s (%lld bytes)",
|
||||
qPrintable(name), qPrintable(filePath), (long long)ls.mp3Data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundManager::play(const QString& name) {
|
||||
if (!m_enabled || !m_initialized) return;
|
||||
|
||||
EventSettings es = m_eventSettings.value(name);
|
||||
if (!es.enabled) return;
|
||||
|
||||
auto it = m_sounds.find(name);
|
||||
if (it == m_sounds.end()) return;
|
||||
|
||||
ma_sound* s = it->sound;
|
||||
float effectiveVolume = m_volume * es.volume;
|
||||
ma_sound_set_volume(s, effectiveVolume);
|
||||
ma_sound_stop(s);
|
||||
ma_sound_seek_to_pcm_frame(s, 0);
|
||||
ma_sound_start(s);
|
||||
}
|
||||
|
||||
ma_context* SoundManager::context() {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void SoundManager::playRawPcm(const int16_t* pcm, int sampleCount, int sampleRate, int channels) {
|
||||
if (!m_engine || !m_initialized) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "SoundManager::playRawPcm: not initialized");
|
||||
return;
|
||||
}
|
||||
if (m_currentPcmSound) ma_sound_stop(m_currentPcmSound);
|
||||
m_currentPcmSampleRate = sampleRate;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "SoundManager::playRawPcm: %d samples %dHz %dch", sampleCount, sampleRate, channels);
|
||||
|
||||
ma_audio_buffer_config bufCfg = ma_audio_buffer_config_init(
|
||||
ma_format_s16, (ma_uint32)channels, (ma_uint64)sampleCount, pcm, NULL);
|
||||
ma_audio_buffer* buf = new ma_audio_buffer;
|
||||
m_currentPcmBuffer = buf;
|
||||
ma_result r = ma_audio_buffer_init_copy(&bufCfg, buf);
|
||||
if (r != MA_SUCCESS) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "SoundManager: audio_buffer_init_copy failed (%d)", r);
|
||||
delete buf; m_currentPcmBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentPcmSound = new ma_sound;
|
||||
r = ma_sound_init_from_data_source(m_engine, (ma_data_source*)buf, 0, nullptr, m_currentPcmSound);
|
||||
if (r != MA_SUCCESS) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "SoundManager: PCM sound init failed (%d)", r);
|
||||
ma_audio_buffer_uninit(buf); delete buf; m_currentPcmBuffer = nullptr;
|
||||
delete m_currentPcmSound; m_currentPcmSound = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ma_sound_set_volume(m_currentPcmSound, m_volume);
|
||||
ma_sound_start(m_currentPcmSound);
|
||||
}
|
||||
|
||||
void SoundManager::pauseCurrentPcm() {
|
||||
if (m_currentPcmSound) ma_sound_stop(m_currentPcmSound);
|
||||
}
|
||||
|
||||
void SoundManager::resumeCurrentPcm() {
|
||||
if (m_currentPcmSound) ma_sound_start(m_currentPcmSound);
|
||||
}
|
||||
|
||||
void SoundManager::stopCurrentPcm() {
|
||||
if (m_currentPcmSound) ma_sound_stop(m_currentPcmSound);
|
||||
m_currentPcmSampleRate = 0;
|
||||
}
|
||||
|
||||
unsigned long long SoundManager::currentPcmCursor() const {
|
||||
if (!m_currentPcmSound) return 0;
|
||||
ma_uint64 cursor = 0;
|
||||
ma_sound_get_cursor_in_pcm_frames(m_currentPcmSound, &cursor);
|
||||
return (unsigned long long)cursor;
|
||||
}
|
||||
|
||||
bool SoundManager::isCurrentPcmPlaying() const {
|
||||
if (!m_currentPcmSound) return false;
|
||||
return ma_sound_is_playing(m_currentPcmSound) != MA_FALSE;
|
||||
}
|
||||
|
||||
void SoundManager::seekCurrentPcm(unsigned long long pcmFrame) {
|
||||
if (m_currentPcmSound) ma_sound_seek_to_pcm_frame(m_currentPcmSound, pcmFrame);
|
||||
}
|
||||
|
||||
static QString decodeDeviceName(const char* name) {
|
||||
QString s = QString::fromUtf8(name);
|
||||
if (s.contains(QChar(0xFFFD)))
|
||||
s = QString::fromLocal8Bit(name);
|
||||
return s;
|
||||
}
|
||||
|
||||
QVector<SoundManager::DeviceInfo> SoundManager::enumeratePlaybackDevices() {
|
||||
QVector<DeviceInfo> result;
|
||||
ma_context* ctx = instance()->m_context;
|
||||
if (!ctx) return result;
|
||||
|
||||
ma_device_info* pDevices = nullptr;
|
||||
ma_uint32 count = 0;
|
||||
if (ma_context_get_devices(ctx, &pDevices, &count, nullptr, nullptr) != MA_SUCCESS) return result;
|
||||
for (ma_uint32 i = 0; i < count; i++)
|
||||
result.append({decodeDeviceName(pDevices[i].name), pDevices[i].isDefault != MA_FALSE});
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<SoundManager::DeviceInfo> SoundManager::enumerateCaptureDevices() {
|
||||
QVector<DeviceInfo> result;
|
||||
ma_context* ctx = instance()->m_context;
|
||||
if (!ctx) return result;
|
||||
|
||||
ma_device_info* pDevices = nullptr;
|
||||
ma_uint32 count = 0;
|
||||
if (ma_context_get_devices(ctx, nullptr, nullptr, &pDevices, &count) != MA_SUCCESS) return result;
|
||||
for (ma_uint32 i = 0; i < count; i++)
|
||||
result.append({decodeDeviceName(pDevices[i].name), pDevices[i].isDefault != MA_FALSE});
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user