|
|
|
|
@ -9,6 +9,7 @@
|
|
|
|
|
#include "../../lib/audio_compressor.h" |
|
|
|
|
#include "../utun_instance.h" |
|
|
|
|
#include "../chat/chat_core.h" |
|
|
|
|
#include "../chat/chat_event.h" |
|
|
|
|
#include "../dm/dm_media.h" |
|
|
|
|
#include "../video/video.h" |
|
|
|
|
#include "media_async.h" |
|
|
|
|
@ -45,11 +46,11 @@ static void attachment_prepare_work(void* arg) {
|
|
|
|
|
} else if (req->transcode) req->error = 0; /* FFmpeg worker стартует после создания каталога. */ |
|
|
|
|
else { |
|
|
|
|
req->error = ma_copy_file(req->source, req->output); |
|
|
|
|
if (!req->error && req->temporary_source && remove(req->source)) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: source cleanup failed path=%s", req->source); req->error = -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
done: |
|
|
|
|
if (req->temporary_source && remove(req->source) && errno != ENOENT) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: source cleanup failed path=%s", req->source); req->error = -1; |
|
|
|
|
} |
|
|
|
|
attachment_release_pcm(req); |
|
|
|
|
if (req->error && remove(req->output) && errno != ENOENT) |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment: partial output cleanup failed path=%s", req->output); |
|
|
|
|
@ -59,10 +60,12 @@ done:
|
|
|
|
|
static void attachment_publish(struct attachment_send_req* req, int error) { |
|
|
|
|
attachment_release_pcm(req); /* Submit мог завершиться ошибкой до запуска work. */ |
|
|
|
|
if (error || req->error || attachment_validate(&req->info)) { |
|
|
|
|
chat_event_attachment(req->inst, req->is_dm, req->target, req->id, 2); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: preparation failed target=%s error=%d worker=%d", req->target, error, req->error); |
|
|
|
|
if (remove(req->output) && errno != ENOENT) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment: output cleanup failed path=%s", req->output); |
|
|
|
|
u_free(req); return; |
|
|
|
|
} |
|
|
|
|
chat_event_attachment(req->inst, req->is_dm, req->target, req->id, 1); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "attachment: prepared target=%s pm=%d kind=%d duration=%u dimensions=%ux%u", |
|
|
|
|
req->target, req->is_dm, req->info.kind, req->info.duration_ms, req->info.width, req->info.height); |
|
|
|
|
if (req->is_dm) { |
|
|
|
|
@ -72,7 +75,11 @@ static void attachment_publish(struct attachment_send_req* req, int error) {
|
|
|
|
|
snprintf(file->conv, sizeof(file->conv), "%s", req->target); |
|
|
|
|
snprintf(file->path, sizeof(file->path), "%s", req->output); |
|
|
|
|
dm_send_file_trampoline(file); |
|
|
|
|
} else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: PM dispatch allocation failed"); |
|
|
|
|
} else { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: PM dispatch allocation failed"); |
|
|
|
|
chat_event_attachment(req->inst, req->is_dm, req->target, req->id, 2); |
|
|
|
|
if (remove(req->output)) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment: rejected output cleanup failed"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
char text[384]; |
|
|
|
|
if (req->info.kind == ATTACHMENT_VOICE) snprintf(text, sizeof(text), "wf=%s;dur=%u;", req->info.waveform, req->info.duration_ms); |
|
|
|
|
@ -88,7 +95,11 @@ static void attachment_publish(struct attachment_send_req* req, int error) {
|
|
|
|
|
message->duration_ms = req->info.duration_ms; message->width = req->info.width; message->height = req->info.height; |
|
|
|
|
message->data = (uint8_t*)(message + 1); message->data_len = (uint32_t)length; memcpy(message->data, text, length); |
|
|
|
|
chat_core_submit_trampoline(message); |
|
|
|
|
} else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: channel dispatch allocation failed"); |
|
|
|
|
} else { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: channel dispatch allocation failed"); |
|
|
|
|
chat_event_attachment(req->inst, req->is_dm, req->target, req->id, 2); |
|
|
|
|
if (remove(req->output)) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment: rejected output cleanup failed"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
u_free(req); |
|
|
|
|
} |
|
|
|
|
@ -126,6 +137,7 @@ void attachment_send_trampoline(void* arg) {
|
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment: UUID generation failed"); attachment_release_pcm(req); u_free(req); return; |
|
|
|
|
} |
|
|
|
|
for (unsigned i = 0; i < 16; i++) snprintf(hex + 2 * i, 3, "%02x", uuid[i]); |
|
|
|
|
memcpy(req->id, uuid, sizeof(req->id)); |
|
|
|
|
const char* base = req->inst->config->global.db_path; |
|
|
|
|
int n = snprintf(req->output, sizeof(req->output), "%s/media/%s/%s.%s", base[0] ? base : ".", |
|
|
|
|
req->is_dm ? "pm-prepared" : req->target, hex, req->info.kind == ATTACHMENT_VOICE ? "opus" : "mp4"); |
|
|
|
|
@ -134,5 +146,6 @@ void attachment_send_trampoline(void* arg) {
|
|
|
|
|
} |
|
|
|
|
if (!req->info.name[0]) snprintf(req->info.name, sizeof(req->info.name), "%s.%s", hex, |
|
|
|
|
req->info.kind == ATTACHMENT_VOICE ? "opus" : "mp4"); |
|
|
|
|
chat_event_attachment(req->inst, req->is_dm, req->target, req->id, 0); |
|
|
|
|
media_async_submit(req->inst->media_async, req->inst->ua, attachment_prepare_work, req, attachment_prepare_done, req); |
|
|
|
|
} |
|
|
|
|
|