Browse Source

Enable shared Qt voice and video composition for PM

master
evgeny 2 days ago
parent
commit
d1f03f2f80
  1. 74
      tools/chatgui/src/inputbar.cpp
  2. 13
      tools/chatgui/src/inputbar.h

74
tools/chatgui/src/inputbar.cpp

@ -26,6 +26,8 @@
extern "C" {
#include "video/video.h"
#include "media_async/attachment_send.h"
#include "mem.h"
}
static bool isImageFile(const QString& suffix) {
@ -183,6 +185,7 @@ InputBar::InputBar(EmojiPanel *emojiPanel, AudioRecorder *recorder, QWidget *par
"QPushButton { border: none; color: white; font-size: 16px; background: transparent; }"
"QPushButton:hover { color: #fdd; }");
connect(m_cancelRecBtn, &QPushButton::clicked, this, [this]() {
m_pttActive = false;
if (m_recorder && m_recorder->isRecording()) m_recorder->stopRecording();
});
roLayout->addWidget(m_cancelRecBtn);
@ -244,17 +247,25 @@ void InputBar::onSendClicked() {
if (hasAttach) {
if (m_pendingAttachAsImage) {
GUI_INFO("send: image=%s name=%s", qPrintable(m_pendingAttachSrc), qPrintable(m_pendingAttachName));
emit sendImageAttachment(m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
emit sendImageAttachment(m_channelIdForRecord, m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
m_attachPreview->hide();
} else if (m_pendingAttachAsVideo) {
GUI_INFO("send: video=%s name=%s", qPrintable(m_pendingAttachSrc), qPrintable(m_pendingAttachName));
emit sendVideoAttachment(m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
auto* request = (struct attachment_send_req*)u_calloc(1, sizeof(struct attachment_send_req));
QByteArray source = m_pendingAttachSrc.toUtf8(), name = (QFileInfo(m_pendingAttachName).completeBaseName() + ".mp4").toUtf8();
if (!request || source.size() >= (int)sizeof(request->source) || name.size() >= (int)sizeof(request->info.name)) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "InputBar: video request allocation/path failed"); u_free(request); return;
}
request->info.kind = ATTACHMENT_VIDEO; request->transcode = 1;
snprintf(request->source, sizeof(request->source), "%s", source.constData());
snprintf(request->info.name, sizeof(request->info.name), "%s", name.constData());
emit submitAttachment(m_channelIdForRecord, request);
m_attachPreviewLabel->setText(QString::fromUtf8("\xF0\x9F\x8E\xAC Перекодирование… 0%"));
m_attachPreview->show();
m_videoProgressTimer->start();
} else {
GUI_INFO("send: file=%s name=%s", qPrintable(m_pendingAttachSrc), qPrintable(m_pendingAttachName));
emit sendFileAttachment(m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
emit sendFileAttachment(m_channelIdForRecord, m_pendingAttachSrc, m_pendingAttachDest, m_pendingAttachName);
m_attachPreview->hide();
}
m_pendingAttachSrc.clear();
@ -280,7 +291,7 @@ void InputBar::setRecordingContext(const QString& mediaDirBase, const QString& c
void InputBar::setDmMode(bool enabled) {
m_dmMode = enabled;
m_pttBtn->setEnabled(!enabled);
m_pttBtn->setEnabled(true);
m_attachBtn->setEnabled(true);
}
@ -292,7 +303,8 @@ void InputBar::setMediaEnabled(bool enabled) {
void InputBar::onPttPressed() {
if (!m_recorder || !m_recorder->isInitialized()) return;
m_recorder->startRecording();
m_pttActive = true;
m_pttActive = m_recorder->isRecording();
m_recordTarget = m_channelIdForRecord;
m_pttBtn->setStyleSheet(m_pttBtn->styleSheet() +
"QPushButton { background: #e74c3c; border-radius: 4px; }");
}
@ -311,47 +323,11 @@ void InputBar::onPttReleased() {
return;
}
const int16_t* pcm = m_recorder->bufferData();
size_t pcmSize = m_recorder->bufferSize();
if (pcmSize == 0) return;
QString mediaPath = m_mediaDirBase + "/" + m_channelIdForRecord;
VoiceEncoder::ensureMediaDir(mediaPath);
GUI_INFO("InputBar::onPttReleased: mediaDir=%s exists=%d channel=%s",
qPrintable(mediaPath), QDir(mediaPath).exists(), qPrintable(m_channelIdForRecord));
QString fileName = VoiceEncoder::generateFileName();
QString mediaFile = mediaPath + "/" + fileName;
float durationSec = 0;
int frames = VoiceEncoder::encodeToFile(pcm, pcmSize, 48000, 1, mediaFile, durationSec);
if (frames <= 0) {
QFile::remove(mediaFile);
return;
}
m_voiceFilePath = mediaFile;
const auto& wf = m_recorder->waveformLevels();
QString wfStr = "wf=";
static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int N = (int)wf.size();
for (int i = 0; i < 100; i++) {
int s = i * N / 100, e = (i + 1) * N / 100;
if (s >= N) s = N - 1;
if (e <= s) e = s + 1;
if (e > N) e = N;
float sum = 0; int cnt = 0;
for (int j = s; j < e; j++) { sum += wf[j]; cnt++; }
float v = cnt > 0 ? sum / cnt : 0;
float db = v > 0.00001f ? 20.0f * log10f(v) : -100.0f;
int idx = (int)((db + 60.0f) / 60.0f * 64.0f);
if (idx < 0) idx = 0; if (idx > 63) idx = 63;
wfStr += b64[idx];
}
wfStr += QString(";dur=%1;").arg(durationMs);
GUI_INFO("InputBar: voice message ready: file=%s dur=%.1fs",
qPrintable(mediaFile), durationSec);
emit sendVoiceMessage(mediaFile, mediaFile, durationMs, wfStr);
auto* request = (struct attachment_send_req*)u_calloc(1, sizeof(struct attachment_send_req));
if (!request) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "InputBar: voice request allocation failed"); return; }
request->info.kind = ATTACHMENT_VOICE; request->preset = VoiceEncoder::preset();
if (!m_recorder->takeRecording(request)) { u_free(request); return; }
emit submitAttachment(m_recordTarget, request);
}
void InputBar::onAttachClicked() {
@ -360,7 +336,7 @@ void InputBar::onAttachClicked() {
if (srcPath.isEmpty()) return;
QFileInfo fi(srcPath);
if (m_dmMode) {
if (m_dmMode && !QStringList{"mp4", "mov", "mkv", "avi", "webm", "m4v"}.contains(fi.suffix().toLower())) {
m_pendingAttachSrc = srcPath;
m_pendingAttachDest = srcPath;
m_pendingAttachName = fi.fileName();
@ -381,9 +357,9 @@ void InputBar::onAttachClicked() {
QString ts = now.toString("yyyyMMdd-HHmmss");
int rnd = rand() & 0xFFFF;
bool asImage = isImageFile(fi.suffix());
bool asImage = !m_dmMode && isImageFile(fi.suffix());
bool asVideo = false;
if (!asImage && video_probe(srcPath.toUtf8().constData())) {
if (!asImage && QStringList{"mp4", "mov", "mkv", "avi", "webm", "m4v"}.contains(fi.suffix().toLower())) {
QMessageBox box(this);
box.setWindowTitle(QString::fromUtf8("Отправить видео"));
box.setText(QString::fromUtf8("Файл содержит видео. Как отправить?"));

13
tools/chatgui/src/inputbar.h

@ -9,6 +9,7 @@ class QProgressBar;
class QTimer;
class EmojiPanel;
class AudioRecorder;
struct attachment_send_req;
class InputBar : public QWidget {
Q_OBJECT
@ -18,19 +19,16 @@ public:
void setRecordingContext(const QString& mediaDirBase, const QString& channelId);
/* DM использует прикрепление оригинального файла без канальной подготовки. */
/* Общий composer для канала и PM. */
void setDmMode(bool enabled);
void setMediaEnabled(bool enabled);
signals:
void sendMessage(const QString &text);
void sendVoiceMessage(const QString& mediaSrc, const QString& mediaDest,
int durationMs, const QString& waveformStr);
void sendFileAttachment(const QString& mediaSrc, const QString& mediaDest,
void submitAttachment(const QString& target, struct attachment_send_req* request);
void sendFileAttachment(const QString& target, const QString& mediaSrc, const QString& mediaDest,
const QString& displayName);
void sendVideoAttachment(const QString& mediaSrc, const QString& mediaDest,
const QString& displayName);
void sendImageAttachment(const QString& mediaSrc, const QString& mediaDest,
void sendImageAttachment(const QString& target, const QString& mediaSrc, const QString& mediaDest,
const QString& displayName);
protected:
@ -70,6 +68,7 @@ private:
QString m_voiceFilePath;
QString m_mediaDirBase;
QString m_channelIdForRecord;
QString m_recordTarget;
QString m_pendingAttachSrc;
QString m_pendingAttachDest;
QString m_pendingAttachName;

Loading…
Cancel
Save