summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-04-26 00:31:03 +0200
committermannol <eniz_vukovic@hotmail.com>2015-04-26 00:31:03 +0200
commit144fc94d6987c8c6f74d8024af5a5c1738fe4678 (patch)
treebc5ad70ea24dafb8e358911ba118fc599f3f9999 /toxav
parent1bfd93e64a2a6d3bf9c90a9aa89abd29f3d826a7 (diff)
Almost done
Diffstat (limited to 'toxav')
-rw-r--r--toxav/audio.c94
-rw-r--r--toxav/audio.h7
-rw-r--r--toxav/av_test.c8
-rw-r--r--toxav/rtp.c276
-rw-r--r--toxav/rtp.h14
-rw-r--r--toxav/toxav.c268
-rw-r--r--toxav/toxav.h78
-rw-r--r--toxav/video.c32
-rw-r--r--toxav/video.h4
9 files changed, 439 insertions, 342 deletions
diff --git a/toxav/audio.c b/toxav/audio.c
index dc85452a..2f068c85 100644
--- a/toxav/audio.c
+++ b/toxav/audio.c
@@ -33,10 +33,11 @@ static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
33static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); 33static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
34 34
35OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count); 35OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count);
36bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
37 int32_t *old_br, int32_t *old_sr, int32_t *old_ch);
36bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); 38bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels);
37 39
38 40
39
40ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data) 41ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data)
41{ 42{
42 ACSession *ac = calloc(sizeof(ACSession), 1); 43 ACSession *ac = calloc(sizeof(ACSession), 1);
@@ -71,10 +72,20 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
71 if (ac->encoder == NULL) 72 if (ac->encoder == NULL)
72 goto DECODER_CLEANUP; 73 goto DECODER_CLEANUP;
73 74
75 ac->test_encoder = create_audio_encoder(48000, 48000, 2);
76 if (ac->test_encoder == NULL) {
77 opus_encoder_destroy(ac->encoder);
78 goto DECODER_CLEANUP;
79 }
80
74 ac->last_encoding_bitrate = 48000; 81 ac->last_encoding_bitrate = 48000;
75 ac->last_encoding_sampling_rate = 48000; 82 ac->last_encoding_sampling_rate = 48000;
76 ac->last_encoding_channel_count = 2; 83 ac->last_encoding_channel_count = 2;
77 84
85 ac->last_test_encoding_bitrate = 48000;
86 ac->last_test_encoding_sampling_rate = 48000;
87 ac->last_test_encoding_channel_count = 2;
88
78 ac->last_decoding_channel_count = 2; 89 ac->last_decoding_channel_count = 2;
79 ac->last_decoding_sampling_rate = 48000; 90 ac->last_decoding_sampling_rate = 48000;
80 ac->last_decoder_reconfiguration = 0; /* Make it possible to reconfigure straight away */ 91 ac->last_decoder_reconfiguration = 0; /* Make it possible to reconfigure straight away */
@@ -141,7 +152,7 @@ void ac_do(ACSession* ac)
141 cs->last_packet_sampling_rate = rc; 152 cs->last_packet_sampling_rate = rc;
142 } else { 153 } else {
143 LOGGER_WARNING("Failed to load packet values!"); 154 LOGGER_WARNING("Failed to load packet values!");
144 rtp_free_msg(NULL, msg); 155 rtp_free_msg(msg);
145 continue; 156 continue;
146 }*/ 157 }*/
147 158
@@ -157,12 +168,12 @@ void ac_do(ACSession* ac)
157 */ 168 */
158 if (!reconfigure_audio_decoder(ac, ac->last_packet_sampling_rate, ac->last_packet_channel_count)) { 169 if (!reconfigure_audio_decoder(ac, ac->last_packet_sampling_rate, ac->last_packet_channel_count)) {
159 LOGGER_WARNING("Failed to reconfigure decoder!"); 170 LOGGER_WARNING("Failed to reconfigure decoder!");
160 rtp_free_msg(NULL, msg); 171 rtp_free_msg(msg);
161 continue; 172 continue;
162 } 173 }
163 174
164 rc = opus_decode(ac->decoder, msg->data + 4, msg->length - 4, tmp, 5760, 0); 175 rc = opus_decode(ac->decoder, msg->data + 4, msg->length - 4, tmp, 5760, 0);
165 rtp_free_msg(NULL, msg); 176 rtp_free_msg(msg);
166 } 177 }
167 178
168 if (rc < 0) { 179 if (rc < 0) {
@@ -183,15 +194,15 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
183 if (!acp || !msg) 194 if (!acp || !msg)
184 return -1; 195 return -1;
185 196
186 if ((msg->header->marker_payloadt & 0x7f) == rtp_TypeDummyAudio % 128) { 197 if ((msg->header->marker_payloadt & 0x7f) == (rtp_TypeAudio + 2) % 128) {
187 LOGGER_WARNING("Got dummy!"); 198 LOGGER_WARNING("Got dummy!");
188 rtp_free_msg(NULL, msg); 199 rtp_free_msg(msg);
189 return 0; 200 return 0;
190 } 201 }
191 202
192 if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeAudio % 128) { 203 if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeAudio % 128) {
193 LOGGER_WARNING("Invalid payload type!"); 204 LOGGER_WARNING("Invalid payload type!");
194 rtp_free_msg(NULL, msg); 205 rtp_free_msg(msg);
195 return -1; 206 return -1;
196 } 207 }
197 208
@@ -203,7 +214,7 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
203 214
204 if (rc == -1) { 215 if (rc == -1) {
205 LOGGER_WARNING("Could not queue the message!"); 216 LOGGER_WARNING("Could not queue the message!");
206 rtp_free_msg(NULL, msg); 217 rtp_free_msg(msg);
207 return -1; 218 return -1;
208 } 219 }
209 220
@@ -211,35 +222,22 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
211} 222}
212int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) 223int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
213{ 224{
214 if (!ac) 225 if (!ac || !reconfigure_audio_encoder(&ac->encoder, bitrate, sampling_rate, channels,
215 return; 226 &ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
216 227 return -1;
217 /* Values are checked in toxav.c */
218 if (ac->last_encoding_sampling_rate != sampling_rate || ac->last_encoding_channel_count != channels) {
219 OpusEncoder* new_encoder = create_audio_encoder(bitrate, sampling_rate, channels);
220 if (new_encoder == NULL)
221 return -1;
222
223 opus_encoder_destroy(ac->encoder);
224 ac->encoder = new_encoder;
225 } else if (ac->last_encoding_bitrate == bitrate)
226 return 0; /* Nothing changed */
227 else {
228 int status = opus_encoder_ctl(ac->encoder, OPUS_SET_BITRATE(bitrate));
229
230 if ( status != OPUS_OK ) {
231 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
232 return -1;
233 }
234 }
235
236 ac->last_encoding_bitrate = bitrate;
237 ac->last_encoding_sampling_rate = sampling_rate;
238 ac->last_encoding_channel_count = channels;
239 228
240 LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels); 229 LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
241 return 0; 230 return 0;
242} 231}
232int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
233{
234 if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bitrate, sampling_rate, channels,
235 &ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
236 return -1;
237
238 LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
239 return 0;
240}
243 241
244 242
245 243
@@ -277,7 +275,7 @@ static void jbuf_clear(struct JitterBuffer *q)
277{ 275{
278 for (; q->bottom != q->top; ++q->bottom) { 276 for (; q->bottom != q->top; ++q->bottom) {
279 if (q->queue[q->bottom % q->size]) { 277 if (q->queue[q->bottom % q->size]) {
280 rtp_free_msg(NULL, q->queue[q->bottom % q->size]); 278 rtp_free_msg(q->queue[q->bottom % q->size]);
281 q->queue[q->bottom % q->size] = NULL; 279 q->queue[q->bottom % q->size] = NULL;
282 } 280 }
283 } 281 }
@@ -372,6 +370,34 @@ FAILURE:
372 opus_encoder_destroy(rc); 370 opus_encoder_destroy(rc);
373 return NULL; 371 return NULL;
374} 372}
373bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
374 int32_t* old_br, int32_t* old_sr, int32_t* old_ch)
375{
376 /* Values are checked in toxav.c */
377 if (*old_sr != new_sr || *old_ch != new_ch) {
378 OpusEncoder* new_encoder = create_audio_encoder(new_br, new_sr, new_ch);
379 if (new_encoder == NULL)
380 return false;
381
382 opus_encoder_destroy(*e);
383 *e = new_encoder;
384 } else if (*old_br == new_br)
385 return true; /* Nothing changed */
386 else {
387 int status = opus_encoder_ctl(*e, OPUS_SET_BITRATE(new_br));
388
389 if ( status != OPUS_OK ) {
390 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
391 return false;
392 }
393 }
394
395 *old_br = new_br;
396 *old_sr = new_sr;
397 *old_ch = new_ch;
398
399 return true;
400}
375bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels) 401bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels)
376{ 402{
377 if (sampling_rate != ac->last_decoding_sampling_rate || channels != ac->last_decoding_channel_count) { 403 if (sampling_rate != ac->last_decoding_sampling_rate || channels != ac->last_decoding_channel_count) {
diff --git a/toxav/audio.h b/toxav/audio.h
index 2cb0d8f6..a36396f1 100644
--- a/toxav/audio.h
+++ b/toxav/audio.h
@@ -38,6 +38,12 @@ typedef struct ACSession_s {
38 int32_t last_encoding_channel_count; 38 int32_t last_encoding_channel_count;
39 int32_t last_encoding_bitrate; 39 int32_t last_encoding_bitrate;
40 40
41 /* Testing encoder for dynamic bitrate streaming */
42 OpusEncoder *test_encoder;
43 int32_t last_test_encoding_sampling_rate;
44 int32_t last_test_encoding_channel_count;
45 int32_t last_test_encoding_bitrate;
46
41 /* decoding */ 47 /* decoding */
42 OpusDecoder *decoder; 48 OpusDecoder *decoder;
43 int32_t last_packet_channel_count; 49 int32_t last_packet_channel_count;
@@ -60,4 +66,5 @@ void ac_kill(ACSession* ac);
60void ac_do(ACSession* ac); 66void ac_do(ACSession* ac);
61int ac_queue_message(void *acp, struct RTPMessage_s *msg); 67int ac_queue_message(void *acp, struct RTPMessage_s *msg);
62int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); 68int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
69int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
63#endif /* AUDIO_H */ \ No newline at end of file 70#endif /* AUDIO_H */ \ No newline at end of file
diff --git a/toxav/av_test.c b/toxav/av_test.c
index dce63184..11de0138 100644
--- a/toxav/av_test.c
+++ b/toxav/av_test.c
@@ -186,7 +186,7 @@ void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
186 unsigned long int i, j; 186 unsigned long int i, j;
187 for (i = 0; i < height; ++i) { 187 for (i = 0; i < height; ++i) {
188 for (j = 0; j < width; ++j) { 188 for (j = 0; j < width; ++j) {
189 uint8_t *point = (void*)img_data + 3 * ((i * width) + j); 189 uint8_t *point = (uint8_t*) img_data + 3 * ((i * width) + j);
190 int yx = y[(i * ystride) + j]; 190 int yx = y[(i * ystride) + j];
191 int ux = u[((i / 2) * ustride) + (j / 2)]; 191 int ux = u[((i / 2) * ustride) + (j / 2)];
192 int vx = v[((i / 2) * vstride) + (j / 2)]; 192 int vx = v[((i / 2) * vstride) + (j / 2)];
@@ -226,7 +226,7 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
226void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) 226void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
227{ 227{
228 if (length == 7 && memcmp("gentoo", data, 7) == 0) { 228 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
229 assert(tox_friend_add_norequest(m, public_key, NULL) != ~0); 229 assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);
230 } 230 }
231} 231}
232 232
@@ -262,7 +262,7 @@ void initialize_tox(Tox** bootstrap, ToxAV** AliceAV, CallControl* AliceCC, ToxA
262 tox_self_get_address(Alice, address); 262 tox_self_get_address(Alice, address);
263 263
264 264
265 assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != ~0); 265 assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
266 266
267 uint8_t off = 1; 267 uint8_t off = 1;
268 268
@@ -563,7 +563,7 @@ int main (int argc, char** argv)
563 } \ 563 } \
564 } \ 564 } \
565 \ 565 \
566 iterate(bootstrap, AliceAV, BobAV); \ 566 iterate_tox(bootstrap, AliceAV, BobAV); \
567 } \ 567 } \
568 printf("Success!\n");\ 568 printf("Success!\n");\
569 } while(0) 569 } while(0)
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 9657da67..a48eba20 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -29,6 +29,7 @@
29 29
30#include "rtp.h" 30#include "rtp.h"
31#include <stdlib.h> 31#include <stdlib.h>
32#include <assert.h>
32 33
33#define size_32 4 34#define size_32 4
34#define RTCP_REPORT_INTERVAL_MS 500 35#define RTCP_REPORT_INTERVAL_MS 500
@@ -37,8 +38,8 @@
37#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) 38#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0)
38#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0) 39#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0)
39#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0) 40#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0)
40#define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0) 41#define ADD_SETTING_MARKER(_h, _v) do { ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0)
41#define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0) 42#define ADD_SETTING_PAYLOAD(_h, _v) do { ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0)
42 43
43#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6) 44#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6)
44#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5) 45#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5)
@@ -70,17 +71,19 @@ typedef struct RTCPSession_s {
70 71
71RTPHeader *parse_header_in ( const uint8_t *payload, int length ); 72RTPHeader *parse_header_in ( const uint8_t *payload, int length );
72RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ); 73RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length );
73RTPMessage *msg_parse ( const uint8_t *data, int length );
74uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload ); 74uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload );
75uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload ); 75uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload );
76void build_header ( RTPSession* session, RTPHeader* header );
77void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
78int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); 76int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
79int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); 77int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
78void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
80 79
81 80
82RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) 81RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
83{ 82{
83 assert(mcb);
84 assert(cs);
85 assert(messenger);
86
84 RTPSession *retu = calloc(1, sizeof(RTPSession)); 87 RTPSession *retu = calloc(1, sizeof(RTPSession));
85 88
86 if ( !retu ) { 89 if ( !retu ) {
@@ -107,6 +110,8 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
107 /* Also set payload type as prefix */ 110 /* Also set payload type as prefix */
108 retu->prefix = payload_type; 111 retu->prefix = payload_type;
109 112
113 retu->cs = cs;
114 retu->mcb = mcb;
110 115
111 /* Initialize rtcp session */ 116 /* Initialize rtcp session */
112 if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) { 117 if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) {
@@ -120,6 +125,14 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
120 retu->rtcp_session->pl_stats = rb_new(4); 125 retu->rtcp_session->pl_stats = rb_new(4);
121 retu->rtcp_session->rtp_session = retu; 126 retu->rtcp_session->rtp_session = retu;
122 127
128 if (-1 == rtp_start_receiving(retu)) {
129 LOGGER_WARNING("Failed to start rtp receiving mode");
130 free(retu->rtcp_session);
131 free(retu->csrc);
132 free(retu);
133 return NULL;
134 }
135
123 return retu; 136 return retu;
124} 137}
125void rtp_kill ( RTPSession *session ) 138void rtp_kill ( RTPSession *session )
@@ -156,11 +169,12 @@ void rtp_do(RTPSession *session)
156 RTCPReport* reports[4]; 169 RTCPReport* reports[4];
157 170
158 int i = 0; 171 int i = 0;
159 for (; rb_read(session->rtcp_session->pl_stats, (void**) reports + i); i++); 172 for (; i < 4; i++)
173 rb_read(session->rtcp_session->pl_stats, (void**) reports + i);
160 174
161 /* Check for timed out reports (> 6 sec) */ 175 /* Check for timed out reports (> 6 sec) */
162 uint64_t now = current_time_monotonic(); 176 uint64_t now = current_time_monotonic();
163 for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++); 177 for (i = 0; i < 4 && (now - reports[i]->timestamp) < 6000; i ++);
164 for (; i < 4; i ++) { 178 for (; i < 4; i ++) {
165 rb_write(session->rtcp_session->pl_stats, reports[i]); 179 rb_write(session->rtcp_session->pl_stats, reports[i]);
166 reports[i] = NULL; 180 reports[i] = NULL;
@@ -168,18 +182,18 @@ void rtp_do(RTPSession *session)
168 if (!rb_empty(session->rtcp_session->pl_stats)) { 182 if (!rb_empty(session->rtcp_session->pl_stats)) {
169 for (i = 0; reports[i] != NULL; i ++) 183 for (i = 0; reports[i] != NULL; i ++)
170 free(reports[i]); 184 free(reports[i]);
171 return; /* As some reports are timed out, we need more... */ 185 return; /* As some reports are timed out, we need more */
172 } 186 }
173 187
174 /* We have 4 on-time reports so we can proceed */ 188 /* We have 4 on-time reports so we can proceed */
175 uint32_t quality = 100; 189 uint32_t quality = 100;
176 for (i = 0; i < 4; i++) { 190 for (i = 0; i < 4; i++) {
177 uint32_t idx = reports[i]->received_packets * 100 / reports[i]->expected_packets; 191 uint32_t current = reports[i]->received_packets * 100 / reports[i]->expected_packets;
178 quality = MIN(quality, idx); 192 quality = MIN(quality, current);
179 free(reports[i]); 193 free(reports[i]);
180 } 194 }
181 195
182 if (quality <= 70) { 196 if (quality <= 90) {
183 session->tstate = rtp_StateBad; 197 session->tstate = rtp_StateBad;
184 LOGGER_WARNING("Stream quality: BAD"); 198 LOGGER_WARNING("Stream quality: BAD");
185 } else if (quality >= 99) { 199 } else if (quality >= 99) {
@@ -220,7 +234,7 @@ int rtp_stop_receiving(RTPSession* session)
220 234
221 return 0; 235 return 0;
222} 236}
223int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) 237int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, bool dummy )
224{ 238{
225 if ( !session ) { 239 if ( !session ) {
226 LOGGER_WARNING("No session!"); 240 LOGGER_WARNING("No session!");
@@ -231,12 +245,31 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
231 uint8_t *it; 245 uint8_t *it;
232 246
233 RTPHeader header[1]; 247 RTPHeader header[1];
234 build_header(session, header); 248 ADD_FLAG_VERSION ( header, session->version );
249 ADD_FLAG_PADDING ( header, session->padding );
250 ADD_FLAG_EXTENSION ( header, session->extension );
251 ADD_FLAG_CSRCC ( header, session->cc );
252 ADD_SETTING_MARKER ( header, session->marker );
253
254 if (dummy)
255 ADD_SETTING_PAYLOAD ( header, (session->payload_type + 2) % 128 );
256 else
257 ADD_SETTING_PAYLOAD ( header, session->payload_type );
235 258
259 header->sequnum = session->sequnum;
260 header->timestamp = current_time_monotonic();
261 header->ssrc = session->ssrc;
262
263 int i;
264 for ( i = 0; i < session->cc; i++ )
265 header->csrc[i] = session->csrc[i];
266
267 header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
268
236 uint32_t parsed_len = length + header->length + 1; 269 uint32_t parsed_len = length + header->length + 1;
270 assert(parsed_len + (session->ext_header ? session->ext_header->length * size_32 : 0) > MAX_RTP_SIZE );
237 271
238 parsed[0] = session->prefix; 272 parsed[0] = session->prefix;
239
240 it = parse_header_out ( header, parsed + 1 ); 273 it = parse_header_out ( header, parsed + 1 );
241 274
242 if ( session->ext_header ) { 275 if ( session->ext_header ) {
@@ -244,8 +277,7 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
244 it = parse_ext_header_out ( session->ext_header, it ); 277 it = parse_ext_header_out ( session->ext_header, it );
245 } 278 }
246 279
247 memcpy ( it, data, length ); 280 memcpy(it, data, length);
248
249 281
250 if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) { 282 if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) {
251 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 283 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
@@ -256,18 +288,11 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
256 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1; 288 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
257 return 0; 289 return 0;
258} 290}
259void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) 291void rtp_free_msg ( RTPMessage *msg )
260{ 292{
261 if ( !session ) { 293 if ( msg->ext_header ) {
262 if ( msg->ext_header ) { 294 free ( msg->ext_header->table );
263 free ( msg->ext_header->table ); 295 free ( msg->ext_header );
264 free ( msg->ext_header );
265 }
266 } else {
267 if ( msg->ext_header && session->ext_header != msg->ext_header ) {
268 free ( msg->ext_header->table );
269 free ( msg->ext_header );
270 }
271 } 296 }
272 297
273 free ( msg->header ); 298 free ( msg->header );
@@ -389,50 +414,6 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
389 414
390 return retu; 415 return retu;
391} 416}
392RTPMessage *msg_parse ( const uint8_t *data, int length )
393{
394 /* TODO: data dynamic, [0]
395 * TODO: dummy payload type
396 * TODO: parse header before allocating message
397 */
398 RTPMessage *retu = calloc(1, sizeof (RTPMessage));
399
400 retu->header = parse_header_in ( data, length ); /* It allocates memory and all */
401
402 if ( !retu->header ) {
403 LOGGER_WARNING("Header failed to extract!");
404 free(retu);
405 return NULL;
406 }
407
408 uint16_t from_pos = retu->header->length;
409 retu->length = length - from_pos;
410
411 if ( GET_FLAG_EXTENSION ( retu->header ) ) {
412 retu->ext_header = parse_ext_header_in ( data + from_pos, length );
413
414 if ( retu->ext_header ) {
415 retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
416 from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
417 } else { /* Error */
418 LOGGER_WARNING("Ext Header failed to extract!");
419 rtp_free_msg(NULL, retu);
420 return NULL;
421 }
422 } else {
423 retu->ext_header = NULL;
424 }
425
426 if ( length - from_pos <= MAX_RTP_SIZE )
427 memcpy ( retu->data, data + from_pos, length - from_pos );
428 else {
429 LOGGER_WARNING("Invalid length!");
430 rtp_free_msg(NULL, retu);
431 return NULL;
432 }
433
434 return retu;
435}
436uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload ) 417uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
437{ 418{
438 uint8_t cc = GET_FLAG_CSRCC ( header ); 419 uint8_t cc = GET_FLAG_CSRCC ( header );
@@ -495,88 +476,95 @@ uint8_t *parse_ext_header_out ( const RTPExtHeader *header, uint8_t *payload )
495 476
496 return it + 4; 477 return it + 4;
497} 478}
498void build_header ( RTPSession *session, RTPHeader *header )
499{
500 ADD_FLAG_VERSION ( header, session->version );
501 ADD_FLAG_PADDING ( header, session->padding );
502 ADD_FLAG_EXTENSION ( header, session->extension );
503 ADD_FLAG_CSRCC ( header, session->cc );
504 ADD_SETTING_MARKER ( header, session->marker );
505 ADD_SETTING_PAYLOAD ( header, session->payload_type );
506
507 header->sequnum = session->sequnum;
508 header->timestamp = current_time_monotonic(); /* milliseconds */
509 header->ssrc = session->ssrc;
510
511 int i;
512 for ( i = 0; i < session->cc; i++ )
513 header->csrc[i] = session->csrc[i];
514
515 header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
516}
517void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
518{
519 if (session->last_expected_packets == 0)
520 return;
521
522 uint8_t parsed[9];
523 parsed[0] = session->prefix;
524
525 uint32_t received_packets = htonl(session->last_received_packets);
526 uint32_t expected_packets = htonl(session->last_expected_packets);
527
528 memcpy(parsed + 1, &received_packets, 4);
529 memcpy(parsed + 5, &expected_packets, 4);
530
531 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
532 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
533 else {
534 LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
535
536 session->last_received_packets = 0;
537 session->last_expected_packets = 0;
538 session->last_sent_report_ts = current_time_monotonic();
539 }
540}
541int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) 479int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
542{ 480{
543 RTPSession *session = object; 481 RTPSession *session = object;
544 RTPMessage *msg;
545 482
546 if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */ 483 if ( !session || length < 13 || length > MAX_RTP_SIZE ) {
547 LOGGER_WARNING("No session or invalid length of received buffer!"); 484 LOGGER_WARNING("No session or invalid length of received buffer!");
548 return -1; 485 return -1;
549 } 486 }
487
488 RTPHeader* header = parse_header_in ( data, length );
550 489
551 msg = msg_parse ( data + 1, length - 1 ); 490 if ( !header ) {
552 491 LOGGER_WARNING("Could not parse message: Header failed to extract!");
553 if ( !msg ) {
554 LOGGER_WARNING("Could not parse message!");
555 return -1; 492 return -1;
556 } 493 }
494
495 RTPExtHeader* ext_header = NULL;
496
497 uint16_t from_pos = header->length;
498 uint16_t msg_length = length - from_pos;
557 499
500 if ( GET_FLAG_EXTENSION ( header ) ) {
501 ext_header = parse_ext_header_in ( data + from_pos, length );
502
503 if ( ext_header ) {
504 msg_length -= ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
505 from_pos += ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
506 } else { /* Error */
507 LOGGER_WARNING("Could not parse message: Ext Header failed to extract!");
508 free(header);
509 return -1;
510 }
511 }
512
513 if (msg_length > MAX_RTP_SIZE) {
514 LOGGER_WARNING("Could not parse message: Invalid length!");
515 free(header);
516 free(ext_header);
517 return -1;
518 }
519
558 /* Check if message came in late */ 520 /* Check if message came in late */
559 if ( msg->header->sequnum > session->rsequnum || msg->header->timestamp > session->rtimestamp ) { 521 if ( header->sequnum > session->rsequnum || header->timestamp > session->rtimestamp ) {
560 /* Not late */ 522 /* Not late */
561 if (msg->header->sequnum > session->rsequnum) 523 if (header->sequnum > session->rsequnum)
562 session->rtcp_session->last_expected_packets += msg->header->sequnum - session->rsequnum; 524 session->rtcp_session->last_expected_packets += header->sequnum - session->rsequnum;
563 else if (msg->header->sequnum < session->rsequnum) 525 else if (header->sequnum < session->rsequnum)
564 session->rtcp_session->last_expected_packets += (msg->header->sequnum + 65535) - session->rsequnum; 526 session->rtcp_session->last_expected_packets += (header->sequnum + 65535) - session->rsequnum;
565 else /* Usual case when transmission starts */ 527 else /* Usual case when transmission starts */
566 session->rtcp_session->last_expected_packets ++; 528 session->rtcp_session->last_expected_packets ++;
567 529
568 session->rsequnum = msg->header->sequnum; 530 session->rsequnum = header->sequnum;
569 session->rtimestamp = msg->header->timestamp; 531 session->rtimestamp = header->timestamp;
570 } 532 }
571 533
572 session->rtcp_session->last_received_packets ++; 534 session->rtcp_session->last_received_packets ++;
573 535
574 if (session->mcb) 536 /* Check if the message is dummy. We don't keep dummy messages */
575 return session->mcb (session->cs, msg); 537 if (GET_SETTING_PAYLOAD(header) == (session->payload_type + 2) % 128) {
576 else { 538 LOGGER_DEBUG("Received dummy rtp message");
577 rtp_free_msg(session, msg); 539 free(header);
540 free(ext_header);
541 return 0;
542 }
543
544 /* Otherwise we will store the message if we have an appropriate handler */
545 if (!session->mcb) {
546 LOGGER_DEBUG("No handler for the message of %d payload", GET_SETTING_PAYLOAD(header));
547 free(header);
548 free(ext_header);
578 return 0; 549 return 0;
579 } 550 }
551
552 RTPMessage *msg = calloc(1, sizeof (RTPMessage) + msg_length);
553
554 if ( !msg ) {
555 LOGGER_WARNING("Could not parse message: Allocation failed!");
556 free(header);
557 free(ext_header);
558 return -1;
559 }
560
561 msg->header = header;
562 msg->ext_header = ext_header;
563 msg->length = msg_length;
564
565 memcpy ( msg->data, data + from_pos, msg_length );
566
567 return session->mcb (session->cs, msg);
580} 568}
581int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) 569int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
582{ 570{
@@ -605,4 +593,28 @@ int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* dat
605 593
606 LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets); 594 LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets);
607 return 0; 595 return 0;
596}
597void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
598{
599 if (session->last_expected_packets == 0)
600 return;
601
602 uint8_t parsed[9];
603 parsed[0] = session->prefix;
604
605 uint32_t received_packets = htonl(session->last_received_packets);
606 uint32_t expected_packets = htonl(session->last_expected_packets);
607
608 memcpy(parsed + 1, &received_packets, 4);
609 memcpy(parsed + 5, &expected_packets, 4);
610
611 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
612 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
613 else {
614 LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
615
616 session->last_received_packets = 0;
617 session->last_expected_packets = 0;
618 session->last_sent_report_ts = current_time_monotonic();
619 }
608} \ No newline at end of file 620} \ No newline at end of file
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 3056b54e..fe07c4f6 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -39,7 +39,7 @@
39} while(0) 39} while(0)
40 40
41#define MAX_SEQU_NUM 65535 41#define MAX_SEQU_NUM 65535
42#define MAX_RTP_SIZE 65535 42#define MAX_RTP_SIZE 1500
43 43
44/** 44/**
45 * Payload type identifier. Also used as rtp callback prefix. (Not dummies) 45 * Payload type identifier. Also used as rtp callback prefix. (Not dummies)
@@ -47,8 +47,6 @@
47enum { 47enum {
48 rtp_TypeAudio = 192, 48 rtp_TypeAudio = 192,
49 rtp_TypeVideo, 49 rtp_TypeVideo,
50 rtp_TypeDummyAudio,
51 rtp_TypeDummyVideo,
52}; 50};
53 51
54typedef enum { 52typedef enum {
@@ -85,8 +83,8 @@ typedef struct RTPMessage_s {
85 RTPHeader *header; 83 RTPHeader *header;
86 RTPExtHeader *ext_header; 84 RTPExtHeader *ext_header;
87 85
88 uint8_t data[MAX_RTP_SIZE];
89 uint32_t length; 86 uint32_t length;
87 uint8_t data[];
90} RTPMessage; 88} RTPMessage;
91 89
92/** 90/**
@@ -128,7 +126,7 @@ typedef struct {
128/** 126/**
129 * Must be called before calling any other rtp function. 127 * Must be called before calling any other rtp function.
130 */ 128 */
131RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ); 129RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) );
132 130
133/** 131/**
134 * Terminate the session. 132 * Terminate the session.
@@ -141,7 +139,7 @@ void rtp_kill ( RTPSession* session );
141void rtp_do(RTPSession *session); 139void rtp_do(RTPSession *session);
142 140
143/** 141/**
144 * By default rtp is not in receiving state 142 * By default rtp is in receiving state
145 */ 143 */
146int rtp_start_receiving (RTPSession *session); 144int rtp_start_receiving (RTPSession *session);
147 145
@@ -153,12 +151,12 @@ int rtp_stop_receiving (RTPSession *session);
153/** 151/**
154 * Sends msg to RTPSession::dest 152 * Sends msg to RTPSession::dest
155 */ 153 */
156int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length ); 154int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
157 155
158/** 156/**
159 * Dealloc msg. 157 * Dealloc msg.
160 */ 158 */
161void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); 159void rtp_free_msg ( RTPMessage *msg );
162 160
163 161
164#endif /* RTP_H */ 162#endif /* RTP_H */
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 5cb614d4..500ca9a8 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -36,6 +36,14 @@
36 36
37#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) 37#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
38 38
39typedef struct ToxAvBitrateAdapter_s {
40 bool active;
41 uint32_t cycle_sent;
42 uint32_t cycle_ratio;
43 uint32_t cycle_repeat;
44 uint64_t start_time;
45 uint32_t bit_rate;
46} ToxAvBitrateAdapter;
39 47
40typedef struct ToxAVCall_s { 48typedef struct ToxAVCall_s {
41 ToxAV* av; 49 ToxAV* av;
@@ -55,7 +63,10 @@ typedef struct ToxAVCall_s {
55 uint32_t audio_bit_rate; /* Sending audio bitrate */ 63 uint32_t audio_bit_rate; /* Sending audio bitrate */
56 uint32_t video_bit_rate; /* Sending video bitrate */ 64 uint32_t video_bit_rate; /* Sending video bitrate */
57 65
58 /** Required for monitoring */ 66 ToxAvBitrateAdapter aba;
67 ToxAvBitrateAdapter vba;
68
69 /** Required for monitoring changes in states */
59 uint8_t previous_self_capabilities; 70 uint8_t previous_self_capabilities;
60 71
61 /** Quality control */ 72 /** Quality control */
@@ -82,8 +93,6 @@ struct toxAV {
82 PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */ 93 PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
83 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ 94 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
84 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ 95 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
85 PAIR(toxav_video_frame_request_cb *, void *) rvcb; /* Video request callback */
86 PAIR(toxav_audio_frame_request_cb *, void *) racb; /* Audio request callback */
87 96
88 /** Decode time measures */ 97 /** Decode time measures */
89 int32_t dmssc; /** Measure count */ 98 int32_t dmssc; /** Measure count */
@@ -103,14 +112,15 @@ int callback_capabilites(void* toxav_inst, MSICall* call);
103bool audio_bitrate_invalid(uint32_t bitrate); 112bool audio_bitrate_invalid(uint32_t bitrate);
104bool video_bitrate_invalid(uint32_t bitrate); 113bool video_bitrate_invalid(uint32_t bitrate);
105void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); 114void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
115void qc_do(ToxAVCall* call);
106ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); 116ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
107ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); 117ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
108void qc_do(ToxAVCall* call);
109void call_remove(ToxAVCall* call); 118void call_remove(ToxAVCall* call);
110bool call_prepare_transmission(ToxAVCall* call); 119bool call_prepare_transmission(ToxAVCall* call);
111void call_kill_transmission(ToxAVCall* call); 120void call_kill_transmission(ToxAVCall* call);
112 121void ba_set(ToxAvBitrateAdapter* ba, uint32_t bit_rate);
113 122bool ba_shoud_send_dummy(ToxAvBitrateAdapter* ba);
123void ba_update_sent_regular(ToxAvBitrateAdapter* ba);
114 124
115ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) 125ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
116{ 126{
@@ -300,7 +310,7 @@ void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data)
300 av->ccb.first = function; 310 av->ccb.first = function;
301 av->ccb.second = user_data; 311 av->ccb.second = user_data;
302 pthread_mutex_unlock(av->mutex); 312 pthread_mutex_unlock(av->mutex);
303} 313}/** Required for monitoring */
304 314
305bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) 315bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
306{ 316{
@@ -505,7 +515,7 @@ END:
505 return rc == TOXAV_ERR_CALL_CONTROL_OK; 515 return rc == TOXAV_ERR_CALL_CONTROL_OK;
506} 516}
507 517
508bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error) 518bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE* error)
509{ 519{
510 TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK; 520 TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK;
511 ToxAVCall* call; 521 ToxAVCall* call;
@@ -528,9 +538,17 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
528 goto END; 538 goto END;
529 } 539 }
530 540
531 /* Decoding mutex is locked because of quality control */ 541 if (call->audio_bit_rate == audio_bit_rate && call->aba.active && call->aba.bit_rate == audio_bit_rate) {
542 pthread_mutex_unlock(av->mutex);
543 goto END;
544 }
545
532 pthread_mutex_lock(call->mutex); 546 pthread_mutex_lock(call->mutex);
533 call->audio_bit_rate = audio_bit_rate; 547 if (force) {
548 call->audio_bit_rate = audio_bit_rate;
549 } else
550 ba_set(&call->aba, audio_bit_rate);
551
534 pthread_mutex_unlock(call->mutex); 552 pthread_mutex_unlock(call->mutex);
535 pthread_mutex_unlock(av->mutex); 553 pthread_mutex_unlock(av->mutex);
536 554
@@ -541,7 +559,7 @@ END:
541 return rc == TOXAV_ERR_BIT_RATE_OK; 559 return rc == TOXAV_ERR_BIT_RATE_OK;
542} 560}
543 561
544bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error) 562bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, bool force, TOXAV_ERR_BIT_RATE* error)
545{ 563{
546 TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK; 564 TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK;
547 ToxAVCall* call; 565 ToxAVCall* call;
@@ -564,9 +582,17 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
564 goto END; 582 goto END;
565 } 583 }
566 584
567 /* Decoding mutex is locked because of quality control */ 585 if (call->video_bit_rate == video_bit_rate && call->vba.active && call->vba.bit_rate == video_bit_rate) {
586 pthread_mutex_unlock(av->mutex);
587 goto END;
588 }
589
568 pthread_mutex_lock(call->mutex); 590 pthread_mutex_lock(call->mutex);
569 call->video_bit_rate = video_bit_rate; 591 if (force) {
592 call->video_bit_rate = video_bit_rate;
593 } else {
594 ba_set(&call->vba, video_bit_rate);
595 }
570 pthread_mutex_unlock(call->mutex); 596 pthread_mutex_unlock(call->mutex);
571 pthread_mutex_unlock(av->mutex); 597 pthread_mutex_unlock(av->mutex);
572 598
@@ -577,14 +603,6 @@ END:
577 return rc == TOXAV_ERR_BIT_RATE_OK; 603 return rc == TOXAV_ERR_BIT_RATE_OK;
578} 604}
579 605
580void toxav_callback_video_frame_request(ToxAV* av, toxav_video_frame_request_cb* function, void* user_data)
581{
582 pthread_mutex_lock(av->mutex);
583 av->rvcb.first = function;
584 av->rvcb.second = user_data;
585 pthread_mutex_unlock(av->mutex);
586}
587
588bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error) 606bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error)
589{ 607{
590 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK; 608 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
@@ -630,7 +648,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
630 memcpy(img.planes[VPX_PLANE_U], u, (width/2) * (height/2)); 648 memcpy(img.planes[VPX_PLANE_U], u, (width/2) * (height/2));
631 memcpy(img.planes[VPX_PLANE_V], v, (width/2) * (height/2)); 649 memcpy(img.planes[VPX_PLANE_V], v, (width/2) * (height/2));
632 650
633 int vrc = vpx_codec_encode(call->video.second->v_encoder, &img, 651 int vrc = vpx_codec_encode(call->video.second->encoder, &img,
634 call->video.second->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 652 call->video.second->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
635 653
636 vpx_img_free(&img); 654 vpx_img_free(&img);
@@ -650,7 +668,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
650 668
651 vc_init_video_splitter_cycle(call->video.second); 669 vc_init_video_splitter_cycle(call->video.second);
652 670
653 while ( (pkt = vpx_codec_get_cx_data(call->video.second->v_encoder, &iter)) ) { 671 while ( (pkt = vpx_codec_get_cx_data(call->video.second->encoder, &iter)) ) {
654 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 672 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
655 int parts = vc_update_video_splitter_cycle(call->video.second, pkt->data.frame.buf, 673 int parts = vc_update_video_splitter_cycle(call->video.second, pkt->data.frame.buf,
656 pkt->data.frame.sz); 674 pkt->data.frame.sz);
@@ -665,7 +683,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
665 for (i = 0; i < parts; i++) { 683 for (i = 0; i < parts; i++) {
666 iter = vc_iterate_split_video_frame(call->video.second, &part_size); 684 iter = vc_iterate_split_video_frame(call->video.second, &part_size);
667 685
668 if (rtp_send_msg(call->video.first, iter, part_size) < 0) { 686 if (rtp_send_data(call->video.first, iter, part_size, false) < 0) {
669 pthread_mutex_unlock(call->mutex_video); 687 pthread_mutex_unlock(call->mutex_video);
670 LOGGER_WARNING("Could not send video frame: %s\n", strerror(errno)); 688 LOGGER_WARNING("Could not send video frame: %s\n", strerror(errno));
671 goto END; 689 goto END;
@@ -684,14 +702,6 @@ END:
684 return rc == TOXAV_ERR_SEND_FRAME_OK; 702 return rc == TOXAV_ERR_SEND_FRAME_OK;
685} 703}
686 704
687void toxav_callback_audio_frame_request(ToxAV* av, toxav_audio_frame_request_cb* function, void* user_data)
688{
689 pthread_mutex_lock(av->mutex);
690 av->racb.first = function;
691 av->racb.second = user_data;
692 pthread_mutex_unlock(av->mutex);
693}
694
695bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error) 705bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error)
696{ 706{
697 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK; 707 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
@@ -746,13 +756,41 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc
746 goto END; 756 goto END;
747 } 757 }
748 758
749// LOGGER_DEBUG("Sending encoded audio frame size: %d; channels: %d; srate: %d", vrc, channels, 759 if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), false) != 0) {
750// ntohl(sampling_rate));
751
752 if (rtp_send_msg(call->audio.first, dest, vrc + sizeof(sampling_rate)) != 0) {
753 LOGGER_WARNING("Failed to send audio packet"); 760 LOGGER_WARNING("Failed to send audio packet");
754 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED; 761 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
755 } 762 }
763
764
765 /* For bitrate measurement; send dummy packet */
766 if (ba_shoud_send_dummy(&call->aba)) {
767 sampling_rate = ntohl(sampling_rate);
768 if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
769 /* FIXME should the bitrate changing fail here? */
770 pthread_mutex_unlock(call->mutex_audio);
771 rc = TOXAV_ERR_SEND_FRAME_INVALID;
772 goto END;
773 }
774
775 sampling_rate = htonl(sampling_rate);
776 memcpy(dest, &sampling_rate, sizeof(sampling_rate));
777 vrc = opus_encode(call->audio.second->test_encoder, pcm, sample_count,
778 dest + sizeof(sampling_rate), sizeof(dest) - sizeof(sampling_rate));
779
780 if (vrc < 0) {
781 LOGGER_WARNING("Failed to encode frame %s", opus_strerror(vrc));
782 pthread_mutex_unlock(call->mutex_audio);
783 rc = TOXAV_ERR_SEND_FRAME_INVALID;
784 goto END;
785 }
786
787 if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), true) != 0) {
788 LOGGER_WARNING("Failed to send audio packet");
789 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
790 }
791 }
792
793 ba_update_sent_regular(&call->aba);
756 } 794 }
757 795
758 pthread_mutex_unlock(call->mutex_audio); 796 pthread_mutex_unlock(call->mutex_audio);
@@ -894,6 +932,57 @@ void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state)
894 av->scb.first(av, friend_number, state, av->scb.second); 932 av->scb.first(av, friend_number, state, av->scb.second);
895} 933}
896 934
935void qc_do(ToxAVCall* call)
936{
937 /*
938 switch(call->audio.first->tstate) {
939 case rtp_StateBad:
940 LOGGER_DEBUG("Suggesting lower bitrate for audio...");
941 call->time_audio_good = 0;
942 call->last_bad_audio_bit_rate = call->audio_bit_rate;
943 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE);
944 break;
945 case rtp_StateGood:
946 if (call->time_audio_good == 0)
947 call->time_audio_good = current_time_monotonic();
948 else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
949 64 > call->audio_bit_rate)
950 if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
951 if (current_time_monotonic() - call->time_audio_good >= 45000)
952 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
953 call->last_bad_audio_bit_rate = 0;
954 } else
955 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
956 break;
957 case rtp_StateNormal:
958 call->time_audio_good = 0;
959 break;
960 }*/
961 /*
962 switch(call->video.first->tstate) {
963 case rtp_StateBad:
964 LOGGER_DEBUG("Suggesting lower bitrate for video...");
965 call->time_video_good = 0;
966 call->last_bad_video_bit_rate = call->video_bit_rate;
967 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE);
968 break;
969 case rtp_StateGood:
970 if (call->time_video_good == 0)
971 call->time_video_good = current_time_monotonic();
972 else if (current_time_monotonic() - call->time_video_good >= 30000)
973 if (call->last_bad_video_bit_rate > call->video_bit_rate) {
974 if (current_time_monotonic() - call->time_video_good >= 45000)
975 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
976 call->last_bad_video_bit_rate = 0;
977 } else
978 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
979 break;
980 case rtp_StateNormal:
981 call->time_video_good = 0;
982 break;
983 }*/
984}
985
897ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) 986ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
898{ 987{
899 /* Assumes mutex locked */ 988 /* Assumes mutex locked */
@@ -984,57 +1073,6 @@ ToxAVCall* call_get(ToxAV* av, uint32_t friend_number)
984 return av->calls[friend_number]; 1073 return av->calls[friend_number];
985} 1074}
986 1075
987void qc_do(ToxAVCall* call)
988{
989 /*
990 switch(call->audio.first->tstate) {
991 case rtp_StateBad:
992 LOGGER_DEBUG("Suggesting lower bitrate for audio...");
993 call->time_audio_good = 0;
994 call->last_bad_audio_bit_rate = call->audio_bit_rate;
995 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE);
996 break;
997 case rtp_StateGood:
998 if (call->time_audio_good == 0)
999 call->time_audio_good = current_time_monotonic();
1000 else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
1001 64 > call->audio_bit_rate)
1002 if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
1003 if (current_time_monotonic() - call->time_audio_good >= 45000)
1004 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
1005 call->last_bad_audio_bit_rate = 0;
1006 } else
1007 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
1008 break;
1009 case rtp_StateNormal:
1010 call->time_audio_good = 0;
1011 break;
1012 }*/
1013 /*
1014 switch(call->video.first->tstate) {
1015 case rtp_StateBad:
1016 LOGGER_DEBUG("Suggesting lower bitrate for video...");
1017 call->time_video_good = 0;
1018 call->last_bad_video_bit_rate = call->video_bit_rate;
1019 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE);
1020 break;
1021 case rtp_StateGood:
1022 if (call->time_video_good == 0)
1023 call->time_video_good = current_time_monotonic();
1024 else if (current_time_monotonic() - call->time_video_good >= 30000)
1025 if (call->last_bad_video_bit_rate > call->video_bit_rate) {
1026 if (current_time_monotonic() - call->time_video_good >= 45000)
1027 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
1028 call->last_bad_video_bit_rate = 0;
1029 } else
1030 invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
1031 break;
1032 case rtp_StateNormal:
1033 call->time_video_good = 0;
1034 break;
1035 }*/
1036}
1037
1038void call_remove(ToxAVCall* call) 1076void call_remove(ToxAVCall* call)
1039{ 1077{
1040 if (call == NULL) 1078 if (call == NULL)
@@ -1098,41 +1136,24 @@ bool call_prepare_transmission(ToxAVCall* call)
1098 goto VIDEO_SENDING_MUTEX_CLEANUP; 1136 goto VIDEO_SENDING_MUTEX_CLEANUP;
1099 } 1137 }
1100 1138
1101
1102 { /* Prepare audio */ 1139 { /* Prepare audio */
1103 call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id);
1104 call->audio.second = ac_new(av, call->friend_id, av->acb.first, av->acb.second); 1140 call->audio.second = ac_new(av, call->friend_id, av->acb.first, av->acb.second);
1141 call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id, call->audio.second, ac_queue_message);
1105 1142
1106 if ( !call->audio.first || !call->audio.second ) { 1143 if ( !call->audio.first || !call->audio.second ) {
1107 LOGGER_ERROR("Error while starting audio!\n"); 1144 LOGGER_ERROR("Error while starting audio!\n");
1108 goto FAILURE; 1145 goto FAILURE;
1109 } 1146 }
1110
1111 call->audio.first->cs = call->audio.second;
1112 call->audio.first->mcb = ac_queue_message;
1113
1114 if (rtp_start_receiving(call->audio.first) != 0) {
1115 LOGGER_WARNING("Failed to enable audio receiving!");
1116 goto FAILURE;
1117 }
1118 } 1147 }
1119 1148
1120 { /* Prepare video */ 1149 { /* Prepare video */
1121 call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id);
1122 call->video.second = vc_new(av, call->friend_id, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz); 1150 call->video.second = vc_new(av, call->friend_id, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz);
1151 call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id, call->video.second, vc_queue_message);
1123 1152
1124 if ( !call->video.first || !call->video.second ) { 1153 if ( !call->video.first || !call->video.second ) {
1125 LOGGER_ERROR("Error while starting video!\n"); 1154 LOGGER_ERROR("Error while starting video!\n");
1126 goto FAILURE; 1155 goto FAILURE;
1127 } 1156 }
1128
1129 call->video.first->cs = call->video.second;
1130 call->video.first->mcb = vc_queue_message;
1131
1132 if (rtp_start_receiving(call->video.first) != 0) {
1133 LOGGER_WARNING("Failed to enable video receiving!");
1134 goto FAILURE;
1135 }
1136 } 1157 }
1137 1158
1138 call->active = 1; 1159 call->active = 1;
@@ -1183,3 +1204,38 @@ void call_kill_transmission(ToxAVCall* call)
1183 pthread_mutex_destroy(call->mutex_video); 1204 pthread_mutex_destroy(call->mutex_video);
1184 pthread_mutex_destroy(call->mutex); 1205 pthread_mutex_destroy(call->mutex);
1185} 1206}
1207
1208void ba_set(ToxAvBitrateAdapter* ba, uint32_t bit_rate)
1209{
1210 ba->bit_rate = bit_rate;
1211 ba->start_time = current_time_monotonic();
1212 ba->cycle_sent = 0;
1213 ba->cycle_repeat = 3;
1214 ba->cycle_ratio = 4;
1215 ba->active = true;
1216}
1217
1218bool ba_shoud_send_dummy(ToxAvBitrateAdapter* ba)
1219{
1220 if (!ba->active || ba->cycle_ratio == 0)
1221 return false;
1222
1223 if (ba->cycle_sent % ba->cycle_ratio == 0)
1224 return true;
1225}
1226
1227void ba_update_sent_regular(ToxAvBitrateAdapter* ba)
1228{
1229 if (!ba->active || ba->cycle_ratio == 0) {
1230 ba->active = false;
1231 return;
1232 }
1233
1234 if (ba->cycle_sent % ba->cycle_ratio == 0) {
1235 ba->cycle_sent = 0;
1236
1237 if (--ba->cycle_repeat == 0)
1238 --ba->cycle_ratio;
1239 } else
1240 ++ba->cycle_sent;
1241}
diff --git a/toxav/toxav.h b/toxav/toxav.h
index bf8756eb..f2c3b2b3 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -217,22 +217,6 @@ typedef enum TOXAV_CALL_STATE {
217 */ 217 */
218 TOXAV_CALL_STATE_END = 16, 218 TOXAV_CALL_STATE_END = 16,
219 /** 219 /**
220 * AV core suggests you to lower bitrate for audio.
221 */
222 TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE = 32,
223 /**
224 * AV core suggests you to lower bitrate for video.
225 */
226 TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE = 64,
227 /**
228 * AV core suggests you to increase bitrate for audio.
229 */
230 TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE = 128,
231 /**
232 * AV core suggests you to increase bitrate for video.
233 */
234 TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE = 256,
235 /**
236 * Set by the AV core if an error occurred on the remote end. 220 * Set by the AV core if an error occurred on the remote end.
237 */ 221 */
238 TOXAV_CALL_STATE_ERROR = 32768 222 TOXAV_CALL_STATE_ERROR = 32768
@@ -349,6 +333,24 @@ typedef enum TOXAV_ERR_BIT_RATE {
349 TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL 333 TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
350} TOXAV_ERR_BIT_RATE; 334} TOXAV_ERR_BIT_RATE;
351/** 335/**
336 * The function type for the `audio_bitrate_control` callback.
337 *
338 * @param friend_number The friend number of the friend for which to set the
339 * audio bit rate.
340 * @param good Is the stream good enough to keep the said bitrate. Upon failed
341 * non forceful bit rate setup this will be set to false and 'bit_rate'
342 * will be set to the bit rate that failed, otherwise 'good' will be set to
343 * true with 'bit_rate' set to new bit rate. If the stream becomes bad,
344 * the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
345 * This callback will never be called when the stream is good.
346 * @param bit_rate The bit rate in Kb/sec.
347 */
348typedef void toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
349/**
350 * Set the callback for the `audio_bitrate_control` event. Pass NULL to unset.
351 */
352void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control_cb *function, void *user_data);
353/**
352 * Set the audio bit rate to be used in subsequent audio frames. 354 * Set the audio bit rate to be used in subsequent audio frames.
353 * 355 *
354 * @param friend_number The friend number of the friend for which to set the 356 * @param friend_number The friend number of the friend for which to set the
@@ -358,7 +360,25 @@ typedef enum TOXAV_ERR_BIT_RATE {
358 * 360 *
359 * @see toxav_call for the valid bit rates. 361 * @see toxav_call for the valid bit rates.
360 */ 362 */
361bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE *error); 363bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
364/**
365 * The function type for the `video_bitrate_control` callback.
366 *
367 * @param friend_number The friend number of the friend for which to set the
368 * video bit rate.
369 * @param good Is the stream good enough to keep the said bitrate. Upon failed
370 * non forceful bit rate setup this will be set to false and 'bit_rate'
371 * will be set to the bit rate that failed, otherwise 'good' will be set to
372 * true with 'bit_rate' set to new bit rate. If the stream becomes bad,
373 * the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
374 * This callback will never be called when the stream is good.
375 * @param bit_rate The bit rate in Kb/sec.
376 */
377typedef void toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
378/**
379 * Set the callback for the `video_bitrate_control` event. Pass NULL to unset.
380 */
381void toxav_callback_video_bitrate_control(ToxAV *av, toxav_video_bitrate_control_cb *function, void *user_data);
362/** 382/**
363 * Set the video bit rate to be used in subsequent video frames. 383 * Set the video bit rate to be used in subsequent video frames.
364 * 384 *
@@ -369,7 +389,7 @@ bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
369 * 389 *
370 * @see toxav_call for the valid bit rates. 390 * @see toxav_call for the valid bit rates.
371 */ 391 */
372bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE *error); 392bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
373/******************************************************************************* 393/*******************************************************************************
374 * 394 *
375 * :: A/V sending 395 * :: A/V sending
@@ -409,17 +429,6 @@ typedef enum TOXAV_ERR_SEND_FRAME {
409 TOXAV_ERR_SEND_FRAME_RTP_FAILED 429 TOXAV_ERR_SEND_FRAME_RTP_FAILED
410} TOXAV_ERR_SEND_FRAME; 430} TOXAV_ERR_SEND_FRAME;
411/** 431/**
412 * The function type for the `video_frame_request` callback.
413 *
414 * @param friend_number The friend number of the friend for which the next video
415 * frame should be sent.
416 */
417typedef void toxav_video_frame_request_cb(ToxAV *av, uint32_t friend_number, void *user_data);
418/**
419 * Set the callback for the `video_frame_request` event. Pass NULL to unset.
420 */
421void toxav_callback_video_frame_request(ToxAV *av, toxav_video_frame_request_cb *function, void *user_data);
422/**
423 * Send a video frame to a friend. 432 * Send a video frame to a friend.
424 * 433 *
425 * This is called in response to receiving the `video_frame_request` event. 434 * This is called in response to receiving the `video_frame_request` event.
@@ -441,17 +450,6 @@ bool toxav_send_video_frame(ToxAV *av, uint32_t friend_number,
441 uint8_t const *y, uint8_t const *u, uint8_t const *v, 450 uint8_t const *y, uint8_t const *u, uint8_t const *v,
442 TOXAV_ERR_SEND_FRAME *error); 451 TOXAV_ERR_SEND_FRAME *error);
443/** 452/**
444 * The function type for the `audio_frame_request` callback.
445 *
446 * @param friend_number The friend number of the friend for which the next audio
447 * frame should be sent.
448 */
449typedef void toxav_audio_frame_request_cb(ToxAV *av, uint32_t friend_number, void *user_data);
450/**
451 * Set the callback for the `audio_frame_request` event. Pass NULL to unset.
452 */
453void toxav_callback_audio_frame_request(ToxAV *av, toxav_audio_frame_request_cb *function, void *user_data);
454/**
455 * Send an audio frame to a friend. 453 * Send an audio frame to a friend.
456 * 454 *
457 * This is called in response to receiving the `audio_frame_request` event. 455 * This is called in response to receiving the `audio_frame_request` event.
diff --git a/toxav/video.c b/toxav/video.c
index 039fc2a0..cdc3c0ae 100644
--- a/toxav/video.c
+++ b/toxav/video.c
@@ -65,15 +65,15 @@ VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* c
65 if ( !(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE)) ) 65 if ( !(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE)) )
66 goto BASE_CLEANUP; 66 goto BASE_CLEANUP;
67 67
68 int rc = vpx_codec_dec_init_ver(vc->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, 68 int rc = vpx_codec_dec_init_ver(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE,
69 NULL, 0, VPX_DECODER_ABI_VERSION); 69 NULL, 0, VPX_DECODER_ABI_VERSION);
70 if ( rc != VPX_CODEC_OK) { 70 if ( rc != VPX_CODEC_OK) {
71 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); 71 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
72 goto BASE_CLEANUP; 72 goto BASE_CLEANUP;
73 } 73 }
74 74
75 if (!create_video_encoder(vc->v_encoder, 500000)) { 75 if (!create_video_encoder(vc->encoder, 500000)) {
76 vpx_codec_destroy(vc->v_decoder); 76 vpx_codec_destroy(vc->decoder);
77 goto BASE_CLEANUP; 77 goto BASE_CLEANUP;
78 } 78 }
79 79
@@ -99,8 +99,8 @@ void vc_kill(VCSession* vc)
99 if (!vc) 99 if (!vc)
100 return; 100 return;
101 101
102 vpx_codec_destroy(vc->v_encoder); 102 vpx_codec_destroy(vc->encoder);
103 vpx_codec_destroy(vc->v_decoder); 103 vpx_codec_destroy(vc->decoder);
104 rb_free(vc->vbuf_raw); 104 rb_free(vc->vbuf_raw);
105 free(vc->split_video_frame); 105 free(vc->split_video_frame);
106 free(vc->frame_buf); 106 free(vc->frame_buf);
@@ -122,17 +122,17 @@ void vc_do(VCSession* vc)
122 if (rb_read(vc->vbuf_raw, (void**)&p)) { 122 if (rb_read(vc->vbuf_raw, (void**)&p)) {
123 pthread_mutex_unlock(vc->queue_mutex); 123 pthread_mutex_unlock(vc->queue_mutex);
124 124
125 rc = vpx_codec_decode(vc->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); 125 rc = vpx_codec_decode(vc->decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
126 free(p); 126 free(p);
127 127
128 if (rc != VPX_CODEC_OK) { 128 if (rc != VPX_CODEC_OK) {
129 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc)); 129 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
130 } else { 130 } else {
131 vpx_codec_iter_t iter = NULL; 131 vpx_codec_iter_t iter = NULL;
132 vpx_image_t *dest = vpx_codec_get_frame(vc->v_decoder, &iter); 132 vpx_image_t *dest = vpx_codec_get_frame(vc->decoder, &iter);
133 133
134 /* Play decoded images */ 134 /* Play decoded images */
135 for (; dest; dest = vpx_codec_get_frame(vc->v_decoder, &iter)) { 135 for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
136 if (vc->vcb.first) 136 if (vc->vcb.first)
137 vc->vcb.first(vc->av, vc->friend_id, dest->d_w, dest->d_h, 137 vc->vcb.first(vc->av, vc->friend_id, dest->d_w, dest->d_h,
138 (const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2], 138 (const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2],
@@ -157,7 +157,7 @@ void vc_init_video_splitter_cycle(VCSession* vc)
157int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length) 157int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length)
158{ 158{
159 if (!vc) 159 if (!vc)
160 return; 160 return 0;
161 161
162 vc->processing_video_frame = payload; 162 vc->processing_video_frame = payload;
163 vc->processing_video_frame_size = length; 163 vc->processing_video_frame_size = length;
@@ -198,15 +198,15 @@ int vc_queue_message(void* vcp, struct RTPMessage_s *msg)
198 if (!vcp || !msg) 198 if (!vcp || !msg)
199 return -1; 199 return -1;
200 200
201 if ((msg->header->marker_payloadt & 0x7f) == rtp_TypeDummyVideo % 128) { 201 if ((msg->header->marker_payloadt & 0x7f) == (rtp_TypeVideo + 2) % 128) {
202 LOGGER_WARNING("Got dummy!"); 202 LOGGER_WARNING("Got dummy!");
203 rtp_free_msg(NULL, msg); 203 rtp_free_msg(msg);
204 return 0; 204 return 0;
205 } 205 }
206 206
207 if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeVideo % 128) { 207 if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeVideo % 128) {
208 LOGGER_WARNING("Invalid payload type!"); 208 LOGGER_WARNING("Invalid payload type!");
209 rtp_free_msg(NULL, msg); 209 rtp_free_msg(msg);
210 return -1; 210 return -1;
211 } 211 }
212 212
@@ -280,15 +280,15 @@ int vc_queue_message(void* vcp, struct RTPMessage_s *msg)
280 vc->frame_size = framebuf_new_length; 280 vc->frame_size = framebuf_new_length;
281 281
282end: 282end:
283 rtp_free_msg(NULL, msg); 283 rtp_free_msg(msg);
284 return 0; 284 return 0;
285} 285}
286int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) 286int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height)
287{ 287{
288 if (!vc) 288 if (!vc)
289 return; 289 return -1;
290 290
291 vpx_codec_enc_cfg_t cfg = *vc->v_encoder[0].config.enc; 291 vpx_codec_enc_cfg_t cfg = *vc->encoder[0].config.enc;
292 if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height) 292 if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height)
293 return 0; /* Nothing changed */ 293 return 0; /* Nothing changed */
294 294
@@ -296,7 +296,7 @@ int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint1
296 cfg.g_w = width; 296 cfg.g_w = width;
297 cfg.g_h = height; 297 cfg.g_h = height;
298 298
299 int rc = vpx_codec_enc_config_set(vc->v_encoder, &cfg); 299 int rc = vpx_codec_enc_config_set(vc->encoder, &cfg);
300 if ( rc != VPX_CODEC_OK) { 300 if ( rc != VPX_CODEC_OK) {
301 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 301 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
302 return -1; 302 return -1;
diff --git a/toxav/video.h b/toxav/video.h
index ed264f36..9c5836a3 100644
--- a/toxav/video.h
+++ b/toxav/video.h
@@ -41,11 +41,11 @@ struct RTPMessage_s;
41typedef struct VCSession_s { 41typedef struct VCSession_s {
42 42
43 /* encoding */ 43 /* encoding */
44 vpx_codec_ctx_t v_encoder[1]; 44 vpx_codec_ctx_t encoder[1];
45 uint32_t frame_counter; 45 uint32_t frame_counter;
46 46
47 /* decoding */ 47 /* decoding */
48 vpx_codec_ctx_t v_decoder[1]; 48 vpx_codec_ctx_t decoder[1];
49 void *vbuf_raw; /* Un-decoded data */ 49 void *vbuf_raw; /* Un-decoded data */
50 50
51 /* Data handling */ 51 /* Data handling */