diff options
Diffstat (limited to 'toxav')
-rw-r--r-- | toxav/Makefile.inc | 134 | ||||
-rw-r--r-- | toxav/media.c | 151 | ||||
-rw-r--r-- | toxav/media.h | 78 | ||||
-rw-r--r-- | toxav/msi.c | 40 | ||||
-rw-r--r-- | toxav/msi.h | 9 | ||||
-rwxr-xr-x | toxav/phone.c | 401 | ||||
-rw-r--r-- | toxav/rtp.c | 55 | ||||
-rw-r--r-- | toxav/rtp.h | 18 | ||||
-rw-r--r-- | toxav/toxav.c | 128 | ||||
-rw-r--r-- | toxav/toxav.h | 47 |
10 files changed, 551 insertions, 510 deletions
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 203d8a07..0472d361 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc | |||
@@ -1,105 +1,43 @@ | |||
1 | if BUILD_AV | 1 | if BUILD_AV |
2 | 2 | ||
3 | lib_LTLIBRARIES += libtoxrtp.la \ | 3 | lib_LTLIBRARIES += libtoxav.la |
4 | libtoxmsi.la \ | 4 | libtoxav_la_include_HEADERS = ../toxav/toxav.h |
5 | libtoxmedia.la | 5 | libtoxav_la_includedir = $(includedir)/tox |
6 | |||
7 | libtoxav_la_SOURCES = ../toxav/rtp.h \ | ||
8 | ../toxav/rtp.c \ | ||
9 | ../toxav/msi.h \ | ||
10 | ../toxav/msi.c \ | ||
11 | ../toxav/media.h \ | ||
12 | ../toxav/media.c \ | ||
13 | ../toxav/toxav.h \ | ||
14 | ../toxav/toxav.c | ||
15 | |||
16 | |||
17 | libtoxav_la_CFLAGS = -I../toxcore \ | ||
18 | -I../toxav \ | ||
19 | $(NACL_CFLAGS) \ | ||
20 | $(OPUS_CFLAGS) \ | ||
21 | $(VPX_CFLAGS) | ||
22 | |||
23 | libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ | ||
24 | $(NACL_LDFLAGS) \ | ||
25 | $(EXTRA_LT_LDFLAGS) | ||
26 | |||
27 | libtoxav_la_LIBS = $(NACL_LIBS) \ | ||
28 | $(OPUS_LIBS) \ | ||
29 | $(VPX_LIBS) | ||
6 | 30 | ||
7 | |||
8 | # ****** RTP ****** # | ||
9 | |||
10 | libtoxrtp_la_include_HEADERS = \ | ||
11 | ../toxav/toxrtp.h | ||
12 | |||
13 | libtoxrtp_la_includedir = $(includedir)/tox | ||
14 | |||
15 | libtoxrtp_la_SOURCES = ../toxav/toxrtp.h \ | ||
16 | ../toxav/toxrtp.c | ||
17 | |||
18 | libtoxrtp_la_CFLAGS = -I../toxcore \ | ||
19 | -I../toxav \ | ||
20 | $(NACL_CFLAGS) | ||
21 | |||
22 | libtoxrtp_la_LDFLAGS = $(TOXRTP_LT_LDFLAGS) \ | ||
23 | $(NACL_LDFLAGS) \ | ||
24 | $(EXTRA_LT_LDFLAGS) | ||
25 | |||
26 | libtoxrtp_la_LIBS = libtoxcore.la \ | ||
27 | $(NACL_LIBS) | ||
28 | |||
29 | |||
30 | 31 | ||
32 | endif | ||
31 | 33 | ||
32 | 34 | ||
33 | # ****** MSI ****** # | ||
34 | |||
35 | libtoxmsi_la_include_HEADERS = \ | ||
36 | ../toxav/toxmsi.h | ||
37 | |||
38 | libtoxmsi_la_includedir = $(includedir)/tox | ||
39 | |||
40 | libtoxmsi_la_SOURCES = ../toxav/toxmsi.h \ | ||
41 | ../toxav/toxmsi.c | ||
42 | |||
43 | libtoxmsi_la_CFLAGS = -I../toxcore \ | ||
44 | -I../toxav \ | ||
45 | $(NACL_CFLAGS) | ||
46 | |||
47 | libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ | ||
48 | $(EXTRA_LT_LDFLAGS) \ | ||
49 | $(NACL_LDFLAGS) | ||
50 | |||
51 | libtoxmsi_la_LIBS = libtoxcore.la \ | ||
52 | $(NACL_LIBS) | ||
53 | |||
54 | 35 | ||
55 | 36 | ||
56 | 37 | ||
57 | 38 | ||
58 | # ****** MEDIA ****** # | 39 | if BUILD_PHONE |
59 | |||
60 | libtoxmedia_la_include_HEADERS = \ | ||
61 | ../toxav/toxmedia.h | ||
62 | |||
63 | libtoxmedia_la_includedir = $(includedir)/tox | ||
64 | |||
65 | libtoxmedia_la_SOURCES = ../toxav/toxmedia.h \ | ||
66 | ../toxav/toxmedia.c | ||
67 | 40 | ||
68 | libtoxmedia_la_CFLAGS = -I../toxcore \ | ||
69 | -I../toxav \ | ||
70 | $(AVFORMAT_CFLAGS) \ | ||
71 | $(AVCODEC_CFLAGS) \ | ||
72 | $(AVUTIL_CFLAGS) \ | ||
73 | $(AVDEVICE_CFLAGS) \ | ||
74 | $(SWSCALE_CFLAGS) \ | ||
75 | $(SDL_CFLAGS) \ | ||
76 | $(OPENAL_CFLAGS) \ | ||
77 | $(NACL_CFLAGS) \ | ||
78 | $(OPUS_CFLAGS) | ||
79 | |||
80 | |||
81 | libtoxmedia_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ | ||
82 | $(TOXRTP_LT_LDFLAGS) \ | ||
83 | $(EXTRA_LT_LDFLAGS) \ | ||
84 | $(NACL_LDFLAGS) | ||
85 | |||
86 | |||
87 | libtoxmedia_la_LIBS = libtoxcore.la \ | ||
88 | $(NACL_LDFLAGS) \ | ||
89 | $(AVFORMAT_LIBS) \ | ||
90 | $(AVCODEC_LIBS) \ | ||
91 | $(AVUTIL_LIBS) \ | ||
92 | $(AVDEVICE_LIBS) \ | ||
93 | $(SWSCALE_LIBS) \ | ||
94 | $(SDL_LIBS) \ | ||
95 | $(OPENAL_LIBS) \ | ||
96 | $(NACL_LIBS) \ | ||
97 | $(OPUS_LIBS) | ||
98 | |||
99 | |||
100 | |||
101 | |||
102 | # ***** PHONE ***** # | ||
103 | 41 | ||
104 | noinst_PROGRAMS += phone | 42 | noinst_PROGRAMS += phone |
105 | 43 | ||
@@ -113,25 +51,17 @@ phone_CFLAGS = -I../toxcore \ | |||
113 | $(AVDEVICE_CFLAGS) \ | 51 | $(AVDEVICE_CFLAGS) \ |
114 | $(SWSCALE_CFLAGS) \ | 52 | $(SWSCALE_CFLAGS) \ |
115 | $(SDL_CFLAGS) \ | 53 | $(SDL_CFLAGS) \ |
116 | $(OPENAL_CFLAGS) \ | 54 | $(OPENAL_CFLAGS) |
117 | $(NACL_CFLAGS) \ | ||
118 | $(OPUS_CFLAGS) | ||
119 | |||
120 | 55 | ||
121 | phone_LDADD = libtoxrtp.la \ | 56 | phone_LDADD = libtoxav.la \ |
122 | libtoxmsi.la \ | ||
123 | libtoxmedia.la \ | ||
124 | libtoxcore.la \ | 57 | libtoxcore.la \ |
125 | $(NACL_LDFLAGS) \ | ||
126 | $(AVFORMAT_LIBS) \ | 58 | $(AVFORMAT_LIBS) \ |
127 | $(AVCODEC_LIBS) \ | 59 | $(AVCODEC_LIBS) \ |
128 | $(AVUTIL_LIBS) \ | 60 | $(AVUTIL_LIBS) \ |
129 | $(AVDEVICE_LIBS) \ | 61 | $(AVDEVICE_LIBS) \ |
130 | $(SWSCALE_LIBS) \ | 62 | $(SWSCALE_LIBS) \ |
131 | $(SDL_LIBS) \ | 63 | $(SDL_LIBS) \ |
132 | $(OPENAL_LIBS) \ | 64 | $(OPENAL_LIBS) |
133 | $(NACL_LIBS) \ | ||
134 | $(OPUS_LIBS) | ||
135 | 65 | ||
136 | 66 | ||
137 | endif \ No newline at end of file | 67 | endif \ No newline at end of file |
diff --git a/toxav/media.c b/toxav/media.c index e18c1803..a327c751 100644 --- a/toxav/media.c +++ b/toxav/media.c | |||
@@ -28,13 +28,8 @@ | |||
28 | #endif /* HAVE_CONFIG_H */ | 28 | #endif /* HAVE_CONFIG_H */ |
29 | 29 | ||
30 | #include <stdio.h> | 30 | #include <stdio.h> |
31 | #include <stdlib.h> | ||
31 | #include <math.h> | 32 | #include <math.h> |
32 | #include <libavcodec/avcodec.h> | ||
33 | #include <libavformat/avformat.h> | ||
34 | #include <libswscale/swscale.h> | ||
35 | #include <libavdevice/avdevice.h> | ||
36 | #include <libavutil/opt.h> | ||
37 | #include <opus/opus.h> | ||
38 | #include <assert.h> | 33 | #include <assert.h> |
39 | 34 | ||
40 | #include "rtp.h" | 35 | #include "rtp.h" |
@@ -206,25 +201,11 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
206 | 201 | ||
207 | int init_video_decoder(CodecState *cs) | 202 | int init_video_decoder(CodecState *cs) |
208 | { | 203 | { |
209 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); | 204 | if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { |
210 | |||
211 | if (!cs->video_decoder) { | ||
212 | fprintf(stderr, "Init video_decoder failed!\n"); | 205 | fprintf(stderr, "Init video_decoder failed!\n"); |
213 | return -1; | 206 | return -1; |
214 | } | 207 | } |
215 | 208 | ||
216 | cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); | ||
217 | |||
218 | if (!cs->video_decoder_ctx) { | ||
219 | fprintf(stderr, "Init video_decoder_ctx failed!\n"); | ||
220 | return -1; | ||
221 | } | ||
222 | |||
223 | if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { | ||
224 | fprintf(stderr, "Opening video decoder failed!\n"); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
228 | return 0; | 209 | return 0; |
229 | } | 210 | } |
230 | 211 | ||
@@ -242,97 +223,32 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | |||
242 | } | 223 | } |
243 | 224 | ||
244 | 225 | ||
245 | int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate) | 226 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) |
246 | { | 227 | { |
247 | cs->video_input_format = av_find_input_format(video_driver); | 228 | vpx_codec_enc_cfg_t cfg; |
248 | 229 | int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | |
249 | if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) { | 230 | if(res) { |
250 | fprintf(stderr, "Opening video_input_format failed!\n"); | 231 | printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
251 | return -1; | ||
252 | } | ||
253 | |||
254 | avformat_find_stream_info(cs->video_format_ctx, NULL); | ||
255 | av_dump_format(cs->video_format_ctx, 0, webcam, 0); | ||
256 | |||
257 | int i; | ||
258 | |||
259 | for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) { | ||
260 | if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
261 | cs->video_stream = i; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec; | ||
267 | cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id); | ||
268 | |||
269 | if (cs->webcam_decoder == NULL) { | ||
270 | fprintf(stderr, "Unsupported codec!\n"); | ||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | if (cs->webcam_decoder_ctx == NULL) { | ||
275 | fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); | ||
276 | return -1; | ||
277 | } | ||
278 | |||
279 | if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) { | ||
280 | fprintf(stderr, "Opening webcam decoder failed!\n"); | ||
281 | return -1; | 232 | return -1; |
282 | } | 233 | } |
283 | 234 | ||
284 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | 235 | cfg.rc_target_bitrate = video_bitrate; |
285 | 236 | cfg.g_w = width; | |
286 | if (!cs->video_encoder) { | 237 | cfg.g_h = height; |
287 | fprintf(stderr, "Init video_encoder failed!\n"); | 238 | if(vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { |
288 | return -1; | 239 | fprintf(stderr, "Failed to initialize encoder\n"); |
289 | } | ||
290 | |||
291 | cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); | ||
292 | |||
293 | if (!cs->video_encoder_ctx) { | ||
294 | fprintf(stderr, "Init video_encoder_ctx failed!\n"); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | cs->video_encoder_ctx->bit_rate = video_bitrate; | ||
299 | cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; | ||
300 | av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); | ||
301 | av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); | ||
302 | |||
303 | cs->video_encoder_ctx->thread_count = 4; | ||
304 | cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; | ||
305 | cs->video_encoder_ctx->rc_buffer_size = video_bitrate * 6; | ||
306 | cs->video_encoder_ctx->profile = 3; | ||
307 | cs->video_encoder_ctx->qmax = 54; | ||
308 | cs->video_encoder_ctx->qmin = 4; | ||
309 | AVRational myrational = {1, 25}; | ||
310 | cs->video_encoder_ctx->time_base = myrational; | ||
311 | cs->video_encoder_ctx->gop_size = 99999; | ||
312 | cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; | ||
313 | cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; | ||
314 | cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; | ||
315 | |||
316 | if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { | ||
317 | fprintf(stderr, "Opening video encoder failed!\n"); | ||
318 | return -1; | 240 | return -1; |
319 | } | 241 | } |
320 | |||
321 | return 0; | 242 | return 0; |
322 | } | 243 | } |
323 | 244 | ||
324 | int init_audio_encoder(CodecState *cs) | 245 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) |
325 | { | 246 | { |
326 | int err = OPUS_OK; | 247 | int err = OPUS_OK; |
327 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err); | 248 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); |
328 | |||
329 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | 249 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); |
330 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); | 250 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); |
331 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); | 251 | |
332 | |||
333 | /* NOTE: What do we do with this? */ | ||
334 | int nfo; | ||
335 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo)); | ||
336 | 252 | ||
337 | return err == OPUS_OK ? 0 : -1; | 253 | return err == OPUS_OK ? 0 : -1; |
338 | } | 254 | } |
@@ -342,30 +258,26 @@ CodecState* codec_init_session ( uint32_t audio_bitrate, | |||
342 | uint16_t audio_frame_duration, | 258 | uint16_t audio_frame_duration, |
343 | uint32_t audio_sample_rate, | 259 | uint32_t audio_sample_rate, |
344 | uint32_t audio_channels, | 260 | uint32_t audio_channels, |
345 | uint32_t video_bitrate, | 261 | uint16_t video_width, |
346 | const char* webcam, | 262 | uint16_t video_height, |
347 | const char* webcam_driver ) | 263 | uint32_t video_bitrate ) |
348 | { | 264 | { |
349 | CodecState* _retu = av_calloc(sizeof(CodecState), 1); | 265 | CodecState* _retu = calloc(sizeof(CodecState), 1); |
350 | assert(_retu); | 266 | assert(_retu); |
351 | 267 | ||
352 | |||
353 | avdevice_register_all(); | ||
354 | avcodec_register_all(); | ||
355 | av_register_all(); | ||
356 | |||
357 | |||
358 | _retu->audio_bitrate = audio_bitrate; | 268 | _retu->audio_bitrate = audio_bitrate; |
359 | _retu->audio_sample_rate = audio_sample_rate; | 269 | _retu->audio_sample_rate = audio_sample_rate; |
360 | 270 | ||
361 | pthread_mutex_init(&_retu->ctrl_mutex, NULL); | ||
362 | |||
363 | |||
364 | /* Encoders */ | 271 | /* Encoders */ |
365 | if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) ) | 272 | if (!video_width || !video_height) { |
273 | video_width = 320; | ||
274 | video_height = 240; | ||
275 | } | ||
276 | |||
277 | if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) ) | ||
366 | printf("Video encoder initialized!\n"); | 278 | printf("Video encoder initialized!\n"); |
367 | 279 | ||
368 | if ( 0 == init_audio_encoder(_retu) ) | 280 | if ( 0 == init_audio_encoder(_retu, audio_channels) ) |
369 | printf("Audio encoder initialized!\n"); | 281 | printf("Audio encoder initialized!\n"); |
370 | 282 | ||
371 | 283 | ||
@@ -391,7 +303,8 @@ void codec_terminate_session ( CodecState* cs ) | |||
391 | opus_decoder_destroy(cs->audio_decoder); | 303 | opus_decoder_destroy(cs->audio_decoder); |
392 | printf("Terminated decoder!\n"); | 304 | printf("Terminated decoder!\n"); |
393 | } | 305 | } |
394 | 306 | ||
395 | /* TODO: Terminate video */ | 307 | /* TODO: Terminate video */ |
396 | 308 | vpx_codec_destroy(&cs->v_decoder); | |
309 | vpx_codec_destroy(&cs->v_encoder); | ||
397 | } | 310 | } |
diff --git a/toxav/media.h b/toxav/media.h index ef2de27c..4230de8f 100644 --- a/toxav/media.h +++ b/toxav/media.h | |||
@@ -27,66 +27,27 @@ | |||
27 | 27 | ||
28 | #include <stdio.h> | 28 | #include <stdio.h> |
29 | #include <math.h> | 29 | #include <math.h> |
30 | #include "../toxcore/tox.h" | 30 | #include <pthread.h> |
31 | 31 | ||
32 | /* Video encoding/decoding */ | 32 | #include <vpx/vpx_decoder.h> |
33 | #include <libavcodec/avcodec.h> | 33 | #include <vpx/vpx_encoder.h> |
34 | #include <libavformat/avformat.h> | 34 | #include <vpx/vp8dx.h> |
35 | #include <libswscale/swscale.h> | 35 | #include <vpx/vp8cx.h> |
36 | #include <libavdevice/avdevice.h> | 36 | #define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) |
37 | #include <libavutil/opt.h> | 37 | #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) |
38 | 38 | ||
39 | /* Audio encoding/decoding */ | 39 | /* Audio encoding/decoding */ |
40 | #include <opus/opus.h> | 40 | #include <opus/opus.h> |
41 | 41 | ||
42 | /* ffmpeg VP8 codec ID */ | ||
43 | #define VIDEO_CODEC AV_CODEC_ID_VP8 | ||
44 | |||
45 | /* ffmpeg Opus codec ID */ | ||
46 | #define AUDIO_CODEC AV_CODEC_ID_OPUS | ||
47 | |||
48 | /* default video bitrate in bytes/s */ | ||
49 | #define VIDEO_BITRATE 10*1000 | ||
50 | |||
51 | /* default audio bitrate in bytes/s */ | ||
52 | #define AUDIO_BITRATE 64000 | ||
53 | |||
54 | /* audio frame duration in miliseconds */ | ||
55 | #define AUDIO_FRAME_DURATION 20 | ||
56 | |||
57 | /* audio sample rate recommended to be 48kHz for Opus */ | ||
58 | #define AUDIO_SAMPLE_RATE 48000 | ||
59 | |||
60 | /* the amount of samples in one audio frame */ | ||
61 | #define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 | ||
62 | |||
63 | /* the quit event for SDL */ | ||
64 | #define FF_QUIT_EVENT (SDL_USEREVENT + 2) | ||
65 | |||
66 | #ifdef __linux__ | ||
67 | #define VIDEO_DRIVER "video4linux2" | ||
68 | #define DEFAULT_WEBCAM "/dev/video0" | ||
69 | #endif | ||
70 | |||
71 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
72 | #define VIDEO_DRIVER "vfwcap" | ||
73 | #define DEFAULT_WEBCAM "0" | ||
74 | #endif | ||
75 | 42 | ||
76 | typedef struct _CodecState{ | 43 | typedef struct _CodecState{ |
77 | 44 | ||
78 | /* video encoding */ | 45 | /* video encoding */ |
79 | AVInputFormat *video_input_format; | 46 | vpx_codec_ctx_t v_encoder; |
80 | AVFormatContext *video_format_ctx; | 47 | uint32_t frame_counter; |
81 | uint8_t video_stream; | ||
82 | AVCodecContext *webcam_decoder_ctx; | ||
83 | AVCodec *webcam_decoder; | ||
84 | AVCodecContext *video_encoder_ctx; | ||
85 | AVCodec *video_encoder; | ||
86 | 48 | ||
87 | /* video decoding */ | 49 | /* video decoding */ |
88 | AVCodecContext *video_decoder_ctx; | 50 | vpx_codec_ctx_t v_decoder; |
89 | AVCodec *video_decoder; | ||
90 | 51 | ||
91 | /* audio encoding */ | 52 | /* audio encoding */ |
92 | OpusEncoder *audio_encoder; | 53 | OpusEncoder *audio_encoder; |
@@ -95,11 +56,6 @@ typedef struct _CodecState{ | |||
95 | 56 | ||
96 | /* audio decoding */ | 57 | /* audio decoding */ |
97 | OpusDecoder *audio_decoder; | 58 | OpusDecoder *audio_decoder; |
98 | |||
99 | pthread_mutex_t ctrl_mutex; | ||
100 | |||
101 | |||
102 | uint32_t frame_rate; | ||
103 | 59 | ||
104 | } CodecState; | 60 | } CodecState; |
105 | 61 | ||
@@ -112,13 +68,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk); | |||
112 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); | 68 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); |
113 | 69 | ||
114 | 70 | ||
115 | CodecState* codec_init_session( uint32_t audio_bitrate, | 71 | CodecState* codec_init_session ( uint32_t audio_bitrate, |
116 | uint16_t audio_frame_duration, | 72 | uint16_t audio_frame_duration, |
117 | uint32_t audio_sample_rate, | 73 | uint32_t audio_sample_rate, |
118 | uint32_t audio_channels, | 74 | uint32_t audio_channels, |
119 | uint32_t video_bitrate, | 75 | uint16_t video_width, |
120 | const char* webcam, | 76 | uint16_t video_height, |
121 | const char* webcam_driver ); | 77 | uint32_t video_bitrate ); |
122 | 78 | ||
123 | void codec_terminate_session(CodecState* cs); | 79 | void codec_terminate_session(CodecState* cs); |
124 | 80 | ||
diff --git a/toxav/msi.c b/toxav/msi.c index 014a904f..f00029ba 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -593,7 +593,7 @@ int send_message ( MSISession* session, MSIMessage* msg, uint32_t to ) | |||
593 | uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; | 593 | uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; |
594 | uint16_t _length = message_to_string ( msg, _msg_string_final ); | 594 | uint16_t _length = message_to_string ( msg, _msg_string_final ); |
595 | 595 | ||
596 | return m_msi_packet((struct Messenger*) session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; | 596 | return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; |
597 | } | 597 | } |
598 | 598 | ||
599 | 599 | ||
@@ -616,7 +616,27 @@ void flush_peer_type ( MSISession* session, MSIMessage* msg, int peer_id ) { | |||
616 | } else {} /* Error */ | 616 | } else {} /* Error */ |
617 | } | 617 | } |
618 | 618 | ||
619 | 619 | void handle_remote_connection_change(Messenger* messenger, int friend_num, uint8_t status, void* session_p) | |
620 | { | ||
621 | MSISession* session = session_p; | ||
622 | |||
623 | switch ( status ) | ||
624 | { | ||
625 | case 0: /* Went offline */ | ||
626 | { | ||
627 | if ( session->call ) { | ||
628 | int i = 0; | ||
629 | for ( ; i < session->call->peer_count; i ++ ) | ||
630 | if ( session->call->peers[i] == friend_num ) { | ||
631 | msi_stopcall(session); /* Stop the call for now */ | ||
632 | return; | ||
633 | } | ||
634 | } | ||
635 | } break; | ||
636 | |||
637 | default: break; | ||
638 | } | ||
639 | } | ||
620 | 640 | ||
621 | /** | 641 | /** |
622 | * @brief Sends error response to peer. | 642 | * @brief Sends error response to peer. |
@@ -694,8 +714,8 @@ void* handle_timeout ( void* arg ) | |||
694 | 714 | ||
695 | } | 715 | } |
696 | 716 | ||
697 | ( *callbacks[MSI_OnTimeout] ) ( _session->agent_handler ); | 717 | ( *callbacks[MSI_OnRequestTimeout] ) ( _session->agent_handler ); |
698 | ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); | 718 | ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); |
699 | 719 | ||
700 | return NULL; | 720 | return NULL; |
701 | } | 721 | } |
@@ -774,7 +794,7 @@ int terminate_call ( MSISession* session ) { | |||
774 | 794 | ||
775 | 795 | ||
776 | /* Check event loop and cancel timed events if there are any | 796 | /* Check event loop and cancel timed events if there are any |
777 | * Notice: This has to be done before possibly | 797 | * NOTE: This has to be done before possibly |
778 | * locking the mutex the second time | 798 | * locking the mutex the second time |
779 | */ | 799 | */ |
780 | event.timer_release ( session->call->request_timer_id ); | 800 | event.timer_release ( session->call->request_timer_id ); |
@@ -797,7 +817,7 @@ int terminate_call ( MSISession* session ) { | |||
797 | pthread_mutex_destroy ( &_call->mutex ); | 817 | pthread_mutex_destroy ( &_call->mutex ); |
798 | 818 | ||
799 | free ( _call ); | 819 | free ( _call ); |
800 | 820 | ||
801 | return 0; | 821 | return 0; |
802 | } | 822 | } |
803 | 823 | ||
@@ -1136,7 +1156,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id ) | |||
1136 | * @return MSISession* The created session. | 1156 | * @return MSISession* The created session. |
1137 | * @retval NULL Error occured. | 1157 | * @retval NULL Error occured. |
1138 | */ | 1158 | */ |
1139 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { | 1159 | MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ) { |
1140 | assert ( messenger ); | 1160 | assert ( messenger ); |
1141 | 1161 | ||
1142 | MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); | 1162 | MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); |
@@ -1152,8 +1172,10 @@ MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { | |||
1152 | _retu->call_timeout = 30000; /* default value? */ | 1172 | _retu->call_timeout = 30000; /* default value? */ |
1153 | 1173 | ||
1154 | 1174 | ||
1155 | m_callback_msi_packet((struct Messenger*) messenger, msi_handle_packet, _retu ); | 1175 | m_callback_msi_packet(messenger, msi_handle_packet, _retu ); |
1156 | 1176 | ||
1177 | /* This is called when remote terminates session */ | ||
1178 | m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); | ||
1157 | 1179 | ||
1158 | return _retu; | 1180 | return _retu; |
1159 | } | 1181 | } |
@@ -1351,7 +1373,7 @@ int msi_stopcall ( MSISession* session ) { | |||
1351 | return -1; | 1373 | return -1; |
1352 | 1374 | ||
1353 | /* just terminate it */ | 1375 | /* just terminate it */ |
1354 | 1376 | ||
1355 | terminate_call ( session ); | 1377 | terminate_call ( session ); |
1356 | 1378 | ||
1357 | return 0; | 1379 | return 0; |
diff --git a/toxav/msi.h b/toxav/msi.h index 20d6671d..4487dae6 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -26,9 +26,10 @@ | |||
26 | #define __TOXMSI | 26 | #define __TOXMSI |
27 | 27 | ||
28 | #include <inttypes.h> | 28 | #include <inttypes.h> |
29 | #include "../toxcore/tox.h" | ||
30 | #include <pthread.h> | 29 | #include <pthread.h> |
31 | 30 | ||
31 | #include "../toxcore/Messenger.h" | ||
32 | |||
32 | /* define size for call_id */ | 33 | /* define size for call_id */ |
33 | #define CALL_ID_LEN 12 | 34 | #define CALL_ID_LEN 12 |
34 | 35 | ||
@@ -106,7 +107,7 @@ typedef struct _MSISession { | |||
106 | const uint8_t* ua_name; | 107 | const uint8_t* ua_name; |
107 | 108 | ||
108 | void* agent_handler; /* Pointer to an object that is handling msi */ | 109 | void* agent_handler; /* Pointer to an object that is handling msi */ |
109 | Tox* messenger_handle; | 110 | Messenger* messenger_handle; |
110 | 111 | ||
111 | uint32_t frequ; | 112 | uint32_t frequ; |
112 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ | 113 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ |
@@ -133,7 +134,7 @@ typedef enum { | |||
133 | 134 | ||
134 | /* Protocol */ | 135 | /* Protocol */ |
135 | MSI_OnError, | 136 | MSI_OnError, |
136 | MSI_OnTimeout | 137 | MSI_OnRequestTimeout |
137 | 138 | ||
138 | } MSICallbackID; | 139 | } MSICallbackID; |
139 | 140 | ||
@@ -156,7 +157,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id); | |||
156 | * @return MSISession* The created session. | 157 | * @return MSISession* The created session. |
157 | * @retval NULL Error occured. | 158 | * @retval NULL Error occured. |
158 | */ | 159 | */ |
159 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ); | 160 | MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ); |
160 | 161 | ||
161 | 162 | ||
162 | /** | 163 | /** |
diff --git a/toxav/phone.c b/toxav/phone.c index 4f078e2b..7806727d 100755 --- a/toxav/phone.c +++ b/toxav/phone.c | |||
@@ -44,18 +44,41 @@ | |||
44 | #include <unistd.h> | 44 | #include <unistd.h> |
45 | #include <assert.h> | 45 | #include <assert.h> |
46 | #include <math.h> | 46 | #include <math.h> |
47 | #include <AL/al.h> | ||
48 | #include <AL/alc.h> | ||
49 | #include <SDL/SDL.h> | ||
50 | #include <SDL/SDL_thread.h> | ||
51 | #include <pthread.h> | 47 | #include <pthread.h> |
52 | #include <opus/opus.h> | ||
53 | 48 | ||
54 | #include "media.h" | 49 | //#include "media.h" |
55 | #include "toxav.h" | 50 | #include "toxav.h" |
56 | #include "../toxcore/event.h" | 51 | #include "../toxcore/event.h" |
57 | #include "../toxcore/tox.h" | 52 | #include "../toxcore/tox.h" |
58 | 53 | ||
54 | #ifdef TOX_FFMPEG | ||
55 | /* Video encoding/decoding */ | ||
56 | #include <libavcodec/avcodec.h> | ||
57 | #include <libavformat/avformat.h> | ||
58 | #include <libswscale/swscale.h> | ||
59 | #include <libavdevice/avdevice.h> | ||
60 | #include <libavutil/opt.h> | ||
61 | #endif | ||
62 | |||
63 | #include <AL/al.h> | ||
64 | #include <AL/alc.h> | ||
65 | #include <SDL/SDL.h> | ||
66 | #include <SDL/SDL_thread.h> | ||
67 | |||
68 | /* the quit event for SDL */ | ||
69 | #define FF_QUIT_EVENT (SDL_USEREVENT + 2) | ||
70 | |||
71 | #ifdef __linux__ | ||
72 | #define VIDEO_DRIVER "video4linux2" | ||
73 | #define DEFAULT_WEBCAM "/dev/video0" | ||
74 | #endif | ||
75 | |||
76 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
77 | #define VIDEO_DRIVER "vfwcap" | ||
78 | #define DEFAULT_WEBCAM "0" | ||
79 | #endif | ||
80 | |||
81 | |||
59 | /* Define client version */ | 82 | /* Define client version */ |
60 | #define _USERAGENT "v.0.3.0" | 83 | #define _USERAGENT "v.0.3.0" |
61 | 84 | ||
@@ -96,6 +119,13 @@ typedef struct av_session_s { | |||
96 | av_friend_t* _friends; | 119 | av_friend_t* _friends; |
97 | int _friend_cout; | 120 | int _friend_cout; |
98 | char _my_public_id[200]; | 121 | char _my_public_id[200]; |
122 | #ifdef TOX_FFMPEG | ||
123 | AVInputFormat *video_input_format; | ||
124 | AVFormatContext *video_format_ctx; | ||
125 | uint8_t video_stream; | ||
126 | AVCodecContext *webcam_decoder_ctx; | ||
127 | AVCodec *webcam_decoder; | ||
128 | #endif | ||
99 | } av_session_t; | 129 | } av_session_t; |
100 | 130 | ||
101 | 131 | ||
@@ -236,8 +266,8 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str) | |||
236 | /* | 266 | /* |
237 | * How av stuff _should_ look like | 267 | * How av stuff _should_ look like |
238 | */ | 268 | */ |
239 | 269 | /* | |
240 | int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | 270 | int display_received_frame(av_session_t* _phone, vpx_image_t *image) |
241 | { | 271 | { |
242 | CodecState* cs = get_cs_temp(_phone->av); | 272 | CodecState* cs = get_cs_temp(_phone->av); |
243 | AVPicture pict; | 273 | AVPicture pict; |
@@ -249,8 +279,8 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | |||
249 | pict.linesize[0] = _phone->video_picture.bmp->pitches[0]; | 279 | pict.linesize[0] = _phone->video_picture.bmp->pitches[0]; |
250 | pict.linesize[1] = _phone->video_picture.bmp->pitches[2]; | 280 | pict.linesize[1] = _phone->video_picture.bmp->pitches[2]; |
251 | pict.linesize[2] = _phone->video_picture.bmp->pitches[1]; | 281 | pict.linesize[2] = _phone->video_picture.bmp->pitches[1]; |
252 | 282 | */ | |
253 | /* Convert the image into YUV format that SDL uses */ | 283 | /* Convert the image into YUV format that SDL uses *//* |
254 | sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, | 284 | sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, |
255 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); | 285 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); |
256 | 286 | ||
@@ -263,60 +293,65 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | |||
263 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); | 293 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); |
264 | return 1; | 294 | return 1; |
265 | } | 295 | } |
266 | 296 | */ | |
297 | #ifdef TOX_FFMPEG | ||
267 | void *encode_video_thread(void *arg) | 298 | void *encode_video_thread(void *arg) |
268 | { | 299 | { |
269 | INFO("Started encode video thread!"); | 300 | INFO("Started encode video thread!"); |
270 | 301 | ||
271 | av_session_t* _phone = arg; | 302 | av_session_t* _phone = arg; |
272 | 303 | ||
273 | _phone->running_encvid = 1; | 304 | _phone->running_encvid = 1; |
274 | 305 | //CodecState *cs = get_cs_temp(_phone->av); | |
275 | CodecState *cs = get_cs_temp(_phone->av); | ||
276 | AVPacket pkt1, *packet = &pkt1; | 306 | AVPacket pkt1, *packet = &pkt1; |
277 | int p = 0; | 307 | //int p = 0; |
278 | int got_packet; | 308 | //int got_packet; |
279 | int video_frame_finished; | 309 | int video_frame_finished; |
280 | AVFrame *s_video_frame; | 310 | AVFrame *s_video_frame; |
281 | AVFrame *webcam_frame; | 311 | AVFrame *webcam_frame; |
282 | s_video_frame = avcodec_alloc_frame(); | 312 | s_video_frame = avcodec_alloc_frame(); |
283 | webcam_frame = avcodec_alloc_frame(); | 313 | webcam_frame = avcodec_alloc_frame(); |
284 | AVPacket enc_video_packet; | 314 | //AVPacket enc_video_packet; |
285 | 315 | ||
286 | uint8_t *buffer; | 316 | uint8_t *buffer; |
287 | int numBytes; | 317 | int numBytes; |
288 | /* Determine required buffer size and allocate buffer */ | 318 | /* Determine required buffer size and allocate buffer */ |
289 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); | 319 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height); |
290 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); | 320 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); |
291 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, | 321 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, |
292 | cs->webcam_decoder_ctx->height); | 322 | _phone->webcam_decoder_ctx->height); |
293 | _phone->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, | 323 | _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, |
294 | cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, | 324 | _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, PIX_FMT_YUV420P, |
295 | SWS_BILINEAR, NULL, NULL, NULL); | 325 | SWS_BILINEAR, NULL, NULL, NULL); |
296 | 326 | ||
327 | |||
328 | vpx_image_t *image = | ||
329 | vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1); | ||
330 | |||
331 | //uint32_t frame_counter = 0; | ||
297 | while (_phone->running_encvid) { | 332 | while (_phone->running_encvid) { |
298 | 333 | ||
299 | if (av_read_frame(cs->video_format_ctx, packet) < 0) { | 334 | if (av_read_frame(_phone->video_format_ctx, packet) < 0) { |
300 | printf("error reading frame\n"); | 335 | printf("error reading frame\n"); |
301 | 336 | ||
302 | if (cs->video_format_ctx->pb->error != 0) | 337 | if (_phone->video_format_ctx->pb->error != 0) |
303 | break; | 338 | break; |
304 | 339 | ||
305 | continue; | 340 | continue; |
306 | } | 341 | } |
307 | 342 | ||
308 | if (packet->stream_index == cs->video_stream) { | 343 | if (packet->stream_index == _phone->video_stream) { |
309 | if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { | 344 | if (avcodec_decode_video2(_phone->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { |
310 | printf("couldn't decode\n"); | 345 | printf("couldn't decode\n"); |
311 | continue; | 346 | continue; |
312 | } | 347 | } |
313 | 348 | ||
314 | av_free_packet(packet); | 349 | av_free_packet(packet); |
315 | sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, | 350 | sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, |
316 | cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); | 351 | _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); |
317 | /* create a new I-frame every 60 frames */ | 352 | /* create a new I-frame every 60 frames */ |
318 | ++p; | 353 | //++p; |
319 | 354 | /* | |
320 | if (p == 60) { | 355 | if (p == 60) { |
321 | 356 | ||
322 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; | 357 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; |
@@ -325,53 +360,66 @@ void *encode_video_thread(void *arg) | |||
325 | p = 0; | 360 | p = 0; |
326 | } else { | 361 | } else { |
327 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; | 362 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; |
328 | } | 363 | }*/ |
329 | 364 | ||
330 | if (video_frame_finished) { | 365 | if (video_frame_finished) { |
331 | 366 | memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0], s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height); | |
332 | if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { | 367 | memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1], s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2); |
368 | memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2], s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2); | ||
369 | toxav_send_video (_phone->av, image); | ||
370 | //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { | ||
371 | /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) { | ||
333 | printf("could not encode video frame\n"); | 372 | printf("could not encode video frame\n"); |
334 | continue; | 373 | continue; |
335 | } | 374 | } |
375 | ++frame_counter; | ||
336 | 376 | ||
337 | if (!got_packet) { | 377 | vpx_codec_iter_t iter = NULL; |
338 | continue; | 378 | vpx_codec_cx_pkt_t *pkt; |
339 | } | 379 | while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) { |
380 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) | ||
381 | toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz); | ||
382 | }*/ | ||
383 | //if (!got_packet) { | ||
384 | // continue; | ||
385 | //} | ||
340 | 386 | ||
341 | if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); | 387 | //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); |
342 | 388 | ||
343 | toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); | 389 | //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); |
344 | 390 | ||
345 | av_free_packet(&enc_video_packet); | 391 | //av_free_packet(&enc_video_packet); |
346 | } | 392 | } |
347 | } else { | 393 | } else { |
348 | av_free_packet(packet); | 394 | av_free_packet(packet); |
349 | } | 395 | } |
350 | } | 396 | } |
351 | 397 | ||
398 | vpx_img_free(image); | ||
399 | |||
352 | /* clean up codecs */ | 400 | /* clean up codecs */ |
353 | pthread_mutex_lock(&cs->ctrl_mutex); | 401 | //pthread_mutex_lock(&cs->ctrl_mutex); |
354 | av_free(buffer); | 402 | av_free(buffer); |
355 | av_free(webcam_frame); | 403 | av_free(webcam_frame); |
356 | av_free(s_video_frame); | 404 | av_free(s_video_frame); |
357 | sws_freeContext(_phone->sws_ctx); | 405 | sws_freeContext(_phone->sws_ctx); |
358 | avcodec_close(cs->webcam_decoder_ctx); | 406 | //avcodec_close(webcam_decoder_ctx); |
359 | avcodec_close(cs->video_encoder_ctx); | 407 | //avcodec_close(cs->video_encoder_ctx); |
360 | pthread_mutex_unlock(&cs->ctrl_mutex); | 408 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
361 | 409 | ||
362 | _phone->running_encvid = -1; | 410 | _phone->running_encvid = -1; |
363 | 411 | ||
364 | pthread_exit ( NULL ); | 412 | pthread_exit ( NULL ); |
365 | } | 413 | } |
414 | #endif | ||
366 | 415 | ||
367 | void *encode_audio_thread(void *arg) | 416 | void *encode_audio_thread(void *arg) |
368 | { | 417 | { |
369 | INFO("Started encode audio thread!"); | 418 | INFO("Started encode audio thread!"); |
370 | av_session_t* _phone = arg; | 419 | av_session_t* _phone = arg; |
371 | _phone->running_encaud = 1; | 420 | _phone->running_encaud = 1; |
372 | 421 | ||
373 | unsigned char encoded_data[4096]; | 422 | int ret = 0; |
374 | int encoded_size = 0; | ||
375 | int16_t frame[4096]; | 423 | int16_t frame[4096]; |
376 | int frame_size = AUDIO_FRAME_SIZE; | 424 | int frame_size = AUDIO_FRAME_SIZE; |
377 | ALint sample = 0; | 425 | ALint sample = 0; |
@@ -383,94 +431,164 @@ void *encode_audio_thread(void *arg) | |||
383 | if (sample >= frame_size) { | 431 | if (sample >= frame_size) { |
384 | alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); | 432 | alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); |
385 | 433 | ||
386 | encoded_size = toxav_encode_audio(_phone->av, frame, frame_size, encoded_data); | 434 | ret = toxav_send_audio(_phone->av, frame, frame_size); |
387 | 435 | ||
388 | if (encoded_size <= 0) { | 436 | if (ret < 0) |
389 | printf("Could not encode audio packet\n"); | 437 | printf("Could not encode or send audio packet\n"); |
390 | } else { | 438 | |
391 | if ( -1 == toxav_send_rtp_payload(_phone->av, TypeAudio, encoded_data, encoded_size) ) | ||
392 | assert(0); | ||
393 | } | ||
394 | } else { | 439 | } else { |
395 | usleep(1000); | 440 | usleep(1000); |
396 | } | 441 | } |
397 | } | 442 | } |
398 | 443 | ||
399 | /* clean up codecs * | 444 | /* clean up codecs * |
400 | pthread_mutex_lock(&cs->ctrl_mutex);*/ | 445 | pthread_mutex_lock(&cs->ctrl_mutex);* / |
401 | alcCaptureStop((ALCdevice*)_phone->audio_capture_device); | 446 | alcCaptureStop((ALCdevice*)_phone->audio_capture_device); |
402 | alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); | 447 | alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); |
403 | /*pthread_mutex_unlock(&cs->ctrl_mutex);*/ | 448 | / *pthread_mutex_unlock(&cs->ctrl_mutex);*/ |
404 | _phone->running_encaud = -1; | 449 | _phone->running_encaud = -1; |
405 | pthread_exit ( NULL ); | 450 | pthread_exit ( NULL ); |
406 | } | 451 | } |
407 | 452 | ||
453 | void convert_to_rgb(vpx_image_t *img, unsigned char *out) | ||
454 | { | ||
455 | const int w = img->d_w; | ||
456 | const int w2 = w/2; | ||
457 | const int pstride = w*3; | ||
458 | const int h = img->d_h; | ||
459 | const int h2 = h/2; | ||
460 | |||
461 | const int strideY = img->stride[0]; | ||
462 | const int strideU = img->stride[1]; | ||
463 | const int strideV = img->stride[2]; | ||
464 | int posy, posx; | ||
465 | for (posy = 0; posy < h2; posy++) { | ||
466 | unsigned char *dst = out + pstride * (posy * 2); | ||
467 | unsigned char *dst2 = out + pstride * (posy * 2 + 1); | ||
468 | const unsigned char *srcY = img->planes[0] + strideY * posy * 2; | ||
469 | const unsigned char *srcY2 = img->planes[0] + strideY * (posy * 2 + 1); | ||
470 | const unsigned char *srcU = img->planes[1] + strideU * posy; | ||
471 | const unsigned char *srcV = img->planes[2] + strideV * posy; | ||
472 | |||
473 | for (posx = 0; posx < w2; posx++) { | ||
474 | unsigned char Y,U,V; | ||
475 | short R,G,B; | ||
476 | short iR,iG,iB; | ||
477 | |||
478 | U = *(srcU++); V = *(srcV++); | ||
479 | iR = (351 * (V-128)) / 256; | ||
480 | iG = - (179 * (V-128)) / 256 - (86 * (U-128)) / 256; | ||
481 | iB = (444 * (U-128)) / 256; | ||
482 | |||
483 | Y = *(srcY++); | ||
484 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
485 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
486 | *(dst++) = R; *(dst++) = G; *(dst++) = B; | ||
487 | |||
488 | Y = *(srcY2++); | ||
489 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
490 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
491 | *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; | ||
492 | |||
493 | Y = *(srcY++) ; | ||
494 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
495 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
496 | *(dst++) = R; *(dst++) = G; *(dst++) = B; | ||
497 | |||
498 | Y = *(srcY2++); | ||
499 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
500 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
501 | *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | |||
506 | #define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff }) | ||
507 | |||
408 | void *decode_video_thread(void *arg) | 508 | void *decode_video_thread(void *arg) |
409 | { | 509 | { |
410 | INFO("Started decode video thread!"); | 510 | INFO("Started decode video thread!"); |
411 | av_session_t* _phone = arg; | 511 | av_session_t* _phone = arg; |
412 | _phone->running_decvid = 1; | 512 | _phone->running_decvid = 1; |
413 | 513 | ||
414 | CodecState *cs = get_cs_temp(_phone->av); | 514 | //CodecState *cs = get_cs_temp(_phone->av); |
415 | cs->video_stream = 0; | 515 | //cs->video_stream = 0; |
416 | 516 | ||
417 | int recved_size; | 517 | //int recved_size; |
418 | uint8_t dest[RTP_PAYLOAD_SIZE]; | 518 | //uint8_t dest[RTP_PAYLOAD_SIZE]; |
419 | 519 | ||
420 | int dec_frame_finished; | 520 | //int dec_frame_finished; |
421 | AVFrame *r_video_frame; | 521 | //AVFrame *r_video_frame; |
422 | r_video_frame = avcodec_alloc_frame(); | 522 | //r_video_frame = avcodec_alloc_frame(); |
423 | AVPacket dec_video_packet; | 523 | //AVPacket dec_video_packet; |
424 | av_new_packet (&dec_video_packet, 65536); | 524 | //av_new_packet (&dec_video_packet, 65536); |
425 | int width = 0; | 525 | int width = 0; |
426 | int height = 0; | 526 | int height = 0; |
427 | 527 | ||
428 | while (_phone->running_decvid) { | 528 | while (_phone->running_decvid) { |
429 | 529 | //recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, dest); | |
430 | recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, 1, dest); | 530 | //if (recved_size) { |
431 | 531 | vpx_image_t *image; | |
432 | if (recved_size) { | 532 | if (toxav_recv_video(_phone->av, &image) == 0) { |
433 | memcpy(dec_video_packet.data, dest, recved_size); | 533 | //memcpy(dec_video_packet.data, dest, recved_size); |
434 | dec_video_packet.size = recved_size; | 534 | //dec_video_packet.size = recved_size; |
435 | 535 | ||
436 | avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); | 536 | //avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); |
437 | 537 | ||
438 | if (dec_frame_finished) { | 538 | //if (dec_frame_finished) { |
439 | 539 | ||
440 | /* Check if size has changed */ | 540 | /* Check if size has changed */ |
441 | if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { | 541 | if (image->d_w != width || image->d_h != height) { |
442 | 542 | ||
443 | width = cs->video_decoder_ctx->width; | 543 | width = image->d_w; |
444 | height = cs->video_decoder_ctx->height; | 544 | height = image->d_h; |
445 | 545 | ||
446 | printf("w: %d h: %d \n", width, height); | 546 | printf("w: %d h: %d \n", width, height); |
447 | 547 | ||
448 | screen = SDL_SetVideoMode(width, height, 0, 0); | 548 | screen = SDL_SetVideoMode(width, height, 0, 0); |
449 | 549 | ||
450 | if (_phone->video_picture.bmp) | 550 | //if (_phone->video_picture.bmp) |
451 | SDL_FreeYUVOverlay(_phone->video_picture.bmp); | 551 | // SDL_FreeYUVOverlay(_phone->video_picture.bmp); |
452 | 552 | ||
453 | _phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); | 553 | //_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); |
454 | _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, | 554 | // _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, |
455 | SWS_BILINEAR, NULL, NULL, NULL); | 555 | // SWS_BILINEAR, NULL, NULL, NULL); |
456 | } | 556 | } |
557 | uint8_t *rgb_image = malloc(width*height*3); | ||
558 | convert_to_rgb(image, rgb_image); | ||
559 | SDL_Surface* img_surface = SDL_CreateRGBSurfaceFrom(rgb_image, width, height, 24, width * 3, mask32(0), mask32(1), mask32(2), 0); | ||
560 | if(SDL_BlitSurface(img_surface, NULL, screen, NULL) == 0) | ||
561 | SDL_UpdateRect(screen, 0, 0, 0, 0); | ||
562 | /* | ||
563 | SDL_LockYUVOverlay(_phone->video_picture.bmp); | ||
564 | memcpy(_phone->video_picture.bmp->pixels[0], image->planes[VPX_PLANE_Y], _phone->video_picture.bmp->pitches[0] * height); | ||
565 | memcpy(_phone->video_picture.bmp->pixels[1], image->planes[VPX_PLANE_V], _phone->video_picture.bmp->pitches[1] * height / 2); | ||
566 | memcpy(_phone->video_picture.bmp->pixels[2], image->planes[VPX_PLANE_U], _phone->video_picture.bmp->pitches[2] * height / 2); | ||
457 | 567 | ||
458 | display_received_frame(_phone, r_video_frame); | 568 | SDL_Rect rect; |
459 | } else { | 569 | rect.x = 0; |
570 | rect.y = 0; | ||
571 | rect.w = width; | ||
572 | rect.h = height; | ||
573 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);*/ | ||
574 | free(rgb_image); | ||
575 | //display_received_frame(_phone, image); | ||
576 | |||
577 | } //else { | ||
460 | /* TODO: request the sender to create a new i-frame immediatly */ | 578 | /* TODO: request the sender to create a new i-frame immediatly */ |
461 | printf("Bad video packet\n"); | 579 | //printf("Bad video packet\n"); |
462 | } | 580 | //} |
463 | } | 581 | //} |
464 | 582 | ||
465 | usleep(1000); | 583 | usleep(1000); |
466 | } | 584 | } |
467 | 585 | ||
468 | /* clean up codecs */ | 586 | /* clean up codecs */ |
469 | av_free(r_video_frame); | 587 | //av_free(r_video_frame); |
470 | 588 | ||
471 | pthread_mutex_lock(&cs->ctrl_mutex); | 589 | //pthread_mutex_lock(&cs->ctrl_mutex); |
472 | avcodec_close(cs->video_decoder_ctx); | 590 | //avcodec_close(cs->video_decoder_ctx); |
473 | pthread_mutex_unlock(&cs->ctrl_mutex); | 591 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
474 | 592 | ||
475 | _phone->running_decvid = -1; | 593 | _phone->running_decvid = -1; |
476 | 594 | ||
@@ -483,11 +601,11 @@ void *decode_audio_thread(void *arg) | |||
483 | av_session_t* _phone = arg; | 601 | av_session_t* _phone = arg; |
484 | _phone->running_decaud = 1; | 602 | _phone->running_decaud = 1; |
485 | 603 | ||
486 | int recved_size; | 604 | //int recved_size; |
487 | uint8_t dest [RTP_PAYLOAD_SIZE]; | 605 | //uint8_t dest [RTP_PAYLOAD_SIZE]; |
488 | 606 | ||
489 | int frame_size = AUDIO_FRAME_SIZE; | 607 | int frame_size = AUDIO_FRAME_SIZE; |
490 | int data_size; | 608 | //int data_size; |
491 | 609 | ||
492 | ALCdevice *dev; | 610 | ALCdevice *dev; |
493 | ALCcontext *ctx; | 611 | ALCcontext *ctx; |
@@ -507,7 +625,7 @@ void *decode_audio_thread(void *arg) | |||
507 | 625 | ||
508 | uint16_t zeros[frame_size]; | 626 | uint16_t zeros[frame_size]; |
509 | memset(zeros, 0, frame_size); | 627 | memset(zeros, 0, frame_size); |
510 | opus_int16 PCM[frame_size]; | 628 | int16_t PCM[frame_size]; |
511 | 629 | ||
512 | int i; | 630 | int i; |
513 | for (i = 0; i < openal_buffers; ++i) { | 631 | for (i = 0; i < openal_buffers; ++i) { |
@@ -527,28 +645,15 @@ void *decode_audio_thread(void *arg) | |||
527 | while (_phone->running_decaud) { | 645 | while (_phone->running_decaud) { |
528 | 646 | ||
529 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); | 647 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); |
530 | 648 | if (ready <= 0) | |
531 | recved_size = toxav_recv_rtp_payload(_phone->av, TypeAudio, ready, dest); | 649 | continue; |
532 | 650 | ||
533 | if ( recved_size == ErrorAudioPacketLost ) { | 651 | dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM); |
534 | printf("Lost packet\n"); | 652 | |
535 | dec_frame_len = toxav_decode_audio(_phone->av, NULL, 0, frame_size, PCM); | ||
536 | |||
537 | } else if ( recved_size ) { | ||
538 | dec_frame_len = toxav_decode_audio(_phone->av, dest, recved_size, frame_size, PCM); | ||
539 | } | ||
540 | |||
541 | |||
542 | /* Play the packet */ | 653 | /* Play the packet */ |
543 | if (dec_frame_len) { | 654 | if (dec_frame_len > 0) { |
544 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); | ||
545 | |||
546 | if (ready <= 0) | ||
547 | continue; | ||
548 | |||
549 | alSourceUnqueueBuffers(source, 1, &buffer); | 655 | alSourceUnqueueBuffers(source, 1, &buffer); |
550 | data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); | 656 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000); |
551 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000); | ||
552 | int error = alGetError(); | 657 | int error = alGetError(); |
553 | 658 | ||
554 | if (error != AL_NO_ERROR) { | 659 | if (error != AL_NO_ERROR) { |
@@ -573,16 +678,16 @@ void *decode_audio_thread(void *arg) | |||
573 | 678 | ||
574 | 679 | ||
575 | ending: | 680 | ending: |
576 | /* clean up codecs * / | 681 | /* clean up codecs */ |
577 | pthread_mutex_lock(&cs->ctrl_mutex); | 682 | //pthread_mutex_lock(&cs->ctrl_mutex); |
578 | 683 | /* | |
579 | alDeleteSources(1, &source); | 684 | alDeleteSources(1, &source); |
580 | alDeleteBuffers(openal_buffers, buffers); | 685 | alDeleteBuffers(openal_buffers, buffers); |
581 | alcMakeContextCurrent(NULL); | 686 | alcMakeContextCurrent(NULL); |
582 | alcDestroyContext(ctx); | 687 | alcDestroyContext(ctx); |
583 | alcCloseDevice(dev); | 688 | alcCloseDevice(dev); |
584 | 689 | */ | |
585 | pthread_mutex_unlock(&cs->ctrl_mutex); */ | 690 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
586 | 691 | ||
587 | _phone->running_decaud = -1; | 692 | _phone->running_decaud = -1; |
588 | 693 | ||
@@ -604,7 +709,7 @@ int phone_startmedia_loop ( ToxAv* arg ) | |||
604 | /* | 709 | /* |
605 | * Rise all threads | 710 | * Rise all threads |
606 | */ | 711 | */ |
607 | 712 | #ifdef TOX_FFMPEG | |
608 | /* Only checks for last peer */ | 713 | /* Only checks for last peer */ |
609 | if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo && | 714 | if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo && |
610 | 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) ) | 715 | 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) ) |
@@ -612,7 +717,7 @@ int phone_startmedia_loop ( ToxAv* arg ) | |||
612 | INFO("Error while starting encode_video_thread()"); | 717 | INFO("Error while starting encode_video_thread()"); |
613 | return -1; | 718 | return -1; |
614 | } | 719 | } |
615 | 720 | #endif | |
616 | /* Always send audio */ | 721 | /* Always send audio */ |
617 | if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) | 722 | if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) |
618 | { | 723 | { |
@@ -779,7 +884,6 @@ av_session_t* av_init_session() | |||
779 | } | 884 | } |
780 | 885 | ||
781 | _retu->_friends = NULL; | 886 | _retu->_friends = NULL; |
782 | _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT); | ||
783 | 887 | ||
784 | 888 | ||
785 | const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); | 889 | const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); |
@@ -821,13 +925,58 @@ av_session_t* av_init_session() | |||
821 | printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); | 925 | printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); |
822 | return 0; | 926 | return 0; |
823 | } | 927 | } |
824 | 928 | uint16_t height = 0, width = 0; | |
825 | 929 | #ifdef TOX_FFMPEG | |
930 | avdevice_register_all(); | ||
931 | avcodec_register_all(); | ||
932 | av_register_all(); | ||
933 | |||
934 | _retu->video_input_format = av_find_input_format(VIDEO_DRIVER); | ||
935 | if (avformat_open_input(&_retu->video_format_ctx, DEFAULT_WEBCAM, _retu->video_input_format, NULL) != 0) { | ||
936 | fprintf(stderr, "Opening video_input_format failed!\n"); | ||
937 | //return -1; | ||
938 | return NULL; | ||
939 | } | ||
940 | |||
941 | avformat_find_stream_info(_retu->video_format_ctx, NULL); | ||
942 | av_dump_format(_retu->video_format_ctx, 0, DEFAULT_WEBCAM, 0); | ||
943 | |||
944 | for (i = 0; i < _retu->video_format_ctx->nb_streams; ++i) { | ||
945 | if (_retu->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
946 | _retu->video_stream = i; | ||
947 | break; | ||
948 | } | ||
949 | } | ||
950 | |||
951 | _retu->webcam_decoder_ctx = _retu->video_format_ctx->streams[_retu->video_stream]->codec; | ||
952 | _retu->webcam_decoder = avcodec_find_decoder(_retu->webcam_decoder_ctx->codec_id); | ||
953 | |||
954 | if (_retu->webcam_decoder == NULL) { | ||
955 | fprintf(stderr, "Unsupported codec!\n"); | ||
956 | //return -1; | ||
957 | return NULL; | ||
958 | } | ||
959 | |||
960 | if (_retu->webcam_decoder_ctx == NULL) { | ||
961 | fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); | ||
962 | //return -1; | ||
963 | return NULL; | ||
964 | } | ||
965 | |||
966 | if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) { | ||
967 | fprintf(stderr, "Opening webcam decoder failed!\n"); | ||
968 | //return -1; | ||
969 | return NULL; | ||
970 | } | ||
971 | width = _retu->webcam_decoder_ctx->width; | ||
972 | height = _retu->webcam_decoder_ctx->height; | ||
973 | #endif | ||
826 | uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; | 974 | uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; |
827 | tox_get_address(_retu->_messenger, _byte_address ); | 975 | tox_get_address(_retu->_messenger, _byte_address ); |
828 | fraddr_to_str( _byte_address, _retu->_my_public_id ); | 976 | fraddr_to_str( _byte_address, _retu->_my_public_id ); |
829 | 977 | ||
830 | 978 | ||
979 | _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT, width, height); | ||
831 | 980 | ||
832 | /* ------------------ */ | 981 | /* ------------------ */ |
833 | 982 | ||
@@ -842,7 +991,7 @@ av_session_t* av_init_session() | |||
842 | toxav_register_callstate_callback(callback_recv_ending, OnEnding); | 991 | toxav_register_callstate_callback(callback_recv_ending, OnEnding); |
843 | 992 | ||
844 | toxav_register_callstate_callback(callback_recv_error, OnError); | 993 | toxav_register_callstate_callback(callback_recv_error, OnError); |
845 | toxav_register_callstate_callback(callback_requ_timeout, OnTimeout); | 994 | toxav_register_callstate_callback(callback_requ_timeout, OnRequestTimeout); |
846 | 995 | ||
847 | /* ------------------ */ | 996 | /* ------------------ */ |
848 | 997 | ||
@@ -1013,9 +1162,9 @@ void do_phone ( av_session_t* _phone ) | |||
1013 | { | 1162 | { |
1014 | ToxAvError rc; | 1163 | ToxAvError rc; |
1015 | 1164 | ||
1016 | if ( _len > 1 && _line[2] == 'v' ) | 1165 | if ( _len > 1 && _line[2] == 'v' ) { |
1017 | rc = toxav_answer(_phone->av, TypeVideo); | 1166 | rc = toxav_answer(_phone->av, TypeVideo); |
1018 | else | 1167 | } else |
1019 | rc = toxav_answer(_phone->av, TypeAudio); | 1168 | rc = toxav_answer(_phone->av, TypeAudio); |
1020 | 1169 | ||
1021 | if ( rc == ErrorInvalidState ) { | 1170 | if ( rc == ErrorInvalidState ) { |
diff --git a/toxav/rtp.c b/toxav/rtp.c index e23fa132..80fcc630 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -30,10 +30,6 @@ | |||
30 | #include <assert.h> | 30 | #include <assert.h> |
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | 32 | ||
33 | #include "../toxcore/util.h" | ||
34 | #include "../toxcore/network.h" | ||
35 | #include "../toxcore/net_crypto.h" | ||
36 | #include "../toxcore/Messenger.h" | ||
37 | 33 | ||
38 | #define PAYLOAD_ID_VALUE_OPUS 1 | 34 | #define PAYLOAD_ID_VALUE_OPUS 1 |
39 | #define PAYLOAD_ID_VALUE_VP8 2 | 35 | #define PAYLOAD_ID_VALUE_VP8 2 |
@@ -241,8 +237,8 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) | |||
241 | 237 | ||
242 | _retu->flags = *_it; ++_it; | 238 | _retu->flags = *_it; ++_it; |
243 | 239 | ||
244 | /* This indicates if the first 2 bytes are valid. | 240 | /* This indicates if the first 2 bits are valid. |
245 | * Now it my happen that this is out of order but | 241 | * Now it may happen that this is out of order but |
246 | * it cuts down chances of parsing some invalid value | 242 | * it cuts down chances of parsing some invalid value |
247 | */ | 243 | */ |
248 | 244 | ||
@@ -299,7 +295,7 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) | |||
299 | * @return RTPExtHeader* Extracted extension header. | 295 | * @return RTPExtHeader* Extracted extension header. |
300 | * @retval NULL Error occurred while extracting extension header. | 296 | * @retval NULL Error occurred while extracting extension header. |
301 | */ | 297 | */ |
302 | RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) | 298 | RTPExtHeader* extract_ext_header ( const uint8_t* payload, uint16_t length ) |
303 | { | 299 | { |
304 | const uint8_t* _it = payload; | 300 | const uint8_t* _it = payload; |
305 | 301 | ||
@@ -551,7 +547,7 @@ int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t l | |||
551 | /* Hopefully this goes well | 547 | /* Hopefully this goes well |
552 | * NOTE: Is this even used? | 548 | * NOTE: Is this even used? |
553 | */ | 549 | */ |
554 | memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port)); | 550 | memcpy(&_msg->from, &ip_port, sizeof(IP_Port)); |
555 | 551 | ||
556 | /* Check if message came in late */ | 552 | /* Check if message came in late */ |
557 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ | 553 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ |
@@ -689,7 +685,7 @@ int rtp_release_session_recv ( RTPSession* session ) | |||
689 | 685 | ||
690 | 686 | ||
691 | /** | 687 | /** |
692 | * @brief Get's oldes message in the list. | 688 | * @brief Gets oldest message in the list. |
693 | * | 689 | * |
694 | * @param session Where the list is. | 690 | * @param session Where the list is. |
695 | * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. | 691 | * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. |
@@ -727,7 +723,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ) | |||
727 | * @retval -1 On error. | 723 | * @retval -1 On error. |
728 | * @retval 0 On success. | 724 | * @retval 0 On success. |
729 | */ | 725 | */ |
730 | int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ) | 726 | int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ) |
731 | { | 727 | { |
732 | RTPMessage* msg = rtp_new_message (session, data, length); | 728 | RTPMessage* msg = rtp_new_message (session, data, length); |
733 | 729 | ||
@@ -743,8 +739,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin | |||
743 | increase_nonce ( _calculated, msg->header->sequnum ); | 739 | increase_nonce ( _calculated, msg->header->sequnum ); |
744 | 740 | ||
745 | /* Need to skip 2 bytes that are for sequnum */ | 741 | /* Need to skip 2 bytes that are for sequnum */ |
746 | int encrypted_length = encrypt_data_symmetric( | 742 | int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ |
747 | (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 ); | 743 | (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); |
748 | 744 | ||
749 | int full_length = encrypted_length + 3; | 745 | int full_length = encrypted_length + 3; |
750 | 746 | ||
@@ -752,7 +748,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin | |||
752 | _send_data[2] = msg->data[1]; | 748 | _send_data[2] = msg->data[1]; |
753 | 749 | ||
754 | 750 | ||
755 | if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) { | 751 | /*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/ |
752 | if ( full_length != send_custom_user_packet(messenger, session->dest, _send_data, full_length) ) { | ||
756 | printf("Rtp error: %s\n", strerror(errno)); | 753 | printf("Rtp error: %s\n", strerror(errno)); |
757 | return -1; | 754 | return -1; |
758 | } | 755 | } |
@@ -816,30 +813,26 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) | |||
816 | * @retval NULL Error occurred. | 813 | * @retval NULL Error occurred. |
817 | */ | 814 | */ |
818 | RTPSession* rtp_init_session ( int payload_type, | 815 | RTPSession* rtp_init_session ( int payload_type, |
819 | Tox* messenger, | 816 | Messenger* messenger, |
820 | int friend_num, | 817 | int friend_num, |
821 | const uint8_t* encrypt_key, | 818 | const uint8_t* encrypt_key, |
822 | const uint8_t* decrypt_key, | 819 | const uint8_t* decrypt_key, |
823 | const uint8_t* encrypt_nonce, | 820 | const uint8_t* encrypt_nonce, |
824 | const uint8_t* decrypt_nonce | 821 | const uint8_t* decrypt_nonce ) |
825 | ) | ||
826 | { | 822 | { |
827 | Messenger* _messenger_casted = (Messenger*) messenger; | ||
828 | |||
829 | IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num ); | ||
830 | |||
831 | /* This should be enough eh? */ | ||
832 | if ( _dest.port == 0) { | ||
833 | return NULL; | ||
834 | } | ||
835 | |||
836 | RTPSession* _retu = calloc(1, sizeof(RTPSession)); | 823 | RTPSession* _retu = calloc(1, sizeof(RTPSession)); |
837 | assert(_retu); | 824 | assert(_retu); |
838 | 825 | ||
839 | networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); | 826 | /*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/ |
827 | if ( -1 == custom_user_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) | ||
828 | { | ||
829 | fprintf(stderr, "Error setting custom register handler for rtp session\n"); | ||
830 | free(_retu); | ||
831 | return NULL; | ||
832 | } | ||
840 | 833 | ||
841 | _retu->version = RTP_VERSION; /* It's always 2 */ | 834 | _retu->version = RTP_VERSION; /* It's always 2 */ |
842 | _retu->padding = 0; /* If some additional data is needed about the packet */ | 835 | _retu->padding = 0; /* If some additional data is needed about the packet */ |
843 | _retu->extension = 0; /* If extension to header is needed */ | 836 | _retu->extension = 0; /* If extension to header is needed */ |
844 | _retu->cc = 1; /* Amount of contributors */ | 837 | _retu->cc = 1; /* Amount of contributors */ |
845 | _retu->csrc = NULL; /* Container */ | 838 | _retu->csrc = NULL; /* Container */ |
@@ -847,7 +840,7 @@ RTPSession* rtp_init_session ( int payload_type, | |||
847 | _retu->marker = 0; | 840 | _retu->marker = 0; |
848 | _retu->payload_type = payload_table[payload_type]; | 841 | _retu->payload_type = payload_table[payload_type]; |
849 | 842 | ||
850 | _retu->dest = *((tox_IP_Port*)&_dest); | 843 | _retu->dest = friend_num; |
851 | 844 | ||
852 | _retu->rsequnum = _retu->sequnum = 1; | 845 | _retu->rsequnum = _retu->sequnum = 1; |
853 | 846 | ||
@@ -894,12 +887,12 @@ RTPSession* rtp_init_session ( int payload_type, | |||
894 | * @retval -1 Error occurred. | 887 | * @retval -1 Error occurred. |
895 | * @retval 0 Success. | 888 | * @retval 0 Success. |
896 | */ | 889 | */ |
897 | int rtp_terminate_session ( RTPSession* session, Tox* messenger ) | 890 | int rtp_terminate_session ( RTPSession* session, Messenger* messenger ) |
898 | { | 891 | { |
899 | if ( !session ) | 892 | if ( !session ) |
900 | return -1; | 893 | return -1; |
901 | 894 | ||
902 | networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL); | 895 | custom_user_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); |
903 | 896 | ||
904 | free ( session->ext_header ); | 897 | free ( session->ext_header ); |
905 | free ( session->csrc ); | 898 | free ( session->csrc ); |
diff --git a/toxav/rtp.h b/toxav/rtp.h index 4b0d681f..03f6a873 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h | |||
@@ -28,10 +28,14 @@ | |||
28 | #define RTP_VERSION 2 | 28 | #define RTP_VERSION 2 |
29 | #include <inttypes.h> | 29 | #include <inttypes.h> |
30 | #include <pthread.h> | 30 | #include <pthread.h> |
31 | #include "../toxcore/tox.h" | 31 | |
32 | #include "../toxcore/util.h" | ||
33 | #include "../toxcore/network.h" | ||
34 | #include "../toxcore/net_crypto.h" | ||
35 | #include "../toxcore/Messenger.h" | ||
32 | 36 | ||
33 | #define MAX_SEQU_NUM 65535 | 37 | #define MAX_SEQU_NUM 65535 |
34 | #define MAX_RTP_SIZE 10400 | 38 | #define MAX_RTP_SIZE 65535 |
35 | 39 | ||
36 | /** | 40 | /** |
37 | * @brief Standard rtp header | 41 | * @brief Standard rtp header |
@@ -72,7 +76,7 @@ typedef struct _RTPMessage { | |||
72 | 76 | ||
73 | uint8_t data[MAX_RTP_SIZE]; | 77 | uint8_t data[MAX_RTP_SIZE]; |
74 | uint32_t length; | 78 | uint32_t length; |
75 | tox_IP_Port from; | 79 | IP_Port from; |
76 | 80 | ||
77 | struct _RTPMessage* next; | 81 | struct _RTPMessage* next; |
78 | } RTPMessage; | 82 | } RTPMessage; |
@@ -128,7 +132,7 @@ typedef struct _RTPSession { | |||
128 | uint8_t prefix; | 132 | uint8_t prefix; |
129 | 133 | ||
130 | pthread_mutex_t mutex; | 134 | pthread_mutex_t mutex; |
131 | tox_IP_Port dest; | 135 | int dest; |
132 | 136 | ||
133 | } RTPSession; | 137 | } RTPSession; |
134 | 138 | ||
@@ -164,7 +168,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ); | |||
164 | * @retval -1 On error. | 168 | * @retval -1 On error. |
165 | * @retval 0 On success. | 169 | * @retval 0 On success. |
166 | */ | 170 | */ |
167 | int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ); | 171 | int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ); |
168 | 172 | ||
169 | 173 | ||
170 | /** | 174 | /** |
@@ -192,7 +196,7 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ); | |||
192 | * @retval NULL Error occurred. | 196 | * @retval NULL Error occurred. |
193 | */ | 197 | */ |
194 | RTPSession* rtp_init_session ( int payload_type, | 198 | RTPSession* rtp_init_session ( int payload_type, |
195 | Tox* messenger, | 199 | Messenger* messenger, |
196 | int friend_num, | 200 | int friend_num, |
197 | const uint8_t* encrypt_key, | 201 | const uint8_t* encrypt_key, |
198 | const uint8_t* decrypt_key, | 202 | const uint8_t* decrypt_key, |
@@ -209,7 +213,7 @@ RTPSession* rtp_init_session ( int payload_type, | |||
209 | * @retval -1 Error occurred. | 213 | * @retval -1 Error occurred. |
210 | * @retval 0 Success. | 214 | * @retval 0 Success. |
211 | */ | 215 | */ |
212 | int rtp_terminate_session ( RTPSession* session, Tox* messenger ); | 216 | int rtp_terminate_session ( RTPSession* session, Messenger* messenger ); |
213 | 217 | ||
214 | 218 | ||
215 | 219 | ||
diff --git a/toxav/toxav.c b/toxav/toxav.c index 8757d7fd..5683795e 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -26,16 +26,16 @@ | |||
26 | #include "config.h" | 26 | #include "config.h" |
27 | #endif /* HAVE_CONFIG_H */ | 27 | #endif /* HAVE_CONFIG_H */ |
28 | 28 | ||
29 | #include "toxav.h" | 29 | #include "media.h" |
30 | #include "../toxcore/tox.h" | ||
31 | #include "rtp.h" | 30 | #include "rtp.h" |
32 | #include "msi.h" | 31 | #include "msi.h" |
33 | #include "media.h" | ||
34 | 32 | ||
35 | #include <stdlib.h> | 33 | #include <stdlib.h> |
36 | #include <string.h> | 34 | #include <string.h> |
37 | #include <assert.h> | 35 | #include <assert.h> |
38 | 36 | ||
37 | #include "toxav.h" | ||
38 | |||
39 | #define inline__ inline __attribute__((always_inline)) | 39 | #define inline__ inline __attribute__((always_inline)) |
40 | 40 | ||
41 | static const uint8_t audio_index = 0, video_index = 1; | 41 | static const uint8_t audio_index = 0, video_index = 1; |
@@ -50,7 +50,7 @@ typedef enum { | |||
50 | 50 | ||
51 | typedef struct _ToxAv | 51 | typedef struct _ToxAv |
52 | { | 52 | { |
53 | Tox* messenger; | 53 | Messenger* messenger; |
54 | 54 | ||
55 | MSISession* msi_session; /** Main msi session */ | 55 | MSISession* msi_session; /** Main msi session */ |
56 | 56 | ||
@@ -89,21 +89,23 @@ typedef struct _ToxAv | |||
89 | 89 | ||
90 | 90 | ||
91 | 91 | ||
92 | ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name ) | 92 | ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name , uint16_t video_width, uint16_t video_height) |
93 | { | 93 | { |
94 | ToxAv* av = calloc ( sizeof(ToxAv), 1); | 94 | ToxAv* av = calloc ( sizeof(ToxAv), 1); |
95 | 95 | if (av == NULL) | |
96 | av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name ); | 96 | return NULL; |
97 | |||
98 | av->messenger = (Messenger *)messenger; | ||
99 | |||
100 | av->msi_session = msi_init_session(av->messenger, (const unsigned char*) ua_name ); | ||
97 | av->msi_session->agent_handler = av; | 101 | av->msi_session->agent_handler = av; |
98 | 102 | ||
99 | av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; | 103 | av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; |
100 | 104 | ||
101 | av->messenger = messenger; | ||
102 | |||
103 | /* NOTE: This should be user defined or? */ | 105 | /* NOTE: This should be user defined or? */ |
104 | av->j_buf = create_queue(20); | 106 | av->j_buf = create_queue(20); |
105 | 107 | ||
106 | av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER); | 108 | av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, video_width, video_height, VIDEO_BITRATE); |
107 | 109 | ||
108 | av->agent_handler = useragent; | 110 | av->agent_handler = useragent; |
109 | 111 | ||
@@ -273,7 +275,7 @@ inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8 | |||
273 | else return -1; | 275 | else return -1; |
274 | } | 276 | } |
275 | 277 | ||
276 | inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest ) | 278 | inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, uint8_t* dest ) |
277 | { | 279 | { |
278 | if ( !dest ) return ErrorInternal; | 280 | if ( !dest ) return ErrorInternal; |
279 | 281 | ||
@@ -283,20 +285,19 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, | |||
283 | 285 | ||
284 | if ( type == TypeAudio ) { | 286 | if ( type == TypeAudio ) { |
285 | 287 | ||
286 | message = rtp_recv_msg(av->rtp_sessions[audio_index]); | 288 | do { |
289 | message = rtp_recv_msg(av->rtp_sessions[audio_index]); | ||
290 | |||
291 | if (message) { | ||
292 | /* push the packet into the queue */ | ||
293 | queue(av->j_buf, message); | ||
294 | } | ||
295 | } while(message); | ||
287 | 296 | ||
288 | if (message) { | 297 | int success = 0; |
289 | /* push the packet into the queue */ | 298 | message = dequeue(av->j_buf, &success); |
290 | queue(av->j_buf, message); | 299 | |
291 | } | 300 | if ( success == 2) return ErrorAudioPacketLost; |
292 | |||
293 | if (ready) { | ||
294 | int success = 0; | ||
295 | message = dequeue(av->j_buf, &success); | ||
296 | |||
297 | if ( success == 2) return ErrorAudioPacketLost; | ||
298 | } | ||
299 | else return 0; | ||
300 | } | 301 | } |
301 | else { | 302 | else { |
302 | message = rtp_recv_msg(av->rtp_sessions[video_index]); | 303 | message = rtp_recv_msg(av->rtp_sessions[video_index]); |
@@ -315,19 +316,75 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, | |||
315 | return 0; | 316 | return 0; |
316 | } | 317 | } |
317 | 318 | ||
318 | inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ) | 319 | inline__ int toxav_recv_video ( ToxAv* av, vpx_image_t **output) |
319 | { | 320 | { |
320 | if ( !dest ) return ErrorInternal; | 321 | if ( !output ) return ErrorInternal; |
322 | uint8_t packet [RTP_PAYLOAD_SIZE]; | ||
323 | int recved_size = 0; | ||
324 | do { | ||
325 | recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); | ||
326 | if (recved_size > 0) { | ||
327 | printf("decode: %s\n", vpx_codec_err_to_string(vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0))); | ||
328 | } | ||
329 | }while (recved_size > 0); | ||
330 | vpx_codec_iter_t iter = NULL; | ||
331 | vpx_image_t *img; | ||
332 | img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); | ||
333 | if (img == NULL) | ||
334 | return ErrorInternal; | ||
321 | 335 | ||
322 | return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1); | 336 | *output = img; |
337 | return 0; | ||
323 | } | 338 | } |
324 | 339 | ||
325 | inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ) | 340 | inline__ int toxav_send_video ( ToxAv* av, vpx_image_t *input) |
326 | { | 341 | { |
327 | if ( !dest ) | 342 | if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { |
343 | printf("could not encode video frame\n"); | ||
328 | return ErrorInternal; | 344 | return ErrorInternal; |
345 | } | ||
346 | ++av->cs->frame_counter; | ||
347 | |||
348 | vpx_codec_iter_t iter = NULL; | ||
349 | const vpx_codec_cx_pkt_t *pkt; | ||
350 | int sent = 0; | ||
351 | while( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { | ||
352 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | ||
353 | if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) | ||
354 | ++sent; | ||
355 | } | ||
356 | } | ||
357 | if (sent > 0) | ||
358 | return 0; | ||
329 | 359 | ||
330 | return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE); | 360 | return ErrorInternal; |
361 | } | ||
362 | |||
363 | inline__ int toxav_recv_audio ( ToxAv* av, int frame_size, int16_t* dest ) | ||
364 | { | ||
365 | if ( !dest ) return ErrorInternal; | ||
366 | uint8_t packet [RTP_PAYLOAD_SIZE]; | ||
367 | |||
368 | int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); | ||
369 | |||
370 | if ( recved_size == ErrorAudioPacketLost ) { | ||
371 | printf("Lost packet\n"); | ||
372 | return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); | ||
373 | } else if ( recved_size ){ | ||
374 | return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); | ||
375 | } else { | ||
376 | return ErrorInternal; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | inline__ int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size) | ||
381 | { | ||
382 | uint8_t temp_data[RTP_PAYLOAD_SIZE]; | ||
383 | int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data)); | ||
384 | if (ret <= 0) | ||
385 | return ErrorInternal; | ||
386 | |||
387 | return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); | ||
331 | } | 388 | } |
332 | 389 | ||
333 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) | 390 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) |
@@ -343,10 +400,3 @@ void* toxav_get_agent_handler ( ToxAv* av ) | |||
343 | { | 400 | { |
344 | return av->agent_handler; | 401 | return av->agent_handler; |
345 | } | 402 | } |
346 | |||
347 | |||
348 | /* Only temporary */ | ||
349 | void* get_cs_temp(ToxAv* av) | ||
350 | { | ||
351 | return av->cs; | ||
352 | } | ||
diff --git a/toxav/toxav.h b/toxav/toxav.h index 96a666a2..63dbf162 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h | |||
@@ -27,6 +27,9 @@ | |||
27 | #define __TOXAV | 27 | #define __TOXAV |
28 | #include <inttypes.h> | 28 | #include <inttypes.h> |
29 | 29 | ||
30 | /* vpx_image_t */ | ||
31 | #include <vpx/vpx_image.h> | ||
32 | |||
30 | typedef void* ( *ToxAVCallback ) ( void* arg ); | 33 | typedef void* ( *ToxAVCallback ) ( void* arg ); |
31 | typedef struct _ToxAv ToxAv; | 34 | typedef struct _ToxAv ToxAv; |
32 | 35 | ||
@@ -35,7 +38,29 @@ typedef struct _ToxAv ToxAv; | |||
35 | typedef struct Tox Tox; | 38 | typedef struct Tox Tox; |
36 | #endif | 39 | #endif |
37 | 40 | ||
38 | #define RTP_PAYLOAD_SIZE 10400 | 41 | #define RTP_PAYLOAD_SIZE 65535 |
42 | |||
43 | /* Default video bitrate in bytes/s */ | ||
44 | #define VIDEO_BITRATE 10*1000*100 | ||
45 | |||
46 | /* Default audio bitrate in bits/s */ | ||
47 | #define AUDIO_BITRATE 64000 | ||
48 | |||
49 | /* Number of audio channels. */ | ||
50 | #define AUDIO_CHANNELS 1 | ||
51 | |||
52 | /* Audio frame duration in miliseconds */ | ||
53 | #define AUDIO_FRAME_DURATION 20 | ||
54 | |||
55 | /* Audio sample rate recommended to be 48kHz for Opus */ | ||
56 | #define AUDIO_SAMPLE_RATE 48000 | ||
57 | |||
58 | /* The amount of samples in one audio frame */ | ||
59 | #define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 | ||
60 | |||
61 | /* Assume 60 fps*/ | ||
62 | #define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) | ||
63 | |||
39 | 64 | ||
40 | /** | 65 | /** |
41 | * @brief Callbacks ids that handle the call states | 66 | * @brief Callbacks ids that handle the call states |
@@ -55,7 +80,7 @@ typedef enum { | |||
55 | 80 | ||
56 | /* Protocol */ | 81 | /* Protocol */ |
57 | OnError, | 82 | OnError, |
58 | OnTimeout | 83 | OnRequestTimeout |
59 | 84 | ||
60 | } ToxAvCallbackID; | 85 | } ToxAvCallbackID; |
61 | 86 | ||
@@ -86,7 +111,7 @@ typedef enum { | |||
86 | } ToxAvError; | 111 | } ToxAvError; |
87 | 112 | ||
88 | 113 | ||
89 | ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name); | 114 | ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name, uint16_t video_width, uint16_t video_height) ; |
90 | void toxav_kill(ToxAv* av); | 115 | void toxav_kill(ToxAv* av); |
91 | 116 | ||
92 | void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); | 117 | void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); |
@@ -103,27 +128,25 @@ int toxav_prepare_transmission(ToxAv* av); | |||
103 | int toxav_kill_transmission(ToxAv* av); | 128 | int toxav_kill_transmission(ToxAv* av); |
104 | 129 | ||
105 | 130 | ||
106 | int toxav_send_rtp_payload(ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length); | 131 | |
107 | 132 | ||
108 | /* Return length of received packet. Returns 0 if nothing recved. Dest has to have | 133 | /* Return length of received packet. Returns 0 if nothing recved. Dest has to have |
109 | * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. | 134 | * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. |
110 | * For video packets set 'ready' at _any_ value. | 135 | * For video packets set 'ready' at _any_ value. |
111 | */ | 136 | */ |
112 | int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest); | ||
113 | |||
114 | |||
115 | 137 | ||
138 | /* returns 0 on success */ | ||
139 | int toxav_recv_video ( ToxAv* av, vpx_image_t **output); | ||
116 | 140 | ||
117 | int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ); | 141 | int toxav_recv_audio( ToxAv* av, int frame_size, int16_t* dest ); |
118 | 142 | ||
119 | /* Please make sure 'dest' has enough storage for RTP_PAYLOAD_SIZE length of data */ | 143 | int toxav_send_video ( ToxAv* av, vpx_image_t *input); |
120 | int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ); | 144 | /* Encode and send audio frame. */ |
145 | int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size); | ||
121 | 146 | ||
122 | 147 | ||
123 | 148 | ||
124 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); | 149 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); |
125 | void* toxav_get_agent_handler ( ToxAv* av ); | 150 | void* toxav_get_agent_handler ( ToxAv* av ); |
126 | 151 | ||
127 | /* Use this to get handle of CodecState from ToxAv struct */ | ||
128 | void* get_cs_temp( ToxAv* av ); | ||
129 | #endif /* __TOXAV */ \ No newline at end of file | 152 | #endif /* __TOXAV */ \ No newline at end of file |