summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
new file mode 100644
index 00000000..8757d7fd
--- /dev/null
+++ b/toxav/toxav.c
@@ -0,0 +1,352 @@
1/** toxav.c
2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *
21 * Report bugs/suggestions at either #tox-dev @ freenode.net:6667 or
22 * my email: eniz_vukovic@hotmail.com
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif /* HAVE_CONFIG_H */
28
29#include "toxav.h"
30#include "../toxcore/tox.h"
31#include "rtp.h"
32#include "msi.h"
33#include "media.h"
34
35#include <stdlib.h>
36#include <string.h>
37#include <assert.h>
38
39#define inline__ inline __attribute__((always_inline))
40
41static const uint8_t audio_index = 0, video_index = 1;
42
43
44typedef enum {
45 ts_closing,
46 ts_running,
47 ts_closed
48
49} ThreadState;
50
51typedef struct _ToxAv
52{
53 Tox* messenger;
54
55 MSISession* msi_session; /** Main msi session */
56
57 RTPSession* rtp_sessions[2]; /* Audio is first and video is second */
58
59 /* TODO: Add media session */
60 struct jitter_buffer* j_buf;
61 CodecState* cs;
62 /* TODO: Add media session threads */
63
64
65 void* agent_handler;
66} ToxAv;
67
68
69
70
71
72/********************************************************************************************************************
73 ********************************************************************************************************************
74 ********************************************************************************************************************
75 ********************************************************************************************************************
76 ********************************************************************************************************************
77 *
78 *
79 *
80 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
81 *
82 *
83 *
84 ********************************************************************************************************************
85 ********************************************************************************************************************
86 ********************************************************************************************************************
87 ********************************************************************************************************************
88 ********************************************************************************************************************/
89
90
91
92ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name )
93{
94 ToxAv* av = calloc ( sizeof(ToxAv), 1);
95
96 av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name );
97 av->msi_session->agent_handler = av;
98
99 av->rtp_sessions[0] = av->rtp_sessions [1] = NULL;
100
101 av->messenger = messenger;
102
103 /* NOTE: This should be user defined or? */
104 av->j_buf = create_queue(20);
105
106 av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER);
107
108 av->agent_handler = useragent;
109
110 return av;
111}
112
113void toxav_kill ( ToxAv* av )
114{
115 msi_terminate_session(av->msi_session);
116
117 if ( av->rtp_sessions[audio_index] ) {
118 rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
119 }
120
121 if ( av->rtp_sessions[video_index] ) {
122 rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle);
123 }
124
125 codec_terminate_session(av->cs);
126
127 free(av);
128}
129
130void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id )
131{
132 msi_register_callback((MSICallback)callback, (MSICallbackID) id);
133}
134
135
136
137int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds )
138{
139 if ( av->msi_session->call ) {
140 return ErrorAlreadyInCall;
141 }
142
143 return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
144}
145
146int toxav_hangup ( ToxAv* av )
147{
148 if ( !av->msi_session->call ) {
149 return ErrorNoCall;
150 }
151
152 if ( av->msi_session->call->state != call_active ) {
153 return ErrorInvalidState;
154 }
155
156 return msi_hangup(av->msi_session);
157}
158
159int toxav_answer ( ToxAv* av, ToxAvCallType call_type )
160{
161 if ( !av->msi_session->call ) {
162 return ErrorNoCall;
163 }
164
165 if ( av->msi_session->call->state != call_starting ) {
166 return ErrorInvalidState;
167 }
168
169 return msi_answer(av->msi_session, call_type);
170}
171
172int toxav_reject ( ToxAv* av, const char* reason )
173{
174 if ( !av->msi_session->call ) {
175 return ErrorNoCall;
176 }
177
178 if ( av->msi_session->call->state != call_starting ) {
179 return ErrorInvalidState;
180 }
181
182 return msi_reject(av->msi_session, (const uint8_t*) reason);
183}
184
185int toxav_cancel ( ToxAv* av, const char* reason )
186{
187 if ( !av->msi_session->call ) {
188 return ErrorNoCall;
189 }
190
191 return msi_cancel(av->msi_session, 0, (const uint8_t*)reason);
192}
193
194/* You can stop the call at any state */
195int toxav_stop_call ( ToxAv* av )
196{
197 if ( !av->msi_session->call ) {
198 return ErrorNoCall;
199 }
200
201 return msi_stopcall(av->msi_session);
202}
203
204
205int toxav_prepare_transmission ( ToxAv* av )
206{
207 assert(av->msi_session);
208 if ( !av->msi_session || !av->msi_session->call ) {
209 return ErrorNoCall;
210 }
211
212 av->rtp_sessions[audio_index] = rtp_init_session(
213 type_audio,
214 av->messenger,
215 av->msi_session->call->peers[0],
216 av->msi_session->call->key_peer,
217 av->msi_session->call->key_local,
218 av->msi_session->call->nonce_peer,
219 av->msi_session->call->nonce_local
220 );
221
222
223 if ( !av->rtp_sessions[audio_index] ) {
224 fprintf(stderr, "Error while starting audio RTP session!\n");
225 return ErrorStartingAudioRtp;
226 }
227
228 av->rtp_sessions[video_index] = rtp_init_session (
229 type_video,
230 av->messenger,
231 av->msi_session->call->peers[0],
232 av->msi_session->call->key_peer,
233 av->msi_session->call->key_local,
234 av->msi_session->call->nonce_peer,
235 av->msi_session->call->nonce_local
236 );
237
238
239 if ( !av->rtp_sessions[video_index] ) {
240 fprintf(stderr, "Error while starting video RTP session!\n");
241 return ErrorStartingVideoRtp;
242 }
243
244 return ErrorNone;
245}
246
247
248int toxav_kill_transmission ( ToxAv* av )
249{
250 /* Both sessions should be active at any time */
251 if ( !av->rtp_sessions[0] || !av->rtp_sessions[0] )
252 return ErrorNoTransmission;
253
254
255 if ( -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
256 fprintf(stderr, "Error while terminating audio RTP session!\n");
257 return ErrorTerminatingAudioRtp;
258 }
259
260 if ( -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
261 fprintf(stderr, "Error while terminating video RTP session!\n");
262 return ErrorTerminatingVideoRtp;
263 }
264
265 return ErrorNone;
266}
267
268
269inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length )
270{
271 if ( av->rtp_sessions[type - TypeAudio] )
272 return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
273 else return -1;
274}
275
276inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest )
277{
278 if ( !dest ) return ErrorInternal;
279
280 if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession;
281
282 RTPMessage* message;
283
284 if ( type == TypeAudio ) {
285
286 message = rtp_recv_msg(av->rtp_sessions[audio_index]);
287
288 if (message) {
289 /* push the packet into the queue */
290 queue(av->j_buf, message);
291 }
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 else {
302 message = rtp_recv_msg(av->rtp_sessions[video_index]);
303 }
304
305 if ( message ) {
306 memcpy(dest, message->data, message->length);
307
308 int length = message->length;
309
310 rtp_free_msg(NULL, message);
311
312 return length;
313 }
314
315 return 0;
316}
317
318inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest )
319{
320 if ( !dest ) return ErrorInternal;
321
322 return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1);
323}
324
325inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest )
326{
327 if ( !dest )
328 return ErrorInternal;
329
330 return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE);
331}
332
333int toxav_get_peer_transmission_type ( ToxAv* av, int peer )
334{
335 assert(av->msi_session);
336 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
337 return ErrorInternal;
338
339 return av->msi_session->call->type_peer[peer];
340}
341
342void* toxav_get_agent_handler ( ToxAv* av )
343{
344 return av->agent_handler;
345}
346
347
348/* Only temporary */
349void* get_cs_temp(ToxAv* av)
350{
351 return av->cs;
352}