mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
The pretty basic adaptive bitrate is *working*
This commit is contained in:
parent
2465f486ac
commit
da6c17222f
|
@ -27,6 +27,9 @@
|
|||
#include "../toxcore/tox.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
#define LOGGING
|
||||
#include "../toxcore/logger.h"
|
||||
|
||||
/* Playing audio data */
|
||||
#include <portaudio.h>
|
||||
/* Reading audio */
|
||||
|
@ -80,6 +83,7 @@
|
|||
typedef struct {
|
||||
bool incoming;
|
||||
uint32_t state;
|
||||
uint32_t abitrate;
|
||||
} CallControl;
|
||||
|
||||
struct toxav_thread_data {
|
||||
|
@ -91,22 +95,6 @@ struct toxav_thread_data {
|
|||
const char* vdout = "AV Test"; /* Video output */
|
||||
PaStream* adout = NULL; /* Audio output */
|
||||
|
||||
const char* stringify_state(TOXAV_CALL_STATE s)
|
||||
{
|
||||
static const char* strings[] =
|
||||
{
|
||||
"NOT SENDING",
|
||||
"SENDING AUDIO",
|
||||
"SENDING VIDEO",
|
||||
"SENDING AUDIO AND VIDEO",
|
||||
"PAUSED",
|
||||
"END",
|
||||
"ERROR"
|
||||
};
|
||||
|
||||
return strings [s];
|
||||
}
|
||||
|
||||
/**
|
||||
* Callbacks
|
||||
*/
|
||||
|
@ -117,9 +105,20 @@ void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool
|
|||
}
|
||||
void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
||||
{
|
||||
printf("Handling CALL STATE callback: %d\n", state);
|
||||
|
||||
((CallControl*)user_data)->state = state;
|
||||
|
||||
if (state & TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE) {
|
||||
uint32_t bitrate = ((CallControl*)user_data)->abitrate;
|
||||
|
||||
if (bitrate < 64) {
|
||||
printf("Changing bitrate to: %d\n", 64);
|
||||
toxav_set_audio_bit_rate(av, friend_number, 64, 0);
|
||||
}
|
||||
} else if (state & TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE) {
|
||||
|
||||
} else {
|
||||
printf("Handling CALL STATE callback: %d\n", state);
|
||||
}
|
||||
}
|
||||
void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||
uint16_t width, uint16_t height,
|
||||
|
@ -331,24 +330,6 @@ int print_help (const char* name)
|
|||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
RingBuffer* rb = rb_new(4);
|
||||
int a[5] = {0, 1, 2, 3, 4};
|
||||
int* x;
|
||||
rb_write(rb, a + 0);
|
||||
rb_write(rb, a + 1);
|
||||
rb_write(rb, a + 2);
|
||||
rb_write(rb, a + 3);
|
||||
// rb_write(rb, a + 4);
|
||||
|
||||
x = rb_write(rb, a + 4);
|
||||
while (rb_read(rb, (void**) &x))
|
||||
// rb_read(rb, (void**)&x);
|
||||
printf("%d ", *x);
|
||||
|
||||
printf("\n");
|
||||
// int r = 43;
|
||||
// printf("%d\n", r >= 40 ? 3 : r / 10);
|
||||
return 0;
|
||||
Pa_Initialize();
|
||||
|
||||
struct stat st;
|
||||
|
@ -688,9 +669,11 @@ int main (int argc, char** argv)
|
|||
memset(&AliceCC, 0, sizeof(CallControl));
|
||||
memset(&BobCC, 0, sizeof(CallControl));
|
||||
|
||||
AliceCC.abitrate = BobCC.abitrate = 8;
|
||||
|
||||
{ /* Call */
|
||||
TOXAV_ERR_CALL rc;
|
||||
toxav_call(AliceAV, 0, 48, 0, &rc);
|
||||
toxav_call(AliceAV, 0, AliceCC.abitrate, 0, &rc);
|
||||
|
||||
if (rc != TOXAV_ERR_CALL_OK) {
|
||||
printf("toxav_call failed: %d\n", rc);
|
||||
|
@ -703,7 +686,7 @@ int main (int argc, char** argv)
|
|||
|
||||
{ /* Answer */
|
||||
TOXAV_ERR_ANSWER rc;
|
||||
toxav_answer(BobAV, 0, 48, 0, &rc);
|
||||
toxav_answer(BobAV, 0, BobCC.abitrate, 0, &rc);
|
||||
|
||||
if (rc != TOXAV_ERR_ANSWER_OK) {
|
||||
printf("toxav_answer failed: %d\n", rc);
|
||||
|
|
|
@ -293,7 +293,7 @@ void cs_do(CSession *cs)
|
|||
/* The maximum for 120 ms 48 KHz audio */
|
||||
int16_t tmp[5760];
|
||||
|
||||
while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
|
||||
if ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
|
||||
LOGGED_UNLOCK(cs->queue_mutex);
|
||||
|
||||
if (success == 2) {
|
||||
|
@ -327,7 +327,7 @@ void cs_do(CSession *cs)
|
|||
if (!reconfigure_audio_decoder(cs, cs->last_packet_sampling_rate, cs->last_packet_channel_count)) {
|
||||
LOGGER_WARNING("Failed to reconfigure decoder!");
|
||||
rtp_free_msg(NULL, msg);
|
||||
continue;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
rc = opus_decode(cs->audio_decoder, msg->data + 4, msg->length - 4, tmp, 5760, 0);
|
||||
|
@ -347,6 +347,7 @@ void cs_do(CSession *cs)
|
|||
|
||||
LOGGED_LOCK(cs->queue_mutex);
|
||||
}
|
||||
DONE:;
|
||||
}
|
||||
|
||||
/********************* VIDEO *********************/
|
||||
|
|
101
toxav/rtp.c
101
toxav/rtp.c
|
@ -50,15 +50,17 @@
|
|||
typedef struct {
|
||||
uint64_t timestamp; /* in ms */
|
||||
|
||||
uint32_t packets_missing;
|
||||
uint32_t received_packets;
|
||||
uint32_t expected_packets;
|
||||
/* ... other stuff in the future */
|
||||
} RTCPReport;
|
||||
|
||||
typedef struct RTCPSession_s {
|
||||
RTPSession *rtp_session;
|
||||
|
||||
uint8_t prefix;
|
||||
uint64_t last_sent_report_ts;
|
||||
uint32_t last_missing_packets;
|
||||
uint32_t last_received_packets;
|
||||
uint32_t last_expected_packets;
|
||||
|
||||
RingBuffer* pl_stats; /* Packet loss stats over time */
|
||||
|
@ -66,6 +68,7 @@ typedef struct RTCPSession_s {
|
|||
|
||||
|
||||
|
||||
|
||||
/* queue_message() is defined in codec.c */
|
||||
void queue_message(RTPSession *session, RTPMessage *msg);
|
||||
RTPHeader *parse_header_in ( const uint8_t *payload, int length );
|
||||
|
@ -91,18 +94,12 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
|
|||
}
|
||||
|
||||
retu->version = RTP_VERSION; /* It's always 2 */
|
||||
retu->padding = 0; /* If some additional data is needed about the packet */
|
||||
retu->extension = 0; /* If extension to header is needed */
|
||||
retu->cc = 1; /* Amount of contributors */
|
||||
retu->csrc = NULL; /* Container */
|
||||
retu->ssrc = random_int();
|
||||
retu->marker = 0;
|
||||
retu->payload_type = payload_type % 128;
|
||||
|
||||
|
||||
retu->tstate = rtp_StateNormal;
|
||||
retu->m = messenger;
|
||||
retu->dest = friend_num;
|
||||
retu->rsequnum = retu->sequnum = 0;
|
||||
retu->ext_header = NULL; /* When needed allocate */
|
||||
|
||||
if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
|
||||
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
||||
|
@ -117,15 +114,16 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
|
|||
|
||||
|
||||
/* Initialize rtcp session */
|
||||
if (!(retu->rtcp = calloc(1, sizeof(RTCPSession)))) {
|
||||
if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) {
|
||||
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
||||
free(retu->csrc);
|
||||
free(retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retu->rtcp->prefix = 222 + payload_type % 192;
|
||||
retu->rtcp->pl_stats = rb_new(4);
|
||||
retu->rtcp_session->prefix = 222 + payload_type % 192;
|
||||
retu->rtcp_session->pl_stats = rb_new(4);
|
||||
retu->rtcp_session->rtp_session = retu;
|
||||
|
||||
return retu;
|
||||
}
|
||||
|
@ -139,11 +137,11 @@ void rtp_kill ( RTPSession *session )
|
|||
free ( session->csrc );
|
||||
|
||||
void* t;
|
||||
while (!rb_empty(session->rtcp->pl_stats)) {
|
||||
rb_read(session->rtcp->pl_stats, (void**) &t);
|
||||
while (!rb_empty(session->rtcp_session->pl_stats)) {
|
||||
rb_read(session->rtcp_session->pl_stats, (void**) &t);
|
||||
free(t);
|
||||
}
|
||||
rb_free(session->rtcp->pl_stats);
|
||||
rb_free(session->rtcp_session->pl_stats);
|
||||
|
||||
LOGGER_DEBUG("Terminated RTP session: %p", session);
|
||||
|
||||
|
@ -152,41 +150,49 @@ void rtp_kill ( RTPSession *session )
|
|||
}
|
||||
void rtp_do(RTPSession *session)
|
||||
{
|
||||
if (!session || !session->rtcp)
|
||||
if (!session || !session->rtcp_session)
|
||||
return;
|
||||
|
||||
if (current_time_monotonic() - session->rtcp->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
|
||||
send_rtcp_report(session->rtcp, session->m, session->dest);
|
||||
if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
|
||||
send_rtcp_report(session->rtcp_session, session->m, session->dest);
|
||||
}
|
||||
|
||||
if (rb_full(session->rtcp->pl_stats)) {
|
||||
if (rb_full(session->rtcp_session->pl_stats)) {
|
||||
RTCPReport* reports[4];
|
||||
|
||||
int i = 0;
|
||||
for (; rb_read(session->rtcp->pl_stats, (void**) reports + i); i++);
|
||||
for (; rb_read(session->rtcp_session->pl_stats, (void**) reports + i); i++);
|
||||
|
||||
/* Check for timed out reports (> 6 sec) */
|
||||
uint64_t now = current_time_monotonic();
|
||||
for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++);
|
||||
for (; i < 4; i ++) {
|
||||
rb_write(session->rtcp->pl_stats, reports[i]);
|
||||
rb_write(session->rtcp_session->pl_stats, reports[i]);
|
||||
reports[i] = NULL;
|
||||
}
|
||||
if (!rb_empty(session->rtcp->pl_stats)) {
|
||||
if (!rb_empty(session->rtcp_session->pl_stats)) {
|
||||
for (i = 0; reports[i] != NULL; i ++)
|
||||
free(reports[i]);
|
||||
return; /* As some reports are timed out, we need more... */
|
||||
}
|
||||
|
||||
/* We have 4 on-time reports so we can proceed */
|
||||
uint32_t quality_loss = 0;
|
||||
uint32_t quality = 100;
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint32_t idx = reports[i]->packets_missing * 100 / reports[i]->expected_packets;
|
||||
quality_loss += idx;
|
||||
uint32_t idx = reports[i]->received_packets * 100 / reports[i]->expected_packets;
|
||||
quality = MIN(quality, idx);
|
||||
free(reports[i]);
|
||||
}
|
||||
|
||||
if (quality_loss > 40) {
|
||||
LOGGER_DEBUG("Packet loss detected");
|
||||
if (quality <= 70) {
|
||||
session->tstate = rtp_StateBad;
|
||||
LOGGER_WARNING("Stream quality: BAD");
|
||||
} else if (quality >= 99) {
|
||||
session->tstate = rtp_StateGood;
|
||||
LOGGER_DEBUG("Stream quality: GOOD");
|
||||
} else {
|
||||
session->tstate = rtp_StateNormal;
|
||||
LOGGER_DEBUG("Stream quality: NORMAL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,8 +206,8 @@ int rtp_start_receiving(RTPSession* session)
|
|||
LOGGER_WARNING("Failed to register rtp receive handler");
|
||||
return -1;
|
||||
}
|
||||
if (custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp->prefix,
|
||||
handle_rtcp_packet, session->rtcp) == -1) {
|
||||
if (custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp_session->prefix,
|
||||
handle_rtcp_packet, session->rtcp_session) == -1) {
|
||||
LOGGER_WARNING("Failed to register rtcp receive handler");
|
||||
custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL);
|
||||
return -1;
|
||||
|
@ -215,7 +221,7 @@ int rtp_stop_receiving(RTPSession* session)
|
|||
return -1;
|
||||
|
||||
custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL);
|
||||
custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp->prefix, NULL, NULL); /* RTCP */
|
||||
custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -516,16 +522,21 @@ void send_rtcp_report(RTCPSession* session, Messenger* m, int32_t friendnumber)
|
|||
uint8_t parsed[9];
|
||||
parsed[0] = session->prefix;
|
||||
|
||||
uint32_t packets_missing = htonl(session->last_missing_packets);
|
||||
uint32_t received_packets = htonl(session->last_received_packets);
|
||||
uint32_t expected_packets = htonl(session->last_expected_packets);
|
||||
|
||||
memcpy(parsed + 1, &packets_missing, 4);
|
||||
memcpy(parsed + 1, &received_packets, 4);
|
||||
memcpy(parsed + 5, &expected_packets, 4);
|
||||
|
||||
if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
|
||||
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
|
||||
else
|
||||
else {
|
||||
LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
|
||||
|
||||
session->last_received_packets = 0;
|
||||
session->last_expected_packets = 0;
|
||||
session->last_sent_report_ts = current_time_monotonic();
|
||||
}
|
||||
}
|
||||
int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object )
|
||||
{
|
||||
|
@ -545,12 +556,21 @@ int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data,
|
|||
}
|
||||
|
||||
/* Check if message came in late */
|
||||
if ( msg->header->sequnum > session->rsequnum && msg->header->timestamp > session->rtimestamp ) {
|
||||
if ( msg->header->sequnum > session->rsequnum || msg->header->timestamp > session->rtimestamp ) {
|
||||
/* Not late */
|
||||
if (msg->header->sequnum > session->rsequnum)
|
||||
session->rtcp_session->last_expected_packets += msg->header->sequnum - session->rsequnum;
|
||||
else if (msg->header->sequnum < session->rsequnum)
|
||||
session->rtcp_session->last_expected_packets += (msg->header->sequnum + 65535) - session->rsequnum;
|
||||
else /* Usual case when transmission starts */
|
||||
session->rtcp_session->last_expected_packets ++;
|
||||
|
||||
session->rsequnum = msg->header->sequnum;
|
||||
session->rtimestamp = msg->header->timestamp;
|
||||
}
|
||||
|
||||
session->rtcp_session->last_received_packets ++;
|
||||
|
||||
queue_message(session, msg);
|
||||
return 0;
|
||||
}
|
||||
|
@ -562,14 +582,15 @@ int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data
|
|||
RTCPSession* session = object;
|
||||
RTCPReport* report = malloc(sizeof(RTCPReport));
|
||||
|
||||
memcpy(&report->packets_missing, data + 1, 4);
|
||||
memcpy(&report->received_packets, data + 1, 4);
|
||||
memcpy(&report->expected_packets, data + 5, 4);
|
||||
|
||||
report->packets_missing = ntohl(report->packets_missing);
|
||||
report->received_packets = ntohl(report->received_packets);
|
||||
report->expected_packets = ntohl(report->expected_packets);
|
||||
|
||||
/* This would cause undefined behaviour */
|
||||
if (report->expected_packets == 0) {
|
||||
/* Invalid values */
|
||||
if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
|
||||
LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
|
||||
free(report);
|
||||
return 0;
|
||||
}
|
||||
|
@ -577,5 +598,7 @@ int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data
|
|||
report->timestamp = current_time_monotonic();
|
||||
|
||||
free(rb_write(session->pl_stats, report));
|
||||
|
||||
LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets);
|
||||
return 0;
|
||||
}
|
16
toxav/rtp.h
16
toxav/rtp.h
|
@ -44,10 +44,16 @@
|
|||
/**
|
||||
* Payload type identifier. Also used as rtp callback prefix.
|
||||
*/
|
||||
typedef enum {
|
||||
enum {
|
||||
rtp_TypeAudio = 192,
|
||||
rtp_TypeVideo
|
||||
} RTPPayloadType;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
rtp_StateBad = -1,
|
||||
rtp_StateNormal,
|
||||
rtp_StateGood,
|
||||
} RTPTransmissionState;
|
||||
|
||||
/**
|
||||
* Standard rtp header.
|
||||
|
@ -108,10 +114,11 @@ typedef struct {
|
|||
|
||||
int dest;
|
||||
|
||||
struct RTCPSession_s *rtcp;
|
||||
struct RTCPSession_s *rtcp_session;
|
||||
struct CSession_s *cs;
|
||||
Messenger *m;
|
||||
|
||||
|
||||
RTPTransmissionState tstate;
|
||||
} RTPSession;
|
||||
|
||||
/**
|
||||
|
@ -150,5 +157,4 @@ int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length );
|
|||
void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
|
||||
|
||||
|
||||
|
||||
#endif /* RTP_H */
|
||||
|
|
167
toxav/toxav.c
167
toxav/toxav.c
|
@ -60,6 +60,12 @@ typedef struct ToxAVCall_s {
|
|||
uint8_t last_self_capabilities;
|
||||
uint8_t last_peer_capabilities;
|
||||
|
||||
/** Quality control */
|
||||
uint64_t time_audio_good;
|
||||
uint32_t last_bad_audio_bit_rate;
|
||||
uint64_t time_video_good;
|
||||
uint32_t last_bad_video_bit_rate;
|
||||
|
||||
struct ToxAVCall_s *prev;
|
||||
struct ToxAVCall_s *next;
|
||||
} ToxAVCall;
|
||||
|
@ -96,11 +102,13 @@ int callback_end(void* toxav_inst, MSICall* call);
|
|||
int callback_error(void* toxav_inst, MSICall* call);
|
||||
int callback_capabilites(void* toxav_inst, MSICall* call);
|
||||
|
||||
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
|
||||
ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
|
||||
void call_remove(ToxAVCall* call);
|
||||
bool audio_bitrate_invalid(uint32_t bitrate);
|
||||
bool video_bitrate_invalid(uint32_t bitrate);
|
||||
void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
|
||||
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
|
||||
ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
|
||||
void qc_do(ToxAVCall* call);
|
||||
void call_remove(ToxAVCall* call);
|
||||
bool call_prepare_transmission(ToxAVCall* call);
|
||||
void call_kill_transmission(ToxAVCall* call);
|
||||
|
||||
|
@ -220,8 +228,9 @@ void toxav_iterate(ToxAV* av)
|
|||
LOGGED_UNLOCK(av->mutex);
|
||||
|
||||
cs_do(i->cs);
|
||||
rtp_do(i->rtps[0]);
|
||||
rtp_do(i->rtps[1]);
|
||||
rtp_do(i->rtps[audio_index]);
|
||||
rtp_do(i->rtps[video_index]);
|
||||
qc_do(i);
|
||||
|
||||
if (i->last_self_capabilities & msi_CapRAudio) /* Receiving audio */
|
||||
rc = MIN(i->cs->last_packet_frame_duration, rc);
|
||||
|
@ -516,8 +525,10 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
|
|||
goto END;
|
||||
}
|
||||
|
||||
/* NOTE: no need to lock*/
|
||||
/* Decoding mutex is locked because of quality control */
|
||||
LOGGED_LOCK(call->mutex_decoding);
|
||||
call->audio_bit_rate = audio_bit_rate;
|
||||
LOGGED_UNLOCK(call->mutex_decoding);
|
||||
LOGGED_UNLOCK(av->mutex);
|
||||
|
||||
END:
|
||||
|
@ -550,8 +561,10 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
|
|||
goto END;
|
||||
}
|
||||
|
||||
/* NOTE: no need to lock*/
|
||||
/* Decoding mutex is locked because of quality control */
|
||||
LOGGED_LOCK(call->mutex_decoding);
|
||||
call->video_bit_rate = video_bit_rate;
|
||||
LOGGED_UNLOCK(call->mutex_decoding);
|
||||
LOGGED_UNLOCK(av->mutex);
|
||||
|
||||
END:
|
||||
|
@ -813,8 +826,7 @@ int callback_start(void* toxav_inst, MSICall* call)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (toxav->scb.first)
|
||||
toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second);
|
||||
invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
|
||||
|
||||
LOGGED_UNLOCK(toxav->mutex);
|
||||
return 0;
|
||||
|
@ -825,8 +837,7 @@ int callback_end(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
LOGGED_LOCK(toxav->mutex);
|
||||
|
||||
if (toxav->scb.first)
|
||||
toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second);
|
||||
invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_END);
|
||||
|
||||
call_kill_transmission(call->av_call);
|
||||
call_remove(call->av_call);
|
||||
|
@ -840,8 +851,7 @@ int callback_error(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
LOGGED_LOCK(toxav->mutex);
|
||||
|
||||
if (toxav->scb.first)
|
||||
toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second);
|
||||
invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR);
|
||||
|
||||
call_kill_transmission(call->av_call);
|
||||
call_remove(call->av_call);
|
||||
|
@ -857,8 +867,7 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
|
|||
|
||||
/* TODO modify cs? */
|
||||
|
||||
if (toxav->scb.first)
|
||||
toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second);
|
||||
invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
|
||||
|
||||
LOGGED_UNLOCK(toxav->mutex);
|
||||
return 0;
|
||||
|
@ -878,6 +887,12 @@ bool video_bitrate_invalid(uint32_t bitrate)
|
|||
return false;
|
||||
}
|
||||
|
||||
void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state)
|
||||
{
|
||||
if (av->scb.first)
|
||||
av->scb.first(av, friend_number, state, av->scb.second);
|
||||
}
|
||||
|
||||
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
|
||||
{
|
||||
/* Assumes mutex locked */
|
||||
|
@ -968,6 +983,94 @@ ToxAVCall* call_get(ToxAV* av, uint32_t friend_number)
|
|||
return av->calls[friend_number];
|
||||
}
|
||||
|
||||
void qc_do(ToxAVCall* call)
|
||||
{
|
||||
/* Please NOTE: The quality control is rather basic,
|
||||
* advanced algorithms will be applied in the future
|
||||
*/
|
||||
switch(call->rtps[audio_index]->tstate) {
|
||||
case rtp_StateBad:
|
||||
LOGGER_DEBUG("Suggesting lower bitrate for audio...");
|
||||
call->time_audio_good = 0;
|
||||
call->last_bad_audio_bit_rate = call->audio_bit_rate;
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_LOWER_AUDIO_BITRATE);
|
||||
break;
|
||||
case rtp_StateGood:
|
||||
if (call->time_audio_good == 0)
|
||||
call->time_audio_good = current_time_monotonic();
|
||||
else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
|
||||
64 > call->audio_bit_rate)
|
||||
if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
|
||||
if (current_time_monotonic() - call->time_audio_good >= 45000)
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
|
||||
call->last_bad_audio_bit_rate = 0;
|
||||
} else
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
|
||||
break;
|
||||
case rtp_StateNormal:
|
||||
call->time_audio_good = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(call->rtps[video_index]->tstate) {
|
||||
case rtp_StateBad:
|
||||
LOGGER_DEBUG("Suggesting lower bitrate for video...");
|
||||
call->time_video_good = 0;
|
||||
call->last_bad_video_bit_rate = call->video_bit_rate;
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_LOWER_VIDEO_BITRATE);
|
||||
break;
|
||||
case rtp_StateGood:
|
||||
if (call->time_video_good == 0)
|
||||
call->time_video_good = current_time_monotonic();
|
||||
else if (current_time_monotonic() - call->time_video_good >= 30000)
|
||||
if (call->last_bad_video_bit_rate > call->video_bit_rate) {
|
||||
if (current_time_monotonic() - call->time_video_good >= 45000)
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
|
||||
call->last_bad_video_bit_rate = 0;
|
||||
} else
|
||||
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
|
||||
break;
|
||||
case rtp_StateNormal:
|
||||
call->time_video_good = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void call_remove(ToxAVCall* call)
|
||||
{
|
||||
if (call == NULL)
|
||||
return;
|
||||
|
||||
uint32_t friend_id = call->friend_id;
|
||||
ToxAV* av = call->av;
|
||||
|
||||
ToxAVCall* prev = call->prev;
|
||||
ToxAVCall* next = call->next;
|
||||
|
||||
free(call);
|
||||
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else if (next)
|
||||
av->calls_head = next->friend_id;
|
||||
else goto CLEAR;
|
||||
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
else if (prev)
|
||||
av->calls_tail = prev->friend_id;
|
||||
else goto CLEAR;
|
||||
|
||||
av->calls[friend_id] = NULL;
|
||||
return;
|
||||
|
||||
CLEAR:
|
||||
av->calls_head = av->calls_tail = 0;
|
||||
free(av->calls);
|
||||
av->calls = NULL;
|
||||
}
|
||||
|
||||
bool call_prepare_transmission(ToxAVCall* call)
|
||||
{
|
||||
/* Assumes mutex locked */
|
||||
|
@ -1089,37 +1192,3 @@ void call_kill_transmission(ToxAVCall* call)
|
|||
pthread_mutex_destroy(call->mutex_video_sending);
|
||||
pthread_mutex_destroy(call->mutex_decoding);
|
||||
}
|
||||
|
||||
void call_remove(ToxAVCall* call)
|
||||
{
|
||||
if (call == NULL)
|
||||
return;
|
||||
|
||||
uint32_t friend_id = call->friend_id;
|
||||
ToxAV* av = call->av;
|
||||
|
||||
ToxAVCall* prev = call->prev;
|
||||
ToxAVCall* next = call->next;
|
||||
|
||||
free(call);
|
||||
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else if (next)
|
||||
av->calls_head = next->friend_id;
|
||||
else goto CLEAR;
|
||||
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
else if (prev)
|
||||
av->calls_tail = prev->friend_id;
|
||||
else goto CLEAR;
|
||||
|
||||
av->calls[friend_id] = NULL;
|
||||
return;
|
||||
|
||||
CLEAR:
|
||||
av->calls_head = av->calls_tail = 0;
|
||||
free(av->calls);
|
||||
av->calls = NULL;
|
||||
}
|
||||
|
|
|
@ -207,21 +207,31 @@ typedef enum TOXAV_CALL_STATE {
|
|||
* The flag that marks that friend is receiving video.
|
||||
*/
|
||||
TOXAV_CALL_STATE_RECEIVING_V = 8,
|
||||
|
||||
/**
|
||||
* The core will never set TOXAV_CALL_STATE_END or TOXAV_CALL_STATE_ERROR
|
||||
* together with other states.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The call has finished. This is the final state after which no more state
|
||||
* transitions can occur for the call.
|
||||
*/
|
||||
TOXAV_CALL_STATE_END = 16,
|
||||
/**
|
||||
* Sent by the AV core if an error occurred on the remote end.
|
||||
* AV core suggests you to lower bitrate for audio.
|
||||
*/
|
||||
TOXAV_CALL_STATE_ERROR = 32
|
||||
TOXAV_CALL_STATE_LOWER_AUDIO_BITRATE = 32,
|
||||
/**
|
||||
* AV core suggests you to lower bitrate for video.
|
||||
*/
|
||||
TOXAV_CALL_STATE_LOWER_VIDEO_BITRATE = 64,
|
||||
/**
|
||||
* AV core suggests you to increase bitrate for audio.
|
||||
*/
|
||||
TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE = 128,
|
||||
/**
|
||||
* AV core suggests you to increase bitrate for video.
|
||||
*/
|
||||
TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE = 256,
|
||||
/**
|
||||
* Set by the AV core if an error occurred on the remote end.
|
||||
*/
|
||||
TOXAV_CALL_STATE_ERROR = 32768
|
||||
} TOXAV_CALL_STATE;
|
||||
/**
|
||||
* The function type for the `call_state` callback.
|
||||
|
|
Loading…
Reference in New Issue
Block a user