- sound_manager: ma_engine_init/playRawPcm логируют через DEBUG_* (qWarning/qDebug терялись в GUI-приложении без консоли); детальный результат старта PCM (rc/is_playing/cursor)
- main: ранняя инициализация лога в GUI-потоке до SoundManager::init, чтобы диагностика инициализации попала в файл
- messagedelegate: лог клика по Play/timeline (filePath/dlState/существует ли файл)
- voiceplayback: лог заголовка opus (sr/ch/frameSamples)
Попутные правки:
- u_async: фикс двойного close wakeup_pipe (eventfd/Windows)
- chat_core: NULL-guard в get_db/is_initialized
- android: sqlite открывается в utun_instance_init, cleanup stale-потока без утечки fd
- android SettingsScreen: компактная раскладка имени интерфейса
- 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
- stopCurrentPcm(): only ma_sound_stop, no delete/uninit in runtime
- playRawPcm(): just stop old sound, create new objects (old ones leak until shutdown)
- shutdown(): cleanup accumulated ma_sound + ma_audio_buffer after engine uninit
- root cause: deleting audio objects from GUI thread while miniaudio worker reads them
- SoundManager: pauseCurrentPcm()/resumeCurrentPcm() — stop/start without destroy
- VoicePlayState: added paused/pausedPosSec fields
- editorEvent: 3-state logic — playing→pause, paused→resume, stopped→new
- Different file click: stops old with full cleanup, plays new from start
- Timer: skips paused items, full cleanup on auto-complete
- SoundManager: added stopCurrentPcm() for pause/stop of PCM playback
- messagedelegate: call stopCurrentPcm on pause, new play, and timer complete
- messagelist: skip old double-nested JSON messages (raw starts with '{')
- sound_manager.h: void* for ma_audio_buffer to avoid header dependency
Three diagnostic points covering the gap between ~MainWindow done and CRT exit:
- DbManager: destroyed — confirms local dtors started after ~MainWindow
- SoundManager: static destructor entered — confirms static destruction phase
- main: static destructors done (g_shutdown_sentinel dtor) — confirms ALL statics done
If process hangs, we know exactly which phase failed.
- Sound files loaded from filesystem (sound_dir in INI config, absolute or relative)
- Per-event enable/disable + volume stored in DB (ui_state table)
- SoundManager: setEvent(), effective volume = master * per-event
- SoundSettingsPage UI: 4 event rows (checkbox + slider)
- chat_core_save_ui_state() for async DB writes via uasync thread
- DbManager::getUiStateInt() for reading settings from GUI thread
- Default sounds copied to sounds/ dir next to DB, config entries written