|
|
|
|
@ -24,7 +24,8 @@ static struct {
|
|
|
|
|
int opening, configure, completed, resume, key; |
|
|
|
|
int range; |
|
|
|
|
uint32_t minimum, maximum; |
|
|
|
|
struct call_video_frame tx, rx[8]; |
|
|
|
|
struct call_video_frame tx[CALL_VIDEO_PORT_TX_FRAMES], rx[8]; |
|
|
|
|
unsigned tx_count; |
|
|
|
|
unsigned count, bytes; |
|
|
|
|
uint64_t decoded_generation; |
|
|
|
|
int decoded_pending, decoded_accepted; |
|
|
|
|
@ -39,7 +40,8 @@ static int schedule(void) {
|
|
|
|
|
task->callback = process; port.pending = task; uasync_post_reserved(port.inst->ua, task); return 0; |
|
|
|
|
} |
|
|
|
|
static void clear_frames(void) { |
|
|
|
|
u_free((void *)port.tx.data); port.tx = (struct call_video_frame){0}; |
|
|
|
|
for (unsigned i = 0; i < port.tx_count; ++i) u_free((void *)port.tx[i].data); |
|
|
|
|
port.tx_count = 0; |
|
|
|
|
for (unsigned i = 0; i < port.count; ++i) u_free((void *)port.rx[i].data); |
|
|
|
|
port.count = port.bytes = 0; |
|
|
|
|
} |
|
|
|
|
@ -102,7 +104,9 @@ static void process(void *arg) {
|
|
|
|
|
struct call_video_format format = port.format; |
|
|
|
|
uint32_t bps = port.bps, applied_bps = port.applied_bps; |
|
|
|
|
uint64_t generation = port.applied_generation, request = port.applied_request; |
|
|
|
|
struct call_video_frame tx = port.tx; port.tx = (struct call_video_frame){0}; |
|
|
|
|
struct call_video_frame tx[CALL_VIDEO_PORT_TX_FRAMES]; |
|
|
|
|
unsigned tx_count = port.tx_count; |
|
|
|
|
memcpy(tx, port.tx, tx_count * sizeof(*tx)); port.tx_count = 0; |
|
|
|
|
port.opening = port.configure = port.completed = port.resume = port.key = 0; |
|
|
|
|
port.range = 0; |
|
|
|
|
port.decoded_pending = 0; |
|
|
|
|
@ -120,8 +124,8 @@ static void process(void *arg) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (inst && id && !active) { |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video port cancelled stale commands call=%llu state=%d tx_bytes=%u", |
|
|
|
|
(unsigned long long)id, session ? session->state : -1, tx.size); |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video port cancelled stale commands call=%llu state=%d tx_frames=%u", |
|
|
|
|
(unsigned long long)id, session ? session->state : -1, tx_count); |
|
|
|
|
// Проверка id внутри close сохраняет порт следующего звонка, открытый worker во время обработки.
|
|
|
|
|
call_video_port_close(id); |
|
|
|
|
} |
|
|
|
|
@ -138,9 +142,9 @@ static void process(void *arg) {
|
|
|
|
|
if (id && resume) call_video_resume_receive(inst, id); |
|
|
|
|
if (id && key) call_video_request_key(inst, id); |
|
|
|
|
if (id && decoded_pending) call_video_decode_result(inst, id, decoded_generation, decoded_accepted); |
|
|
|
|
if (id && tx.data) sent = call_video_send_frame(inst, &tx); |
|
|
|
|
for (unsigned i = 0; i < tx_count && sent == 1; ++i) sent = call_video_send_frame(inst, &tx[i]); |
|
|
|
|
} |
|
|
|
|
u_free((void *)tx.data); |
|
|
|
|
for (unsigned i = 0; i < tx_count; ++i) u_free((void *)tx[i].data); |
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
|
if (port.id == id) { |
|
|
|
|
port.status.minimum_bps = minimum; port.status.maximum_bps = maximum; |
|
|
|
|
@ -209,16 +213,37 @@ int call_video_port_applied(uint64_t id, uint64_t generation, uint64_t request,
|
|
|
|
|
if (!result) { port.applied_generation = generation; port.applied_request = request; port.applied_bps = bps; port.completed = 1; } |
|
|
|
|
pthread_mutex_unlock(&lock); return result; |
|
|
|
|
} |
|
|
|
|
int call_video_port_send(const struct call_video_frame *f) { |
|
|
|
|
if (!f || !f->data || !f->size || f->size > CALL_VIDEO_MAX_FRAME || f->offset || f->length != f->size) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port invalid TX frame"); return -1; |
|
|
|
|
int call_video_port_send(const struct call_video_frame *frames, unsigned count) { |
|
|
|
|
if (!frames || !count || count > CALL_VIDEO_PORT_TX_FRAMES) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port invalid TX batch count=%u", count); return -1; |
|
|
|
|
} |
|
|
|
|
uint32_t bytes = 0; |
|
|
|
|
for (unsigned i = 0; i < count; ++i) { |
|
|
|
|
const struct call_video_frame *f = &frames[i]; |
|
|
|
|
if (!f->data || !f->size || f->size > CALL_VIDEO_MAX_FRAME - bytes || f->offset || f->length != f->size |
|
|
|
|
|| f->call_id != frames[0].call_id || !call_video_same_format(&f->format, &frames[0].format) |
|
|
|
|
|| (i && (f->frame_id <= frames[i - 1].frame_id || f->pts_us <= frames[i - 1].pts_us))) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port invalid TX batch frame=%u count=%u bytes=%u", i, count, bytes); return -1; |
|
|
|
|
} |
|
|
|
|
bytes += f->size; |
|
|
|
|
} |
|
|
|
|
pthread_mutex_lock(&lock); |
|
|
|
|
int result = f->call_id && f->call_id == port.id && port.inst ? 0 : -1; |
|
|
|
|
if (!result && !port.tx.data && !schedule()) { |
|
|
|
|
uint8_t *data = u_malloc(f->size); |
|
|
|
|
if (data) { memcpy(data, f->data, f->size); port.tx = *f; port.tx.data = data; result = 1; } |
|
|
|
|
else { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port TX allocation failed"); result = -1; } |
|
|
|
|
int result = frames[0].call_id && frames[0].call_id == port.id && port.inst ? 0 : -1; |
|
|
|
|
if (!result && !port.tx_count) { |
|
|
|
|
unsigned copied = 0; |
|
|
|
|
for (; copied < count; ++copied) { |
|
|
|
|
uint8_t *data = u_malloc(frames[copied].size); |
|
|
|
|
if (!data) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port TX allocation failed frame=%u bytes=%u", copied, bytes); break; } |
|
|
|
|
memcpy(data, frames[copied].data, frames[copied].size); port.tx[copied] = frames[copied]; port.tx[copied].data = data; |
|
|
|
|
} |
|
|
|
|
if (copied == count && !schedule()) { |
|
|
|
|
port.tx_count = count; result = 1; |
|
|
|
|
if (count > 1) DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video port TX batch accepted call=%llu frames=%u bytes=%u", |
|
|
|
|
(unsigned long long)port.id, count, bytes); |
|
|
|
|
} else { |
|
|
|
|
for (unsigned i = 0; i < copied; ++i) u_free((void *)port.tx[i].data); |
|
|
|
|
result = -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pthread_mutex_unlock(&lock); return result; |
|
|
|
|
} |
|
|
|
|
|