diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-04-26 00:31:03 +0200 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-04-26 00:31:03 +0200 |
commit | 144fc94d6987c8c6f74d8024af5a5c1738fe4678 (patch) | |
tree | bc5ad70ea24dafb8e358911ba118fc599f3f9999 | |
parent | 1bfd93e64a2a6d3bf9c90a9aa89abd29f3d826a7 (diff) |
Almost done
-rw-r--r-- | toxav/audio.c | 94 | ||||
-rw-r--r-- | toxav/audio.h | 7 | ||||
-rw-r--r-- | toxav/av_test.c | 8 | ||||
-rw-r--r-- | toxav/rtp.c | 276 | ||||
-rw-r--r-- | toxav/rtp.h | 14 | ||||
-rw-r--r-- | toxav/toxav.c | 268 | ||||
-rw-r--r-- | toxav/toxav.h | 78 | ||||
-rw-r--r-- | toxav/video.c | 32 | ||||
-rw-r--r-- | toxav/video.h | 4 |
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); | |||
33 | static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); | 33 | static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); |
34 | 34 | ||
35 | OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count); | 35 | OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count); |
36 | bool 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); | ||
36 | bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); | 38 | bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); |
37 | 39 | ||
38 | 40 | ||
39 | |||
40 | ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data) | 41 | ACSession* 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 | } |
212 | int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) | 223 | int 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 | } |
232 | int 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 | } |
373 | bool 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 | } | ||
375 | bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels) | 401 | bool 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); | |||
60 | void ac_do(ACSession* ac); | 66 | void ac_do(ACSession* ac); |
61 | int ac_queue_message(void *acp, struct RTPMessage_s *msg); | 67 | int ac_queue_message(void *acp, struct RTPMessage_s *msg); |
62 | int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); | 68 | int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); |
69 | int 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, | |||
226 | void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata) | 226 | void 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 | ||
71 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ); | 72 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ); |
72 | RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ); | 73 | RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ); |
73 | RTPMessage *msg_parse ( const uint8_t *data, int length ); | ||
74 | uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload ); | 74 | uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload ); |
75 | uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload ); | 75 | uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload ); |
76 | void build_header ( RTPSession* session, RTPHeader* header ); | ||
77 | void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber ); | ||
78 | int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); | 76 | int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); |
79 | int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); | 77 | int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); |
78 | void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber ); | ||
80 | 79 | ||
81 | 80 | ||
82 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) | 81 | RTPSession *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 | } |
125 | void rtp_kill ( RTPSession *session ) | 138 | void 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 | } |
223 | int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) | 237 | int 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 | } |
259 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) | 291 | void 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 | } |
392 | RTPMessage *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 | } | ||
436 | uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload ) | 417 | uint8_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 | } |
498 | void 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 | } | ||
517 | void 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 | } | ||
541 | int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) | 479 | int 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 | } |
581 | int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) | 569 | int 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 | } | ||
597 | void 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 @@ | |||
47 | enum { | 47 | enum { |
48 | rtp_TypeAudio = 192, | 48 | rtp_TypeAudio = 192, |
49 | rtp_TypeVideo, | 49 | rtp_TypeVideo, |
50 | rtp_TypeDummyAudio, | ||
51 | rtp_TypeDummyVideo, | ||
52 | }; | 50 | }; |
53 | 51 | ||
54 | typedef enum { | 52 | typedef 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 | */ |
131 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ); | 129 | RTPSession *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 ); | |||
141 | void rtp_do(RTPSession *session); | 139 | void 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 | */ |
146 | int rtp_start_receiving (RTPSession *session); | 144 | int 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 | */ |
156 | int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length ); | 154 | int 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 | */ |
161 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); | 159 | void 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 | ||
39 | typedef 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 | ||
40 | typedef struct ToxAVCall_s { | 48 | typedef 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); | |||
103 | bool audio_bitrate_invalid(uint32_t bitrate); | 112 | bool audio_bitrate_invalid(uint32_t bitrate); |
104 | bool video_bitrate_invalid(uint32_t bitrate); | 113 | bool video_bitrate_invalid(uint32_t bitrate); |
105 | void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); | 114 | void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); |
115 | void qc_do(ToxAVCall* call); | ||
106 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); | 116 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); |
107 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); | 117 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); |
108 | void qc_do(ToxAVCall* call); | ||
109 | void call_remove(ToxAVCall* call); | 118 | void call_remove(ToxAVCall* call); |
110 | bool call_prepare_transmission(ToxAVCall* call); | 119 | bool call_prepare_transmission(ToxAVCall* call); |
111 | void call_kill_transmission(ToxAVCall* call); | 120 | void call_kill_transmission(ToxAVCall* call); |
112 | 121 | void ba_set(ToxAvBitrateAdapter* ba, uint32_t bit_rate); | |
113 | 122 | bool ba_shoud_send_dummy(ToxAvBitrateAdapter* ba); | |
123 | void ba_update_sent_regular(ToxAvBitrateAdapter* ba); | ||
114 | 124 | ||
115 | ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | 125 | ToxAV* 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 | ||
305 | bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) | 315 | bool 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 | ||
508 | bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error) | 518 | bool 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 | ||
544 | bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error) | 562 | bool 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 | ||
580 | void 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 | |||
588 | bool 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) | 606 | bool 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 | ||
687 | void 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 | |||
695 | bool 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) | 705 | bool 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 | ||
935 | void 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 | |||
897 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | 986 | ToxAVCall* 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 | ||
987 | void 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 | |||
1038 | void call_remove(ToxAVCall* call) | 1076 | void 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 | |||
1208 | void 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 | |||
1218 | bool 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 | |||
1227 | void 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 | */ | ||
348 | typedef 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 | */ | ||
352 | void 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 | */ |
361 | bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE *error); | 363 | bool 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 | */ | ||
377 | typedef 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 | */ | ||
381 | void 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 | */ |
372 | bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE *error); | 392 | bool 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 | */ | ||
417 | typedef 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 | */ | ||
421 | void 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 | */ | ||
449 | typedef 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 | */ | ||
453 | void 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) | |||
157 | int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length) | 157 | int 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 | ||
282 | end: | 282 | end: |
283 | rtp_free_msg(NULL, msg); | 283 | rtp_free_msg(msg); |
284 | return 0; | 284 | return 0; |
285 | } | 285 | } |
286 | int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) | 286 | int 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; | |||
41 | typedef struct VCSession_s { | 41 | typedef 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 */ |