summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2014-11-18 00:46:46 +0100
committermannol <eniz_vukovic@hotmail.com>2014-11-18 00:46:46 +0100
commit386c9748d48d3bb4513e8e5c32e2b30a4d6a00d4 (patch)
tree55d0fb2e9fb6e1149317b9de355c28dd86c57014 /toxav/toxav.c
parent4e6f993e7d22865ee2ac90bd7dd3ff25b078c55c (diff)
av refactor
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c1052
1 files changed, 255 insertions, 797 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 24e42572..88e24bce 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -28,13 +28,12 @@ typedef struct Messenger Tox;
28 28
29#define _GNU_SOURCE /* implicit declaration warning */ 29#define _GNU_SOURCE /* implicit declaration warning */
30 30
31#include "rtp.h"
32#include "codec.h" 31#include "codec.h"
33#include "msi.h" 32#include "msi.h"
34#include "toxav.h"
35#include "group.h" 33#include "group.h"
36 34
37#include "../toxcore/logger.h" 35#include "../toxcore/logger.h"
36#include "../toxcore/util.h"
38 37
39#include <assert.h> 38#include <assert.h>
40#include <stdlib.h> 39#include <stdlib.h>
@@ -42,21 +41,13 @@ typedef struct Messenger Tox;
42 41
43/* Assume 24 fps*/ 42/* Assume 24 fps*/
44#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) 43#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
45#define MAX_DECODE_TIME_US 0
46
47#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
48#define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/
49#define VIDEOFRAME_HEADER_SIZE 0x2
50
51
52#define inline__ inline __attribute__((always_inline))
53 44
54/* call index invalid: true if invalid */ 45/* call index invalid: true if invalid */
55#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls) 46#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls)
56 47
57 48
58const ToxAvCSettings av_DefaultSettings = { 49const ToxAvCSettings av_DefaultSettings = {
59 TypeAudio, 50 av_TypeAudio,
60 51
61 500, 52 500,
62 1280, 53 1280,
@@ -68,108 +59,49 @@ const ToxAvCSettings av_DefaultSettings = {
68 1 59 1
69}; 60};
70 61
71const uint32_t av_jbufdc = 3; 62static const uint32_t jbuf_capacity = 6;
72const uint32_t av_VADd = 40;
73
74
75static const uint8_t audio_index = 0, video_index = 1; 63static const uint8_t audio_index = 0, video_index = 1;
76 64
77typedef struct {
78 uint32_t size;
79 uint8_t data[0];
80} DECODE_PACKET;
81
82#define VIDEO_DECODE_QUEUE_SIZE 2
83#define AUDIO_DECODE_QUEUE_SIZE 16
84
85typedef struct _CallSpecific { 65typedef struct _CallSpecific {
86 RTPSession *crtps[2]; /** Audio is first and video is second */ 66 RTPSession *crtps[2]; /** Audio is first and video is second */
87 CodecState *cs;/** Each call have its own encoders and decoders. 67 CSSession *cs;/** Each call have its own encoders and decoders.
88 * You can, but don't have to, reuse encoders for 68 * You can, but don't have to, reuse encoders for
89 * multiple calls. If you choose to reuse encoders, 69 * multiple calls. If you choose to reuse encoders,
90 * make sure to also reuse encoded payload for every call. 70 * make sure to also reuse encoded payload for every call.
91 * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and 71 * Decoders have to be unique for each call.
92 * reuse them really.
93 */ 72 */
94 JitterBuffer *j_buf; /** Jitter buffer for audio */ 73
95
96 uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/
97 uint8_t frame_id, frame_outid; /* id of input and output video frame */
98 void *frame_buf; /* buffer for split video payloads */
99
100 _Bool call_active; 74 _Bool call_active;
101 pthread_mutex_t mutex; 75 pthread_mutex_t mutex;
102
103 /* used in the "decode on another thread" system */
104 volatile _Bool exit, decoding;
105 uint8_t video_decode_read, video_decode_write, audio_decode_read, audio_decode_write;
106 pthread_mutex_t decode_cond_mutex;
107 pthread_cond_t decode_cond;
108 DECODE_PACKET *volatile video_decode_queue[VIDEO_DECODE_QUEUE_SIZE];
109 DECODE_PACKET *volatile audio_decode_queue[AUDIO_DECODE_QUEUE_SIZE];
110} CallSpecific; 76} CallSpecific;
111 77
112struct _ToxAv { 78struct _ToxAv {
113 Messenger *messenger; 79 Messenger *messenger;
114 MSISession *msi_session; /** Main msi session */ 80 MSISession *msi_session; /** Main msi session */
115 CallSpecific *calls; /** Per-call params */ 81 CallSpecific *calls; /** Per-call params */
116
117 void (*audio_callback)(ToxAv *, int32_t, int16_t *, int, void *);
118 void (*video_callback)(ToxAv *, int32_t, vpx_image_t *, void *);
119
120 void *audio_callback_userdata;
121 void *video_callback_userdata;
122
123 uint32_t max_calls; 82 uint32_t max_calls;
83
84 /* Decode time measure */
85 int32_t dectmsscount; /** Measure count */
86 int32_t dectmsstotal; /** Last cycle total */
87 int32_t avgdectms; /** Average decoding time in ms */
124}; 88};
125 89
126static void *toxav_decoding(void *arg);
127 90
128static MSICSettings msicsettings_cast (const ToxAvCSettings *from) 91static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
129{ 92{
130 MSICSettings csettings; 93 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
131 csettings.call_type = from->call_type; 94 return (const MSICSettings *) from;
132
133 csettings.video_bitrate = from->video_bitrate;
134 csettings.max_video_width = from->max_video_width;
135 csettings.max_video_height = from->max_video_height;
136
137 csettings.audio_bitrate = from->audio_bitrate;
138 csettings.audio_frame_duration = from->audio_frame_duration;
139 csettings.audio_sample_rate = from->audio_sample_rate;
140 csettings.audio_channels = from->audio_channels;
141
142 return csettings;
143} 95}
144 96
145static ToxAvCSettings toxavcsettings_cast (const MSICSettings *from) 97static const ToxAvCSettings* toxavcsettings_cast (const MSICSettings *from)
146{ 98{
147 ToxAvCSettings csettings; 99 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
148 csettings.call_type = from->call_type; 100 return (const ToxAvCSettings *) from;
149 101
150 csettings.video_bitrate = from->video_bitrate;
151 csettings.max_video_width = from->max_video_width;
152 csettings.max_video_height = from->max_video_height;
153
154 csettings.audio_bitrate = from->audio_bitrate;
155 csettings.audio_frame_duration = from->audio_frame_duration;
156 csettings.audio_sample_rate = from->audio_sample_rate;
157 csettings.audio_channels = from->audio_channels;
158
159 return csettings;
160} 102}
161 103
162/** 104
163 * @brief Start new A/V session. There can only be one session at the time. If you register more
164 * it will result in undefined behaviour.
165 *
166 * @param messenger The messenger handle.
167 * @param userdata The agent handling A/V session (i.e. phone).
168 * @param video_width Width of video frame.
169 * @param video_height Height of video frame.
170 * @return ToxAv*
171 * @retval NULL On error.
172 */
173ToxAv *toxav_new( Tox *messenger, int32_t max_calls) 105ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
174{ 106{
175 ToxAv *av = calloc ( sizeof(ToxAv), 1); 107 ToxAv *av = calloc ( sizeof(ToxAv), 1);
@@ -180,7 +112,7 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
180 } 112 }
181 113
182 av->messenger = (Messenger *)messenger; 114 av->messenger = (Messenger *)messenger;
183 av->msi_session = msi_init_session(av->messenger, max_calls); 115 av->msi_session = msi_new(av->messenger, max_calls);
184 av->msi_session->agent_handler = av; 116 av->msi_session->agent_handler = av;
185 av->calls = calloc(sizeof(CallSpecific), max_calls); 117 av->calls = calloc(sizeof(CallSpecific), max_calls);
186 av->max_calls = max_calls; 118 av->max_calls = max_calls;
@@ -188,355 +120,242 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
188 return av; 120 return av;
189} 121}
190 122
191/**
192 * @brief Remove A/V session.
193 *
194 * @param av Handler.
195 * @return void
196 */
197void toxav_kill ( ToxAv *av ) 123void toxav_kill ( ToxAv *av )
198{ 124{
199 uint32_t i; 125 uint32_t i;
200 126
201 for (i = 0; i < av->max_calls; i ++) { 127 for (i = 0; i < av->max_calls; i ++) {
202 if ( av->calls[i].crtps[audio_index] ) 128 if ( av->calls[i].crtps[audio_index] )
203 rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); 129 rtp_kill(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
204 130
205 131
206 if ( av->calls[i].crtps[video_index] ) 132 if ( av->calls[i].crtps[video_index] )
207 rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); 133 rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
208 134
209 135 if ( av->calls[i].cs ) cs_kill(av->calls[i].cs);
210
211 if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf);
212
213 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
214 } 136 }
215 137
216 msi_terminate_session(av->msi_session); 138 msi_kill(av->msi_session);
217 139
218 free(av->calls); 140 free(av->calls);
219 free(av); 141 free(av);
220} 142}
221 143
222/** 144uint32_t toxav_do_interval(ToxAv* av)
223 * @brief Register callback for call state.
224 *
225 * @param av Handler.
226 * @param callback The callback
227 * @param id One of the ToxAvCallbackID values
228 * @return void
229 */
230void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
231{ 145{
232 msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata); 146 int i = 0;
147 uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */
148
149 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) {
150 /* This should work. Video payload will always come in greater intervals */
151 rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc);
152 }
153
154 return rc - av->avgdectms;
233} 155}
234 156
235/** 157void toxav_do(ToxAv* av)
236 * @brief Register callback for receiving audio data
237 *
238 * @param callback The callback
239 * @return void
240 */
241void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *),
242 void *user_data)
243{ 158{
244 av->audio_callback = callback; 159 msi_do(av->msi_session);
245 av->audio_callback_userdata = user_data; 160
161 uint64_t start = current_time_monotonic();
162
163 uint32_t i = 0;
164 for(;i < av->max_calls; i ++)
165 if (av->calls[i].call_active) cs_do(av->calls[i].cs);
166
167 uint64_t end = current_time_monotonic();
168
169 /* TODO maybe use variable for sizes */
170 av->dectmsstotal += end - start;
171 if (++av->dectmsscount == 3) {
172 av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */;
173 av->dectmsscount = 0;
174 av->dectmsstotal = 0;
175 }
246} 176}
247 177
248/** 178void toxav_register_callstate_callback ( ToxAv* av, ToxAVCallback cb, ToxAvCallbackID id, void* userdata )
249 * @brief Register callback for receiving video data
250 *
251 * @param callback The callback
252 * @return void
253 */
254void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *),
255 void *user_data)
256{ 179{
257 av->video_callback = callback; 180 msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata);
258 av->video_callback_userdata = user_data;
259} 181}
260 182
261/** 183void toxav_register_audio_callback(ToxAvAudioCallback cb, void* userdata)
262 * @brief Call user. Use its friend_id. 184{
263 * 185 cs_register_audio_callback(cb, userdata);
264 * @param av Handler. 186}
265 * @param user The user. 187
266 * @param call_type Call type. 188void toxav_register_video_callback(ToxAvVideoCallback cb, void* userdata)
267 * @param ringing_seconds Ringing timeout. 189{
268 * @return int 190 cs_register_video_callback(cb, userdata);
269 * @retval 0 Success. 191}
270 * @retval ToxAvError On error. 192
271 */ 193int toxav_call (ToxAv *av,
272int toxav_call (ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds ) 194 int32_t *call_index,
195 int user,
196 const ToxAvCSettings *csettings,
197 int ringing_seconds )
273{ 198{
274 return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); 199 return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user);
275} 200}
276 201
277/**
278 * @brief Hangup active call.
279 *
280 * @param av Handler.
281 * @return int
282 * @retval 0 Success.
283 * @retval ToxAvError On error.
284 */
285int toxav_hangup ( ToxAv *av, int32_t call_index ) 202int toxav_hangup ( ToxAv *av, int32_t call_index )
286{ 203{
287 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 204 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
288 return ErrorNoCall; 205 return av_ErrorNoCall;
289 } 206 }
290 207
291 if ( av->msi_session->calls[call_index]->state != call_active ) { 208 if ( av->msi_session->calls[call_index]->state != call_active ) {
292 return ErrorInvalidState; 209 return av_ErrorInvalidState;
293 } 210 }
294 211
295 return msi_hangup(av->msi_session, call_index); 212 return msi_hangup(av->msi_session, call_index);
296} 213}
297 214
298/**
299 * @brief Answer incomming call.
300 *
301 * @param av Handler.
302 * @param call_type Answer with...
303 * @return int
304 * @retval 0 Success.
305 * @retval ToxAvError On error.
306 */
307int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) 215int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings )
308{ 216{
309 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 217 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
310 return ErrorNoCall; 218 return av_ErrorNoCall;
311 } 219 }
312 220
313 if ( av->msi_session->calls[call_index]->state != call_starting ) { 221 if ( av->msi_session->calls[call_index]->state != call_starting ) {
314 return ErrorInvalidState; 222 return av_ErrorInvalidState;
315 } 223 }
316 224
317 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); 225 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings));
318} 226}
319 227
320/**
321 * @brief Reject incomming call.
322 *
323 * @param av Handler.
324 * @param reason Optional reason. Set NULL if none.
325 * @return int
326 * @retval 0 Success.
327 * @retval ToxAvError On error.
328 */
329int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) 228int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
330{ 229{
331 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 230 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
332 return ErrorNoCall; 231 return av_ErrorNoCall;
333 } 232 }
334 233
335 if ( av->msi_session->calls[call_index]->state != call_starting ) { 234 if ( av->msi_session->calls[call_index]->state != call_starting ) {
336 return ErrorInvalidState; 235 return av_ErrorInvalidState;
337 } 236 }
338 237
339 return msi_reject(av->msi_session, call_index, reason); 238 return msi_reject(av->msi_session, call_index, reason);
340} 239}
341 240
342/**
343 * @brief Cancel outgoing request.
344 *
345 * @param av Handler.
346 * @param reason Optional reason.
347 * @param peer_id peer friend_id
348 * @return int
349 * @retval 0 Success.
350 * @retval ToxAvError On error.
351 */
352int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) 241int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
353{ 242{
354 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 243 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
355 return ErrorNoCall; 244 return av_ErrorNoCall;
356 } 245 }
357 246
358 if ( av->msi_session->calls[call_index]->state != call_inviting ) { 247 if ( av->msi_session->calls[call_index]->state != call_inviting ) {
359 return ErrorInvalidState; 248 return av_ErrorInvalidState;
360 } 249 }
361 250
362 return msi_cancel(av->msi_session, call_index, peer_id, reason); 251 return msi_cancel(av->msi_session, call_index, peer_id, reason);
363} 252}
364 253
365/**
366 * @brief Notify peer that we are changing call type
367 *
368 * @param av Handler.
369 * @return int
370 * @param call_type Change to...
371 * @retval 0 Success.
372 * @retval ToxAvError On error.
373 */
374int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) 254int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings)
375{ 255{
376 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 256 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
377 return ErrorNoCall; 257 return av_ErrorNoCall;
378 } 258 }
379 259
380 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); 260 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings));
381} 261}
382 262
383/**
384 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
385 *
386 * @param av Handler.
387 * @return int
388 * @retval 0 Success.
389 * @retval ToxAvError On error.
390 */
391int toxav_stop_call ( ToxAv *av, int32_t call_index ) 263int toxav_stop_call ( ToxAv *av, int32_t call_index )
392{ 264{
393 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 265 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
394 return ErrorNoCall; 266 return av_ErrorNoCall;
395 } 267 }
396 268
397 return msi_stopcall(av->msi_session, call_index); 269 return msi_stopcall(av->msi_session, call_index);
398} 270}
399 271
400/** 272int toxav_prepare_transmission ( ToxAv* av, int32_t call_index, int support_video )
401 * @brief Must be call before any RTP transmission occurs.
402 *
403 * @param av Handler.
404 * @return int
405 * @retval 0 Success.
406 * @retval ToxAvError On error.
407 */
408int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, uint32_t jbuf_capacity, uint32_t VAD_treshold,
409 int support_video )
410{ 273{
411 if ( !av->msi_session || cii(call_index, av->msi_session) || 274 if ( !av->msi_session || cii(call_index, av->msi_session) ||
412 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer || 275 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer ||
413 av->calls[call_index].call_active) { 276 av->calls[call_index].call_active) {
414 LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); 277 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
415 return ErrorInternal; 278 return av_ErrorInternal;
416 } 279 }
417 280
418 CallSpecific *call = &av->calls[call_index]; 281 CallSpecific *call = &av->calls[call_index];
419 282
283 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) {
284 LOGGER_WARNING("Failed to init call mutex!");
285 return av_ErrorInternal;
286 }
287
288 const ToxAvCSettings* c_peer = toxavcsettings_cast
289 (&av->msi_session->calls[call_index]->csettings_peer[0]);
290 const ToxAvCSettings* c_self = toxavcsettings_cast
291 (&av->msi_session->calls[call_index]->csettings_local);
292
293 LOGGER_DEBUG(
294 "Type: %u(s) %u(p)\n"
295 "Video bitrate: %u(s) %u(p)\n"
296 "Video height: %u(s) %u(p)\n"
297 "Video width: %u(s) %u(p)\n"
298 "Audio bitrate: %u(s) %u(p)\n"
299 "Audio framedur: %u(s) %u(p)\n"
300 "Audio sample rate: %u(s) %u(p)\n"
301 "Audio channels: %u(s) %u(p)\n",
302 c_self->call_type, c_peer->call_type,
303 c_self->video_bitrate, c_peer->video_bitrate,
304 c_self->max_video_height, c_peer->max_video_height,
305 c_self->max_video_width, c_peer->max_video_width,
306 c_self->audio_bitrate, c_peer->audio_bitrate,
307 c_self->audio_frame_duration, c_peer->audio_frame_duration,
308 c_self->audio_sample_rate, c_peer->audio_sample_rate,
309 c_self->audio_channels, c_peer->audio_channels );
310
311 if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ){
312 pthread_mutex_destroy(&call->mutex);
313 LOGGER_ERROR("Error while starting Codec State!\n");
314 return av_ErrorInternal;
315 }
316
317 call->cs->agent = av;
318 call->cs->call_idx = call_index;
319
420 call->crtps[audio_index] = 320 call->crtps[audio_index] =
421 rtp_init_session(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]); 321 rtp_new(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
422
423 322
424 if ( !call->crtps[audio_index] ) { 323 if ( !call->crtps[audio_index] ) {
425 LOGGER_ERROR("Error while starting audio RTP session!\n"); 324 LOGGER_ERROR("Error while starting audio RTP session!\n");
426 return ErrorInternal; 325 return av_ErrorInternal;
427 } 326 }
428 327
429 call->crtps[audio_index]->call_index = call_index; 328 call->crtps[audio_index]->cs = call->cs;
430 call->crtps[audio_index]->av = av;
431 329
432 if ( support_video ) { 330 if ( support_video ) {
433 call->crtps[video_index] = 331 call->crtps[video_index] =
434 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); 332 rtp_new(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
435 333
436 if ( !call->crtps[video_index] ) { 334 if ( !call->crtps[video_index] ) {
437 LOGGER_ERROR("Error while starting video RTP session!\n"); 335 LOGGER_ERROR("Error while starting video RTP session!\n");
438 goto error; 336 goto error;
439 } 337 }
440 338
441 call->crtps[video_index]->call_index = call_index; 339 call->crtps[video_index]->cs = call->cs;
442 call->crtps[video_index]->av = av;
443
444 call->frame_limit = 0;
445 call->frame_id = 0;
446 call->frame_outid = 0;
447
448 call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1);
449
450 if (!call->frame_buf) {
451 LOGGER_WARNING("Frame buffer allocation failed!");
452 goto error;
453 }
454
455 }
456
457 if ( !(call->j_buf = create_queue(jbuf_capacity)) ) {
458 LOGGER_WARNING("Jitter buffer creaton failed!");
459 goto error;
460 }
461
462 ToxAvCSettings csettings_peer = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[0]);
463 ToxAvCSettings csettings_local = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_local);
464 LOGGER_DEBUG(
465 "Type: %u \n"
466 "Video bitrate: %u \n"
467 "Video height: %u \n"
468 "Video width: %u \n"
469 "Audio bitrate: %u \n"
470 "Audio framedur: %u \n"
471 "Audio sample rate: %u \n"
472 "Audio channels: %u \n",
473 csettings_peer.call_type,
474 csettings_peer.video_bitrate,
475 csettings_peer.max_video_height,
476 csettings_peer.max_video_width,
477 csettings_peer.audio_bitrate,
478 csettings_peer.audio_frame_duration,
479 csettings_peer.audio_sample_rate,
480 csettings_peer.audio_channels );
481
482 if ( (call->cs = codec_init_session(csettings_local.audio_bitrate,
483 csettings_local.audio_frame_duration,
484 csettings_local.audio_sample_rate,
485 csettings_local.audio_channels,
486 csettings_peer.audio_channels,
487 VAD_treshold,
488 csettings_local.max_video_width,
489 csettings_local.max_video_height,
490 csettings_local.video_bitrate) )) {
491
492 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
493
494 //todo: add error checks
495 pthread_mutex_init(&call->decode_cond_mutex, NULL);
496 pthread_cond_init(&call->decode_cond, NULL);
497
498 void **arg = malloc(2 * sizeof(void *));
499 arg[0] = av;
500 arg[1] = call;
501
502 pthread_t temp;
503 pthread_attr_t attr;
504
505 pthread_attr_init(&attr);
506 pthread_attr_setstacksize(&attr, 1 << 18);
507 pthread_create(&temp, &attr, toxav_decoding, arg);
508 pthread_attr_destroy(&attr);
509
510
511 LOGGER_WARNING("Got here");
512 call->call_active = 1;
513
514 return ErrorNone;
515 } 340 }
516 341
342 call->call_active = 1;
343 return av_ErrorNone;
517error: 344error:
518 rtp_terminate_session(call->crtps[audio_index], av->messenger); 345 rtp_kill(call->crtps[audio_index], av->messenger);
519 rtp_terminate_session(call->crtps[video_index], av->messenger); 346 rtp_kill(call->crtps[video_index], av->messenger);
520 free(call->frame_buf); 347 cs_kill(call->cs);
521 terminate_queue(call->j_buf); 348 pthread_mutex_destroy(&call->mutex);
522 codec_terminate_session(call->cs); 349 memset(call, 0, sizeof(CallSpecific));
523 350
524 return ErrorInternal; 351 return av_ErrorInternal;
525} 352}
526 353
527/**
528 * @brief Call this at the end of the transmission.
529 *
530 * @param av Handler.
531 * @return int
532 * @retval 0 Success.
533 * @retval ToxAvError On error.
534 */
535int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) 354int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
536{ 355{
537 if (cii(call_index, av->msi_session)) { 356 if (cii(call_index, av->msi_session)) {
538 LOGGER_WARNING("Invalid call index: %d", call_index); 357 LOGGER_WARNING("Invalid call index: %d", call_index);
539 return ErrorNoCall; 358 return av_ErrorNoCall;
540 } 359 }
541 360
542 CallSpecific *call = &av->calls[call_index]; 361 CallSpecific *call = &av->calls[call_index];
@@ -546,234 +365,110 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
546 if (!call->call_active) { 365 if (!call->call_active) {
547 pthread_mutex_unlock(&call->mutex); 366 pthread_mutex_unlock(&call->mutex);
548 LOGGER_WARNING("Action on inactive call: %d", call_index); 367 LOGGER_WARNING("Action on inactive call: %d", call_index);
549 return ErrorNoCall; 368 return av_ErrorNoCall;
550 } 369 }
551 370
552 371 rtp_kill(call->crtps[audio_index], av->messenger); call->crtps[audio_index] = NULL;
372 rtp_kill(call->crtps[video_index], av->messenger); call->crtps[video_index] = NULL;
373 cs_kill(call->cs); call->cs = NULL;
374
553 call->call_active = 0; 375 call->call_active = 0;
554 376
555 rtp_terminate_session(call->crtps[audio_index], av->messenger);
556 call->crtps[audio_index] = NULL;
557 rtp_terminate_session(call->crtps[video_index], av->messenger);
558 call->crtps[video_index] = NULL;
559 terminate_queue(call->j_buf);
560 call->j_buf = NULL;
561
562 int i;
563 DECODE_PACKET *p;
564
565 call->exit = 1;
566 pthread_mutex_lock(&call->decode_cond_mutex);
567 pthread_cond_signal(&call->decode_cond);
568 pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex);
569 pthread_mutex_unlock(&call->decode_cond_mutex);
570 pthread_mutex_destroy(&call->decode_cond_mutex);
571 pthread_cond_destroy(&call->decode_cond);
572
573 for (i = 0; i != VIDEO_DECODE_QUEUE_SIZE; i++) {
574 p = call->video_decode_queue[i];
575 call->video_decode_queue[i] = NULL;
576
577 if (p) {
578 free(p);
579 }
580 }
581
582 for (i = 0; i != AUDIO_DECODE_QUEUE_SIZE; i++) {
583 p = call->audio_decode_queue[i];
584 call->audio_decode_queue[i] = NULL;
585
586 if (p) {
587 free(p);
588 }
589 }
590
591 codec_terminate_session(call->cs);
592 call->cs = NULL;
593
594 free(call->frame_buf);
595
596 pthread_mutex_unlock(&call->mutex); 377 pthread_mutex_unlock(&call->mutex);
597 pthread_mutex_destroy(&call->mutex); 378 pthread_mutex_destroy(&call->mutex);
598 379
599 memset(call, 0, sizeof(CallSpecific)); 380 return av_ErrorNone;
600 return ErrorNone;
601} 381}
602 382
603 383static int toxav_send_rtp_payload(ToxAv *av,
604/** 384 CallSpecific *call,
605 * @brief Send RTP payload. 385 ToxAvCallType type,
606 * 386 const uint8_t *payload,
607 * @param av Handler.
608 * @param type Type of payload.
609 * @param payload The payload.
610 * @param length Size of it.
611 * @return int
612 * @retval 0 Success.
613 * @retval -1 Failure.
614 */
615static int toxav_send_rtp_payload(ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
616 unsigned int length) 387 unsigned int length)
617{ 388{
618 CallSpecific *call = &av->calls[call_index]; 389 if (call->crtps[type - av_TypeAudio]) {
619 390
620 if (call->crtps[type - TypeAudio]) { 391 /* Audio */
621 392 if (type == av_TypeAudio)
622 if (type == TypeAudio) { 393 return rtp_send_msg(call->crtps[audio_index], av->messenger, payload, length);
623 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length); 394
624 } else { 395 /* Video */
625 if (length == 0 || length > MAX_VIDEOFRAME_SIZE) { 396 int parts = cs_split_video_payload(call->cs, payload, length);
626 LOGGER_ERROR("Invalid video frame size: %u\n", length); 397 if (parts == -1) return av_ErrorInternal;
627 return ErrorInternal; 398
628 } 399 uint16_t part_size;
629 400 const uint8_t* iter;
630 /* number of pieces - 1*/ 401
631 uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE; 402 int i;
632 403 for (i = 0; i < parts; i++) {
633 uint8_t load[2 + VIDEOFRAME_PIECE_SIZE]; 404 iter = cs_get_split_video_frame(call->cs, &part_size);
634 load[0] = call->frame_outid++; 405 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) != 0)
635 load[1] = 0; 406 return av_ErrorInternal;
636
637 int i;
638
639 for (i = 0; i < numparts; i++) {
640 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE);
641 payload += VIDEOFRAME_PIECE_SIZE;
642
643 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger,
644 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) {
645
646 return ErrorInternal;
647 }
648
649 load[1]++;
650 }
651
652 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */
653 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1;
654 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length);
655
656 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length);
657 } 407 }
658 } else { 408
659 return ErrorNoRtpSession; 409 return av_ErrorNone;
660 } 410
661} 411 } else return av_ErrorNoRtpSession;
662
663/**
664 * @brief Encode and send video packet.
665 *
666 * @param av Handler.
667 * @param input The packet.
668 * @return int
669 * @retval 0 Success.
670 * @retval ToxAvError On error.
671 */
672int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
673{
674
675 if (cii(call_index, av->msi_session)) {
676 LOGGER_WARNING("Invalid call index: %d", call_index);
677 return ErrorNoCall;
678 }
679
680 CallSpecific *call = &av->calls[call_index];
681 pthread_mutex_lock(&call->mutex);
682
683
684 if (!call->call_active) {
685 pthread_mutex_unlock(&call->mutex);
686 LOGGER_WARNING("Action on inactive call: %d", call_index);
687 return ErrorNoCall;
688 }
689
690 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
691 pthread_mutex_unlock(&call->mutex);
692
693 return rc;
694} 412}
695 413
696/** 414int toxav_prepare_video_frame ( ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input)
697 * @brief Encode video frame
698 *
699 * @param av Handler
700 * @param dest Where to
701 * @param dest_max Max size
702 * @param input What to encode
703 * @return int
704 * @retval ToxAvError On error.
705 * @retval >0 On success
706 */
707int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
708{ 415{
709 if (cii(call_index, av->msi_session)) { 416 if (cii(call_index, av->msi_session)) {
710 LOGGER_WARNING("Invalid call index: %d", call_index); 417 LOGGER_WARNING("Invalid call index: %d", call_index);
711 return ErrorNoCall; 418 return av_ErrorNoCall;
712 } 419 }
713 420
714 421
715 CallSpecific *call = &av->calls[call_index]; 422 CallSpecific *call = &av->calls[call_index];
716 pthread_mutex_lock(&call->mutex); 423 pthread_mutex_lock(&call->mutex);
717 424
718 if (!call->call_active) { 425 if (!call->call_active) {
719 pthread_mutex_unlock(&call->mutex); 426 pthread_mutex_unlock(&call->mutex);
720 LOGGER_WARNING("Action on inactive call: %d", call_index); 427 LOGGER_WARNING("Action on inactive call: %d", call_index);
721 return ErrorNoCall; 428 return av_ErrorNoCall;
722 } 429 }
723 430
724 if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) { 431 if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
725 pthread_mutex_unlock(&call->mutex); 432 pthread_mutex_unlock(&call->mutex);
726 return ErrorInternal; 433 return av_ErrorInternal;
727 } 434 }
728 435
729 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 436 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
730 437
731 if ( rc != VPX_CODEC_OK) { 438 if ( rc != VPX_CODEC_OK) {
732 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 439 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
733 pthread_mutex_unlock(&call->mutex); 440 pthread_mutex_unlock(&call->mutex);
734 return ErrorInternal; 441 return av_ErrorInternal;
735 } 442 }
736 443
737 ++call->cs->frame_counter; 444 ++call->cs->frame_counter;
738 445
739 vpx_codec_iter_t iter = NULL; 446 vpx_codec_iter_t iter = NULL;
740 const vpx_codec_cx_pkt_t *pkt; 447 const vpx_codec_cx_pkt_t *pkt;
741 int copied = 0; 448 int copied = 0;
742 449
743 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 450 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
744 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 451 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
745 if ( copied + pkt->data.frame.sz > dest_max ) { 452 if ( copied + pkt->data.frame.sz > dest_max ) {
746 pthread_mutex_unlock(&call->mutex); 453 pthread_mutex_unlock(&call->mutex);
747 return ErrorPacketTooLarge; 454 return av_ErrorPacketTooLarge;
748 } 455 }
749 456
750 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 457 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
751 copied += pkt->data.frame.sz; 458 copied += pkt->data.frame.sz;
752 } 459 }
753 } 460 }
754 461
755 pthread_mutex_unlock(&call->mutex); 462 pthread_mutex_unlock(&call->mutex);
756 return copied; 463 return copied;
757} 464}
758 465
759/** 466int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
760 * @brief Send audio frame.
761 *
762 * @param av Handler.
763 * @param data The audio data encoded with toxav_prepare_audio_frame().
764 * @param size Its size in number of bytes.
765 * @return int
766 * @retval 0 Success.
767 * @retval ToxAvError On error.
768 */
769int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
770{ 467{
771 if (size > MAX_CRYPTO_DATA_SIZE)
772 return ErrorInternal;
773 468
774 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { 469 if (cii(call_index, av->msi_session)) {
775 LOGGER_WARNING("Action on inactive call: %d", call_index); 470 LOGGER_WARNING("Invalid call index: %d", call_index);
776 return ErrorNoCall; 471 return av_ErrorNoCall;
777 } 472 }
778 473
779 CallSpecific *call = &av->calls[call_index]; 474 CallSpecific *call = &av->calls[call_index];
@@ -783,100 +478,93 @@ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsig
783 if (!call->call_active) { 478 if (!call->call_active) {
784 pthread_mutex_unlock(&call->mutex); 479 pthread_mutex_unlock(&call->mutex);
785 LOGGER_WARNING("Action on inactive call: %d", call_index); 480 LOGGER_WARNING("Action on inactive call: %d", call_index);
786 return ErrorNoCall; 481 return av_ErrorNoCall;
787 } 482 }
788 483
789 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, data, size); 484 int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size);
790 pthread_mutex_unlock(&call->mutex); 485 pthread_mutex_unlock(&call->mutex);
791 486
792 return rc; 487 return rc;
793} 488}
794 489
795/** 490int toxav_prepare_audio_frame ( ToxAv *av,
796 * @brief Encode audio frame 491 int32_t call_index,
797 * 492 uint8_t *dest,
798 * @param av Handler 493 int dest_max,
799 * @param dest dest 494 const int16_t *frame,
800 * @param dest_max Max dest size
801 * @param frame The frame
802 * @param frame_size The frame size
803 * @return int
804 * @retval ToxAvError On error.
805 * @retval >0 On success
806 */
807int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
808 int frame_size) 495 int frame_size)
809{ 496{
810 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { 497 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
811 LOGGER_WARNING("Action on inactive call: %d", call_index); 498 LOGGER_WARNING("Action on inactive call: %d", call_index);
812 return ErrorNoCall; 499 return av_ErrorNoCall;
813 } 500 }
814 501
815 CallSpecific *call = &av->calls[call_index]; 502 CallSpecific *call = &av->calls[call_index];
816 pthread_mutex_lock(&call->mutex); 503 pthread_mutex_lock(&call->mutex);
817 504
818 505
819 if (!call->call_active) { 506 if (!call->call_active) {
820 pthread_mutex_unlock(&call->mutex); 507 pthread_mutex_unlock(&call->mutex);
821 LOGGER_WARNING("Action on inactive call: %d", call_index); 508 LOGGER_WARNING("Action on inactive call: %d", call_index);
822 return ErrorNoCall; 509 return av_ErrorNoCall;
823 } 510 }
824 511
825 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); 512 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
826 pthread_mutex_unlock(&call->mutex); 513 pthread_mutex_unlock(&call->mutex);
827 514
828 if (rc < 0) { 515 if (rc < 0) {
829 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 516 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
830 return ErrorInternal; 517 return av_ErrorInternal;
831 } 518 }
519
520 return rc;
521}
522
523int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
524{
525 if (size > MAX_CRYPTO_DATA_SIZE)
526 return av_ErrorInternal;
527
528 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
529 LOGGER_WARNING("Action on inactive call: %d", call_index);
530 return av_ErrorNoCall;
531 }
532
533 CallSpecific *call = &av->calls[call_index];
534 pthread_mutex_lock(&call->mutex);
535
536
537 if (!call->call_active) {
538 pthread_mutex_unlock(&call->mutex);
539 LOGGER_WARNING("Action on inactive call: %d", call_index);
540 return av_ErrorNoCall;
541 }
542
543 int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size);
544 pthread_mutex_unlock(&call->mutex);
832 545
833 return rc; 546 return rc;
834} 547}
835 548
836/**
837 * @brief Get peer transmission type. It can either be audio or video.
838 *
839 * @param av Handler.
840 * @param peer The peer
841 * @return int
842 * @retval ToxAvCallType On success.
843 * @retval ToxAvError On error.
844 */
845int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) 549int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest )
846{ 550{
847 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 551 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
848 || av->msi_session->calls[call_index]->peer_count <= peer ) 552 || av->msi_session->calls[call_index]->peer_count <= peer )
849 return ErrorInternal; 553 return av_ErrorInternal;
850 554
851 *dest = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); 555 *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]);
852 return ErrorNone; 556 return av_ErrorNone;
853} 557}
854 558
855/**
856 * @brief Get id of peer participating in conversation
857 *
858 * @param av Handler
859 * @param peer peer index
860 * @return int
861 * @retval ToxAvError No peer id
862 */
863int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) 559int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
864{ 560{
865 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 561 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
866 || av->msi_session->calls[call_index]->peer_count <= peer ) 562 || av->msi_session->calls[call_index]->peer_count <= peer )
867 return ErrorInternal; 563 return av_ErrorInternal;
868 564
869 return av->msi_session->calls[call_index]->peers[peer]; 565 return av->msi_session->calls[call_index]->peers[peer];
870} 566}
871 567
872/**
873 * @brief Get id of peer participating in conversation
874 *
875 * @param av Handler
876 * @param peer peer index
877 * @return int
878 * @retval ToxAvError No peer id
879 */
880ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) 568ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
881{ 569{
882 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) 570 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] )
@@ -886,270 +574,40 @@ ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
886 574
887} 575}
888 576
889/** 577int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
890 * @brief Is certain capability supported
891 *
892 * @param av Handler
893 * @return int
894 * @retval 1 Yes.
895 * @retval 0 No.
896 */
897inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
898{ 578{
899 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0; 579 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CsCapabilities) capability : 0;
900 /* 0 is error here */ 580 /* 0 is error here */
901} 581}
902 582
903inline__ Tox *toxav_get_tox(ToxAv *av) 583Tox *toxav_get_tox(ToxAv *av)
904{ 584{
905 return (Tox *)av->messenger; 585 return (Tox *)av->messenger;
906} 586}
907 587
908int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy) 588int toxav_set_vad_treshold(ToxAv* av, int32_t call_index, uint32_t treshold)
909{
910 if ( !av->calls[call_index].cs ) return ErrorInvalidCodecState;
911
912 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
913}
914
915
916static void decode_video(ToxAv *av, CallSpecific *call, DECODE_PACKET *p)
917{
918 int32_t call_index = call - av->calls;
919
920 int rc = vpx_codec_decode(&call->cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
921
922 if (rc != VPX_CODEC_OK) {
923 LOGGER_ERROR("Error decoding video: %s\n", vpx_codec_err_to_string(rc));
924 }
925
926 vpx_codec_iter_t iter = NULL;
927 vpx_image_t *img;
928 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
929
930 if (img && av->video_callback) {
931 av->video_callback(av, call_index, img, av->video_callback_userdata);
932 } else {
933 LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
934 }
935
936 free(p);
937}
938
939static void decode_audio(ToxAv *av, CallSpecific *call, DECODE_PACKET *p)
940{ 589{
941 int32_t call_index = call - av->calls; 590 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
942 591 /* TODO on't use default framedur... */
943 // ToxAvCSettings csettings; 592 cs_set_vad_treshold(av->calls[call_index].cs, treshold, av_DefaultSettings.audio_frame_duration);
944 // toxav_get_peer_csettings(av, call_index, 0, &csettings); 593
945 594 return av_ErrorNone;
946 int frame_size = 10000; /* FIXME: not static? */
947 int16_t dest[frame_size];
948
949 int dec_size = opus_decode(call->cs->audio_decoder, p->data, p->size, dest, frame_size, (p->size == 0));
950 free(p);
951
952 if (dec_size < 0) {
953 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
954 return;
955 }
956
957 if ( av->audio_callback )
958 av->audio_callback(av, call_index, dest, dec_size, av->audio_callback_userdata);
959 else
960 LOGGER_WARNING("Audio packet dropped due to missing callback!");
961} 595}
962 596
963static void *toxav_decoding(void *arg) 597int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref)
964{ 598{
965 void **pp = arg; 599 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
966 ToxAv *av = pp[0];
967 CallSpecific *call = pp[1];
968 free(pp);
969 600
970 while (1) { 601 return cs_calculate_vad(av->calls[call_index].cs, PCM, frame_size, ref);
971 DECODE_PACKET *p;
972 _Bool video = 0;
973
974 pthread_mutex_lock(&call->decode_cond_mutex);
975
976 if (call->exit) {
977 break;
978 }
979
980 uint8_t r;
981
982 /* first check for available packets, otherwise wait for condition*/
983 r = call->audio_decode_read;
984 p = call->audio_decode_queue[r];
985
986 if (!p) {
987 r = call->video_decode_read;
988 p = call->video_decode_queue[r];
989
990 if (!p) {
991 pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex);
992 r = call->audio_decode_read;
993 p = call->audio_decode_queue[r];
994
995 if (!p) {
996 r = call->video_decode_read;
997 p = call->video_decode_queue[r];
998 video = 1;
999 }
1000 } else {
1001 video = 1;
1002 }
1003 }
1004
1005 if (video) {
1006 if (p) {
1007 call->video_decode_queue[r] = NULL;
1008 call->video_decode_read = (r + 1) % VIDEO_DECODE_QUEUE_SIZE;
1009 }
1010 } else {
1011 call->audio_decode_queue[r] = NULL;
1012 call->audio_decode_read = (r + 1) % AUDIO_DECODE_QUEUE_SIZE;
1013 }
1014
1015 pthread_mutex_unlock(&call->decode_cond_mutex);
1016
1017 if (p) {
1018 if (video) {
1019 decode_video(av, call, p);
1020 } else {
1021 decode_audio(av, call, p);
1022 }
1023 }
1024 }
1025
1026 call->exit = 0;
1027 pthread_cond_signal(&call->decode_cond);
1028 pthread_mutex_unlock(&call->decode_cond_mutex);
1029
1030 return NULL;
1031} 602}
1032 603
1033void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg) 604int toxav_get_active_count(ToxAv* av)
1034{ 605{
1035 ToxAv *av = _session->av; 606 if (!av) return av_ErrorInternal;
1036 int32_t call_index = _session->call_index; 607
1037 CallSpecific *call = &av->calls[call_index]; 608 int rc = 0, i = 0;
1038 609 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) rc++;
1039 if (!call->call_active) return; 610 return rc;
1040
1041 if (_session->payload_type == type_audio % 128) {
1042 queue(call->j_buf, _msg);
1043
1044 int success = 0;
1045
1046 while ((_msg = dequeue(call->j_buf, &success)) || success == 2) {
1047 DECODE_PACKET *p;
1048
1049 if (success == 2) {
1050 p = malloc(sizeof(DECODE_PACKET));
1051
1052 if (p) {
1053 p->size = 0;
1054 }
1055 } else {
1056 p = malloc(sizeof(DECODE_PACKET) + _msg->length);
1057
1058 if (p) {
1059 p->size = _msg->length;
1060 memcpy(p->data, _msg->data, _msg->length);
1061 }
1062
1063 rtp_free_msg(NULL, _msg);
1064 }
1065
1066 if (p) {
1067 /* do the decoding on another thread */
1068 pthread_mutex_lock(&call->decode_cond_mutex);
1069 uint8_t w = call->audio_decode_write;
1070
1071 if (call->audio_decode_queue[w] == NULL) {
1072 call->audio_decode_queue[w] = p;
1073 call->audio_decode_write = (w + 1) % AUDIO_DECODE_QUEUE_SIZE;
1074 pthread_cond_signal(&call->decode_cond);
1075 } else {
1076 LOGGER_DEBUG("Dropped audio frame\n");
1077 free(p);
1078 }
1079
1080 pthread_mutex_unlock(&call->decode_cond_mutex);
1081 } else {
1082 //malloc failed
1083 }
1084 }
1085
1086 } else {
1087 uint8_t *packet = _msg->data;
1088 int recved_size = _msg->length;
1089
1090 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
1091 goto end;
1092 }
1093
1094 uint8_t i = packet[0] - call->frame_id;
1095
1096 if (i == 0) {
1097 /* piece of current frame */
1098 } else if (i > 0 && i < 128) {
1099 /* received a piece of a frame ahead, flush current frame and start reading this new frame */
1100 DECODE_PACKET *p = malloc(sizeof(DECODE_PACKET) + call->frame_limit);
1101
1102 if (p) {
1103 p->size = call->frame_limit;
1104 memcpy(p->data, call->frame_buf, call->frame_limit);
1105
1106 /* do the decoding on another thread */
1107 pthread_mutex_lock(&call->decode_cond_mutex);
1108 uint8_t w = call->video_decode_write;
1109
1110 if (call->video_decode_queue[w] == NULL) {
1111 call->video_decode_queue[w] = p;
1112 call->video_decode_write = (w + 1) % VIDEO_DECODE_QUEUE_SIZE;
1113 pthread_cond_signal(&call->decode_cond);
1114 } else {
1115 LOGGER_DEBUG("Dropped video frame\n");
1116 free(p);
1117 }
1118
1119 pthread_mutex_unlock(&call->decode_cond_mutex);
1120 } else {
1121 //malloc failed
1122 }
1123
1124 call->frame_id = packet[0];
1125 memset(call->frame_buf, 0, call->frame_limit);
1126 call->frame_limit = 0;
1127 } else {
1128 /* old packet, dont read */
1129 LOGGER_DEBUG("Old packet: %u\n", i);
1130 goto end;
1131 }
1132
1133 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
1134 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
1135 /* packet out of buffer range */
1136 goto end;
1137 }
1138
1139 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
1140 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
1141 recved_size - VIDEOFRAME_HEADER_SIZE);
1142 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
1143
1144 if (limit > call->frame_limit) {
1145 call->frame_limit = limit;
1146 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
1147 }
1148
1149end:
1150 ;
1151 rtp_free_msg(NULL, _msg);
1152 }
1153} 611}
1154 612
1155 613