ffi-tox 0.1.1 → 0.1.3

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