diff options
Diffstat (limited to 'toxav/media.c')
-rw-r--r-- | toxav/media.c | 144 |
1 files changed, 77 insertions, 67 deletions
diff --git a/toxav/media.c b/toxav/media.c index a9a4adb8..16156d9d 100644 --- a/toxav/media.c +++ b/toxav/media.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include "config.h" | 26 | #include "config.h" |
27 | #endif /* HAVE_CONFIG_H */ | 27 | #endif /* HAVE_CONFIG_H */ |
28 | 28 | ||
29 | #include "../toxcore/logger.h" | ||
30 | |||
29 | #include <stdio.h> | 31 | #include <stdio.h> |
30 | #include <stdlib.h> | 32 | #include <stdlib.h> |
31 | #include <math.h> | 33 | #include <math.h> |
@@ -34,40 +36,31 @@ | |||
34 | #include "rtp.h" | 36 | #include "rtp.h" |
35 | #include "media.h" | 37 | #include "media.h" |
36 | 38 | ||
37 | struct jitter_buffer { | 39 | int empty_queue(JitterBuffer *q) |
38 | RTPMessage **queue; | ||
39 | uint16_t capacity; | ||
40 | uint16_t size; | ||
41 | uint16_t front; | ||
42 | uint16_t rear; | ||
43 | uint8_t queue_ready; | ||
44 | uint16_t current_id; | ||
45 | uint32_t current_ts; | ||
46 | uint8_t id_set; | ||
47 | }; | ||
48 | |||
49 | int empty_queue(struct jitter_buffer *q) | ||
50 | { | 40 | { |
51 | while (q->size > 0) { | 41 | while (q->size > 0) { |
52 | rtp_free_msg(NULL, q->queue[q->front]); | 42 | rtp_free_msg(NULL, q->queue[q->front]); |
53 | q->front++; | 43 | q->front++; |
54 | 44 | ||
55 | if (q->front == q->capacity) | 45 | if (q->front == q->capacity) |
56 | q->front = 0; | 46 | q->front = 0; |
57 | 47 | ||
58 | q->size--; | 48 | q->size--; |
59 | } | 49 | } |
60 | 50 | ||
61 | q->id_set = 0; | 51 | q->id_set = 0; |
62 | q->queue_ready = 0; | 52 | q->queue_ready = 0; |
63 | return 0; | 53 | return 0; |
64 | } | 54 | } |
65 | 55 | ||
66 | struct jitter_buffer *create_queue(int capacity) | 56 | JitterBuffer *create_queue(int capacity) |
67 | { | 57 | { |
68 | struct jitter_buffer *q; | 58 | JitterBuffer *q; |
69 | q = calloc(sizeof(struct jitter_buffer), 1); | 59 | |
70 | q->queue = calloc(sizeof(RTPMessage *), capacity); | 60 | if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL; |
61 | |||
62 | if (!(q->queue = calloc(sizeof(RTPMessage *), capacity))) return NULL; | ||
63 | |||
71 | q->size = 0; | 64 | q->size = 0; |
72 | q->capacity = capacity; | 65 | q->capacity = capacity; |
73 | q->front = 0; | 66 | q->front = 0; |
@@ -79,17 +72,17 @@ struct jitter_buffer *create_queue(int capacity) | |||
79 | return q; | 72 | return q; |
80 | } | 73 | } |
81 | 74 | ||
82 | /* returns 1 if 'a' has a higher sequence number than 'b' */ | 75 | void terminate_queue(JitterBuffer *q) |
83 | uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b) | ||
84 | { | 76 | { |
85 | /* TODO: There is already this kind of function in toxrtp.c. | 77 | empty_queue(q); |
86 | * Maybe merge? | 78 | free(q->queue); |
87 | */ | 79 | free(q); |
88 | return (sn_a > sn_b || ts_a > ts_b); | ||
89 | } | 80 | } |
90 | 81 | ||
82 | #define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b) | ||
83 | |||
91 | /* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ | 84 | /* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ |
92 | RTPMessage *dequeue(struct jitter_buffer *q, int *success) | 85 | RTPMessage *dequeue(JitterBuffer *q, int *success) |
93 | { | 86 | { |
94 | if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */ | 87 | if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */ |
95 | q->queue_ready = 0; | 88 | q->queue_ready = 0; |
@@ -112,14 +105,13 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success) | |||
112 | q->current_id = next_id; | 105 | q->current_id = next_id; |
113 | q->current_ts = next_ts; | 106 | q->current_ts = next_ts; |
114 | } else { | 107 | } else { |
115 | if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) { | 108 | if (sequnum_older(next_id, q->current_id, next_ts, q->current_ts)) { |
116 | /*printf("nextid: %d current: %d\n", next_id, q->current_id);*/ | 109 | LOGGER_DEBUG("nextid: %d current: %d\n", next_id, q->current_id); |
117 | q->current_id = (q->current_id + 1) % MAX_SEQU_NUM; | 110 | q->current_id = (q->current_id + 1) % MAX_SEQU_NUM; |
118 | *success = 2; /* tell the decoder the packet is lost */ | 111 | *success = 2; /* tell the decoder the packet is lost */ |
119 | return NULL; | 112 | return NULL; |
120 | } else { | 113 | } else { |
121 | /* packet too old */ | 114 | LOGGER_DEBUG("Packet too old"); |
122 | /*printf("packet too old\n");*/ | ||
123 | *success = 0; | 115 | *success = 0; |
124 | return NULL; | 116 | return NULL; |
125 | } | 117 | } |
@@ -139,12 +131,11 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success) | |||
139 | } | 131 | } |
140 | 132 | ||
141 | 133 | ||
142 | int queue(struct jitter_buffer *q, RTPMessage *pk) | 134 | void queue(JitterBuffer *q, RTPMessage *pk) |
143 | { | 135 | { |
144 | if (q->size == q->capacity) { /* Full, empty queue */ | 136 | if (q->size == q->capacity) { /* Full, empty queue */ |
137 | LOGGER_DEBUG("Queue full s(%d) c(%d), emptying...", q->size, q->capacity); | ||
145 | empty_queue(q); | 138 | empty_queue(q); |
146 | /*rtp_free_msg(NULL, pk);*/ | ||
147 | return 0; | ||
148 | } | 139 | } |
149 | 140 | ||
150 | if (q->size > 8) | 141 | if (q->size > 8) |
@@ -169,13 +160,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
169 | if (b < 0) | 160 | if (b < 0) |
170 | b += q->capacity; | 161 | b += q->capacity; |
171 | 162 | ||
172 | if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum, | 163 | if (sequnum_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum, |
173 | q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) { | 164 | q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) { |
174 | RTPMessage *temp; | 165 | RTPMessage *temp; |
175 | temp = q->queue[a]; | 166 | temp = q->queue[a]; |
176 | q->queue[a] = q->queue[b]; | 167 | q->queue[a] = q->queue[b]; |
177 | q->queue[b] = temp; | 168 | q->queue[b] = temp; |
178 | /*printf("had to swap\n");*/ | 169 | LOGGER_DEBUG("Had to swap"); |
179 | } else { | 170 | } else { |
180 | break; | 171 | break; |
181 | } | 172 | } |
@@ -185,19 +176,15 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
185 | if (a < 0) | 176 | if (a < 0) |
186 | a += q->capacity; | 177 | a += q->capacity; |
187 | } | 178 | } |
188 | |||
189 | if (pk) | ||
190 | return 1; | ||
191 | |||
192 | return 0; | ||
193 | } | 179 | } |
194 | 180 | ||
195 | 181 | ||
196 | int init_video_decoder(CodecState *cs) | 182 | int init_video_decoder(CodecState *cs) |
197 | { | 183 | { |
198 | if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, | 184 | int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION); |
199 | VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { | 185 | |
200 | /*fprintf(stderr, "Init video_decoder failed!\n");*/ | 186 | if ( rc != VPX_CODEC_OK) { |
187 | LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); | ||
201 | return -1; | 188 | return -1; |
202 | } | 189 | } |
203 | 190 | ||
@@ -210,7 +197,7 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | |||
210 | cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); | 197 | cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); |
211 | 198 | ||
212 | if ( rc != OPUS_OK ) { | 199 | if ( rc != OPUS_OK ) { |
213 | /*fprintf(stderr, "Error while starting audio decoder!\n");*/ | 200 | LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); |
214 | return -1; | 201 | return -1; |
215 | } | 202 | } |
216 | 203 | ||
@@ -221,10 +208,10 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | |||
221 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) | 208 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) |
222 | { | 209 | { |
223 | vpx_codec_enc_cfg_t cfg; | 210 | vpx_codec_enc_cfg_t cfg; |
224 | int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | 211 | int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); |
225 | 212 | ||
226 | if (res) { | 213 | if (rc) { |
227 | /*fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res));*/ | 214 | LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc)); |
228 | return -1; | 215 | return -1; |
229 | } | 216 | } |
230 | 217 | ||
@@ -232,9 +219,10 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t | |||
232 | cfg.g_w = width; | 219 | cfg.g_w = width; |
233 | cfg.g_h = height; | 220 | cfg.g_h = height; |
234 | 221 | ||
235 | if (vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, | 222 | rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); |
236 | VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { | 223 | |
237 | /*fprintf(stderr, "Failed to initialize encoder\n");*/ | 224 | if ( rc != VPX_CODEC_OK) { |
225 | LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); | ||
238 | return -1; | 226 | return -1; |
239 | } | 227 | } |
240 | 228 | ||
@@ -243,13 +231,30 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t | |||
243 | 231 | ||
244 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) | 232 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) |
245 | { | 233 | { |
246 | int err = OPUS_OK; | 234 | int rc = OPUS_OK; |
247 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); | 235 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc); |
248 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | 236 | |
249 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); | 237 | if ( rc != OPUS_OK ) { |
238 | LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); | ||
239 | return -1; | ||
240 | } | ||
241 | |||
242 | rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | ||
250 | 243 | ||
244 | if ( rc != OPUS_OK ) { | ||
245 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); | ||
250 | |||
251 | if ( rc != OPUS_OK ) { | ||
252 | LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); | ||
253 | return -1; | ||
254 | } | ||
251 | 255 | ||
252 | return err == OPUS_OK ? 0 : -1; | 256 | |
257 | return 0; | ||
253 | } | 258 | } |
254 | 259 | ||
255 | 260 | ||
@@ -262,7 +267,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate, | |||
262 | uint32_t video_bitrate ) | 267 | uint32_t video_bitrate ) |
263 | { | 268 | { |
264 | CodecState *retu = calloc(sizeof(CodecState), 1); | 269 | CodecState *retu = calloc(sizeof(CodecState), 1); |
265 | assert(retu); | 270 | |
271 | if (!retu) return NULL; | ||
266 | 272 | ||
267 | retu->audio_bitrate = audio_bitrate; | 273 | retu->audio_bitrate = audio_bitrate; |
268 | retu->audio_sample_rate = audio_sample_rate; | 274 | retu->audio_sample_rate = audio_sample_rate; |
@@ -271,8 +277,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate, | |||
271 | if (!video_width || !video_height) { /* Disable video */ | 277 | if (!video_width || !video_height) { /* Disable video */ |
272 | /*video_width = 320; | 278 | /*video_width = 320; |
273 | video_height = 240; */ | 279 | video_height = 240; */ |
274 | } | 280 | } else { |
275 | else { | ||
276 | retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0; | 281 | retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0; |
277 | retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; | 282 | retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; |
278 | } | 283 | } |
@@ -280,24 +285,29 @@ CodecState *codec_init_session ( uint32_t audio_bitrate, | |||
280 | retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0; | 285 | retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0; |
281 | retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0; | 286 | retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0; |
282 | 287 | ||
288 | if ( retu->capabilities == 0 ) { /* everything failed */ | ||
289 | free (retu); | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
283 | return retu; | 293 | return retu; |
284 | } | 294 | } |
285 | 295 | ||
286 | void codec_terminate_session ( CodecState *cs ) | 296 | void codec_terminate_session ( CodecState *cs ) |
287 | { | 297 | { |
288 | if ( cs->audio_encoder ) | 298 | if ( cs->audio_encoder ) |
289 | opus_encoder_destroy(cs->audio_encoder); | 299 | opus_encoder_destroy(cs->audio_encoder); |
290 | 300 | ||
291 | if ( cs->audio_decoder ) | 301 | if ( cs->audio_decoder ) |
292 | opus_decoder_destroy(cs->audio_decoder); | 302 | opus_decoder_destroy(cs->audio_decoder); |
293 | |||
294 | 303 | ||
295 | /* TODO: Terminate video | 304 | |
296 | * Do what??? | 305 | /* TODO: Terminate video |
306 | * Do what? | ||
297 | */ | 307 | */ |
298 | if ( cs->capabilities & v_decoding ) | 308 | if ( cs->capabilities & v_decoding ) |
299 | vpx_codec_destroy(&cs->v_decoder); | 309 | vpx_codec_destroy(&cs->v_decoder); |
300 | 310 | ||
301 | if ( cs->capabilities & v_encoding ) | 311 | if ( cs->capabilities & v_encoding ) |
302 | vpx_codec_destroy(&cs->v_encoder); | 312 | vpx_codec_destroy(&cs->v_encoder); |
303 | } | 313 | } |