diff --git a/src/media_async/attachment_send.c b/src/media_async/attachment_send.c index 1898c327..df775ce6 100644 --- a/src/media_async/attachment_send.c +++ b/src/media_async/attachment_send.c @@ -133,7 +133,7 @@ static void attachment_publish(struct attachment_send_req* req, int error) { static void attachment_video_done(void* arg, int error, const struct video_info* info) { struct attachment_send_req* req = arg; - if (!error && info && info->is_video && info->duration_ms > 0 && info->duration_ms <= 86400000 && + if (!error && info && info->is_video && info->duration_ms > 0 && info->duration_ms <= ATTACHMENT_DURATION_MAX_MS && info->width > 0 && info->width <= 16384 && info->height > 0 && info->height <= 16384) { req->info.duration_ms = (uint32_t)info->duration_ms; req->info.width = (uint16_t)info->width; req->info.height = (uint16_t)info->height; diff --git a/src/media_async/voice_file.c b/src/media_async/voice_file.c index 29b8ab10..2b982130 100644 --- a/src/media_async/voice_file.c +++ b/src/media_async/voice_file.c @@ -12,8 +12,16 @@ int voice_file_encode(const int16_t* pcm, size_t count, int rate, int channels, static const char levels[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if (!pcm || !info || !path || (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000) || (channels != 1 && channels != 2) || preset < 0 || preset > 2) goto invalid; - size_t frame = (size_t)(rate / 50) * channels, samples = count / frame * frame; - if (samples < (size_t)rate * channels / 2 || samples / channels / rate > 86400) goto invalid; + size_t frame = (size_t)(rate / 50) * channels, frames = count / frame; + if (frames < 25 || frames > ATTACHMENT_DURATION_MAX_MS / 20) { + DEBUG_WARN(DEBUG_CATEGORY_MEDIA, + "voice_file: invalid duration count=%zu rate=%d channels=%d frames=%zu allowed_frames=25..%u", + count, rate, channels, frames, ATTACHMENT_DURATION_MAX_MS / 20); + return -1; + } + size_t samples = frames * frame; + DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "voice_file: encode count=%zu rate=%d channels=%d frames=%zu duration=%ums discarded=%zu", + count, rate, channels, frames, (uint32_t)(frames * 20), count - samples); opus_codec_encoder_t* encoder = opus_codec_encoder_create(rate, channels); if (!encoder) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice_file: encoder creation failed"); return -1; } opus_codec_encoder_bitrate_set(encoder, bitrates[preset]); @@ -34,7 +42,7 @@ int voice_file_encode(const int16_t* pcm, size_t count, int rate, int channels, } uint16_t end = 0; if (fwrite(&end, 2, 1, file) != 1 || fflush(file)) goto done; - info->kind = ATTACHMENT_VOICE; info->duration_ms = (uint32_t)(samples / frame * 20); + info->kind = ATTACHMENT_VOICE; info->duration_ms = (uint32_t)(frames * 20); info->width = info->height = 0; for (size_t i = 0; i < 100; i++) { size_t first = i * samples / 100, last = (i + 1) * samples / 100; @@ -57,6 +65,6 @@ done: } else DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "voice_file: prepared path=%s duration=%ums rate=%d channels=%d", path, info->duration_ms, rate, channels); return error; invalid: - DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "voice_file: invalid/short recording count=%zu rate=%d channels=%d preset=%d", count, rate, channels, preset); + DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "voice_file: invalid parameters count=%zu rate=%d channels=%d preset=%d", count, rate, channels, preset); return -1; } diff --git a/src/media_async/voice_file.h b/src/media_async/voice_file.h index 3ce3fd72..c99d3265 100644 --- a/src/media_async/voice_file.h +++ b/src/media_async/voice_file.h @@ -2,7 +2,8 @@ * PCM принадлежит вызывающему; encode заполняет duration/waveform по реально * записанным кадрам. При ошибке неполный файл удаляется; возврат 0 / -1. * count — число interleaved int16 отсчётов; rate — 8/12/16/24/48 kHz, channels — 1/2, preset — 0..2. - * Пишутся полные кадры по 20мс (хвост отбрасывается), минимум 500мс, максимум 24ч. + * Пишутся полные кадры по 20мс (хвост отбрасывается), минимум 500мс, максимум ATTACHMENT_DURATION_MAX_MS. + * Недопустимая длительность отвергается до создания encoder, открытия path и изменения info. * name задаёт caller; encode устанавливает kind=VOICE и обнуляет width/height. */ #ifndef VOICE_FILE_H #define VOICE_FILE_H