summaryrefslogtreecommitdiff
path: root/toxav/media.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/media.c')
-rw-r--r--toxav/media.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/toxav/media.c b/toxav/media.c
new file mode 100644
index 00000000..c4894076
--- /dev/null
+++ b/toxav/media.c
@@ -0,0 +1,309 @@
1/** media.c
2 *
3 * Audio and video codec intitialization, encoding/decoding and playback
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif /* HAVE_CONFIG_H */
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <math.h>
32#include <assert.h>
33
34#include "rtp.h"
35#include "media.h"
36
37struct jitter_buffer {
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
50struct jitter_buffer *create_queue(int capacity)
51{
52 struct jitter_buffer *q;
53 q = (struct jitter_buffer *)calloc(sizeof(struct jitter_buffer),1);
54 q->queue = (RTPMessage **)calloc(sizeof(RTPMessage*), capacity);
55 int i = 0;
56
57 for (i = 0; i < capacity; ++i) {
58 q->queue[i] = NULL;
59 }
60
61 q->size = 0;
62 q->capacity = capacity;
63 q->front = 0;
64 q->rear = -1;
65 q->queue_ready = 0;
66 q->current_id = 0;
67 q->current_ts = 0;
68 q->id_set = 0;
69 return q;
70}
71
72/* returns 1 if 'a' has a higher sequence number than 'b' */
73uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
74{
75 /* TODO: There is already this kind of function in toxrtp.c.
76 * Maybe merge?
77 */
78 return (sn_a > sn_b || ts_a > ts_b);
79}
80
81/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
82RTPMessage *dequeue(struct jitter_buffer *q, int *success)
83{
84 if (q->size == 0 || q->queue_ready == 0) {
85 q->queue_ready = 0;
86 *success = 0;
87 return NULL;
88 }
89
90 int front = q->front;
91
92 if (q->id_set == 0) {
93 q->current_id = q->queue[front]->header->sequnum;
94 q->current_ts = q->queue[front]->header->timestamp;
95 q->id_set = 1;
96 } else {
97 int next_id = q->queue[front]->header->sequnum;
98 int next_ts = q->queue[front]->header->timestamp;
99
100 /* if this packet is indeed the expected packet */
101 if (next_id == (q->current_id + 1) % MAX_SEQU_NUM) {
102 q->current_id = next_id;
103 q->current_ts = next_ts;
104 } else {
105 if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) {
106 printf("nextid: %d current: %d\n", next_id, q->current_id);
107 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
108 *success = 2; /* tell the decoder the packet is lost */
109 return NULL;
110 } else {
111 /* packet too old */
112 printf("packet too old\n");
113 *success = 0;
114 return NULL;
115 }
116 }
117 }
118
119 q->size--;
120 q->front++;
121
122 if (q->front == q->capacity)
123 q->front = 0;
124
125 *success = 1;
126 q->current_id = q->queue[front]->header->sequnum;
127 q->current_ts = q->queue[front]->header->timestamp;
128 return q->queue[front];
129}
130
131int empty_queue(struct jitter_buffer *q)
132{
133 while (q->size > 0) {
134 q->size--;
135 rtp_free_msg(NULL, q->queue[q->front]);
136 q->front++;
137
138 if (q->front == q->capacity)
139 q->front = 0;
140 }
141
142 q->id_set = 0;
143 q->queue_ready = 0;
144 return 0;
145}
146
147int queue(struct jitter_buffer *q, RTPMessage *pk)
148{
149 if (q->size == q->capacity) {
150 printf("buffer full, emptying buffer...\n");
151 empty_queue(q);
152 return 0;
153 }
154
155 if (q->size > 8)
156 q->queue_ready = 1;
157
158 ++q->size;
159 ++q->rear;
160
161 if (q->rear == q->capacity)
162 q->rear = 0;
163
164 q->queue[q->rear] = pk;
165
166 int a;
167 int b;
168 int j;
169 a = q->rear;
170
171 for (j = 0; j < q->size - 1; ++j) {
172 b = a - 1;
173
174 if (b < 0)
175 b += q->capacity;
176
177 if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
178 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
179 RTPMessage *temp;
180 temp = q->queue[a];
181 q->queue[a] = q->queue[b];
182 q->queue[b] = temp;
183 printf("had to swap\n");
184 } else {
185 break;
186 }
187
188 a -= 1;
189
190 if (a < 0)
191 a += q->capacity;
192 }
193
194 if (pk)
195 return 1;
196
197 return 0;
198}
199
200
201int init_video_decoder(CodecState *cs)
202{
203 if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) {
204 fprintf(stderr, "Init video_decoder failed!\n");
205 return -1;
206 }
207
208 return 0;
209}
210
211int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
212{
213 int rc;
214 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
215
216 if ( rc != OPUS_OK ){
217 fprintf(stderr, "Error while starting audio decoder!\n");
218 return -1;
219 }
220
221 return 0;
222}
223
224
225int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
226{
227 vpx_codec_enc_cfg_t cfg;
228 int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
229 if(res) {
230 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
231 return -1;
232 }
233
234 cfg.rc_target_bitrate = video_bitrate;
235 cfg.g_w = width;
236 cfg.g_h = height;
237 if(vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) {
238 fprintf(stderr, "Failed to initialize encoder\n");
239 return -1;
240 }
241 return 0;
242}
243
244int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
245{
246 int err = OPUS_OK;
247 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err);
248 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
249 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
250
251
252 return err == OPUS_OK ? 0 : -1;
253}
254
255
256CodecState* codec_init_session ( uint32_t audio_bitrate,
257 uint16_t audio_frame_duration,
258 uint32_t audio_sample_rate,
259 uint32_t audio_channels,
260 uint16_t video_width,
261 uint16_t video_height,
262 uint32_t video_bitrate )
263{
264 CodecState* _retu = calloc(sizeof(CodecState), 1);
265 assert(_retu);
266
267 _retu->audio_bitrate = audio_bitrate;
268 _retu->audio_sample_rate = audio_sample_rate;
269
270 /* Encoders */
271 if (!video_width || !video_height) {
272 video_width = 320;
273 video_height = 240;
274 }
275
276 if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) )
277 printf("Video encoder initialized!\n");
278
279 if ( 0 == init_audio_encoder(_retu, audio_channels) )
280 printf("Audio encoder initialized!\n");
281
282
283 /* Decoders */
284 if ( 0 == init_video_decoder(_retu) )
285 printf("Video decoder initialized!\n");
286
287 if ( 0 == init_audio_decoder(_retu, audio_channels) )
288 printf("Audio decoder initialized!\n");
289
290
291 return _retu;
292}
293
294void codec_terminate_session ( CodecState* cs )
295{
296 if ( cs->audio_encoder ) {
297 opus_encoder_destroy(cs->audio_encoder);
298 printf("Terminated encoder!\n");
299 }
300
301 if ( cs->audio_decoder ) {
302 opus_decoder_destroy(cs->audio_decoder);
303 printf("Terminated decoder!\n");
304 }
305
306 /* TODO: Terminate video */
307 vpx_codec_destroy(&cs->v_decoder);
308 vpx_codec_destroy(&cs->v_encoder);
309}