|
|
|
|
@ -38,6 +38,7 @@
|
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <stdarg.h> |
|
|
|
|
#include <limits.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
#ifdef __ANDROID__ |
|
|
|
|
@ -1371,15 +1372,18 @@ void* utun_bridge_voice_decode_open(const char* file_path,
|
|
|
|
|
|
|
|
|
|
uint32_t magic = 0; uint32_t sr = 0; uint16_t ch = 0, fs = 0; |
|
|
|
|
if (fread(&magic, 4, 1, f) != 1 || magic != OPUS_MAGIC_D) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "voice_decode: bad magic"); fclose(f); return NULL; } |
|
|
|
|
if (fread(&sr, 4, 1, f) != 1) { fclose(f); return NULL; } |
|
|
|
|
if (fread(&ch, 2, 1, f) != 1) { fclose(f); return NULL; } |
|
|
|
|
if (fread(&fs, 2, 1, f) != 1) { fclose(f); return NULL; } |
|
|
|
|
if (fread(&sr, 4, 1, f) != 1 || fread(&ch, 2, 1, f) != 1 || fread(&fs, 2, 1, f) != 1 || |
|
|
|
|
(sr != 8000 && sr != 12000 && sr != 16000 && sr != 24000 && sr != 48000) || |
|
|
|
|
(ch != 1 && ch != 2) || fs != sr / 50) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: invalid header rate=%u channels=%u frame=%u", sr, ch, fs); |
|
|
|
|
fclose(f); return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
opus_codec_decoder_t* dec = opus_codec_decoder_create((int)sr, (int)ch); |
|
|
|
|
if (!dec) { fclose(f); return NULL; } |
|
|
|
|
if (!dec) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: decoder allocation failed"); fclose(f); return NULL; } |
|
|
|
|
|
|
|
|
|
struct voice_decode_handle* h = u_calloc(1, sizeof(*h)); |
|
|
|
|
if (!h) { opus_codec_decoder_destroy(dec); fclose(f); return NULL; } |
|
|
|
|
if (!h) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: handle allocation failed"); opus_codec_decoder_destroy(dec); fclose(f); return NULL; } |
|
|
|
|
|
|
|
|
|
h->dec = dec; h->file = f; |
|
|
|
|
h->sample_rate = (int)sr; h->channels = (int)ch; h->frame_samples = (int)fs; |
|
|
|
|
@ -1388,12 +1392,16 @@ void* utun_bridge_voice_decode_open(const char* file_path,
|
|
|
|
|
long pos = ftell(f); |
|
|
|
|
h->total_samples = 0; |
|
|
|
|
for (;;) { |
|
|
|
|
uint16_t plen; |
|
|
|
|
if (fread(&plen, 2, 1, f) != 1 || plen == 0) break; |
|
|
|
|
fseek(f, plen, SEEK_CUR); |
|
|
|
|
uint16_t plen = 0; |
|
|
|
|
if (fread(&plen, 2, 1, f) != 1) goto invalid_stream; |
|
|
|
|
if (!plen) { |
|
|
|
|
if (!h->total_samples || fgetc(f) != EOF || ferror(f)) goto invalid_stream; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (plen > 4000 || h->total_samples > INT_MAX - (int)fs * ch || fseek(f, plen, SEEK_CUR)) goto invalid_stream; |
|
|
|
|
h->total_samples += (int)fs * (int)ch; |
|
|
|
|
} |
|
|
|
|
fseek(f, pos, SEEK_SET); |
|
|
|
|
if (fseek(f, pos, SEEK_SET)) goto invalid_stream; |
|
|
|
|
|
|
|
|
|
*out_sample_rate = h->sample_rate; |
|
|
|
|
*out_channels = h->channels; |
|
|
|
|
@ -1402,6 +1410,9 @@ void* utun_bridge_voice_decode_open(const char* file_path,
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "voice_decode_open: %s rate=%d ch=%d fs=%d total=%d", |
|
|
|
|
file_path, h->sample_rate, h->channels, h->frame_samples, h->total_samples); |
|
|
|
|
return h; |
|
|
|
|
invalid_stream: |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: truncated/invalid stream path=%s samples=%d", file_path, h->total_samples); |
|
|
|
|
utun_bridge_voice_decode_close(h); return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int utun_bridge_voice_decode_read(void* handle, int16_t* buf, int max_samples) { |
|
|
|
|
@ -1414,12 +1425,12 @@ int utun_bridge_voice_decode_read(void* handle, int16_t* buf, int max_samples) {
|
|
|
|
|
|
|
|
|
|
while (written + h->frame_samples * h->channels <= max_samples) { |
|
|
|
|
uint16_t plen; |
|
|
|
|
if (fread(&plen, 2, 1, h->file) != 1 || plen == 0) break; |
|
|
|
|
if (plen > sizeof(packet)) { fseek(h->file, plen, SEEK_CUR); break; } |
|
|
|
|
if (fread(packet, 1, plen, h->file) != plen) break; |
|
|
|
|
if (fread(&plen, 2, 1, h->file) != 1 || plen == 0 || plen > 4000 || fread(packet, 1, plen, h->file) != plen) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: stream changed after validation"); return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int decoded = opus_codec_decode(h->dec, packet, plen, buf + written, h->frame_samples); |
|
|
|
|
if (decoded < 0) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "voice_decode_read: error %d", decoded); break; } |
|
|
|
|
if (decoded != h->frame_samples) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice decode: invalid packet result=%d", decoded); return -1; } |
|
|
|
|
written += decoded * h->channels; |
|
|
|
|
} |
|
|
|
|
h->pcm_consumed += written; |
|
|
|
|
|