From 01012675d0719835f5a232ecded99977fadb2cfa Mon Sep 17 00:00:00 2001 From: Evgeny Date: Mon, 27 Jul 2026 00:22:00 +0300 Subject: [PATCH] fix: voice playback coordinate bug + debug logging + device name encoding - messagedelegate: editorEvent now adjusts me->pos() by option.rect.topLeft() - voiceplayback: enhanced debug logging for file open/decode/play - messagelist: debug voice file path + exists check - inputbar: debug mediaDir path on record - sound_manager: debug in playRawPcm, decodeDeviceName() for mixed encodings - voiceencoder: debug file write path --- tools/chatgui/src/inputbar.cpp | 3 +++ tools/chatgui/src/messagedelegate.cpp | 7 ++++++- tools/chatgui/src/messagelist.cpp | 5 +++++ tools/chatgui/src/sound_manager.cpp | 19 +++++++++++++++---- tools/chatgui/src/voicemessageencoder.cpp | 3 ++- tools/chatgui/src/voiceplayback.cpp | 15 +++++++++++++-- 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/tools/chatgui/src/inputbar.cpp b/tools/chatgui/src/inputbar.cpp index 77c78b41..e2f26ada 100644 --- a/tools/chatgui/src/inputbar.cpp +++ b/tools/chatgui/src/inputbar.cpp @@ -15,6 +15,7 @@ #include #include #include +#include static QPushButton *makeIconBtn(const QString &text, const QString &tooltip, QWidget *parent) { auto *btn = new QPushButton(text, parent); @@ -214,6 +215,8 @@ void InputBar::onPttReleased() { QString mediaPath = m_mediaDirBase + "/" + m_channelIdForRecord; VoiceEncoder::ensureMediaDir(mediaPath); + qDebug("InputBar::onPttReleased: mediaDir=%s exists=%d channel=%s", + qPrintable(mediaPath), QDir(mediaPath).exists(), qPrintable(m_channelIdForRecord)); QString fileName = VoiceEncoder::generateFileName(); QString filePath = mediaPath + "/" + fileName; diff --git a/tools/chatgui/src/messagedelegate.cpp b/tools/chatgui/src/messagedelegate.cpp index 064929d3..fe870610 100644 --- a/tools/chatgui/src/messagedelegate.cpp +++ b/tools/chatgui/src/messagedelegate.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include MessageDelegate::MessageDelegate(QObject *parent) : QStyledItemDelegate(parent) {} @@ -61,9 +63,12 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, if (!L.isVoice) return false; QMouseEvent* me = static_cast(event); - if (!L.voicePlayBtnRect.contains(me->pos())) return false; + QPoint localPos = me->pos() - option.rect.topLeft(); + if (!L.voicePlayBtnRect.contains(localPos)) return false; QString filePath = index.data(MsgVoiceFileRole).toString(); + qDebug("MessageDelegate::editorEvent voice click: filePath=%s exists=%d", + qPrintable(filePath), QFile::exists(filePath)); if (filePath.isEmpty()) return false; ensureVoiceTimer(); diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index 8444b86e..bb93f9e0 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,10 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data, if (!fname.isEmpty()) { QString fullPath = mediaDirBase + "/" + channelId + "/" + fname; item->setData(fullPath, MsgVoiceFileRole); + qDebug("setVoiceMessageRoles: voice file=%s dur=%s exists=%d", + qPrintable(fullPath), qPrintable(dur), QFile::exists(fullPath)); + } else { + qWarning("setVoiceMessageRoles: empty filename, raw='%s'", qPrintable(raw)); } } } diff --git a/tools/chatgui/src/sound_manager.cpp b/tools/chatgui/src/sound_manager.cpp index 2d09d470..8e41859c 100644 --- a/tools/chatgui/src/sound_manager.cpp +++ b/tools/chatgui/src/sound_manager.cpp @@ -141,7 +141,11 @@ ma_context* SoundManager::context() { } void SoundManager::playRawPcm(const int16_t* pcm, int sampleCount, int sampleRate, int channels) { - if (!m_engine || !m_initialized) return; + if (!m_engine || !m_initialized) { + qWarning("SoundManager::playRawPcm: not initialized (engine=%p init=%d)", (void*)m_engine, m_initialized); + return; + } + qDebug("SoundManager::playRawPcm: %d samples %dHz %dch vol=%.2f", sampleCount, sampleRate, channels, m_volume); ma_audio_buffer_config bufCfg = ma_audio_buffer_config_init( ma_format_s16, (ma_uint32)channels, (ma_uint64)sampleCount, pcm, NULL); @@ -165,7 +169,14 @@ void SoundManager::playRawPcm(const int16_t* pcm, int sampleCount, int sampleRat ma_sound_set_volume(sound, m_volume); ma_sound_start(sound); - qDebug("SoundManager: playing PCM (%d samples, %dHz, %dch)", sampleCount, sampleRate, channels); + qDebug("SoundManager::playRawPcm: started"); +} + +static QString decodeDeviceName(const char* name) { + QString s = QString::fromUtf8(name); + if (s.contains(QChar(0xFFFD))) + s = QString::fromLocal8Bit(name); + return s; } QVector SoundManager::enumeratePlaybackDevices() { @@ -177,7 +188,7 @@ QVector SoundManager::enumeratePlaybackDevices() { 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({QString::fromLocal8Bit(pDevices[i].name), pDevices[i].isDefault != MA_FALSE}); + result.append({decodeDeviceName(pDevices[i].name), pDevices[i].isDefault != MA_FALSE}); return result; } @@ -190,6 +201,6 @@ QVector SoundManager::enumerateCaptureDevices() { 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({QString::fromLocal8Bit(pDevices[i].name), pDevices[i].isDefault != MA_FALSE}); + result.append({decodeDeviceName(pDevices[i].name), pDevices[i].isDefault != MA_FALSE}); return result; } diff --git a/tools/chatgui/src/voicemessageencoder.cpp b/tools/chatgui/src/voicemessageencoder.cpp index d8f9008a..92344d71 100644 --- a/tools/chatgui/src/voicemessageencoder.cpp +++ b/tools/chatgui/src/voicemessageencoder.cpp @@ -47,10 +47,11 @@ int VoiceEncoder::encodeToFile(const std::vector& pcm, int sampleRate, QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { - qWarning("VoiceEncoder: cannot open file %s", qPrintable(filePath)); + qWarning("VoiceEncoder: cannot open file %s (%s)", qPrintable(filePath), qPrintable(file.errorString())); opus_codec_encoder_destroy(enc); return -1; } + qDebug("VoiceEncoder::encodeToFile: writing to %s pcm=%zu samples", qPrintable(filePath), pcm.size()); /* write header */ uint32_t magic = OPUS_MAGIC; diff --git a/tools/chatgui/src/voiceplayback.cpp b/tools/chatgui/src/voiceplayback.cpp index db68873e..7d87be1b 100644 --- a/tools/chatgui/src/voiceplayback.cpp +++ b/tools/chatgui/src/voiceplayback.cpp @@ -13,10 +13,15 @@ static const uint32_t OPUS_MAGIC = 0x5355504F; int VoicePlayer::decodeOpusFile(const QString& filePath, std::vector& outPcm, int& outSampleRate, int& outChannels, float& outDurationSec) { QFile file(filePath); + if (!file.exists()) { + qWarning("VoicePlayer: file not found: %s", qPrintable(filePath)); + return -1; + } if (!file.open(QIODevice::ReadOnly)) { - qWarning("VoicePlayer: cannot open %s", qPrintable(filePath)); + qWarning("VoicePlayer: cannot open %s (%s)", qPrintable(filePath), qPrintable(file.errorString())); return -1; } + qDebug("VoicePlayer: opened file %s size=%lld", qPrintable(filePath), (long long)file.size()); uint32_t magic, sr32; uint16_t ch16, frameSamples; @@ -68,11 +73,17 @@ int VoicePlayer::decodeOpusFile(const QString& filePath, std::vector& o } void VoicePlayer::playOpusFile(const QString& filePath) { + qDebug("VoicePlayer::playOpusFile: %s", qPrintable(filePath)); std::vector pcm; int sampleRate, channels; float duration; - if (decodeOpusFile(filePath, pcm, sampleRate, channels, duration) <= 0) return; + if (decodeOpusFile(filePath, pcm, sampleRate, channels, duration) <= 0) { + qWarning("VoicePlayer::playOpusFile: decode failed for %s", qPrintable(filePath)); + return; + } + qDebug("VoicePlayer::playOpusFile: decoded %zu samples %dHz %dch %.1fs → playing", + pcm.size(), sampleRate, channels, duration); SoundManager::instance()->playRawPcm(pcm.data(), pcm.size() / channels, sampleRate, channels); }