summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-04-16 02:00:34 +0200
committermannol <eniz_vukovic@hotmail.com>2015-04-16 02:00:34 +0200
commitda6c17222f54c933c826e9c557e66629ee57790f (patch)
tree2cf5e0ff002bef5d69f0048475ea7becc11bd389 /toxav/toxav.c
parent2465f486acd90ed8395c8a83a13af09ecd024c98 (diff)
The pretty basic adaptive bitrate is *working*
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c165
1 files changed, 117 insertions, 48 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 721b9d91..0e94e5dd 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -60,6 +60,12 @@ typedef struct ToxAVCall_s {
60 uint8_t last_self_capabilities; 60 uint8_t last_self_capabilities;
61 uint8_t last_peer_capabilities; 61 uint8_t last_peer_capabilities;
62 62
63 /** Quality control */
64 uint64_t time_audio_good;
65 uint32_t last_bad_audio_bit_rate;
66 uint64_t time_video_good;
67 uint32_t last_bad_video_bit_rate;
68
63 struct ToxAVCall_s *prev; 69 struct ToxAVCall_s *prev;
64 struct ToxAVCall_s *next; 70 struct ToxAVCall_s *next;
65} ToxAVCall; 71} ToxAVCall;
@@ -96,11 +102,13 @@ int callback_end(void* toxav_inst, MSICall* call);
96int callback_error(void* toxav_inst, MSICall* call); 102int callback_error(void* toxav_inst, MSICall* call);
97int callback_capabilites(void* toxav_inst, MSICall* call); 103int callback_capabilites(void* toxav_inst, MSICall* call);
98 104
105bool audio_bitrate_invalid(uint32_t bitrate);
106bool video_bitrate_invalid(uint32_t bitrate);
107void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
99ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); 108ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
100ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); 109ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
110void qc_do(ToxAVCall* call);
101void call_remove(ToxAVCall* call); 111void call_remove(ToxAVCall* call);
102bool audio_bitrate_invalid(uint32_t bitrate);
103bool video_bitrate_invalid(uint32_t bitrate);
104bool call_prepare_transmission(ToxAVCall* call); 112bool call_prepare_transmission(ToxAVCall* call);
105void call_kill_transmission(ToxAVCall* call); 113void call_kill_transmission(ToxAVCall* call);
106 114
@@ -220,8 +228,9 @@ void toxav_iterate(ToxAV* av)
220 LOGGED_UNLOCK(av->mutex); 228 LOGGED_UNLOCK(av->mutex);
221 229
222 cs_do(i->cs); 230 cs_do(i->cs);
223 rtp_do(i->rtps[0]); 231 rtp_do(i->rtps[audio_index]);
224 rtp_do(i->rtps[1]); 232 rtp_do(i->rtps[video_index]);
233 qc_do(i);
225 234
226 if (i->last_self_capabilities & msi_CapRAudio) /* Receiving audio */ 235 if (i->last_self_capabilities & msi_CapRAudio) /* Receiving audio */
227 rc = MIN(i->cs->last_packet_frame_duration, rc); 236 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_
516 goto END; 525 goto END;
517 } 526 }
518 527
519 /* NOTE: no need to lock*/ 528 /* Decoding mutex is locked because of quality control */
529 LOGGED_LOCK(call->mutex_decoding);
520 call->audio_bit_rate = audio_bit_rate; 530 call->audio_bit_rate = audio_bit_rate;
531 LOGGED_UNLOCK(call->mutex_decoding);
521 LOGGED_UNLOCK(av->mutex); 532 LOGGED_UNLOCK(av->mutex);
522 533
523END: 534END:
@@ -550,8 +561,10 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
550 goto END; 561 goto END;
551 } 562 }
552 563
553 /* NOTE: no need to lock*/ 564 /* Decoding mutex is locked because of quality control */
565 LOGGED_LOCK(call->mutex_decoding);
554 call->video_bit_rate = video_bit_rate; 566 call->video_bit_rate = video_bit_rate;
567 LOGGED_UNLOCK(call->mutex_decoding);
555 LOGGED_UNLOCK(av->mutex); 568 LOGGED_UNLOCK(av->mutex);
556 569
557END: 570END:
@@ -813,8 +826,7 @@ int callback_start(void* toxav_inst, MSICall* call)
813 return -1; 826 return -1;
814 } 827 }
815 828
816 if (toxav->scb.first) 829 invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
817 toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second);
818 830
819 LOGGED_UNLOCK(toxav->mutex); 831 LOGGED_UNLOCK(toxav->mutex);
820 return 0; 832 return 0;
@@ -825,8 +837,7 @@ int callback_end(void* toxav_inst, MSICall* call)
825 ToxAV* toxav = toxav_inst; 837 ToxAV* toxav = toxav_inst;
826 LOGGED_LOCK(toxav->mutex); 838 LOGGED_LOCK(toxav->mutex);
827 839
828 if (toxav->scb.first) 840 invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_END);
829 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second);
830 841
831 call_kill_transmission(call->av_call); 842 call_kill_transmission(call->av_call);
832 call_remove(call->av_call); 843 call_remove(call->av_call);
@@ -840,8 +851,7 @@ int callback_error(void* toxav_inst, MSICall* call)
840 ToxAV* toxav = toxav_inst; 851 ToxAV* toxav = toxav_inst;
841 LOGGED_LOCK(toxav->mutex); 852 LOGGED_LOCK(toxav->mutex);
842 853
843 if (toxav->scb.first) 854 invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR);
844 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second);
845 855
846 call_kill_transmission(call->av_call); 856 call_kill_transmission(call->av_call);
847 call_remove(call->av_call); 857 call_remove(call->av_call);
@@ -857,8 +867,7 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
857 867
858 /* TODO modify cs? */ 868 /* TODO modify cs? */
859 869
860 if (toxav->scb.first) 870 invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
861 toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second);
862 871
863 LOGGED_UNLOCK(toxav->mutex); 872 LOGGED_UNLOCK(toxav->mutex);
864 return 0; 873 return 0;
@@ -878,6 +887,12 @@ bool video_bitrate_invalid(uint32_t bitrate)
878 return false; 887 return false;
879} 888}
880 889
890void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state)
891{
892 if (av->scb.first)
893 av->scb.first(av, friend_number, state, av->scb.second);
894}
895
881ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) 896ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
882{ 897{
883 /* Assumes mutex locked */ 898 /* Assumes mutex locked */
@@ -968,6 +983,94 @@ ToxAVCall* call_get(ToxAV* av, uint32_t friend_number)
968 return av->calls[friend_number]; 983 return av->calls[friend_number];
969} 984}
970 985
986void qc_do(ToxAVCall* call)
987{
988 /* Please NOTE: The quality control is rather basic,
989 * advanced algorithms will be applied in the future
990 */
991 switch(call->rtps[audio_index]->tstate) {
992 case rtp_StateBad:
993 LOGGER_DEBUG("Suggesting lower bitrate for audio...");
994 call->time_audio_good = 0;
995 call->last_bad_audio_bit_rate = call->audio_bit_rate;
996 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_LOWER_AUDIO_BITRATE);
997 break;
998 case rtp_StateGood:
999 if (call->time_audio_good == 0)
1000 call->time_audio_good = current_time_monotonic();
1001 else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
1002 64 > call->audio_bit_rate)
1003 if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
1004 if (current_time_monotonic() - call->time_audio_good >= 45000)
1005 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
1006 call->last_bad_audio_bit_rate = 0;
1007 } else
1008 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
1009 break;
1010 case rtp_StateNormal:
1011 call->time_audio_good = 0;
1012 break;
1013 }
1014
1015 switch(call->rtps[video_index]->tstate) {
1016 case rtp_StateBad:
1017 LOGGER_DEBUG("Suggesting lower bitrate for video...");
1018 call->time_video_good = 0;
1019 call->last_bad_video_bit_rate = call->video_bit_rate;
1020 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_LOWER_VIDEO_BITRATE);
1021 break;
1022 case rtp_StateGood:
1023 if (call->time_video_good == 0)
1024 call->time_video_good = current_time_monotonic();
1025 else if (current_time_monotonic() - call->time_video_good >= 30000)
1026 if (call->last_bad_video_bit_rate > call->video_bit_rate) {
1027 if (current_time_monotonic() - call->time_video_good >= 45000)
1028 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
1029 call->last_bad_video_bit_rate = 0;
1030 } else
1031 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
1032 break;
1033 case rtp_StateNormal:
1034 call->time_video_good = 0;
1035 break;
1036 }
1037
1038}
1039
1040void call_remove(ToxAVCall* call)
1041{
1042 if (call == NULL)
1043 return;
1044
1045 uint32_t friend_id = call->friend_id;
1046 ToxAV* av = call->av;
1047
1048 ToxAVCall* prev = call->prev;
1049 ToxAVCall* next = call->next;
1050
1051 free(call);
1052
1053 if (prev)
1054 prev->next = next;
1055 else if (next)
1056 av->calls_head = next->friend_id;
1057 else goto CLEAR;
1058
1059 if (next)
1060 next->prev = prev;
1061 else if (prev)
1062 av->calls_tail = prev->friend_id;
1063 else goto CLEAR;
1064
1065 av->calls[friend_id] = NULL;
1066 return;
1067
1068CLEAR:
1069 av->calls_head = av->calls_tail = 0;
1070 free(av->calls);
1071 av->calls = NULL;
1072}
1073
971bool call_prepare_transmission(ToxAVCall* call) 1074bool call_prepare_transmission(ToxAVCall* call)
972{ 1075{
973 /* Assumes mutex locked */ 1076 /* Assumes mutex locked */
@@ -1089,37 +1192,3 @@ void call_kill_transmission(ToxAVCall* call)
1089 pthread_mutex_destroy(call->mutex_video_sending); 1192 pthread_mutex_destroy(call->mutex_video_sending);
1090 pthread_mutex_destroy(call->mutex_decoding); 1193 pthread_mutex_destroy(call->mutex_decoding);
1091} 1194}
1092
1093void call_remove(ToxAVCall* call)
1094{
1095 if (call == NULL)
1096 return;
1097
1098 uint32_t friend_id = call->friend_id;
1099 ToxAV* av = call->av;
1100
1101 ToxAVCall* prev = call->prev;
1102 ToxAVCall* next = call->next;
1103
1104 free(call);
1105
1106 if (prev)
1107 prev->next = next;
1108 else if (next)
1109 av->calls_head = next->friend_id;
1110 else goto CLEAR;
1111
1112 if (next)
1113 next->prev = prev;
1114 else if (prev)
1115 av->calls_tail = prev->friend_id;
1116 else goto CLEAR;
1117
1118 av->calls[friend_id] = NULL;
1119 return;
1120
1121CLEAR:
1122 av->calls_head = av->calls_tail = 0;
1123 free(av->calls);
1124 av->calls = NULL;
1125}