Initial commit
This commit is contained in:
32
local_pod_repo/toxcore/.gitignore
vendored
Normal file
32
local_pod_repo/toxcore/.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
|
||||
# Bundler
|
||||
.bundle
|
||||
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
|
||||
#
|
||||
# Note: if you ignore the Pods directory, make sure to uncomment
|
||||
# `pod install` in .travis.yml
|
||||
#
|
||||
# Pods/
|
||||
187
local_pod_repo/toxcore/0002_zoff_tc___capabilites.diff
Normal file
187
local_pod_repo/toxcore/0002_zoff_tc___capabilites.diff
Normal file
@@ -0,0 +1,187 @@
|
||||
commit f9a7099bcf2a37095384bbf9418afce815d67138
|
||||
Author: zoff99 <zoff99@users.noreply.github.com>
|
||||
Date: Sat Apr 16 10:21:57 2022 +0200
|
||||
|
||||
capabilites
|
||||
|
||||
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
|
||||
index 715b23fd9..d7388d54d 100644
|
||||
--- a/toxcore/Messenger.c
|
||||
+++ b/toxcore/Messenger.c
|
||||
@@ -113,6 +113,15 @@ static bool send_online_packet(Messenger *m, int32_t friendnumber)
|
||||
return false;
|
||||
}
|
||||
|
||||
+ uint8_t buf[TOX_CAPABILITIES_SIZE + 1];
|
||||
+ buf[0] = PACKET_ID_ONLINE;
|
||||
+ net_pack_u64(buf + 1, TOX_CAPABILITIES_CURRENT);
|
||||
+
|
||||
+ if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
+ m->friendlist[friendnumber].friendcon_id), buf, (TOX_CAPABILITIES_SIZE + 1), false) == -1) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
uint8_t packet = PACKET_ID_ONLINE;
|
||||
return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
|
||||
m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), false) != -1;
|
||||
@@ -166,6 +175,7 @@ static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t sta
|
||||
m->friendlist[i].userstatus = USERSTATUS_NONE;
|
||||
m->friendlist[i].is_typing = false;
|
||||
m->friendlist[i].message_id = 0;
|
||||
+ m->friendlist[i].toxcore_capabilities = TOX_CAPABILITY_BASIC;
|
||||
friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &m_handle_status, &m_handle_packet,
|
||||
&m_handle_lossy_packet, m, i);
|
||||
|
||||
@@ -1862,6 +1872,19 @@ static int m_handle_status(void *object, int i, bool status, void *userdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* get capabilities of friend's toxcore
|
||||
+ * return TOX_CAPABILITY_BASIC on any error
|
||||
+ */
|
||||
+uint64_t m_get_friend_toxcore_capabilities(const Messenger *m, int32_t friendnumber)
|
||||
+{
|
||||
+ if (!m_friend_exists(m, friendnumber)) {
|
||||
+ return TOX_CAPABILITY_BASIC;
|
||||
+ }
|
||||
+
|
||||
+ // return toxcore_capabilities for friend, not matter if ONLINE or OFFLINE
|
||||
+ return m->friendlist[friendnumber].toxcore_capabilities;
|
||||
+}
|
||||
+
|
||||
static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata)
|
||||
{
|
||||
if (len == 0) {
|
||||
@@ -1874,9 +1897,20 @@ static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t le
|
||||
const uint16_t data_length = len - 1;
|
||||
|
||||
if (m->friendlist[i].status != FRIEND_ONLINE) {
|
||||
- if (packet_id == PACKET_ID_ONLINE && len == 1) {
|
||||
- set_friend_status(m, i, FRIEND_ONLINE, userdata);
|
||||
- send_online_packet(m, i);
|
||||
+ if (packet_id == PACKET_ID_ONLINE) {
|
||||
+ if (len == (TOX_CAPABILITIES_SIZE + 1)) {
|
||||
+ uint64_t received_caps;
|
||||
+ net_unpack_u64(data, &received_caps);
|
||||
+ m->friendlist[i].toxcore_capabilities = received_caps;
|
||||
+ LOGGER_DEBUG(m->log, "got capabilties: %llu friendnum: %d",
|
||||
+ (long long unsigned int)m->friendlist[i].toxcore_capabilities, (int)i);
|
||||
+ } else if (len == 1) {
|
||||
+ set_friend_status(m, i, FRIEND_ONLINE, userdata);
|
||||
+ send_online_packet(m, i);
|
||||
+ LOGGER_DEBUG(m->log, "got online packet for friendnum: %d", (int)i);
|
||||
+ } else {
|
||||
+ return -1;
|
||||
+ }
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
|
||||
index 3bb818a32..dce79eed2 100644
|
||||
--- a/toxcore/Messenger.h
|
||||
+++ b/toxcore/Messenger.h
|
||||
@@ -72,6 +72,30 @@ typedef struct Messenger_Options {
|
||||
uint8_t state_plugins_length;
|
||||
} Messenger_Options;
|
||||
|
||||
+/* this means no special capabilities, in other words clients that are older
|
||||
+ * and did not implement this feature yet
|
||||
+ */
|
||||
+#define TOX_CAPABILITY_BASIC 0
|
||||
+/* ATTENTION: if you are adding new flags in your fork or toxcore,
|
||||
+ * or in c-toxcore master,
|
||||
+ * please coordinate with us first!
|
||||
+ * thank you, the Tox Devs.
|
||||
+ */
|
||||
+#define TOX_CAPABILITY_CAPABILITIES ((uint64_t)1) << 0
|
||||
+#define TOX_CAPABILITY_MSGV2 ((uint64_t)1) << 1
|
||||
+#define TOX_CAPABILITY_TOXAV_H264 ((uint64_t)1) << 2
|
||||
+#define TOX_CAPABILITY_MSGV3 ((uint64_t)1) << 3
|
||||
+/* add new flags/bits here */
|
||||
+/* if the TOX_CAPABILITY_NEXT_IMPLEMENTATION flag is set it means
|
||||
+ * we are using a different system for indicating capabilities now,
|
||||
+ * and TOX_CAPABILITIES_* should be ignored and just the new (not yet known)
|
||||
+ * system should be used
|
||||
+ */
|
||||
+#define TOX_CAPABILITY_NEXT_IMPLEMENTATION ((uint64_t)1) << 63
|
||||
+/* hardcoded capabilities of this version/branch of toxcore */
|
||||
+#define TOX_CAPABILITIES_CURRENT (uint64_t)(TOX_CAPABILITY_CAPABILITIES | TOX_CAPABILITY_MSGV3)
|
||||
+/* size of the FLAGS in bytes */
|
||||
+#define TOX_CAPABILITIES_SIZE sizeof(uint64_t)
|
||||
|
||||
struct Receipts {
|
||||
uint32_t packet_num;
|
||||
@@ -226,6 +254,7 @@ typedef struct Friend {
|
||||
|
||||
struct Receipts *receipts_start;
|
||||
struct Receipts *receipts_end;
|
||||
+ uint64_t toxcore_capabilities;
|
||||
} Friend;
|
||||
|
||||
struct Messenger {
|
||||
@@ -494,6 +523,10 @@ non_null() int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf);
|
||||
non_null() uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);
|
||||
non_null() uint8_t m_get_self_userstatus(const Messenger *m);
|
||||
|
||||
+/* get capabilities of friend's toxcore
|
||||
+ * return TOX_CAPABILITY_BASIC on any error
|
||||
+ */
|
||||
+uint64_t m_get_friend_toxcore_capabilities(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief returns timestamp of last time friendnumber was seen online or 0 if never seen.
|
||||
* if friendnumber is invalid this function will return UINT64_MAX.
|
||||
diff --git a/toxcore/tox.c b/toxcore/tox.c
|
||||
index cf350c59e..845bee680 100644
|
||||
--- a/toxcore/tox.c
|
||||
+++ b/toxcore/tox.c
|
||||
@@ -1299,6 +1299,20 @@ uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, Tox_
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
+uint64_t tox_friend_get_capabilities(const Tox *tox, uint32_t friend_number)
|
||||
+{
|
||||
+ tox_lock(tox);
|
||||
+ const uint64_t capabilities = m_get_friend_toxcore_capabilities(tox->m, friend_number);
|
||||
+ tox_unlock(tox);
|
||||
+
|
||||
+ return capabilities;
|
||||
+}
|
||||
+
|
||||
+uint64_t tox_self_get_capabilities(void)
|
||||
+{
|
||||
+ return (TOX_CAPABILITIES_CURRENT);
|
||||
+}
|
||||
+
|
||||
size_t tox_self_get_friend_list_size(const Tox *tox)
|
||||
{
|
||||
assert(tox != nullptr);
|
||||
diff --git a/toxcore/tox.h b/toxcore/tox.h
|
||||
index 56f9daf05..2ce668c42 100644
|
||||
--- a/toxcore/tox.h
|
||||
+++ b/toxcore/tox.h
|
||||
@@ -1136,9 +1136,12 @@ void tox_self_get_public_key(const Tox *tox, uint8_t *public_key);
|
||||
*/
|
||||
void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key);
|
||||
|
||||
+/**
|
||||
+ * Return the capabilities flags for this tox instance.
|
||||
+ */
|
||||
+uint64_t tox_self_get_capabilities(void);
|
||||
/** @} */
|
||||
|
||||
-
|
||||
/** @{
|
||||
* @name User-visible client information (nickname/status)
|
||||
*/
|
||||
@@ -1525,6 +1528,11 @@ typedef enum Tox_Err_Friend_Query {
|
||||
|
||||
} Tox_Err_Friend_Query;
|
||||
|
||||
+/**
|
||||
+ * Return the capabilities flags for a friend. If the friend number is invalid, the
|
||||
+ * return value is unspecified.
|
||||
+ */
|
||||
+uint64_t tox_friend_get_capabilities(const Tox *tox, uint32_t friend_number);
|
||||
|
||||
/**
|
||||
* @brief Return the length of the friend's name.
|
||||
674
local_pod_repo/toxcore/LICENSE
Normal file
674
local_pod_repo/toxcore/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
8
local_pod_repo/toxcore/Podfile
Normal file
8
local_pod_repo/toxcore/Podfile
Normal file
@@ -0,0 +1,8 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
|
||||
# ignore all warnings from all pods
|
||||
inhibit_all_warnings!
|
||||
|
||||
def common_pods
|
||||
pod "msgpack-c", :path => '../msgpack-c'
|
||||
end
|
||||
12
local_pod_repo/toxcore/README.md
Normal file
12
local_pod_repo/toxcore/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# toxcore
|
||||
|
||||
CocoaPods wrapper for [c-toxcore](https://github.com/TokTok/c-toxcore).
|
||||
|
||||
#### Note
|
||||
|
||||
Pod has same version number as toxcore.
|
||||
|
||||
## Authors
|
||||
|
||||
Dmytro Vorobiov, d@dvor.me<br>
|
||||
https://github.com/Zoxcore
|
||||
69
local_pod_repo/toxcore/build-vpx.sh
Executable file
69
local_pod_repo/toxcore/build-vpx.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
TEMP_DIR="temp"
|
||||
LIBVPX_DIR="libvpx"
|
||||
VPX_FRAMEWORK="vpx.framework"
|
||||
|
||||
# $1 - framework directory
|
||||
remove_old_framework() {
|
||||
if [ -d "$1" ]; then
|
||||
echo "Removing $1"
|
||||
rm -rf "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
clone_libvpx() {
|
||||
echo "Cloning libvpx"
|
||||
mkdir $TEMP_DIR
|
||||
cd $TEMP_DIR
|
||||
git clone --branch v1.4.0 --depth 1 https://github.com/webmproject/libvpx.git $LIBVPX_DIR
|
||||
}
|
||||
|
||||
# $1 - patch file name
|
||||
patch_vpx() {
|
||||
echo "Patching libvpx"
|
||||
cd $LIBVPX_DIR
|
||||
git apply ../../$1
|
||||
cd ../..
|
||||
}
|
||||
|
||||
build_vpx() {
|
||||
echo "Building vpx framework"
|
||||
$TEMP_DIR/$LIBVPX_DIR/build/make/iosbuild.sh --show-build-output --verbose
|
||||
|
||||
echo "Moving headers from $VPX_FRAMEWORK/Headers/vpx/ to $VPX_FRAMEWORK/Headers/"
|
||||
mv $VPX_FRAMEWORK/Headers/vpx/* $VPX_FRAMEWORK/Headers/
|
||||
rm -rf $VPX_FRAMEWORK/Headers/vpx
|
||||
}
|
||||
|
||||
# $2 - directory to move framework to
|
||||
move_vpx() {
|
||||
echo "Moving framework from $VPX_FRAMEWORK to $1/$VPX_FRAMEWORK"
|
||||
mkdir $1
|
||||
mv $VPX_FRAMEWORK $1/$VPX_FRAMEWORK
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
echo "Removing $TEMP_DIR directory"
|
||||
rm -rf $TEMP_DIR
|
||||
}
|
||||
|
||||
# $1 - patch file name
|
||||
# $2 - directory install framework to
|
||||
do_all() {
|
||||
echo "Building for $2"
|
||||
|
||||
remove_old_framework $2
|
||||
|
||||
clone_libvpx
|
||||
patch_vpx $1
|
||||
build_vpx
|
||||
move_vpx $2
|
||||
|
||||
cleanup
|
||||
}
|
||||
|
||||
do_all vpx-osx.diff osx
|
||||
do_all vpx-ios.diff ios
|
||||
|
||||
echo "Done"
|
||||
75
local_pod_repo/toxcore/install-tox.sh
Executable file
75
local_pod_repo/toxcore/install-tox.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
|
||||
_HOME2_=$(dirname $0)
|
||||
export _HOME2_
|
||||
_HOME_=$(cd $_HOME2_;pwd)
|
||||
export _HOME_
|
||||
|
||||
echo $_HOME_
|
||||
cd $_HOME_
|
||||
|
||||
GIT_PATH="toxcore-git"
|
||||
OUTPUT="toxcore"
|
||||
|
||||
DIRS=(
|
||||
"toxcore"
|
||||
"toxav"
|
||||
"toxdns"
|
||||
"toxencryptsave"
|
||||
)
|
||||
|
||||
echo "Removing old toxcore directory"
|
||||
rm -rf $OUTPUT
|
||||
mkdir $OUTPUT
|
||||
|
||||
rm -Rf $GIT_PATH/
|
||||
git clone https://github.com/TokTok/c-toxcore $GIT_PATH/
|
||||
|
||||
cd $GIT_PATH/
|
||||
git checkout "v0.2.18"
|
||||
|
||||
echo "Applying msgv3_addon.patch"
|
||||
git apply --reject --whitespace=fix ../msgv3_addon.patch
|
||||
|
||||
echo "Applying 0002_zoff_tc___capabilites.diff"
|
||||
git apply --reject --whitespace=fix ../0002_zoff_tc___capabilites.diff
|
||||
|
||||
cd ..
|
||||
|
||||
for dir in ${DIRS[@]}; do
|
||||
echo "Copying files from $GIT_PATH/$dir to $OUTPUT/$dir"
|
||||
cp -rv $GIT_PATH/$dir $OUTPUT
|
||||
done
|
||||
|
||||
cd $GIT_PATH/
|
||||
echo "cleanup"
|
||||
git checkout toxcore/*
|
||||
cd ..
|
||||
|
||||
echo "Changing all .c files to .m files (making Xcode happy)"
|
||||
for file in toxcore/**/*.c; do
|
||||
mv -v "$file" "${file%.c}.m"
|
||||
done
|
||||
|
||||
for file in toxcore/toxcore/events/*.c; do
|
||||
mv -v "$file" "${file%.c}.m"
|
||||
done
|
||||
|
||||
remove_files_matching() {
|
||||
for file in $1; do
|
||||
echo "Removing $file"
|
||||
rm $file
|
||||
done
|
||||
}
|
||||
|
||||
remove_files_matching "toxcore/**/*.bazel"
|
||||
remove_files_matching "toxcore/**/*_test.cpp"
|
||||
remove_files_matching "toxcore/**/*_test.cc"
|
||||
remove_files_matching "toxcore/**/*.api.h"
|
||||
|
||||
echo "patching toxcore includes ..."
|
||||
cd toxcore/
|
||||
grep -rl '#include <sodium.h>' | grep -v 'install-tox.sh' | xargs -L1 sed -i -e 's_#include <sodium.h>_#include "sodium.h"_'
|
||||
grep -rl '#include <opus.h>' | grep -v 'install-tox.sh' | xargs -L1 sed -i -e 's_#include <opus.h>_#include "opus.h"_'
|
||||
grep -rl '#include "../third_party/cmp/cmp.h"' | grep -v 'install-tox.sh' | xargs -L1 sed -i -e 'sx#include "../third_party/cmp/cmp.h"x#include "cmp.h"x'
|
||||
cd ..
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 1
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 0
|
||||
#define ARCH_X86_64 0
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 0
|
||||
#define HAVE_NEON 1
|
||||
#define HAVE_NEON_ASM 0
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 0
|
||||
#define HAVE_SSE 0
|
||||
#define HAVE_SSE2 0
|
||||
#define HAVE_SSE3 0
|
||||
#define HAVE_SSSE3 0
|
||||
#define HAVE_SSE4_1 0
|
||||
#define HAVE_AVX 0
|
||||
#define HAVE_AVX2 0
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 0
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 0
|
||||
#define CONFIG_POSTPROC 0
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 0
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 1
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 0
|
||||
#define ARCH_X86_64 0
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 1
|
||||
#define HAVE_NEON 1
|
||||
#define HAVE_NEON_ASM 1
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 0
|
||||
#define HAVE_SSE 0
|
||||
#define HAVE_SSE2 0
|
||||
#define HAVE_SSE3 0
|
||||
#define HAVE_SSSE3 0
|
||||
#define HAVE_SSE4_1 0
|
||||
#define HAVE_AVX 0
|
||||
#define HAVE_AVX2 0
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 0
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 0
|
||||
#define CONFIG_POSTPROC 0
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 0
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 1
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 0
|
||||
#define ARCH_X86_64 0
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 1
|
||||
#define HAVE_NEON 1
|
||||
#define HAVE_NEON_ASM 1
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 0
|
||||
#define HAVE_SSE 0
|
||||
#define HAVE_SSE2 0
|
||||
#define HAVE_SSE3 0
|
||||
#define HAVE_SSSE3 0
|
||||
#define HAVE_SSE4_1 0
|
||||
#define HAVE_AVX 0
|
||||
#define HAVE_AVX2 0
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 0
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 0
|
||||
#define CONFIG_POSTPROC 0
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 0
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
138
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8.h
Normal file
138
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*!\defgroup vp8 VP8
|
||||
* \ingroup codecs
|
||||
* VP8 is vpx's newest video compression algorithm that uses motion
|
||||
* compensated prediction, Discrete Cosine Transform (DCT) coding of the
|
||||
* prediction error signal and context dependent entropy coding techniques
|
||||
* based on arithmetic principles. It features:
|
||||
* - YUV 4:2:0 image format
|
||||
* - Macro-block based coding (16x16 luma plus two 8x8 chroma)
|
||||
* - 1/4 (1/8) pixel accuracy motion compensated prediction
|
||||
* - 4x4 DCT transform
|
||||
* - 128 level linear quantizer
|
||||
* - In loop deblocking filter
|
||||
* - Context-based entropy coding
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/*!\file
|
||||
* \brief Provides controls common to both the VP8 encoder and decoder.
|
||||
*/
|
||||
#ifndef VPX_VP8_H_
|
||||
#define VPX_VP8_H_
|
||||
|
||||
#include "./vpx_codec.h"
|
||||
#include "./vpx_image.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\brief Control functions
|
||||
*
|
||||
* The set of macros define the control functions of VP8 interface
|
||||
*/
|
||||
enum vp8_com_control_id {
|
||||
VP8_SET_REFERENCE = 1, /**< pass in an external frame into decoder to be used as reference frame */
|
||||
VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */
|
||||
VP8_SET_POSTPROC = 3, /**< set the decoder's post processing settings */
|
||||
VP8_SET_DBG_COLOR_REF_FRAME = 4, /**< set the reference frames to color for each macroblock */
|
||||
VP8_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */
|
||||
VP8_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */
|
||||
VP8_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */
|
||||
|
||||
/* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+)
|
||||
* for its control ids. These should be migrated to something like the
|
||||
* VP8_DECODER_CTRL_ID_START range next time we're ready to break the ABI.
|
||||
*/
|
||||
VP9_GET_REFERENCE = 128, /**< get a pointer to a reference frame */
|
||||
VP8_COMMON_CTRL_ID_MAX,
|
||||
VP8_DECODER_CTRL_ID_START = 256
|
||||
};
|
||||
|
||||
/*!\brief post process flags
|
||||
*
|
||||
* The set of macros define VP8 decoder post processing flags
|
||||
*/
|
||||
enum vp8_postproc_level {
|
||||
VP8_NOFILTERING = 0,
|
||||
VP8_DEBLOCK = 1 << 0,
|
||||
VP8_DEMACROBLOCK = 1 << 1,
|
||||
VP8_ADDNOISE = 1 << 2,
|
||||
VP8_DEBUG_TXT_FRAME_INFO = 1 << 3, /**< print frame information */
|
||||
VP8_DEBUG_TXT_MBLK_MODES = 1 << 4, /**< print macro block modes over each macro block */
|
||||
VP8_DEBUG_TXT_DC_DIFF = 1 << 5, /**< print dc diff for each macro block */
|
||||
VP8_DEBUG_TXT_RATE_INFO = 1 << 6, /**< print video rate info (encoder only) */
|
||||
VP8_MFQE = 1 << 10
|
||||
};
|
||||
|
||||
/*!\brief post process flags
|
||||
*
|
||||
* This define a structure that describe the post processing settings. For
|
||||
* the best objective measure (using the PSNR metric) set post_proc_flag
|
||||
* to VP8_DEBLOCK and deblocking_level to 1.
|
||||
*/
|
||||
|
||||
typedef struct vp8_postproc_cfg {
|
||||
int post_proc_flag; /**< the types of post processing to be done, should be combination of "vp8_postproc_level" */
|
||||
int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */
|
||||
int noise_level; /**< the strength of additive noise, valid range [0, 16] */
|
||||
} vp8_postproc_cfg_t;
|
||||
|
||||
/*!\brief reference frame type
|
||||
*
|
||||
* The set of macros define the type of VP8 reference frames
|
||||
*/
|
||||
typedef enum vpx_ref_frame_type {
|
||||
VP8_LAST_FRAME = 1,
|
||||
VP8_GOLD_FRAME = 2,
|
||||
VP8_ALTR_FRAME = 4
|
||||
} vpx_ref_frame_type_t;
|
||||
|
||||
/*!\brief reference frame data struct
|
||||
*
|
||||
* Define the data struct to access vp8 reference frames.
|
||||
*/
|
||||
typedef struct vpx_ref_frame {
|
||||
vpx_ref_frame_type_t frame_type; /**< which reference frame */
|
||||
vpx_image_t img; /**< reference frame data in image format */
|
||||
} vpx_ref_frame_t;
|
||||
|
||||
/*!\brief VP9 specific reference frame data struct
|
||||
*
|
||||
* Define the data struct to access vp9 reference frames.
|
||||
*/
|
||||
typedef struct vp9_ref_frame {
|
||||
int idx; /**< frame index to get (input) */
|
||||
vpx_image_t img; /**< img structure to populate (output) */
|
||||
} vp9_ref_frame_t;
|
||||
|
||||
/*!\brief vp8 decoder control function parameter type
|
||||
*
|
||||
* defines the data type for each of VP8 decoder control function requires
|
||||
*/
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_REF_FRAME, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_MB_MODES, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_B_MODES, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_DISPLAY_MV, int)
|
||||
VPX_CTRL_USE_TYPE(VP9_GET_REFERENCE, vp9_ref_frame_t *)
|
||||
|
||||
/*! @} - end defgroup vp8 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8_H_
|
||||
699
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8cx.h
Normal file
699
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8cx.h
Normal file
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef VPX_VP8CX_H_
|
||||
#define VPX_VP8CX_H_
|
||||
|
||||
/*!\defgroup vp8_encoder WebM VP8/VP9 Encoder
|
||||
* \ingroup vp8
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#include "./vp8.h"
|
||||
#include "./vpx_encoder.h"
|
||||
|
||||
/*!\file
|
||||
* \brief Provides definitions for using VP8 or VP9 encoder algorithm within the
|
||||
* vpx Codec Interface.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\name Algorithm interface for VP8
|
||||
*
|
||||
* This interface provides the capability to encode raw VP8 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp8_cx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp8_cx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
/*!\name Algorithm interface for VP9
|
||||
*
|
||||
* This interface provides the capability to encode raw VP9 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp9_cx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp9_cx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
|
||||
/*
|
||||
* Algorithm Flags
|
||||
*/
|
||||
|
||||
/*!\brief Don't reference the last frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the last frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* last frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_LAST (1<<16)
|
||||
|
||||
|
||||
/*!\brief Don't reference the golden frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the golden frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* golden frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_GF (1<<17)
|
||||
|
||||
|
||||
/*!\brief Don't reference the alternate reference frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the alt ref frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* alt ref frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_ARF (1<<21)
|
||||
|
||||
|
||||
/*!\brief Don't update the last frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the last frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_LAST (1<<18)
|
||||
|
||||
|
||||
/*!\brief Don't update the golden frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the golden frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_GF (1<<22)
|
||||
|
||||
|
||||
/*!\brief Don't update the alternate reference frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the alt ref frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_ARF (1<<23)
|
||||
|
||||
|
||||
/*!\brief Force golden frame update
|
||||
*
|
||||
* When this flag is set, the encoder copy the contents of the current frame
|
||||
* to the golden frame buffer.
|
||||
*/
|
||||
#define VP8_EFLAG_FORCE_GF (1<<19)
|
||||
|
||||
|
||||
/*!\brief Force alternate reference frame update
|
||||
*
|
||||
* When this flag is set, the encoder copy the contents of the current frame
|
||||
* to the alternate reference frame buffer.
|
||||
*/
|
||||
#define VP8_EFLAG_FORCE_ARF (1<<24)
|
||||
|
||||
|
||||
/*!\brief Disable entropy update
|
||||
*
|
||||
* When this flag is set, the encoder will not update its internal entropy
|
||||
* model based on the entropy of this frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_ENTROPY (1<<20)
|
||||
|
||||
|
||||
/*!\brief VPx encoder control functions
|
||||
*
|
||||
* This set of macros define the control functions available for VPx
|
||||
* encoder interface.
|
||||
*
|
||||
* \sa #vpx_codec_control
|
||||
*/
|
||||
enum vp8e_enc_control_id {
|
||||
/*!\brief Codec control function to set mode of entropy update in encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_UPD_ENTROPY = 5,
|
||||
|
||||
/*!\brief Codec control function to set reference update mode in encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_UPD_REFERENCE,
|
||||
|
||||
/*!\brief Codec control function to set which reference frame encoder can use.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_USE_REFERENCE,
|
||||
|
||||
/*!\brief Codec control function to pass an ROI map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ROI_MAP,
|
||||
|
||||
/*!\brief Codec control function to pass an Active map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ACTIVEMAP,
|
||||
|
||||
/*!\brief Codec control function to set encoder scaling mode.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_SCALEMODE = 11,
|
||||
|
||||
/*!\brief Codec control function to set encoder internal speed settings.
|
||||
*
|
||||
* Changes in this value influences, among others, the encoder's selection
|
||||
* of motion estimation methods. Values greater than 0 will increase encoder
|
||||
* speed at the expense of quality.
|
||||
*
|
||||
* \note Valid range for VP8: -16..16
|
||||
* \note Valid range for VP9: -8..8
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_CPUUSED = 13,
|
||||
|
||||
/*!\brief Codec control function to enable automatic set and use alf frames.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ENABLEAUTOALTREF,
|
||||
|
||||
/*!\brief control function to set noise sensitivity
|
||||
*
|
||||
* 0: off, 1: OnYOnly, 2: OnYUV,
|
||||
* 3: OnYUVAggressive, 4: Adaptive
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_NOISE_SENSITIVITY,
|
||||
|
||||
/*!\brief Codec control function to set sharpness.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_SHARPNESS,
|
||||
|
||||
/*!\brief Codec control function to set the threshold for MBs treated static.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_STATIC_THRESHOLD,
|
||||
|
||||
/*!\brief Codec control function to set the number of token partitions.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_TOKEN_PARTITIONS,
|
||||
|
||||
/*!\brief Codec control function to get last quantizer chosen by the encoder.
|
||||
*
|
||||
* Return value uses internal quantizer scale defined by the codec.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_GET_LAST_QUANTIZER,
|
||||
|
||||
/*!\brief Codec control function to get last quantizer chosen by the encoder.
|
||||
*
|
||||
* Return value uses the 0..63 scale as used by the rc_*_quantizer config
|
||||
* parameters.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_GET_LAST_QUANTIZER_64,
|
||||
|
||||
/*!\brief Codec control function to set the max no of frames to create arf.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ARNR_MAXFRAMES,
|
||||
|
||||
/*!\brief Codec control function to set the filter strength for the arf.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ARNR_STRENGTH,
|
||||
|
||||
/*!\deprecated control function to set the filter type to use for the arf. */
|
||||
VP8E_SET_ARNR_TYPE,
|
||||
|
||||
/*!\brief Codec control function to set visual tuning.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_TUNING,
|
||||
|
||||
/*!\brief Codec control function to set constrained quality level.
|
||||
*
|
||||
* \attention For this value to be used vpx_codec_enc_cfg_t::g_usage must be
|
||||
* set to #VPX_CQ.
|
||||
* \note Valid range: 0..63
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_CQ_LEVEL,
|
||||
|
||||
/*!\brief Codec control function to set Max data rate for Intra frames.
|
||||
*
|
||||
* This value controls additional clamping on the maximum size of a
|
||||
* keyframe. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* unlimited, or no additional clamping beyond the codec's built-in
|
||||
* algorithm.
|
||||
*
|
||||
* For example, to allocate no more than 4.5 frames worth of bitrate
|
||||
* to a keyframe, set this to 450.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_MAX_INTRA_BITRATE_PCT,
|
||||
|
||||
/*!\brief Codec control function to set reference and update frame flags.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_FRAME_FLAGS,
|
||||
|
||||
/*!\brief Codec control function to set max data rate for Inter frames.
|
||||
*
|
||||
* This value controls additional clamping on the maximum size of an
|
||||
* inter frame. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* unlimited, or no additional clamping beyond the codec's built-in
|
||||
* algorithm.
|
||||
*
|
||||
* For example, to allow no more than 4.5 frames worth of bitrate
|
||||
* to an inter frame, set this to 450.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_MAX_INTER_BITRATE_PCT,
|
||||
|
||||
/*!\brief Boost percentage for Golden Frame in CBR mode.
|
||||
*
|
||||
* This value controls the amount of boost given to Golden Frame in
|
||||
* CBR mode. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* the feature is off, i.e., no golden frame boost in CBR mode and
|
||||
* average bitrate target is used.
|
||||
*
|
||||
* For example, to allow 100% more bits, i.e, 2X, in a golden frame
|
||||
* than average frame, set this to 100.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_GF_CBR_BOOST_PCT,
|
||||
|
||||
/*!\brief Codec control function to set the temporal layer id.
|
||||
*
|
||||
* For temporal scalability: this control allows the application to set the
|
||||
* layer id for each frame to be encoded. Note that this control must be set
|
||||
* for every frame prior to encoding. The usage of this control function
|
||||
* supersedes the internal temporal pattern counter, which is now deprecated.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_TEMPORAL_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to set encoder screen content mode.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_SCREEN_CONTENT_MODE,
|
||||
|
||||
/*!\brief Codec control function to set lossless encoding mode.
|
||||
*
|
||||
* VP9 can operate in lossless encoding mode, in which the bitstream
|
||||
* produced will be able to decode and reconstruct a perfect copy of
|
||||
* input source. This control function provides a mean to switch encoder
|
||||
* into lossless coding mode(1) or normal coding mode(0) that may be lossy.
|
||||
* 0 = lossy coding mode
|
||||
* 1 = lossless coding mode
|
||||
*
|
||||
* By default, encoder operates in normal coding mode (maybe lossy).
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_LOSSLESS,
|
||||
|
||||
/*!\brief Codec control function to set number of tile columns.
|
||||
*
|
||||
* In encoding and decoding, VP9 allows an input image frame be partitioned
|
||||
* into separated vertical tile columns, which can be encoded or decoded
|
||||
* independently. This enables easy implementation of parallel encoding and
|
||||
* decoding. This control requests the encoder to use column tiles in
|
||||
* encoding an input frame, with number of tile columns (in Log2 unit) as
|
||||
* the parameter:
|
||||
* 0 = 1 tile column
|
||||
* 1 = 2 tile columns
|
||||
* 2 = 4 tile columns
|
||||
* .....
|
||||
* n = 2**n tile columns
|
||||
* The requested tile columns will be capped by encoder based on image size
|
||||
* limitation (The minimum width of a tile column is 256 pixel, the maximum
|
||||
* is 4096).
|
||||
*
|
||||
* By default, the value is 0, i.e. one single column tile for entire image.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TILE_COLUMNS,
|
||||
|
||||
/*!\brief Codec control function to set number of tile rows.
|
||||
*
|
||||
* In encoding and decoding, VP9 allows an input image frame be partitioned
|
||||
* into separated horizontal tile rows. Tile rows are encoded or decoded
|
||||
* sequentially. Even though encoding/decoding of later tile rows depends on
|
||||
* earlier ones, this allows the encoder to output data packets for tile rows
|
||||
* prior to completely processing all tile rows in a frame, thereby reducing
|
||||
* the latency in processing between input and output. The parameter
|
||||
* for this control describes the number of tile rows, which has a valid
|
||||
* range [0, 2]:
|
||||
* 0 = 1 tile row
|
||||
* 1 = 2 tile rows
|
||||
* 2 = 4 tile rows
|
||||
*
|
||||
* By default, the value is 0, i.e. one single row tile for entire image.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TILE_ROWS,
|
||||
|
||||
/*!\brief Codec control function to enable frame parallel decoding feature.
|
||||
*
|
||||
* VP9 has a bitstream feature to reduce decoding dependency between frames
|
||||
* by turning off backward update of probability context used in encoding
|
||||
* and decoding. This allows staged parallel processing of more than one
|
||||
* video frames in the decoder. This control function provides a mean to
|
||||
* turn this feature on or off for bitstreams produced by encoder.
|
||||
*
|
||||
* By default, this feature is off.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_FRAME_PARALLEL_DECODING,
|
||||
|
||||
/*!\brief Codec control function to set adaptive quantization mode.
|
||||
*
|
||||
* VP9 has a segment based feature that allows encoder to adaptively change
|
||||
* quantization parameter for each segment within a frame to improve the
|
||||
* subjective quality. This control makes encoder operate in one of the
|
||||
* several AQ_modes supported.
|
||||
*
|
||||
* By default, encoder operates with AQ_Mode 0(adaptive quantization off).
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_AQ_MODE,
|
||||
|
||||
/*!\brief Codec control function to enable/disable periodic Q boost.
|
||||
*
|
||||
* One VP9 encoder speed feature is to enable quality boost by lowering
|
||||
* frame level Q periodically. This control function provides a mean to
|
||||
* turn on/off this feature.
|
||||
* 0 = off
|
||||
* 1 = on
|
||||
*
|
||||
* By default, the encoder is allowed to use this feature for appropriate
|
||||
* encoding modes.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_FRAME_PERIODIC_BOOST,
|
||||
|
||||
/*!\brief Codec control function to set noise sensitivity.
|
||||
*
|
||||
* 0: off, 1: On(YOnly)
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_NOISE_SENSITIVITY,
|
||||
|
||||
/*!\brief Codec control function to turn on/off SVC in encoder.
|
||||
* \note Return value is VPX_CODEC_INVALID_PARAM if the encoder does not
|
||||
* support SVC in its current encoding mode
|
||||
* 0: off, 1: on
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC,
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief Codec control function to set parameters for SVC.
|
||||
* \note Parameters contain min_q, max_q, scaling factor for each of the
|
||||
* SVC layers.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC_PARAMETERS,
|
||||
#endif
|
||||
|
||||
/*!\brief Codec control function to set svc layer for spatial and temporal.
|
||||
* \note Valid ranges: 0..#vpx_codec_enc_cfg::ss_number_layers for spatial
|
||||
* layer and 0..#vpx_codec_enc_cfg::ts_number_layers for
|
||||
* temporal layer.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to set content type.
|
||||
* \note Valid parameter range:
|
||||
* VP9E_CONTENT_DEFAULT = Regular video content (Default)
|
||||
* VP9E_CONTENT_SCREEN = Screen capture content
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TUNE_CONTENT,
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief Codec control function to get svc layer ID.
|
||||
* \note The layer ID returned is for the data packet from the registered
|
||||
* callback function.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_GET_SVC_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to register callback to get per layer packet.
|
||||
* \note Parameter for this control function is a structure with a callback
|
||||
* function and a pointer to private data used by the callback.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_REGISTER_CX_CALLBACK,
|
||||
#endif
|
||||
|
||||
/*!\brief Codec control function to set color space info.
|
||||
* \note Valid ranges: 0..7, default is "UNKNOWN".
|
||||
* 0 = UNKNOWN,
|
||||
* 1 = BT_601
|
||||
* 2 = BT_709
|
||||
* 3 = SMPTE_170
|
||||
* 4 = SMPTE_240
|
||||
* 5 = BT_2020
|
||||
* 6 = RESERVED
|
||||
* 7 = SRGB
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_COLOR_SPACE,
|
||||
};
|
||||
|
||||
/*!\brief vpx 1-D scaling mode
|
||||
*
|
||||
* This set of constants define 1-D vpx scaling modes
|
||||
*/
|
||||
typedef enum vpx_scaling_mode_1d {
|
||||
VP8E_NORMAL = 0,
|
||||
VP8E_FOURFIVE = 1,
|
||||
VP8E_THREEFIVE = 2,
|
||||
VP8E_ONETWO = 3
|
||||
} VPX_SCALING_MODE;
|
||||
|
||||
|
||||
/*!\brief vpx region of interest map
|
||||
*
|
||||
* These defines the data structures for the region of interest map
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct vpx_roi_map {
|
||||
/*! An id between 0 and 3 for each 16x16 region within a frame. */
|
||||
unsigned char *roi_map;
|
||||
unsigned int rows; /**< Number of rows. */
|
||||
unsigned int cols; /**< Number of columns. */
|
||||
// TODO(paulwilkins): broken for VP9 which has 8 segments
|
||||
// q and loop filter deltas for each segment
|
||||
// (see MAX_MB_SEGMENTS)
|
||||
int delta_q[4]; /**< Quantizer deltas. */
|
||||
int delta_lf[4]; /**< Loop filter deltas. */
|
||||
/*! Static breakout threshold for each segment. */
|
||||
unsigned int static_threshold[4];
|
||||
} vpx_roi_map_t;
|
||||
|
||||
/*!\brief vpx active region map
|
||||
*
|
||||
* These defines the data structures for active region map
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef struct vpx_active_map {
|
||||
unsigned char *active_map; /**< specify an on (1) or off (0) each 16x16 region within a frame */
|
||||
unsigned int rows; /**< number of rows */
|
||||
unsigned int cols; /**< number of cols */
|
||||
} vpx_active_map_t;
|
||||
|
||||
/*!\brief vpx image scaling mode
|
||||
*
|
||||
* This defines the data structure for image scaling mode
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_scaling_mode {
|
||||
VPX_SCALING_MODE h_scaling_mode; /**< horizontal scaling mode */
|
||||
VPX_SCALING_MODE v_scaling_mode; /**< vertical scaling mode */
|
||||
} vpx_scaling_mode_t;
|
||||
|
||||
/*!\brief VP8 token partition mode
|
||||
*
|
||||
* This defines VP8 partitioning mode for compressed data, i.e., the number of
|
||||
* sub-streams in the bitstream. Used for parallelized decoding.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
VP8_ONE_TOKENPARTITION = 0,
|
||||
VP8_TWO_TOKENPARTITION = 1,
|
||||
VP8_FOUR_TOKENPARTITION = 2,
|
||||
VP8_EIGHT_TOKENPARTITION = 3
|
||||
} vp8e_token_partitions;
|
||||
|
||||
/*!brief VP9 encoder content type */
|
||||
typedef enum {
|
||||
VP9E_CONTENT_DEFAULT,
|
||||
VP9E_CONTENT_SCREEN,
|
||||
VP9E_CONTENT_INVALID
|
||||
} vp9e_tune_content;
|
||||
|
||||
/*!\brief VP8 model tuning parameters
|
||||
*
|
||||
* Changes the encoder to tune for certain types of input material.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
VP8_TUNE_PSNR,
|
||||
VP8_TUNE_SSIM
|
||||
} vp8e_tuning;
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief vp9 svc layer parameters
|
||||
*
|
||||
* This defines the spatial and temporal layer id numbers for svc encoding.
|
||||
* This is used with the #VP9E_SET_SVC_LAYER_ID control to set the spatial and
|
||||
* temporal layer id for the current frame.
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_svc_layer_id {
|
||||
int spatial_layer_id; /**< Spatial layer id number. */
|
||||
int temporal_layer_id; /**< Temporal layer id number. */
|
||||
} vpx_svc_layer_id_t;
|
||||
#else
|
||||
/*!\brief vp9 svc layer parameters
|
||||
*
|
||||
* This defines the temporal layer id numbers for svc encoding.
|
||||
* This is used with the #VP9E_SET_SVC_LAYER_ID control to set the
|
||||
* temporal layer id for the current frame.
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_svc_layer_id {
|
||||
int temporal_layer_id; /**< Temporal layer id number. */
|
||||
} vpx_svc_layer_id_t;
|
||||
#endif
|
||||
|
||||
/*!\brief VP8 encoder control function parameter type
|
||||
*
|
||||
* Defines the data types that VP8E control functions take. Note that
|
||||
* additional common controls are defined in vp8.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* These controls have been deprecated in favor of the flags parameter to
|
||||
* vpx_codec_encode(). See the definition of VP8_EFLAG_* above.
|
||||
*/
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_ENTROPY, int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_REFERENCE, int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_USE_REFERENCE, int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_FRAME_FLAGS, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TEMPORAL_LAYER_ID, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int)
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, void *)
|
||||
VPX_CTRL_USE_TYPE(VP9E_REGISTER_CX_CALLBACK, void *)
|
||||
#endif
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SHARPNESS, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_STATIC_THRESHOLD, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TOKEN_PARTITIONS, int) /* vp8e_token_partitions */
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH, unsigned int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_ARNR_TYPE, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, int) /* vp8e_tuning */
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TILE_COLUMNS, int)
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TILE_ROWS, int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *)
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
VPX_CTRL_USE_TYPE(VP9E_GET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
|
||||
#endif
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTER_BITRATE_PCT, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SCREEN_CONTENT_MODE, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_GF_CBR_BOOST_PCT, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_LOSSLESS, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PARALLEL_DECODING, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_AQ_MODE, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PERIODIC_BOOST, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_NOISE_SENSITIVITY, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TUNE_CONTENT, int) /* vp9e_tune_content */
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_SPACE, int)
|
||||
/*! @} - end defgroup vp8_encoder */
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8CX_H_
|
||||
159
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8dx.h
Normal file
159
local_pod_repo/toxcore/ios/vpx.framework/Headers/vp8dx.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\defgroup vp8_decoder WebM VP8/VP9 Decoder
|
||||
* \ingroup vp8
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/*!\file
|
||||
* \brief Provides definitions for using VP8 or VP9 within the vpx Decoder
|
||||
* interface.
|
||||
*/
|
||||
#ifndef VPX_VP8DX_H_
|
||||
#define VPX_VP8DX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Include controls common to both the encoder and decoder */
|
||||
#include "./vp8.h"
|
||||
|
||||
/*!\name Algorithm interface for VP8
|
||||
*
|
||||
* This interface provides the capability to decode VP8 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp8_dx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp8_dx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
/*!\name Algorithm interface for VP9
|
||||
*
|
||||
* This interface provides the capability to decode VP9 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp9_dx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp9_dx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
|
||||
/*!\enum vp8_dec_control_id
|
||||
* \brief VP8 decoder control functions
|
||||
*
|
||||
* This set of macros define the control functions available for the VP8
|
||||
* decoder interface.
|
||||
*
|
||||
* \sa #vpx_codec_control
|
||||
*/
|
||||
enum vp8_dec_control_id {
|
||||
/** control function to get info on which reference frames were updated
|
||||
* by the last decode
|
||||
*/
|
||||
VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START,
|
||||
|
||||
/** check if the indicated frame is corrupted */
|
||||
VP8D_GET_FRAME_CORRUPTED,
|
||||
|
||||
/** control function to get info on which reference frames were used
|
||||
* by the last decode
|
||||
*/
|
||||
VP8D_GET_LAST_REF_USED,
|
||||
|
||||
/** decryption function to decrypt encoded buffer data immediately
|
||||
* before decoding. Takes a vpx_decrypt_init, which contains
|
||||
* a callback function and opaque context pointer.
|
||||
*/
|
||||
VPXD_SET_DECRYPTOR,
|
||||
VP8D_SET_DECRYPTOR = VPXD_SET_DECRYPTOR,
|
||||
|
||||
/** control function to get the dimensions that the current frame is decoded
|
||||
* at. This may be different to the intended display size for the frame as
|
||||
* specified in the wrapper or frame header (see VP9D_GET_DISPLAY_SIZE). */
|
||||
VP9D_GET_FRAME_SIZE,
|
||||
|
||||
/** control function to get the current frame's intended display dimensions
|
||||
* (as specified in the wrapper or frame header). This may be different to
|
||||
* the decoded dimensions of this frame (see VP9D_GET_FRAME_SIZE). */
|
||||
VP9D_GET_DISPLAY_SIZE,
|
||||
|
||||
/** control function to get the bit depth of the stream. */
|
||||
VP9D_GET_BIT_DEPTH,
|
||||
|
||||
/** control function to set the byte alignment of the planes in the reference
|
||||
* buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets
|
||||
* legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly
|
||||
* follows Y plane, and V plane directly follows U plane. Default value is 0.
|
||||
*/
|
||||
VP9_SET_BYTE_ALIGNMENT,
|
||||
|
||||
/** control function to invert the decoding order to from right to left. The
|
||||
* function is used in a test to confirm the decoding independence of tile
|
||||
* columns. The function may be used in application where this order
|
||||
* of decoding is desired.
|
||||
*
|
||||
* TODO(yaowu): Rework the unit test that uses this control, and in a future
|
||||
* release, this test-only control shall be removed.
|
||||
*/
|
||||
VP9_INVERT_TILE_DECODE_ORDER,
|
||||
|
||||
VP8_DECODER_CTRL_ID_MAX
|
||||
};
|
||||
|
||||
/** Decrypt n bytes of data from input -> output, using the decrypt_state
|
||||
* passed in VPXD_SET_DECRYPTOR.
|
||||
*/
|
||||
typedef void (*vpx_decrypt_cb)(void *decrypt_state, const unsigned char *input,
|
||||
unsigned char *output, int count);
|
||||
|
||||
/*!\brief Structure to hold decryption state
|
||||
*
|
||||
* Defines a structure to hold the decryption state and access function.
|
||||
*/
|
||||
typedef struct vpx_decrypt_init {
|
||||
/*! Decrypt callback. */
|
||||
vpx_decrypt_cb decrypt_cb;
|
||||
|
||||
/*! Decryption state. */
|
||||
void *decrypt_state;
|
||||
} vpx_decrypt_init;
|
||||
|
||||
/*!\brief A deprecated alias for vpx_decrypt_init.
|
||||
*/
|
||||
typedef vpx_decrypt_init vp8_decrypt_init;
|
||||
|
||||
|
||||
/*!\brief VP8 decoder control function parameter type
|
||||
*
|
||||
* Defines the data types that VP8D control functions take. Note that
|
||||
* additional common controls are defined in vp8.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *)
|
||||
VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR, vpx_decrypt_init *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR, vpx_decrypt_init *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE, int *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_BIT_DEPTH, unsigned int *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_FRAME_SIZE, int *)
|
||||
VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int)
|
||||
|
||||
/*! @} - end defgroup vp8_decoder */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8DX_H_
|
||||
479
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_codec.h
Normal file
479
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_codec.h
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\defgroup codec Common Algorithm Interface
|
||||
* This abstraction allows applications to easily support multiple video
|
||||
* formats with minimal code duplication. This section describes the interface
|
||||
* common to all codecs (both encoders and decoders).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the codec algorithm interface to applications.
|
||||
*
|
||||
* This file describes the interface between an application and a
|
||||
* video codec algorithm.
|
||||
*
|
||||
* An application instantiates a specific codec instance by using
|
||||
* vpx_codec_init() and a pointer to the algorithm's interface structure:
|
||||
* <pre>
|
||||
* my_app.c:
|
||||
* extern vpx_codec_iface_t my_codec;
|
||||
* {
|
||||
* vpx_codec_ctx_t algo;
|
||||
* res = vpx_codec_init(&algo, &my_codec);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Once initialized, the instance is manged using other functions from
|
||||
* the vpx_codec_* family.
|
||||
*/
|
||||
#ifndef VPX_VPX_CODEC_H_
|
||||
#define VPX_VPX_CODEC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_integer.h"
|
||||
#include "./vpx_image.h"
|
||||
|
||||
/*!\brief Decorator indicating a function is deprecated */
|
||||
#ifndef DEPRECATED
|
||||
#if defined(__GNUC__) && __GNUC__
|
||||
#define DEPRECATED __attribute__ ((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DEPRECATED
|
||||
#else
|
||||
#define DEPRECATED
|
||||
#endif
|
||||
#endif /* DEPRECATED */
|
||||
|
||||
#ifndef DECLSPEC_DEPRECATED
|
||||
#if defined(__GNUC__) && __GNUC__
|
||||
#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */
|
||||
#elif defined(_MSC_VER)
|
||||
#define DECLSPEC_DEPRECATED __declspec(deprecated) /**< \copydoc #DEPRECATED */
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */
|
||||
#endif
|
||||
#endif /* DECLSPEC_DEPRECATED */
|
||||
|
||||
/*!\brief Decorator indicating a function is potentially unused */
|
||||
#ifdef UNUSED
|
||||
#elif __GNUC__
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_CODEC_ABI_VERSION (3 + VPX_IMAGE_ABI_VERSION) /**<\hideinitializer*/
|
||||
|
||||
/*!\brief Algorithm return codes */
|
||||
typedef enum {
|
||||
/*!\brief Operation completed without error */
|
||||
VPX_CODEC_OK,
|
||||
|
||||
/*!\brief Unspecified error */
|
||||
VPX_CODEC_ERROR,
|
||||
|
||||
/*!\brief Memory operation failed */
|
||||
VPX_CODEC_MEM_ERROR,
|
||||
|
||||
/*!\brief ABI version mismatch */
|
||||
VPX_CODEC_ABI_MISMATCH,
|
||||
|
||||
/*!\brief Algorithm does not have required capability */
|
||||
VPX_CODEC_INCAPABLE,
|
||||
|
||||
/*!\brief The given bitstream is not supported.
|
||||
*
|
||||
* The bitstream was unable to be parsed at the highest level. The decoder
|
||||
* is unable to proceed. This error \ref SHOULD be treated as fatal to the
|
||||
* stream. */
|
||||
VPX_CODEC_UNSUP_BITSTREAM,
|
||||
|
||||
/*!\brief Encoded bitstream uses an unsupported feature
|
||||
*
|
||||
* The decoder does not implement a feature required by the encoder. This
|
||||
* return code should only be used for features that prevent future
|
||||
* pictures from being properly decoded. This error \ref MAY be treated as
|
||||
* fatal to the stream or \ref MAY be treated as fatal to the current GOP.
|
||||
*/
|
||||
VPX_CODEC_UNSUP_FEATURE,
|
||||
|
||||
/*!\brief The coded data for this stream is corrupt or incomplete
|
||||
*
|
||||
* There was a problem decoding the current frame. This return code
|
||||
* should only be used for failures that prevent future pictures from
|
||||
* being properly decoded. This error \ref MAY be treated as fatal to the
|
||||
* stream or \ref MAY be treated as fatal to the current GOP. If decoding
|
||||
* is continued for the current GOP, artifacts may be present.
|
||||
*/
|
||||
VPX_CODEC_CORRUPT_FRAME,
|
||||
|
||||
/*!\brief An application-supplied parameter is not valid.
|
||||
*
|
||||
*/
|
||||
VPX_CODEC_INVALID_PARAM,
|
||||
|
||||
/*!\brief An iterator reached the end of list.
|
||||
*
|
||||
*/
|
||||
VPX_CODEC_LIST_END
|
||||
|
||||
}
|
||||
vpx_codec_err_t;
|
||||
|
||||
|
||||
/*! \brief Codec capabilities bitfield
|
||||
*
|
||||
* Each codec advertises the capabilities it supports as part of its
|
||||
* ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces
|
||||
* or functionality, and are not required to be supported.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_CAP_* defines.
|
||||
*/
|
||||
typedef long vpx_codec_caps_t;
|
||||
#define VPX_CODEC_CAP_DECODER 0x1 /**< Is a decoder */
|
||||
#define VPX_CODEC_CAP_ENCODER 0x2 /**< Is an encoder */
|
||||
|
||||
|
||||
/*! \brief Initialization-time Feature Enabling
|
||||
*
|
||||
* Certain codec features must be known at initialization time, to allow for
|
||||
* proper memory allocation.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_USE_* defines.
|
||||
*/
|
||||
typedef long vpx_codec_flags_t;
|
||||
|
||||
|
||||
/*!\brief Codec interface structure.
|
||||
*
|
||||
* Contains function pointers and other data private to the codec
|
||||
* implementation. This structure is opaque to the application.
|
||||
*/
|
||||
typedef const struct vpx_codec_iface vpx_codec_iface_t;
|
||||
|
||||
|
||||
/*!\brief Codec private data structure.
|
||||
*
|
||||
* Contains data private to the codec implementation. This structure is opaque
|
||||
* to the application.
|
||||
*/
|
||||
typedef struct vpx_codec_priv vpx_codec_priv_t;
|
||||
|
||||
|
||||
/*!\brief Iterator
|
||||
*
|
||||
* Opaque storage used for iterating over lists.
|
||||
*/
|
||||
typedef const void *vpx_codec_iter_t;
|
||||
|
||||
|
||||
/*!\brief Codec context structure
|
||||
*
|
||||
* All codecs \ref MUST support this context structure fully. In general,
|
||||
* this data should be considered private to the codec algorithm, and
|
||||
* not be manipulated or examined by the calling application. Applications
|
||||
* may reference the 'name' member to get a printable description of the
|
||||
* algorithm.
|
||||
*/
|
||||
typedef struct vpx_codec_ctx {
|
||||
const char *name; /**< Printable interface name */
|
||||
vpx_codec_iface_t *iface; /**< Interface pointers */
|
||||
vpx_codec_err_t err; /**< Last returned error */
|
||||
const char *err_detail; /**< Detailed info, if available */
|
||||
vpx_codec_flags_t init_flags; /**< Flags passed at init time */
|
||||
union {
|
||||
/**< Decoder Configuration Pointer */
|
||||
const struct vpx_codec_dec_cfg *dec;
|
||||
/**< Encoder Configuration Pointer */
|
||||
const struct vpx_codec_enc_cfg *enc;
|
||||
const void *raw;
|
||||
} config; /**< Configuration pointer aliasing union */
|
||||
vpx_codec_priv_t *priv; /**< Algorithm private storage */
|
||||
} vpx_codec_ctx_t;
|
||||
|
||||
/*!\brief Bit depth for codec
|
||||
* *
|
||||
* This enumeration determines the bit depth of the codec.
|
||||
*/
|
||||
typedef enum vpx_bit_depth {
|
||||
VPX_BITS_8 = 8, /**< 8 bits */
|
||||
VPX_BITS_10 = 10, /**< 10 bits */
|
||||
VPX_BITS_12 = 12, /**< 12 bits */
|
||||
} vpx_bit_depth_t;
|
||||
|
||||
/*
|
||||
* Library Version Number Interface
|
||||
*
|
||||
* For example, see the following sample return values:
|
||||
* vpx_codec_version() (1<<16 | 2<<8 | 3)
|
||||
* vpx_codec_version_str() "v1.2.3-rc1-16-gec6a1ba"
|
||||
* vpx_codec_version_extra_str() "rc1-16-gec6a1ba"
|
||||
*/
|
||||
|
||||
/*!\brief Return the version information (as an integer)
|
||||
*
|
||||
* Returns a packed encoding of the library version number. This will only include
|
||||
* the major.minor.patch component of the version number. Note that this encoded
|
||||
* value should be accessed through the macros provided, as the encoding may change
|
||||
* in the future.
|
||||
*
|
||||
*/
|
||||
int vpx_codec_version(void);
|
||||
#define VPX_VERSION_MAJOR(v) ((v>>16)&0xff) /**< extract major from packed version */
|
||||
#define VPX_VERSION_MINOR(v) ((v>>8)&0xff) /**< extract minor from packed version */
|
||||
#define VPX_VERSION_PATCH(v) ((v>>0)&0xff) /**< extract patch from packed version */
|
||||
|
||||
/*!\brief Return the version major number */
|
||||
#define vpx_codec_version_major() ((vpx_codec_version()>>16)&0xff)
|
||||
|
||||
/*!\brief Return the version minor number */
|
||||
#define vpx_codec_version_minor() ((vpx_codec_version()>>8)&0xff)
|
||||
|
||||
/*!\brief Return the version patch number */
|
||||
#define vpx_codec_version_patch() ((vpx_codec_version()>>0)&0xff)
|
||||
|
||||
|
||||
/*!\brief Return the version information (as a string)
|
||||
*
|
||||
* Returns a printable string containing the full library version number. This may
|
||||
* contain additional text following the three digit version number, as to indicate
|
||||
* release candidates, prerelease versions, etc.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_version_str(void);
|
||||
|
||||
|
||||
/*!\brief Return the version information (as a string)
|
||||
*
|
||||
* Returns a printable "extra string". This is the component of the string returned
|
||||
* by vpx_codec_version_str() following the three digit version number.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_version_extra_str(void);
|
||||
|
||||
|
||||
/*!\brief Return the build configuration
|
||||
*
|
||||
* Returns a printable string containing an encoded version of the build
|
||||
* configuration. This may be useful to vpx support.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_build_config(void);
|
||||
|
||||
|
||||
/*!\brief Return the name for a given interface
|
||||
*
|
||||
* Returns a human readable string for name of the given codec interface.
|
||||
*
|
||||
* \param[in] iface Interface pointer
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_iface_name(vpx_codec_iface_t *iface);
|
||||
|
||||
|
||||
/*!\brief Convert error number to printable string
|
||||
*
|
||||
* Returns a human readable string for the last error returned by the
|
||||
* algorithm. The returned error will be one line and will not contain
|
||||
* any newline characters.
|
||||
*
|
||||
*
|
||||
* \param[in] err Error number.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_err_to_string(vpx_codec_err_t err);
|
||||
|
||||
|
||||
/*!\brief Retrieve error synopsis for codec context
|
||||
*
|
||||
* Returns a human readable string for the last error returned by the
|
||||
* algorithm. The returned error will be one line and will not contain
|
||||
* any newline characters.
|
||||
*
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_error(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/*!\brief Retrieve detailed error information for codec context
|
||||
*
|
||||
* Returns a human readable string providing detailed information about
|
||||
* the last error.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
*
|
||||
* \retval NULL
|
||||
* No detailed information is available.
|
||||
*/
|
||||
const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/* REQUIRED FUNCTIONS
|
||||
*
|
||||
* The following functions are required to be implemented for all codecs.
|
||||
* They represent the base case functionality expected of all codecs.
|
||||
*/
|
||||
|
||||
/*!\brief Destroy a codec instance
|
||||
*
|
||||
* Destroys a codec context, freeing any associated memory buffers.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The codec algorithm initialized.
|
||||
* \retval #VPX_CODEC_MEM_ERROR
|
||||
* Memory allocation failed.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/*!\brief Get the capabilities of an algorithm.
|
||||
*
|
||||
* Retrieves the capabilities bitfield from the algorithm's interface.
|
||||
*
|
||||
* \param[in] iface Pointer to the algorithm interface
|
||||
*
|
||||
*/
|
||||
vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface);
|
||||
|
||||
|
||||
/*!\brief Control algorithm
|
||||
*
|
||||
* This function is used to exchange algorithm specific data with the codec
|
||||
* instance. This can be used to implement features specific to a particular
|
||||
* algorithm.
|
||||
*
|
||||
* This wrapper function dispatches the request to the helper function
|
||||
* associated with the given ctrl_id. It tries to call this function
|
||||
* transparently, but will return #VPX_CODEC_ERROR if the request could not
|
||||
* be dispatched.
|
||||
*
|
||||
* Note that this function should not be used directly. Call the
|
||||
* #vpx_codec_control wrapper macro instead.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] ctrl_id Algorithm specific control identifier
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The control request was processed.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* The control request was not processed.
|
||||
* \retval #VPX_CODEC_INVALID_PARAM
|
||||
* The data was not valid.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx,
|
||||
int ctrl_id,
|
||||
...);
|
||||
#if defined(VPX_DISABLE_CTRL_TYPECHECKS) && VPX_DISABLE_CTRL_TYPECHECKS
|
||||
# define vpx_codec_control(ctx,id,data) vpx_codec_control_(ctx,id,data)
|
||||
# define VPX_CTRL_USE_TYPE(id, typ)
|
||||
# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ)
|
||||
# define VPX_CTRL_VOID(id, typ)
|
||||
|
||||
#else
|
||||
/*!\brief vpx_codec_control wrapper macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_().
|
||||
*
|
||||
* \internal
|
||||
* It works by dispatching the call to the control function through a wrapper
|
||||
* function named with the id parameter.
|
||||
*/
|
||||
# define vpx_codec_control(ctx,id,data) vpx_codec_control_##id(ctx,id,data)\
|
||||
/**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control type definition macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_(). It defines the type of the argument for a given
|
||||
* control identifier.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function with
|
||||
* the correctly typed arguments as a wrapper to the type-unsafe internal
|
||||
* function.
|
||||
*/
|
||||
# define VPX_CTRL_USE_TYPE(id, typ) \
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) UNUSED;\
|
||||
\
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id, data);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control deprecated type definition macro
|
||||
*
|
||||
* Like #VPX_CTRL_USE_TYPE, but indicates that the specified control is
|
||||
* deprecated and should not be used. Consult the documentation for your
|
||||
* codec for more information.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function with the correctly typed arguments as a
|
||||
* wrapper to the type-unsafe internal function.
|
||||
*/
|
||||
# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \
|
||||
DECLSPEC_DEPRECATED static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) DEPRECATED UNUSED;\
|
||||
\
|
||||
DECLSPEC_DEPRECATED static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id, data);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control void type definition macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_(). It indicates that a given control identifier takes
|
||||
* no argument.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function without a data argument as a wrapper to the
|
||||
* type-unsafe internal function.
|
||||
*/
|
||||
# define VPX_CTRL_VOID(id) \
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int) UNUSED;\
|
||||
\
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*!@} - end defgroup codec*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // VPX_VPX_CODEC_H_
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* GENERATED FILE: DO NOT EDIT! */
|
||||
|
||||
#ifndef VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
#define VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
|
||||
#if defined __aarch64__
|
||||
#define VPX_FRAMEWORK_TARGET "arm64-darwin-gcc"
|
||||
#include "vpx/vpx/arm64-darwin-gcc/vpx_config.h"
|
||||
#elif defined __ARM_ARCH_7A__
|
||||
#define VPX_FRAMEWORK_TARGET "armv7-darwin-gcc"
|
||||
#include "vpx/vpx/armv7-darwin-gcc/vpx_config.h"
|
||||
#elif defined __ARM_ARCH_7S__
|
||||
#define VPX_FRAMEWORK_TARGET "armv7s-darwin-gcc"
|
||||
#include "vpx/vpx/armv7s-darwin-gcc/vpx_config.h"
|
||||
#elif defined __i386__
|
||||
#define VPX_FRAMEWORK_TARGET "x86-iphonesimulator-gcc"
|
||||
#include "vpx/vpx/x86-iphonesimulator-gcc/vpx_config.h"
|
||||
#elif defined __x86_64__
|
||||
#define VPX_FRAMEWORK_TARGET "x86_64-iphonesimulator-gcc"
|
||||
#include "vpx/vpx/x86_64-iphonesimulator-gcc/vpx_config.h"
|
||||
#endif
|
||||
|
||||
#endif // VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
378
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_decoder.h
Normal file
378
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_decoder.h
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef VPX_VPX_DECODER_H_
|
||||
#define VPX_VPX_DECODER_H_
|
||||
|
||||
/*!\defgroup decoder Decoder Algorithm Interface
|
||||
* \ingroup codec
|
||||
* This abstraction allows applications using this decoder to easily support
|
||||
* multiple video formats with minimal code duplication. This section describes
|
||||
* the interface common to all decoders.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the decoder algorithm interface to applications.
|
||||
*
|
||||
* This file describes the interface between an application and a
|
||||
* video decoder algorithm.
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_codec.h"
|
||||
#include "./vpx_frame_buffer.h"
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_DECODER_ABI_VERSION (3 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
|
||||
|
||||
/*! \brief Decoder capabilities bitfield
|
||||
*
|
||||
* Each decoder advertises the capabilities it supports as part of its
|
||||
* ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces
|
||||
* or functionality, and are not required to be supported by a decoder.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_CAP_* defines.
|
||||
*/
|
||||
#define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */
|
||||
#define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */
|
||||
#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */
|
||||
#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to
|
||||
packet loss */
|
||||
#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /**< Can receive encoded frames
|
||||
one fragment at a time */
|
||||
|
||||
/*! \brief Initialization-time Feature Enabling
|
||||
*
|
||||
* Certain codec features must be known at initialization time, to allow for
|
||||
* proper memory allocation.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_USE_* defines.
|
||||
*/
|
||||
#define VPX_CODEC_CAP_FRAME_THREADING 0x200000 /**< Can support frame-based
|
||||
multi-threading */
|
||||
#define VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x400000 /**< Can support external
|
||||
frame buffers */
|
||||
|
||||
#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */
|
||||
#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded
|
||||
frames */
|
||||
#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 /**< The input frame should be
|
||||
passed to the decoder one
|
||||
fragment at a time */
|
||||
#define VPX_CODEC_USE_FRAME_THREADING 0x80000 /**< Enable frame-based
|
||||
multi-threading */
|
||||
|
||||
/*!\brief Stream properties
|
||||
*
|
||||
* This structure is used to query or set properties of the decoded
|
||||
* stream. Algorithms may extend this structure with data specific
|
||||
* to their bitstream by setting the sz member appropriately.
|
||||
*/
|
||||
typedef struct vpx_codec_stream_info {
|
||||
unsigned int sz; /**< Size of this structure */
|
||||
unsigned int w; /**< Width (or 0 for unknown/default) */
|
||||
unsigned int h; /**< Height (or 0 for unknown/default) */
|
||||
unsigned int is_kf; /**< Current frame is a keyframe */
|
||||
} vpx_codec_stream_info_t;
|
||||
|
||||
/* REQUIRED FUNCTIONS
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders.
|
||||
* They represent the base case functionality expected of all decoders.
|
||||
*/
|
||||
|
||||
|
||||
/*!\brief Initialization Configurations
|
||||
*
|
||||
* This structure is used to pass init time configuration options to the
|
||||
* decoder.
|
||||
*/
|
||||
typedef struct vpx_codec_dec_cfg {
|
||||
unsigned int threads; /**< Maximum number of threads to use, default 1 */
|
||||
unsigned int w; /**< Width */
|
||||
unsigned int h; /**< Height */
|
||||
} vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */
|
||||
|
||||
|
||||
/*!\brief Initialize a decoder instance
|
||||
*
|
||||
* Initializes a decoder context using the given interface. Applications
|
||||
* should call the vpx_codec_dec_init convenience macro instead of this
|
||||
* function directly, to ensure that the ABI version number parameter
|
||||
* is properly initialized.
|
||||
*
|
||||
* If the library was configured with --disable-multithread, this call
|
||||
* is not thread safe and should be guarded with a lock if being used
|
||||
* in a multithreaded context.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
* \param[in] iface Pointer to the algorithm interface to use.
|
||||
* \param[in] cfg Configuration to use, if known. May be NULL.
|
||||
* \param[in] flags Bitfield of VPX_CODEC_USE_* flags
|
||||
* \param[in] ver ABI version number. Must be set to
|
||||
* VPX_DECODER_ABI_VERSION
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The decoder algorithm initialized.
|
||||
* \retval #VPX_CODEC_MEM_ERROR
|
||||
* Memory allocation failed.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_iface_t *iface,
|
||||
const vpx_codec_dec_cfg_t *cfg,
|
||||
vpx_codec_flags_t flags,
|
||||
int ver);
|
||||
|
||||
/*!\brief Convenience macro for vpx_codec_dec_init_ver()
|
||||
*
|
||||
* Ensures the ABI version parameter is properly set.
|
||||
*/
|
||||
#define vpx_codec_dec_init(ctx, iface, cfg, flags) \
|
||||
vpx_codec_dec_init_ver(ctx, iface, cfg, flags, VPX_DECODER_ABI_VERSION)
|
||||
|
||||
|
||||
/*!\brief Parse stream info from a buffer
|
||||
*
|
||||
* Performs high level parsing of the bitstream. Construction of a decoder
|
||||
* context is not necessary. Can be used to determine if the bitstream is
|
||||
* of the proper format, and to extract information from the stream.
|
||||
*
|
||||
* \param[in] iface Pointer to the algorithm interface
|
||||
* \param[in] data Pointer to a block of data to parse
|
||||
* \param[in] data_sz Size of the data buffer
|
||||
* \param[in,out] si Pointer to stream info to update. The size member
|
||||
* \ref MUST be properly initialized, but \ref MAY be
|
||||
* clobbered by the algorithm. This parameter \ref MAY
|
||||
* be NULL.
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Bitstream is parsable and stream information updated
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface,
|
||||
const uint8_t *data,
|
||||
unsigned int data_sz,
|
||||
vpx_codec_stream_info_t *si);
|
||||
|
||||
|
||||
/*!\brief Return information about the current stream.
|
||||
*
|
||||
* Returns information about the stream that has been parsed during decoding.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in,out] si Pointer to stream info to update. The size member
|
||||
* \ref MUST be properly initialized, but \ref MAY be
|
||||
* clobbered by the algorithm. This parameter \ref MAY
|
||||
* be NULL.
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Bitstream is parsable and stream information updated
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_stream_info_t *si);
|
||||
|
||||
|
||||
/*!\brief Decode data
|
||||
*
|
||||
* Processes a buffer of coded data. If the processing results in a new
|
||||
* decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be
|
||||
* generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode
|
||||
* time stamp) order. Frames produced will always be in PTS (presentation
|
||||
* time stamp) order.
|
||||
* If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled,
|
||||
* data and data_sz can contain a fragment of the encoded frame. Fragment
|
||||
* \#n must contain at least partition \#n, but can also contain subsequent
|
||||
* partitions (\#n+1 - \#n+i), and if so, fragments \#n+1, .., \#n+i must
|
||||
* be empty. When no more data is available, this function should be called
|
||||
* with NULL as data and 0 as data_sz. The memory passed to this function
|
||||
* must be available until the frame has been decoded.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] data Pointer to this block of new coded data. If
|
||||
* NULL, a VPX_CODEC_CB_PUT_FRAME event is posted
|
||||
* for the previously decoded frame.
|
||||
* \param[in] data_sz Size of the coded data, in bytes.
|
||||
* \param[in] user_priv Application specific data to associate with
|
||||
* this frame.
|
||||
* \param[in] deadline Soft deadline the decoder should attempt to meet,
|
||||
* in us. Set to zero for unlimited.
|
||||
*
|
||||
* \return Returns #VPX_CODEC_OK if the coded data was processed completely
|
||||
* and future pictures can be decoded without error. Otherwise,
|
||||
* see the descriptions of the other error codes in ::vpx_codec_err_t
|
||||
* for recoverability capabilities.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
|
||||
const uint8_t *data,
|
||||
unsigned int data_sz,
|
||||
void *user_priv,
|
||||
long deadline);
|
||||
|
||||
|
||||
/*!\brief Decoded frames iterator
|
||||
*
|
||||
* Iterates over a list of the frames available for display. The iterator
|
||||
* storage should be initialized to NULL to start the iteration. Iteration is
|
||||
* complete when this function returns NULL.
|
||||
*
|
||||
* The list of available frames becomes valid upon completion of the
|
||||
* vpx_codec_decode call, and remains valid until the next call to vpx_codec_decode.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in,out] iter Iterator storage, initialized to NULL
|
||||
*
|
||||
* \return Returns a pointer to an image, if one is ready for display. Frames
|
||||
* produced will always be in PTS (presentation time stamp) order.
|
||||
*/
|
||||
vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_iter_t *iter);
|
||||
|
||||
|
||||
/*!\defgroup cap_put_frame Frame-Based Decoding Functions
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_PUT_FRAME capability. Calling these functions
|
||||
* for codecs that don't advertise this capability will result in an error
|
||||
* code being returned, usually VPX_CODEC_ERROR
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief put frame callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to notify the application of
|
||||
* the availability of decoded image data.
|
||||
*/
|
||||
typedef void (*vpx_codec_put_frame_cb_fn_t)(void *user_priv,
|
||||
const vpx_image_t *img);
|
||||
|
||||
|
||||
/*!\brief Register for notification of frame completion.
|
||||
*
|
||||
* Registers a given function to be called when a decoded frame is
|
||||
* available.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb Pointer to the callback function
|
||||
* \param[in] user_priv User's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Callback successfully registered.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* posting slice completion.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_put_frame_cb_fn_t cb,
|
||||
void *user_priv);
|
||||
|
||||
|
||||
/*!@} - end defgroup cap_put_frame */
|
||||
|
||||
/*!\defgroup cap_put_slice Slice-Based Decoding Functions
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_PUT_SLICE capability. Calling these functions
|
||||
* for codecs that don't advertise this capability will result in an error
|
||||
* code being returned, usually VPX_CODEC_ERROR
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief put slice callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to notify the application of
|
||||
* the availability of partially decoded image data. The
|
||||
*/
|
||||
typedef void (*vpx_codec_put_slice_cb_fn_t)(void *user_priv,
|
||||
const vpx_image_t *img,
|
||||
const vpx_image_rect_t *valid,
|
||||
const vpx_image_rect_t *update);
|
||||
|
||||
|
||||
/*!\brief Register for notification of slice completion.
|
||||
*
|
||||
* Registers a given function to be called when a decoded slice is
|
||||
* available.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb Pointer to the callback function
|
||||
* \param[in] user_priv User's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Callback successfully registered.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* posting slice completion.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_put_slice_cb_fn_t cb,
|
||||
void *user_priv);
|
||||
|
||||
|
||||
/*!@} - end defgroup cap_put_slice*/
|
||||
|
||||
/*!\defgroup cap_external_frame_buffer External Frame Buffer Functions
|
||||
*
|
||||
* The following section is required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER capability.
|
||||
* Calling this function for codecs that don't advertise this capability
|
||||
* will result in an error code being returned, usually VPX_CODEC_ERROR.
|
||||
*
|
||||
* \note
|
||||
* Currently this only works with VP9.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief Pass in external frame buffers for the decoder to use.
|
||||
*
|
||||
* Registers functions to be called when libvpx needs a frame buffer
|
||||
* to decode the current frame and a function to be called when libvpx does
|
||||
* not internally reference the frame buffer. This set function must
|
||||
* be called before the first call to decode or libvpx will assume the
|
||||
* default behavior of allocating frame buffers internally.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb_get Pointer to the get callback function
|
||||
* \param[in] cb_release Pointer to the release callback function
|
||||
* \param[in] cb_priv Callback's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* External frame buffers will be used by libvpx.
|
||||
* \retval #VPX_CODEC_INVALID_PARAM
|
||||
* One or more of the callbacks were NULL.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* using external frame buffers.
|
||||
*
|
||||
* \note
|
||||
* When decoding VP9, the application may be required to pass in at least
|
||||
* #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS external frame
|
||||
* buffers.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_set_frame_buffer_functions(
|
||||
vpx_codec_ctx_t *ctx,
|
||||
vpx_get_frame_buffer_cb_fn_t cb_get,
|
||||
vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv);
|
||||
|
||||
/*!@} - end defgroup cap_external_frame_buffer */
|
||||
|
||||
/*!@} - end defgroup decoder*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // VPX_VPX_DECODER_H_
|
||||
|
||||
1023
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_encoder.h
Normal file
1023
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_encoder.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VPX_FRAME_BUFFER_H_
|
||||
#define VPX_VPX_FRAME_BUFFER_H_
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the decoder external frame buffer interface.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_integer.h"
|
||||
|
||||
/*!\brief The maximum number of work buffers used by libvpx.
|
||||
* Support maximum 4 threads to decode video in parallel.
|
||||
* Each thread will use one work buffer.
|
||||
* TODO(hkuang): Add support to set number of worker threads dynamically.
|
||||
*/
|
||||
#define VPX_MAXIMUM_WORK_BUFFERS 8
|
||||
|
||||
/*!\brief The maximum number of reference buffers that a VP9 encoder may use.
|
||||
*/
|
||||
#define VP9_MAXIMUM_REF_BUFFERS 8
|
||||
|
||||
/*!\brief External frame buffer
|
||||
*
|
||||
* This structure holds allocated frame buffers used by the decoder.
|
||||
*/
|
||||
typedef struct vpx_codec_frame_buffer {
|
||||
uint8_t *data; /**< Pointer to the data buffer */
|
||||
size_t size; /**< Size of data in bytes */
|
||||
void *priv; /**< Frame's private data */
|
||||
} vpx_codec_frame_buffer_t;
|
||||
|
||||
/*!\brief get frame buffer callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to retrieve data for the frame
|
||||
* buffer in order for the decode call to complete. The callback must
|
||||
* allocate at least min_size in bytes and assign it to fb->data. The callback
|
||||
* must zero out all the data allocated. Then the callback must set fb->size
|
||||
* to the allocated size. The application does not need to align the allocated
|
||||
* data. The callback is triggered when the decoder needs a frame buffer to
|
||||
* decode a compressed image into. This function may be called more than once
|
||||
* for every call to vpx_codec_decode. The application may set fb->priv to
|
||||
* some data which will be passed back in the ximage and the release function
|
||||
* call. |fb| is guaranteed to not be NULL. On success the callback must
|
||||
* return 0. Any failure the callback must return a value less than 0.
|
||||
*
|
||||
* \param[in] priv Callback's private data
|
||||
* \param[in] new_size Size in bytes needed by the buffer
|
||||
* \param[in,out] fb Pointer to vpx_codec_frame_buffer_t
|
||||
*/
|
||||
typedef int (*vpx_get_frame_buffer_cb_fn_t)(
|
||||
void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
/*!\brief release frame buffer callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder when the frame buffer is not
|
||||
* referenced by any other buffers. |fb| is guaranteed to not be NULL. On
|
||||
* success the callback must return 0. Any failure the callback must return
|
||||
* a value less than 0.
|
||||
*
|
||||
* \param[in] priv Callback's private data
|
||||
* \param[in] fb Pointer to vpx_codec_frame_buffer_t
|
||||
*/
|
||||
typedef int (*vpx_release_frame_buffer_cb_fn_t)(
|
||||
void *priv, vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_FRAME_BUFFER_H_
|
||||
224
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_image.h
Normal file
224
local_pod_repo/toxcore/ios/vpx.framework/Headers/vpx_image.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the vpx image descriptor and associated operations
|
||||
*
|
||||
*/
|
||||
#ifndef VPX_VPX_IMAGE_H_
|
||||
#define VPX_VPX_IMAGE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_IMAGE_ABI_VERSION (3) /**<\hideinitializer*/
|
||||
|
||||
|
||||
#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */
|
||||
#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */
|
||||
#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel. */
|
||||
#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */
|
||||
|
||||
/*!\brief List of supported image formats */
|
||||
typedef enum vpx_img_fmt {
|
||||
VPX_IMG_FMT_NONE,
|
||||
VPX_IMG_FMT_RGB24, /**< 24 bit per pixel packed RGB */
|
||||
VPX_IMG_FMT_RGB32, /**< 32 bit per pixel packed 0RGB */
|
||||
VPX_IMG_FMT_RGB565, /**< 16 bit per pixel, 565 */
|
||||
VPX_IMG_FMT_RGB555, /**< 16 bit per pixel, 555 */
|
||||
VPX_IMG_FMT_UYVY, /**< UYVY packed YUV */
|
||||
VPX_IMG_FMT_YUY2, /**< YUYV packed YUV */
|
||||
VPX_IMG_FMT_YVYU, /**< YVYU packed YUV */
|
||||
VPX_IMG_FMT_BGR24, /**< 24 bit per pixel packed BGR */
|
||||
VPX_IMG_FMT_RGB32_LE, /**< 32 bit packed BGR0 */
|
||||
VPX_IMG_FMT_ARGB, /**< 32 bit packed ARGB, alpha=255 */
|
||||
VPX_IMG_FMT_ARGB_LE, /**< 32 bit packed BGRA, alpha=255 */
|
||||
VPX_IMG_FMT_RGB565_LE, /**< 16 bit per pixel, gggbbbbb rrrrrggg */
|
||||
VPX_IMG_FMT_RGB555_LE, /**< 16 bit per pixel, gggbbbbb 0rrrrrgg */
|
||||
VPX_IMG_FMT_YV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */
|
||||
VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2,
|
||||
VPX_IMG_FMT_VPXYV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 3, /** < planar 4:2:0 format with vpx color space */
|
||||
VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4,
|
||||
VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5,
|
||||
VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6,
|
||||
VPX_IMG_FMT_I440 = VPX_IMG_FMT_PLANAR | 7,
|
||||
VPX_IMG_FMT_444A = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 6,
|
||||
VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I44016 = VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH
|
||||
} vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */
|
||||
|
||||
/*!\brief List of supported color spaces */
|
||||
typedef enum vpx_color_space {
|
||||
VPX_CS_UNKNOWN = 0, /**< Unknown */
|
||||
VPX_CS_BT_601 = 1, /**< BT.601 */
|
||||
VPX_CS_BT_709 = 2, /**< BT.709 */
|
||||
VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */
|
||||
VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */
|
||||
VPX_CS_BT_2020 = 5, /**< BT.2020 */
|
||||
VPX_CS_RESERVED = 6, /**< Reserved */
|
||||
VPX_CS_SRGB = 7 /**< sRGB */
|
||||
} vpx_color_space_t; /**< alias for enum vpx_color_space */
|
||||
|
||||
/**\brief Image Descriptor */
|
||||
typedef struct vpx_image {
|
||||
vpx_img_fmt_t fmt; /**< Image Format */
|
||||
vpx_color_space_t cs; /**< Color Space */
|
||||
|
||||
/* Image storage dimensions */
|
||||
unsigned int w; /**< Stored image width */
|
||||
unsigned int h; /**< Stored image height */
|
||||
unsigned int bit_depth; /**< Stored image bit-depth */
|
||||
|
||||
/* Image display dimensions */
|
||||
unsigned int d_w; /**< Displayed image width */
|
||||
unsigned int d_h; /**< Displayed image height */
|
||||
|
||||
/* Chroma subsampling info */
|
||||
unsigned int x_chroma_shift; /**< subsampling order, X */
|
||||
unsigned int y_chroma_shift; /**< subsampling order, Y */
|
||||
|
||||
/* Image data pointers. */
|
||||
#define VPX_PLANE_PACKED 0 /**< To be used for all packed formats */
|
||||
#define VPX_PLANE_Y 0 /**< Y (Luminance) plane */
|
||||
#define VPX_PLANE_U 1 /**< U (Chroma) plane */
|
||||
#define VPX_PLANE_V 2 /**< V (Chroma) plane */
|
||||
#define VPX_PLANE_ALPHA 3 /**< A (Transparency) plane */
|
||||
unsigned char *planes[4]; /**< pointer to the top left pixel for each plane */
|
||||
int stride[4]; /**< stride between rows for each plane */
|
||||
|
||||
int bps; /**< bits per sample (for packed formats) */
|
||||
|
||||
/* The following member may be set by the application to associate data
|
||||
* with this image.
|
||||
*/
|
||||
void *user_priv; /**< may be set by the application to associate data
|
||||
* with this image. */
|
||||
|
||||
/* The following members should be treated as private. */
|
||||
unsigned char *img_data; /**< private */
|
||||
int img_data_owner; /**< private */
|
||||
int self_allocd; /**< private */
|
||||
|
||||
void *fb_priv; /**< Frame buffer data associated with the image. */
|
||||
} vpx_image_t; /**< alias for struct vpx_image */
|
||||
|
||||
/**\brief Representation of a rectangle on a surface */
|
||||
typedef struct vpx_image_rect {
|
||||
unsigned int x; /**< leftmost column */
|
||||
unsigned int y; /**< topmost row */
|
||||
unsigned int w; /**< width */
|
||||
unsigned int h; /**< height */
|
||||
} vpx_image_rect_t; /**< alias for struct vpx_image_rect */
|
||||
|
||||
/*!\brief Open a descriptor, allocating storage for the underlying image
|
||||
*
|
||||
* Returns a descriptor for storing an image of the given format. The
|
||||
* storage for the descriptor is allocated on the heap.
|
||||
*
|
||||
* \param[in] img Pointer to storage for descriptor. If this parameter
|
||||
* is NULL, the storage for the descriptor will be
|
||||
* allocated on the heap.
|
||||
* \param[in] fmt Format for the image
|
||||
* \param[in] d_w Width of the image
|
||||
* \param[in] d_h Height of the image
|
||||
* \param[in] align Alignment, in bytes, of the image buffer and
|
||||
* each row in the image(stride).
|
||||
*
|
||||
* \return Returns a pointer to the initialized image descriptor. If the img
|
||||
* parameter is non-null, the value of the img parameter will be
|
||||
* returned.
|
||||
*/
|
||||
vpx_image_t *vpx_img_alloc(vpx_image_t *img,
|
||||
vpx_img_fmt_t fmt,
|
||||
unsigned int d_w,
|
||||
unsigned int d_h,
|
||||
unsigned int align);
|
||||
|
||||
/*!\brief Open a descriptor, using existing storage for the underlying image
|
||||
*
|
||||
* Returns a descriptor for storing an image of the given format. The
|
||||
* storage for descriptor has been allocated elsewhere, and a descriptor is
|
||||
* desired to "wrap" that storage.
|
||||
*
|
||||
* \param[in] img Pointer to storage for descriptor. If this parameter
|
||||
* is NULL, the storage for the descriptor will be
|
||||
* allocated on the heap.
|
||||
* \param[in] fmt Format for the image
|
||||
* \param[in] d_w Width of the image
|
||||
* \param[in] d_h Height of the image
|
||||
* \param[in] align Alignment, in bytes, of each row in the image.
|
||||
* \param[in] img_data Storage to use for the image
|
||||
*
|
||||
* \return Returns a pointer to the initialized image descriptor. If the img
|
||||
* parameter is non-null, the value of the img parameter will be
|
||||
* returned.
|
||||
*/
|
||||
vpx_image_t *vpx_img_wrap(vpx_image_t *img,
|
||||
vpx_img_fmt_t fmt,
|
||||
unsigned int d_w,
|
||||
unsigned int d_h,
|
||||
unsigned int align,
|
||||
unsigned char *img_data);
|
||||
|
||||
|
||||
/*!\brief Set the rectangle identifying the displayed portion of the image
|
||||
*
|
||||
* Updates the displayed rectangle (aka viewport) on the image surface to
|
||||
* match the specified coordinates and size.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
* \param[in] x leftmost column
|
||||
* \param[in] y topmost row
|
||||
* \param[in] w width
|
||||
* \param[in] h height
|
||||
*
|
||||
* \return 0 if the requested rectangle is valid, nonzero otherwise.
|
||||
*/
|
||||
int vpx_img_set_rect(vpx_image_t *img,
|
||||
unsigned int x,
|
||||
unsigned int y,
|
||||
unsigned int w,
|
||||
unsigned int h);
|
||||
|
||||
|
||||
/*!\brief Flip the image vertically (top for bottom)
|
||||
*
|
||||
* Adjusts the image descriptor's pointers and strides to make the image
|
||||
* be referenced upside-down.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
*/
|
||||
void vpx_img_flip(vpx_image_t *img);
|
||||
|
||||
/*!\brief Close an image descriptor
|
||||
*
|
||||
* Frees all allocated storage associated with an image descriptor.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
*/
|
||||
void vpx_img_free(vpx_image_t *img);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_IMAGE_H_
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VPX_VPX_INTEGER_H_
|
||||
#define VPX_VPX_INTEGER_H_
|
||||
|
||||
/* get ptrdiff_t, size_t, wchar_t, NULL */
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define VPX_FORCE_INLINE __forceinline
|
||||
#define VPX_INLINE __inline
|
||||
#else
|
||||
#define VPX_FORCE_INLINE __inline__ __attribute__(always_inline)
|
||||
// TODO(jbb): Allow a way to force inline off for older compilers.
|
||||
#define VPX_INLINE inline
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600)) || defined(VPX_EMULATE_INTTYPES)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT32_MIN _I32_MIN
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT16_MIN _I16_MIN
|
||||
#endif
|
||||
|
||||
#ifndef _UINTPTR_T_DEFINED
|
||||
typedef size_t uintptr_t;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* Most platforms have the C99 standard integer types. */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# if !defined(__STDC_FORMAT_MACROS)
|
||||
# define __STDC_FORMAT_MACROS
|
||||
# endif
|
||||
# if !defined(__STDC_LIMIT_MACROS)
|
||||
# define __STDC_LIMIT_MACROS
|
||||
# endif
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
||||
|
||||
/* VS2010 defines stdint.h, but not inttypes.h */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#define PRId64 "I64d"
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_INTEGER_H_
|
||||
@@ -0,0 +1,7 @@
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 4
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_EXTRA ""
|
||||
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||
#define VERSION_STRING_NOSP "v1.4.0"
|
||||
#define VERSION_STRING " v1.4.0"
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 0
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 1
|
||||
#define ARCH_X86_64 0
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 0
|
||||
#define HAVE_NEON 0
|
||||
#define HAVE_NEON_ASM 0
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 1
|
||||
#define HAVE_SSE 1
|
||||
#define HAVE_SSE2 1
|
||||
#define HAVE_SSE3 1
|
||||
#define HAVE_SSSE3 1
|
||||
#define HAVE_SSE4_1 1
|
||||
#define HAVE_AVX 1
|
||||
#define HAVE_AVX2 1
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 1
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||
#define CONFIG_POSTPROC 1
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 1
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 0
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 0
|
||||
#define ARCH_X86_64 1
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 0
|
||||
#define HAVE_NEON 0
|
||||
#define HAVE_NEON_ASM 0
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 1
|
||||
#define HAVE_SSE 1
|
||||
#define HAVE_SSE2 1
|
||||
#define HAVE_SSE3 1
|
||||
#define HAVE_SSSE3 1
|
||||
#define HAVE_SSE4_1 1
|
||||
#define HAVE_AVX 1
|
||||
#define HAVE_AVX2 1
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 1
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||
#define CONFIG_POSTPROC 1
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 1
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
BIN
local_pod_repo/toxcore/ios/vpx.framework/vpx
Normal file
BIN
local_pod_repo/toxcore/ios/vpx.framework/vpx
Normal file
Binary file not shown.
162
local_pod_repo/toxcore/msgv3_addon.patch
Normal file
162
local_pod_repo/toxcore/msgv3_addon.patch
Normal file
@@ -0,0 +1,162 @@
|
||||
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
|
||||
index 93fbae88..29e215b1 100644
|
||||
--- a/toxcore/Messenger.c
|
||||
+++ b/toxcore/Messenger.c
|
||||
@@ -497,7 +497,7 @@ bool m_friend_exists(const Messenger *m, int32_t friendnumber)
|
||||
int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,
|
||||
uint32_t *message_id)
|
||||
{
|
||||
- if (type > MESSAGE_ACTION) {
|
||||
+ if (type > MESSAGE_HIGH_LEVEL_ACK) {
|
||||
LOGGER_WARNING(m->log, "message type %d is invalid", type);
|
||||
return -5;
|
||||
}
|
||||
@@ -2053,7 +2053,8 @@ static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t le
|
||||
}
|
||||
|
||||
case PACKET_ID_MESSAGE: // fall-through
|
||||
- case PACKET_ID_ACTION: {
|
||||
+ case PACKET_ID_ACTION:
|
||||
+ case PACKET_ID_HIGH_LEVEL_ACK: {
|
||||
if (data_length == 0) {
|
||||
break;
|
||||
}
|
||||
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
|
||||
index b1395e62..6d15b9a6 100644
|
||||
--- a/toxcore/Messenger.h
|
||||
+++ b/toxcore/Messenger.h
|
||||
@@ -29,8 +29,9 @@
|
||||
#define FRIEND_ADDRESS_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
|
||||
|
||||
typedef enum Message_Type {
|
||||
- MESSAGE_NORMAL,
|
||||
- MESSAGE_ACTION,
|
||||
+ MESSAGE_NORMAL = 0,
|
||||
+ MESSAGE_ACTION = 1,
|
||||
+ MESSAGE_HIGH_LEVEL_ACK = 2,
|
||||
} Message_Type;
|
||||
|
||||
typedef struct Messenger Messenger;
|
||||
diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c
|
||||
index f52282d02..4be4d8c69 100644
|
||||
--- a/toxcore/crypto_core.c
|
||||
+++ b/toxcore/crypto_core.c
|
||||
@@ -462,6 +462,11 @@ void random_nonce(const Random *rng, uint8_t *nonce)
|
||||
random_bytes(rng, nonce, crypto_box_NONCEBYTES);
|
||||
}
|
||||
|
||||
+void new_symmetric_key_implicit_random(uint8_t *key)
|
||||
+{
|
||||
+ randombytes(key, CRYPTO_SYMMETRIC_KEY_SIZE);
|
||||
+}
|
||||
+
|
||||
void new_symmetric_key(const Random *rng, uint8_t *key)
|
||||
{
|
||||
random_bytes(rng, key, CRYPTO_SYMMETRIC_KEY_SIZE);
|
||||
diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h
|
||||
index 0aaadeacf..5f525c747 100644
|
||||
--- a/toxcore/crypto_core.h
|
||||
+++ b/toxcore/crypto_core.h
|
||||
@@ -408,6 +408,15 @@ void increment_nonce(uint8_t *nonce);
|
||||
non_null()
|
||||
void increment_nonce_number(uint8_t *nonce, uint32_t increment);
|
||||
|
||||
+/**
|
||||
+ * @brief Fill a key @ref CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes.
|
||||
+ *
|
||||
+ * This does the same as `new_symmetric_key` but without giving the Random object implicitly.
|
||||
+ * It is as safe as `new_symmetric_key`.
|
||||
+ */
|
||||
+non_null()
|
||||
+void new_symmetric_key_implicit_random(uint8_t *key);
|
||||
+
|
||||
/**
|
||||
* @brief Fill a key @ref CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes.
|
||||
*/
|
||||
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h
|
||||
index dd4dfcc5..1ec62f0d 100644
|
||||
--- a/toxcore/net_crypto.h
|
||||
+++ b/toxcore/net_crypto.h
|
||||
@@ -55,6 +55,7 @@
|
||||
#define PACKET_ID_TYPING 51
|
||||
#define PACKET_ID_MESSAGE 64
|
||||
#define PACKET_ID_ACTION 65 // PACKET_ID_MESSAGE + MESSAGE_ACTION
|
||||
+#define PACKET_ID_HIGH_LEVEL_ACK 66 // MSG V3
|
||||
#define PACKET_ID_MSI 69 // Used by AV to setup calls and etc
|
||||
#define PACKET_ID_FILE_SENDREQUEST 80
|
||||
#define PACKET_ID_FILE_CONTROL 81
|
||||
diff --git a/toxcore/tox.c b/toxcore/tox.c
|
||||
index 7d24aa1b..1df6c4fd 100644
|
||||
--- a/toxcore/tox.c
|
||||
+++ b/toxcore/tox.c
|
||||
@@ -999,6 +999,17 @@ bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, Tox_Err_Set
|
||||
return false;
|
||||
}
|
||||
|
||||
+bool tox_messagev3_get_new_message_id(uint8_t *msg_id)
|
||||
+{
|
||||
+ if (msg_id == nullptr) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Tox keys are 32 bytes like TOX_MSGV3_MSGID_LENGTH. */
|
||||
+ new_symmetric_key_implicit_random(msg_id);
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
size_t tox_self_get_name_size(const Tox *tox)
|
||||
{
|
||||
assert(tox != nullptr);
|
||||
diff --git a/toxcore/tox.h b/toxcore/tox.h
|
||||
index 54ca2aff..79dbdf21 100644
|
||||
--- a/toxcore/tox.h
|
||||
+++ b/toxcore/tox.h
|
||||
@@ -296,6 +296,11 @@ uint32_t tox_max_friend_request_length(void);
|
||||
|
||||
uint32_t tox_max_message_length(void);
|
||||
|
||||
+#define TOX_MSGV3_MSGID_LENGTH 32
|
||||
+#define TOX_MSGV3_TIMESTAMP_LENGTH 4
|
||||
+#define TOX_MSGV3_GUARD 2
|
||||
+#define TOX_MSGV3_MAX_MESSAGE_LENGTH (TOX_MAX_MESSAGE_LENGTH - TOX_MSGV3_MSGID_LENGTH - TOX_MSGV3_TIMESTAMP_LENGTH - TOX_MSGV3_GUARD)
|
||||
+
|
||||
/**
|
||||
* @brief Maximum size of custom packets. TODO(iphydf): should be LENGTH?
|
||||
*
|
||||
@@ -381,13 +386,18 @@ typedef enum Tox_Message_Type {
|
||||
/**
|
||||
* Normal text message. Similar to PRIVMSG on IRC.
|
||||
*/
|
||||
- TOX_MESSAGE_TYPE_NORMAL,
|
||||
+ TOX_MESSAGE_TYPE_NORMAL = 0,
|
||||
|
||||
/**
|
||||
* A message describing an user action. This is similar to /me (CTCP ACTION)
|
||||
* on IRC.
|
||||
*/
|
||||
- TOX_MESSAGE_TYPE_ACTION,
|
||||
+ TOX_MESSAGE_TYPE_ACTION = 1,
|
||||
+
|
||||
+ /**
|
||||
+ * A high level ACK for MSG ID (MSG V3 functionality)
|
||||
+ */
|
||||
+ TOX_MESSAGE_TYPE_HIGH_LEVEL_ACK = 2,
|
||||
|
||||
} Tox_Message_Type;
|
||||
|
||||
@@ -1161,6 +1171,15 @@ size_t tox_self_get_name_size(const Tox *tox);
|
||||
*/
|
||||
void tox_self_get_name(const Tox *tox, uint8_t *name);
|
||||
|
||||
+/**
|
||||
+ * Write new message ID to a byte array.
|
||||
+ *
|
||||
+ * @param msg_id A valid memory location at least TOX_HASH_LENGTH bytes in size.
|
||||
+ *
|
||||
+ * @return true on success.
|
||||
+ */
|
||||
+bool tox_messagev3_get_new_message_id(uint8_t *msg_id);
|
||||
+
|
||||
/**
|
||||
* @brief Set the client's status message.
|
||||
*
|
||||
138
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8.h
Normal file
138
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*!\defgroup vp8 VP8
|
||||
* \ingroup codecs
|
||||
* VP8 is vpx's newest video compression algorithm that uses motion
|
||||
* compensated prediction, Discrete Cosine Transform (DCT) coding of the
|
||||
* prediction error signal and context dependent entropy coding techniques
|
||||
* based on arithmetic principles. It features:
|
||||
* - YUV 4:2:0 image format
|
||||
* - Macro-block based coding (16x16 luma plus two 8x8 chroma)
|
||||
* - 1/4 (1/8) pixel accuracy motion compensated prediction
|
||||
* - 4x4 DCT transform
|
||||
* - 128 level linear quantizer
|
||||
* - In loop deblocking filter
|
||||
* - Context-based entropy coding
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/*!\file
|
||||
* \brief Provides controls common to both the VP8 encoder and decoder.
|
||||
*/
|
||||
#ifndef VPX_VP8_H_
|
||||
#define VPX_VP8_H_
|
||||
|
||||
#include "./vpx_codec.h"
|
||||
#include "./vpx_image.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\brief Control functions
|
||||
*
|
||||
* The set of macros define the control functions of VP8 interface
|
||||
*/
|
||||
enum vp8_com_control_id {
|
||||
VP8_SET_REFERENCE = 1, /**< pass in an external frame into decoder to be used as reference frame */
|
||||
VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */
|
||||
VP8_SET_POSTPROC = 3, /**< set the decoder's post processing settings */
|
||||
VP8_SET_DBG_COLOR_REF_FRAME = 4, /**< set the reference frames to color for each macroblock */
|
||||
VP8_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */
|
||||
VP8_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */
|
||||
VP8_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */
|
||||
|
||||
/* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+)
|
||||
* for its control ids. These should be migrated to something like the
|
||||
* VP8_DECODER_CTRL_ID_START range next time we're ready to break the ABI.
|
||||
*/
|
||||
VP9_GET_REFERENCE = 128, /**< get a pointer to a reference frame */
|
||||
VP8_COMMON_CTRL_ID_MAX,
|
||||
VP8_DECODER_CTRL_ID_START = 256
|
||||
};
|
||||
|
||||
/*!\brief post process flags
|
||||
*
|
||||
* The set of macros define VP8 decoder post processing flags
|
||||
*/
|
||||
enum vp8_postproc_level {
|
||||
VP8_NOFILTERING = 0,
|
||||
VP8_DEBLOCK = 1 << 0,
|
||||
VP8_DEMACROBLOCK = 1 << 1,
|
||||
VP8_ADDNOISE = 1 << 2,
|
||||
VP8_DEBUG_TXT_FRAME_INFO = 1 << 3, /**< print frame information */
|
||||
VP8_DEBUG_TXT_MBLK_MODES = 1 << 4, /**< print macro block modes over each macro block */
|
||||
VP8_DEBUG_TXT_DC_DIFF = 1 << 5, /**< print dc diff for each macro block */
|
||||
VP8_DEBUG_TXT_RATE_INFO = 1 << 6, /**< print video rate info (encoder only) */
|
||||
VP8_MFQE = 1 << 10
|
||||
};
|
||||
|
||||
/*!\brief post process flags
|
||||
*
|
||||
* This define a structure that describe the post processing settings. For
|
||||
* the best objective measure (using the PSNR metric) set post_proc_flag
|
||||
* to VP8_DEBLOCK and deblocking_level to 1.
|
||||
*/
|
||||
|
||||
typedef struct vp8_postproc_cfg {
|
||||
int post_proc_flag; /**< the types of post processing to be done, should be combination of "vp8_postproc_level" */
|
||||
int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */
|
||||
int noise_level; /**< the strength of additive noise, valid range [0, 16] */
|
||||
} vp8_postproc_cfg_t;
|
||||
|
||||
/*!\brief reference frame type
|
||||
*
|
||||
* The set of macros define the type of VP8 reference frames
|
||||
*/
|
||||
typedef enum vpx_ref_frame_type {
|
||||
VP8_LAST_FRAME = 1,
|
||||
VP8_GOLD_FRAME = 2,
|
||||
VP8_ALTR_FRAME = 4
|
||||
} vpx_ref_frame_type_t;
|
||||
|
||||
/*!\brief reference frame data struct
|
||||
*
|
||||
* Define the data struct to access vp8 reference frames.
|
||||
*/
|
||||
typedef struct vpx_ref_frame {
|
||||
vpx_ref_frame_type_t frame_type; /**< which reference frame */
|
||||
vpx_image_t img; /**< reference frame data in image format */
|
||||
} vpx_ref_frame_t;
|
||||
|
||||
/*!\brief VP9 specific reference frame data struct
|
||||
*
|
||||
* Define the data struct to access vp9 reference frames.
|
||||
*/
|
||||
typedef struct vp9_ref_frame {
|
||||
int idx; /**< frame index to get (input) */
|
||||
vpx_image_t img; /**< img structure to populate (output) */
|
||||
} vp9_ref_frame_t;
|
||||
|
||||
/*!\brief vp8 decoder control function parameter type
|
||||
*
|
||||
* defines the data type for each of VP8 decoder control function requires
|
||||
*/
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_REF_FRAME, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_MB_MODES, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_B_MODES, int)
|
||||
VPX_CTRL_USE_TYPE(VP8_SET_DBG_DISPLAY_MV, int)
|
||||
VPX_CTRL_USE_TYPE(VP9_GET_REFERENCE, vp9_ref_frame_t *)
|
||||
|
||||
/*! @} - end defgroup vp8 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8_H_
|
||||
699
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8cx.h
Normal file
699
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8cx.h
Normal file
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef VPX_VP8CX_H_
|
||||
#define VPX_VP8CX_H_
|
||||
|
||||
/*!\defgroup vp8_encoder WebM VP8/VP9 Encoder
|
||||
* \ingroup vp8
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#include "./vp8.h"
|
||||
#include "./vpx_encoder.h"
|
||||
|
||||
/*!\file
|
||||
* \brief Provides definitions for using VP8 or VP9 encoder algorithm within the
|
||||
* vpx Codec Interface.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\name Algorithm interface for VP8
|
||||
*
|
||||
* This interface provides the capability to encode raw VP8 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp8_cx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp8_cx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
/*!\name Algorithm interface for VP9
|
||||
*
|
||||
* This interface provides the capability to encode raw VP9 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp9_cx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp9_cx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
|
||||
/*
|
||||
* Algorithm Flags
|
||||
*/
|
||||
|
||||
/*!\brief Don't reference the last frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the last frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* last frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_LAST (1<<16)
|
||||
|
||||
|
||||
/*!\brief Don't reference the golden frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the golden frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* golden frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_GF (1<<17)
|
||||
|
||||
|
||||
/*!\brief Don't reference the alternate reference frame
|
||||
*
|
||||
* When this flag is set, the encoder will not use the alt ref frame as a
|
||||
* predictor. When not set, the encoder will choose whether to use the
|
||||
* alt ref frame or not automatically.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_REF_ARF (1<<21)
|
||||
|
||||
|
||||
/*!\brief Don't update the last frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the last frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_LAST (1<<18)
|
||||
|
||||
|
||||
/*!\brief Don't update the golden frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the golden frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_GF (1<<22)
|
||||
|
||||
|
||||
/*!\brief Don't update the alternate reference frame
|
||||
*
|
||||
* When this flag is set, the encoder will not update the alt ref frame with
|
||||
* the contents of the current frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_ARF (1<<23)
|
||||
|
||||
|
||||
/*!\brief Force golden frame update
|
||||
*
|
||||
* When this flag is set, the encoder copy the contents of the current frame
|
||||
* to the golden frame buffer.
|
||||
*/
|
||||
#define VP8_EFLAG_FORCE_GF (1<<19)
|
||||
|
||||
|
||||
/*!\brief Force alternate reference frame update
|
||||
*
|
||||
* When this flag is set, the encoder copy the contents of the current frame
|
||||
* to the alternate reference frame buffer.
|
||||
*/
|
||||
#define VP8_EFLAG_FORCE_ARF (1<<24)
|
||||
|
||||
|
||||
/*!\brief Disable entropy update
|
||||
*
|
||||
* When this flag is set, the encoder will not update its internal entropy
|
||||
* model based on the entropy of this frame.
|
||||
*/
|
||||
#define VP8_EFLAG_NO_UPD_ENTROPY (1<<20)
|
||||
|
||||
|
||||
/*!\brief VPx encoder control functions
|
||||
*
|
||||
* This set of macros define the control functions available for VPx
|
||||
* encoder interface.
|
||||
*
|
||||
* \sa #vpx_codec_control
|
||||
*/
|
||||
enum vp8e_enc_control_id {
|
||||
/*!\brief Codec control function to set mode of entropy update in encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_UPD_ENTROPY = 5,
|
||||
|
||||
/*!\brief Codec control function to set reference update mode in encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_UPD_REFERENCE,
|
||||
|
||||
/*!\brief Codec control function to set which reference frame encoder can use.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_USE_REFERENCE,
|
||||
|
||||
/*!\brief Codec control function to pass an ROI map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ROI_MAP,
|
||||
|
||||
/*!\brief Codec control function to pass an Active map to encoder.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ACTIVEMAP,
|
||||
|
||||
/*!\brief Codec control function to set encoder scaling mode.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_SCALEMODE = 11,
|
||||
|
||||
/*!\brief Codec control function to set encoder internal speed settings.
|
||||
*
|
||||
* Changes in this value influences, among others, the encoder's selection
|
||||
* of motion estimation methods. Values greater than 0 will increase encoder
|
||||
* speed at the expense of quality.
|
||||
*
|
||||
* \note Valid range for VP8: -16..16
|
||||
* \note Valid range for VP9: -8..8
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_CPUUSED = 13,
|
||||
|
||||
/*!\brief Codec control function to enable automatic set and use alf frames.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ENABLEAUTOALTREF,
|
||||
|
||||
/*!\brief control function to set noise sensitivity
|
||||
*
|
||||
* 0: off, 1: OnYOnly, 2: OnYUV,
|
||||
* 3: OnYUVAggressive, 4: Adaptive
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_NOISE_SENSITIVITY,
|
||||
|
||||
/*!\brief Codec control function to set sharpness.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_SHARPNESS,
|
||||
|
||||
/*!\brief Codec control function to set the threshold for MBs treated static.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_STATIC_THRESHOLD,
|
||||
|
||||
/*!\brief Codec control function to set the number of token partitions.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_TOKEN_PARTITIONS,
|
||||
|
||||
/*!\brief Codec control function to get last quantizer chosen by the encoder.
|
||||
*
|
||||
* Return value uses internal quantizer scale defined by the codec.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_GET_LAST_QUANTIZER,
|
||||
|
||||
/*!\brief Codec control function to get last quantizer chosen by the encoder.
|
||||
*
|
||||
* Return value uses the 0..63 scale as used by the rc_*_quantizer config
|
||||
* parameters.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_GET_LAST_QUANTIZER_64,
|
||||
|
||||
/*!\brief Codec control function to set the max no of frames to create arf.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ARNR_MAXFRAMES,
|
||||
|
||||
/*!\brief Codec control function to set the filter strength for the arf.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_ARNR_STRENGTH,
|
||||
|
||||
/*!\deprecated control function to set the filter type to use for the arf. */
|
||||
VP8E_SET_ARNR_TYPE,
|
||||
|
||||
/*!\brief Codec control function to set visual tuning.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_TUNING,
|
||||
|
||||
/*!\brief Codec control function to set constrained quality level.
|
||||
*
|
||||
* \attention For this value to be used vpx_codec_enc_cfg_t::g_usage must be
|
||||
* set to #VPX_CQ.
|
||||
* \note Valid range: 0..63
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_CQ_LEVEL,
|
||||
|
||||
/*!\brief Codec control function to set Max data rate for Intra frames.
|
||||
*
|
||||
* This value controls additional clamping on the maximum size of a
|
||||
* keyframe. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* unlimited, or no additional clamping beyond the codec's built-in
|
||||
* algorithm.
|
||||
*
|
||||
* For example, to allocate no more than 4.5 frames worth of bitrate
|
||||
* to a keyframe, set this to 450.
|
||||
*
|
||||
* Supported in codecs: VP8, VP9
|
||||
*/
|
||||
VP8E_SET_MAX_INTRA_BITRATE_PCT,
|
||||
|
||||
/*!\brief Codec control function to set reference and update frame flags.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_FRAME_FLAGS,
|
||||
|
||||
/*!\brief Codec control function to set max data rate for Inter frames.
|
||||
*
|
||||
* This value controls additional clamping on the maximum size of an
|
||||
* inter frame. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* unlimited, or no additional clamping beyond the codec's built-in
|
||||
* algorithm.
|
||||
*
|
||||
* For example, to allow no more than 4.5 frames worth of bitrate
|
||||
* to an inter frame, set this to 450.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_MAX_INTER_BITRATE_PCT,
|
||||
|
||||
/*!\brief Boost percentage for Golden Frame in CBR mode.
|
||||
*
|
||||
* This value controls the amount of boost given to Golden Frame in
|
||||
* CBR mode. It is expressed as a percentage of the average
|
||||
* per-frame bitrate, with the special (and default) value 0 meaning
|
||||
* the feature is off, i.e., no golden frame boost in CBR mode and
|
||||
* average bitrate target is used.
|
||||
*
|
||||
* For example, to allow 100% more bits, i.e, 2X, in a golden frame
|
||||
* than average frame, set this to 100.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_GF_CBR_BOOST_PCT,
|
||||
|
||||
/*!\brief Codec control function to set the temporal layer id.
|
||||
*
|
||||
* For temporal scalability: this control allows the application to set the
|
||||
* layer id for each frame to be encoded. Note that this control must be set
|
||||
* for every frame prior to encoding. The usage of this control function
|
||||
* supersedes the internal temporal pattern counter, which is now deprecated.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_TEMPORAL_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to set encoder screen content mode.
|
||||
*
|
||||
* Supported in codecs: VP8
|
||||
*/
|
||||
VP8E_SET_SCREEN_CONTENT_MODE,
|
||||
|
||||
/*!\brief Codec control function to set lossless encoding mode.
|
||||
*
|
||||
* VP9 can operate in lossless encoding mode, in which the bitstream
|
||||
* produced will be able to decode and reconstruct a perfect copy of
|
||||
* input source. This control function provides a mean to switch encoder
|
||||
* into lossless coding mode(1) or normal coding mode(0) that may be lossy.
|
||||
* 0 = lossy coding mode
|
||||
* 1 = lossless coding mode
|
||||
*
|
||||
* By default, encoder operates in normal coding mode (maybe lossy).
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_LOSSLESS,
|
||||
|
||||
/*!\brief Codec control function to set number of tile columns.
|
||||
*
|
||||
* In encoding and decoding, VP9 allows an input image frame be partitioned
|
||||
* into separated vertical tile columns, which can be encoded or decoded
|
||||
* independently. This enables easy implementation of parallel encoding and
|
||||
* decoding. This control requests the encoder to use column tiles in
|
||||
* encoding an input frame, with number of tile columns (in Log2 unit) as
|
||||
* the parameter:
|
||||
* 0 = 1 tile column
|
||||
* 1 = 2 tile columns
|
||||
* 2 = 4 tile columns
|
||||
* .....
|
||||
* n = 2**n tile columns
|
||||
* The requested tile columns will be capped by encoder based on image size
|
||||
* limitation (The minimum width of a tile column is 256 pixel, the maximum
|
||||
* is 4096).
|
||||
*
|
||||
* By default, the value is 0, i.e. one single column tile for entire image.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TILE_COLUMNS,
|
||||
|
||||
/*!\brief Codec control function to set number of tile rows.
|
||||
*
|
||||
* In encoding and decoding, VP9 allows an input image frame be partitioned
|
||||
* into separated horizontal tile rows. Tile rows are encoded or decoded
|
||||
* sequentially. Even though encoding/decoding of later tile rows depends on
|
||||
* earlier ones, this allows the encoder to output data packets for tile rows
|
||||
* prior to completely processing all tile rows in a frame, thereby reducing
|
||||
* the latency in processing between input and output. The parameter
|
||||
* for this control describes the number of tile rows, which has a valid
|
||||
* range [0, 2]:
|
||||
* 0 = 1 tile row
|
||||
* 1 = 2 tile rows
|
||||
* 2 = 4 tile rows
|
||||
*
|
||||
* By default, the value is 0, i.e. one single row tile for entire image.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TILE_ROWS,
|
||||
|
||||
/*!\brief Codec control function to enable frame parallel decoding feature.
|
||||
*
|
||||
* VP9 has a bitstream feature to reduce decoding dependency between frames
|
||||
* by turning off backward update of probability context used in encoding
|
||||
* and decoding. This allows staged parallel processing of more than one
|
||||
* video frames in the decoder. This control function provides a mean to
|
||||
* turn this feature on or off for bitstreams produced by encoder.
|
||||
*
|
||||
* By default, this feature is off.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_FRAME_PARALLEL_DECODING,
|
||||
|
||||
/*!\brief Codec control function to set adaptive quantization mode.
|
||||
*
|
||||
* VP9 has a segment based feature that allows encoder to adaptively change
|
||||
* quantization parameter for each segment within a frame to improve the
|
||||
* subjective quality. This control makes encoder operate in one of the
|
||||
* several AQ_modes supported.
|
||||
*
|
||||
* By default, encoder operates with AQ_Mode 0(adaptive quantization off).
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_AQ_MODE,
|
||||
|
||||
/*!\brief Codec control function to enable/disable periodic Q boost.
|
||||
*
|
||||
* One VP9 encoder speed feature is to enable quality boost by lowering
|
||||
* frame level Q periodically. This control function provides a mean to
|
||||
* turn on/off this feature.
|
||||
* 0 = off
|
||||
* 1 = on
|
||||
*
|
||||
* By default, the encoder is allowed to use this feature for appropriate
|
||||
* encoding modes.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_FRAME_PERIODIC_BOOST,
|
||||
|
||||
/*!\brief Codec control function to set noise sensitivity.
|
||||
*
|
||||
* 0: off, 1: On(YOnly)
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_NOISE_SENSITIVITY,
|
||||
|
||||
/*!\brief Codec control function to turn on/off SVC in encoder.
|
||||
* \note Return value is VPX_CODEC_INVALID_PARAM if the encoder does not
|
||||
* support SVC in its current encoding mode
|
||||
* 0: off, 1: on
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC,
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief Codec control function to set parameters for SVC.
|
||||
* \note Parameters contain min_q, max_q, scaling factor for each of the
|
||||
* SVC layers.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC_PARAMETERS,
|
||||
#endif
|
||||
|
||||
/*!\brief Codec control function to set svc layer for spatial and temporal.
|
||||
* \note Valid ranges: 0..#vpx_codec_enc_cfg::ss_number_layers for spatial
|
||||
* layer and 0..#vpx_codec_enc_cfg::ts_number_layers for
|
||||
* temporal layer.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_SVC_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to set content type.
|
||||
* \note Valid parameter range:
|
||||
* VP9E_CONTENT_DEFAULT = Regular video content (Default)
|
||||
* VP9E_CONTENT_SCREEN = Screen capture content
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_TUNE_CONTENT,
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief Codec control function to get svc layer ID.
|
||||
* \note The layer ID returned is for the data packet from the registered
|
||||
* callback function.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_GET_SVC_LAYER_ID,
|
||||
|
||||
/*!\brief Codec control function to register callback to get per layer packet.
|
||||
* \note Parameter for this control function is a structure with a callback
|
||||
* function and a pointer to private data used by the callback.
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_REGISTER_CX_CALLBACK,
|
||||
#endif
|
||||
|
||||
/*!\brief Codec control function to set color space info.
|
||||
* \note Valid ranges: 0..7, default is "UNKNOWN".
|
||||
* 0 = UNKNOWN,
|
||||
* 1 = BT_601
|
||||
* 2 = BT_709
|
||||
* 3 = SMPTE_170
|
||||
* 4 = SMPTE_240
|
||||
* 5 = BT_2020
|
||||
* 6 = RESERVED
|
||||
* 7 = SRGB
|
||||
*
|
||||
* Supported in codecs: VP9
|
||||
*/
|
||||
VP9E_SET_COLOR_SPACE,
|
||||
};
|
||||
|
||||
/*!\brief vpx 1-D scaling mode
|
||||
*
|
||||
* This set of constants define 1-D vpx scaling modes
|
||||
*/
|
||||
typedef enum vpx_scaling_mode_1d {
|
||||
VP8E_NORMAL = 0,
|
||||
VP8E_FOURFIVE = 1,
|
||||
VP8E_THREEFIVE = 2,
|
||||
VP8E_ONETWO = 3
|
||||
} VPX_SCALING_MODE;
|
||||
|
||||
|
||||
/*!\brief vpx region of interest map
|
||||
*
|
||||
* These defines the data structures for the region of interest map
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct vpx_roi_map {
|
||||
/*! An id between 0 and 3 for each 16x16 region within a frame. */
|
||||
unsigned char *roi_map;
|
||||
unsigned int rows; /**< Number of rows. */
|
||||
unsigned int cols; /**< Number of columns. */
|
||||
// TODO(paulwilkins): broken for VP9 which has 8 segments
|
||||
// q and loop filter deltas for each segment
|
||||
// (see MAX_MB_SEGMENTS)
|
||||
int delta_q[4]; /**< Quantizer deltas. */
|
||||
int delta_lf[4]; /**< Loop filter deltas. */
|
||||
/*! Static breakout threshold for each segment. */
|
||||
unsigned int static_threshold[4];
|
||||
} vpx_roi_map_t;
|
||||
|
||||
/*!\brief vpx active region map
|
||||
*
|
||||
* These defines the data structures for active region map
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef struct vpx_active_map {
|
||||
unsigned char *active_map; /**< specify an on (1) or off (0) each 16x16 region within a frame */
|
||||
unsigned int rows; /**< number of rows */
|
||||
unsigned int cols; /**< number of cols */
|
||||
} vpx_active_map_t;
|
||||
|
||||
/*!\brief vpx image scaling mode
|
||||
*
|
||||
* This defines the data structure for image scaling mode
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_scaling_mode {
|
||||
VPX_SCALING_MODE h_scaling_mode; /**< horizontal scaling mode */
|
||||
VPX_SCALING_MODE v_scaling_mode; /**< vertical scaling mode */
|
||||
} vpx_scaling_mode_t;
|
||||
|
||||
/*!\brief VP8 token partition mode
|
||||
*
|
||||
* This defines VP8 partitioning mode for compressed data, i.e., the number of
|
||||
* sub-streams in the bitstream. Used for parallelized decoding.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
VP8_ONE_TOKENPARTITION = 0,
|
||||
VP8_TWO_TOKENPARTITION = 1,
|
||||
VP8_FOUR_TOKENPARTITION = 2,
|
||||
VP8_EIGHT_TOKENPARTITION = 3
|
||||
} vp8e_token_partitions;
|
||||
|
||||
/*!brief VP9 encoder content type */
|
||||
typedef enum {
|
||||
VP9E_CONTENT_DEFAULT,
|
||||
VP9E_CONTENT_SCREEN,
|
||||
VP9E_CONTENT_INVALID
|
||||
} vp9e_tune_content;
|
||||
|
||||
/*!\brief VP8 model tuning parameters
|
||||
*
|
||||
* Changes the encoder to tune for certain types of input material.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
VP8_TUNE_PSNR,
|
||||
VP8_TUNE_SSIM
|
||||
} vp8e_tuning;
|
||||
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
/*!\brief vp9 svc layer parameters
|
||||
*
|
||||
* This defines the spatial and temporal layer id numbers for svc encoding.
|
||||
* This is used with the #VP9E_SET_SVC_LAYER_ID control to set the spatial and
|
||||
* temporal layer id for the current frame.
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_svc_layer_id {
|
||||
int spatial_layer_id; /**< Spatial layer id number. */
|
||||
int temporal_layer_id; /**< Temporal layer id number. */
|
||||
} vpx_svc_layer_id_t;
|
||||
#else
|
||||
/*!\brief vp9 svc layer parameters
|
||||
*
|
||||
* This defines the temporal layer id numbers for svc encoding.
|
||||
* This is used with the #VP9E_SET_SVC_LAYER_ID control to set the
|
||||
* temporal layer id for the current frame.
|
||||
*
|
||||
*/
|
||||
typedef struct vpx_svc_layer_id {
|
||||
int temporal_layer_id; /**< Temporal layer id number. */
|
||||
} vpx_svc_layer_id_t;
|
||||
#endif
|
||||
|
||||
/*!\brief VP8 encoder control function parameter type
|
||||
*
|
||||
* Defines the data types that VP8E control functions take. Note that
|
||||
* additional common controls are defined in vp8.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* These controls have been deprecated in favor of the flags parameter to
|
||||
* vpx_codec_encode(). See the definition of VP8_EFLAG_* above.
|
||||
*/
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_ENTROPY, int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_REFERENCE, int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_USE_REFERENCE, int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_FRAME_FLAGS, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TEMPORAL_LAYER_ID, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int)
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, void *)
|
||||
VPX_CTRL_USE_TYPE(VP9E_REGISTER_CX_CALLBACK, void *)
|
||||
#endif
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SHARPNESS, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_STATIC_THRESHOLD, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TOKEN_PARTITIONS, int) /* vp8e_token_partitions */
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH, unsigned int)
|
||||
VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_ARNR_TYPE, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, int) /* vp8e_tuning */
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TILE_COLUMNS, int)
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TILE_ROWS, int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *)
|
||||
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
|
||||
VPX_CTRL_USE_TYPE(VP9E_GET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
|
||||
#endif
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int)
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTER_BITRATE_PCT, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8E_SET_SCREEN_CONTENT_MODE, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_GF_CBR_BOOST_PCT, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_LOSSLESS, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PARALLEL_DECODING, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_AQ_MODE, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PERIODIC_BOOST, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_NOISE_SENSITIVITY, unsigned int)
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_TUNE_CONTENT, int) /* vp9e_tune_content */
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP9E_SET_COLOR_SPACE, int)
|
||||
/*! @} - end defgroup vp8_encoder */
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8CX_H_
|
||||
159
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8dx.h
Normal file
159
local_pod_repo/toxcore/osx/vpx.framework/Headers/vp8dx.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\defgroup vp8_decoder WebM VP8/VP9 Decoder
|
||||
* \ingroup vp8
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/*!\file
|
||||
* \brief Provides definitions for using VP8 or VP9 within the vpx Decoder
|
||||
* interface.
|
||||
*/
|
||||
#ifndef VPX_VP8DX_H_
|
||||
#define VPX_VP8DX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Include controls common to both the encoder and decoder */
|
||||
#include "./vp8.h"
|
||||
|
||||
/*!\name Algorithm interface for VP8
|
||||
*
|
||||
* This interface provides the capability to decode VP8 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp8_dx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp8_dx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
/*!\name Algorithm interface for VP9
|
||||
*
|
||||
* This interface provides the capability to decode VP9 streams.
|
||||
* @{
|
||||
*/
|
||||
extern vpx_codec_iface_t vpx_codec_vp9_dx_algo;
|
||||
extern vpx_codec_iface_t *vpx_codec_vp9_dx(void);
|
||||
/*!@} - end algorithm interface member group*/
|
||||
|
||||
|
||||
/*!\enum vp8_dec_control_id
|
||||
* \brief VP8 decoder control functions
|
||||
*
|
||||
* This set of macros define the control functions available for the VP8
|
||||
* decoder interface.
|
||||
*
|
||||
* \sa #vpx_codec_control
|
||||
*/
|
||||
enum vp8_dec_control_id {
|
||||
/** control function to get info on which reference frames were updated
|
||||
* by the last decode
|
||||
*/
|
||||
VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START,
|
||||
|
||||
/** check if the indicated frame is corrupted */
|
||||
VP8D_GET_FRAME_CORRUPTED,
|
||||
|
||||
/** control function to get info on which reference frames were used
|
||||
* by the last decode
|
||||
*/
|
||||
VP8D_GET_LAST_REF_USED,
|
||||
|
||||
/** decryption function to decrypt encoded buffer data immediately
|
||||
* before decoding. Takes a vpx_decrypt_init, which contains
|
||||
* a callback function and opaque context pointer.
|
||||
*/
|
||||
VPXD_SET_DECRYPTOR,
|
||||
VP8D_SET_DECRYPTOR = VPXD_SET_DECRYPTOR,
|
||||
|
||||
/** control function to get the dimensions that the current frame is decoded
|
||||
* at. This may be different to the intended display size for the frame as
|
||||
* specified in the wrapper or frame header (see VP9D_GET_DISPLAY_SIZE). */
|
||||
VP9D_GET_FRAME_SIZE,
|
||||
|
||||
/** control function to get the current frame's intended display dimensions
|
||||
* (as specified in the wrapper or frame header). This may be different to
|
||||
* the decoded dimensions of this frame (see VP9D_GET_FRAME_SIZE). */
|
||||
VP9D_GET_DISPLAY_SIZE,
|
||||
|
||||
/** control function to get the bit depth of the stream. */
|
||||
VP9D_GET_BIT_DEPTH,
|
||||
|
||||
/** control function to set the byte alignment of the planes in the reference
|
||||
* buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets
|
||||
* legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly
|
||||
* follows Y plane, and V plane directly follows U plane. Default value is 0.
|
||||
*/
|
||||
VP9_SET_BYTE_ALIGNMENT,
|
||||
|
||||
/** control function to invert the decoding order to from right to left. The
|
||||
* function is used in a test to confirm the decoding independence of tile
|
||||
* columns. The function may be used in application where this order
|
||||
* of decoding is desired.
|
||||
*
|
||||
* TODO(yaowu): Rework the unit test that uses this control, and in a future
|
||||
* release, this test-only control shall be removed.
|
||||
*/
|
||||
VP9_INVERT_TILE_DECODE_ORDER,
|
||||
|
||||
VP8_DECODER_CTRL_ID_MAX
|
||||
};
|
||||
|
||||
/** Decrypt n bytes of data from input -> output, using the decrypt_state
|
||||
* passed in VPXD_SET_DECRYPTOR.
|
||||
*/
|
||||
typedef void (*vpx_decrypt_cb)(void *decrypt_state, const unsigned char *input,
|
||||
unsigned char *output, int count);
|
||||
|
||||
/*!\brief Structure to hold decryption state
|
||||
*
|
||||
* Defines a structure to hold the decryption state and access function.
|
||||
*/
|
||||
typedef struct vpx_decrypt_init {
|
||||
/*! Decrypt callback. */
|
||||
vpx_decrypt_cb decrypt_cb;
|
||||
|
||||
/*! Decryption state. */
|
||||
void *decrypt_state;
|
||||
} vpx_decrypt_init;
|
||||
|
||||
/*!\brief A deprecated alias for vpx_decrypt_init.
|
||||
*/
|
||||
typedef vpx_decrypt_init vp8_decrypt_init;
|
||||
|
||||
|
||||
/*!\brief VP8 decoder control function parameter type
|
||||
*
|
||||
* Defines the data types that VP8D control functions take. Note that
|
||||
* additional common controls are defined in vp8.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *)
|
||||
VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR, vpx_decrypt_init *)
|
||||
VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR, vpx_decrypt_init *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE, int *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_BIT_DEPTH, unsigned int *)
|
||||
VPX_CTRL_USE_TYPE(VP9D_GET_FRAME_SIZE, int *)
|
||||
VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int)
|
||||
|
||||
/*! @} - end defgroup vp8_decoder */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VP8DX_H_
|
||||
479
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_codec.h
Normal file
479
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_codec.h
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\defgroup codec Common Algorithm Interface
|
||||
* This abstraction allows applications to easily support multiple video
|
||||
* formats with minimal code duplication. This section describes the interface
|
||||
* common to all codecs (both encoders and decoders).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the codec algorithm interface to applications.
|
||||
*
|
||||
* This file describes the interface between an application and a
|
||||
* video codec algorithm.
|
||||
*
|
||||
* An application instantiates a specific codec instance by using
|
||||
* vpx_codec_init() and a pointer to the algorithm's interface structure:
|
||||
* <pre>
|
||||
* my_app.c:
|
||||
* extern vpx_codec_iface_t my_codec;
|
||||
* {
|
||||
* vpx_codec_ctx_t algo;
|
||||
* res = vpx_codec_init(&algo, &my_codec);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Once initialized, the instance is manged using other functions from
|
||||
* the vpx_codec_* family.
|
||||
*/
|
||||
#ifndef VPX_VPX_CODEC_H_
|
||||
#define VPX_VPX_CODEC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_integer.h"
|
||||
#include "./vpx_image.h"
|
||||
|
||||
/*!\brief Decorator indicating a function is deprecated */
|
||||
#ifndef DEPRECATED
|
||||
#if defined(__GNUC__) && __GNUC__
|
||||
#define DEPRECATED __attribute__ ((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DEPRECATED
|
||||
#else
|
||||
#define DEPRECATED
|
||||
#endif
|
||||
#endif /* DEPRECATED */
|
||||
|
||||
#ifndef DECLSPEC_DEPRECATED
|
||||
#if defined(__GNUC__) && __GNUC__
|
||||
#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */
|
||||
#elif defined(_MSC_VER)
|
||||
#define DECLSPEC_DEPRECATED __declspec(deprecated) /**< \copydoc #DEPRECATED */
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED /**< \copydoc #DEPRECATED */
|
||||
#endif
|
||||
#endif /* DECLSPEC_DEPRECATED */
|
||||
|
||||
/*!\brief Decorator indicating a function is potentially unused */
|
||||
#ifdef UNUSED
|
||||
#elif __GNUC__
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_CODEC_ABI_VERSION (3 + VPX_IMAGE_ABI_VERSION) /**<\hideinitializer*/
|
||||
|
||||
/*!\brief Algorithm return codes */
|
||||
typedef enum {
|
||||
/*!\brief Operation completed without error */
|
||||
VPX_CODEC_OK,
|
||||
|
||||
/*!\brief Unspecified error */
|
||||
VPX_CODEC_ERROR,
|
||||
|
||||
/*!\brief Memory operation failed */
|
||||
VPX_CODEC_MEM_ERROR,
|
||||
|
||||
/*!\brief ABI version mismatch */
|
||||
VPX_CODEC_ABI_MISMATCH,
|
||||
|
||||
/*!\brief Algorithm does not have required capability */
|
||||
VPX_CODEC_INCAPABLE,
|
||||
|
||||
/*!\brief The given bitstream is not supported.
|
||||
*
|
||||
* The bitstream was unable to be parsed at the highest level. The decoder
|
||||
* is unable to proceed. This error \ref SHOULD be treated as fatal to the
|
||||
* stream. */
|
||||
VPX_CODEC_UNSUP_BITSTREAM,
|
||||
|
||||
/*!\brief Encoded bitstream uses an unsupported feature
|
||||
*
|
||||
* The decoder does not implement a feature required by the encoder. This
|
||||
* return code should only be used for features that prevent future
|
||||
* pictures from being properly decoded. This error \ref MAY be treated as
|
||||
* fatal to the stream or \ref MAY be treated as fatal to the current GOP.
|
||||
*/
|
||||
VPX_CODEC_UNSUP_FEATURE,
|
||||
|
||||
/*!\brief The coded data for this stream is corrupt or incomplete
|
||||
*
|
||||
* There was a problem decoding the current frame. This return code
|
||||
* should only be used for failures that prevent future pictures from
|
||||
* being properly decoded. This error \ref MAY be treated as fatal to the
|
||||
* stream or \ref MAY be treated as fatal to the current GOP. If decoding
|
||||
* is continued for the current GOP, artifacts may be present.
|
||||
*/
|
||||
VPX_CODEC_CORRUPT_FRAME,
|
||||
|
||||
/*!\brief An application-supplied parameter is not valid.
|
||||
*
|
||||
*/
|
||||
VPX_CODEC_INVALID_PARAM,
|
||||
|
||||
/*!\brief An iterator reached the end of list.
|
||||
*
|
||||
*/
|
||||
VPX_CODEC_LIST_END
|
||||
|
||||
}
|
||||
vpx_codec_err_t;
|
||||
|
||||
|
||||
/*! \brief Codec capabilities bitfield
|
||||
*
|
||||
* Each codec advertises the capabilities it supports as part of its
|
||||
* ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces
|
||||
* or functionality, and are not required to be supported.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_CAP_* defines.
|
||||
*/
|
||||
typedef long vpx_codec_caps_t;
|
||||
#define VPX_CODEC_CAP_DECODER 0x1 /**< Is a decoder */
|
||||
#define VPX_CODEC_CAP_ENCODER 0x2 /**< Is an encoder */
|
||||
|
||||
|
||||
/*! \brief Initialization-time Feature Enabling
|
||||
*
|
||||
* Certain codec features must be known at initialization time, to allow for
|
||||
* proper memory allocation.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_USE_* defines.
|
||||
*/
|
||||
typedef long vpx_codec_flags_t;
|
||||
|
||||
|
||||
/*!\brief Codec interface structure.
|
||||
*
|
||||
* Contains function pointers and other data private to the codec
|
||||
* implementation. This structure is opaque to the application.
|
||||
*/
|
||||
typedef const struct vpx_codec_iface vpx_codec_iface_t;
|
||||
|
||||
|
||||
/*!\brief Codec private data structure.
|
||||
*
|
||||
* Contains data private to the codec implementation. This structure is opaque
|
||||
* to the application.
|
||||
*/
|
||||
typedef struct vpx_codec_priv vpx_codec_priv_t;
|
||||
|
||||
|
||||
/*!\brief Iterator
|
||||
*
|
||||
* Opaque storage used for iterating over lists.
|
||||
*/
|
||||
typedef const void *vpx_codec_iter_t;
|
||||
|
||||
|
||||
/*!\brief Codec context structure
|
||||
*
|
||||
* All codecs \ref MUST support this context structure fully. In general,
|
||||
* this data should be considered private to the codec algorithm, and
|
||||
* not be manipulated or examined by the calling application. Applications
|
||||
* may reference the 'name' member to get a printable description of the
|
||||
* algorithm.
|
||||
*/
|
||||
typedef struct vpx_codec_ctx {
|
||||
const char *name; /**< Printable interface name */
|
||||
vpx_codec_iface_t *iface; /**< Interface pointers */
|
||||
vpx_codec_err_t err; /**< Last returned error */
|
||||
const char *err_detail; /**< Detailed info, if available */
|
||||
vpx_codec_flags_t init_flags; /**< Flags passed at init time */
|
||||
union {
|
||||
/**< Decoder Configuration Pointer */
|
||||
const struct vpx_codec_dec_cfg *dec;
|
||||
/**< Encoder Configuration Pointer */
|
||||
const struct vpx_codec_enc_cfg *enc;
|
||||
const void *raw;
|
||||
} config; /**< Configuration pointer aliasing union */
|
||||
vpx_codec_priv_t *priv; /**< Algorithm private storage */
|
||||
} vpx_codec_ctx_t;
|
||||
|
||||
/*!\brief Bit depth for codec
|
||||
* *
|
||||
* This enumeration determines the bit depth of the codec.
|
||||
*/
|
||||
typedef enum vpx_bit_depth {
|
||||
VPX_BITS_8 = 8, /**< 8 bits */
|
||||
VPX_BITS_10 = 10, /**< 10 bits */
|
||||
VPX_BITS_12 = 12, /**< 12 bits */
|
||||
} vpx_bit_depth_t;
|
||||
|
||||
/*
|
||||
* Library Version Number Interface
|
||||
*
|
||||
* For example, see the following sample return values:
|
||||
* vpx_codec_version() (1<<16 | 2<<8 | 3)
|
||||
* vpx_codec_version_str() "v1.2.3-rc1-16-gec6a1ba"
|
||||
* vpx_codec_version_extra_str() "rc1-16-gec6a1ba"
|
||||
*/
|
||||
|
||||
/*!\brief Return the version information (as an integer)
|
||||
*
|
||||
* Returns a packed encoding of the library version number. This will only include
|
||||
* the major.minor.patch component of the version number. Note that this encoded
|
||||
* value should be accessed through the macros provided, as the encoding may change
|
||||
* in the future.
|
||||
*
|
||||
*/
|
||||
int vpx_codec_version(void);
|
||||
#define VPX_VERSION_MAJOR(v) ((v>>16)&0xff) /**< extract major from packed version */
|
||||
#define VPX_VERSION_MINOR(v) ((v>>8)&0xff) /**< extract minor from packed version */
|
||||
#define VPX_VERSION_PATCH(v) ((v>>0)&0xff) /**< extract patch from packed version */
|
||||
|
||||
/*!\brief Return the version major number */
|
||||
#define vpx_codec_version_major() ((vpx_codec_version()>>16)&0xff)
|
||||
|
||||
/*!\brief Return the version minor number */
|
||||
#define vpx_codec_version_minor() ((vpx_codec_version()>>8)&0xff)
|
||||
|
||||
/*!\brief Return the version patch number */
|
||||
#define vpx_codec_version_patch() ((vpx_codec_version()>>0)&0xff)
|
||||
|
||||
|
||||
/*!\brief Return the version information (as a string)
|
||||
*
|
||||
* Returns a printable string containing the full library version number. This may
|
||||
* contain additional text following the three digit version number, as to indicate
|
||||
* release candidates, prerelease versions, etc.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_version_str(void);
|
||||
|
||||
|
||||
/*!\brief Return the version information (as a string)
|
||||
*
|
||||
* Returns a printable "extra string". This is the component of the string returned
|
||||
* by vpx_codec_version_str() following the three digit version number.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_version_extra_str(void);
|
||||
|
||||
|
||||
/*!\brief Return the build configuration
|
||||
*
|
||||
* Returns a printable string containing an encoded version of the build
|
||||
* configuration. This may be useful to vpx support.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_build_config(void);
|
||||
|
||||
|
||||
/*!\brief Return the name for a given interface
|
||||
*
|
||||
* Returns a human readable string for name of the given codec interface.
|
||||
*
|
||||
* \param[in] iface Interface pointer
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_iface_name(vpx_codec_iface_t *iface);
|
||||
|
||||
|
||||
/*!\brief Convert error number to printable string
|
||||
*
|
||||
* Returns a human readable string for the last error returned by the
|
||||
* algorithm. The returned error will be one line and will not contain
|
||||
* any newline characters.
|
||||
*
|
||||
*
|
||||
* \param[in] err Error number.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_err_to_string(vpx_codec_err_t err);
|
||||
|
||||
|
||||
/*!\brief Retrieve error synopsis for codec context
|
||||
*
|
||||
* Returns a human readable string for the last error returned by the
|
||||
* algorithm. The returned error will be one line and will not contain
|
||||
* any newline characters.
|
||||
*
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
*
|
||||
*/
|
||||
const char *vpx_codec_error(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/*!\brief Retrieve detailed error information for codec context
|
||||
*
|
||||
* Returns a human readable string providing detailed information about
|
||||
* the last error.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
*
|
||||
* \retval NULL
|
||||
* No detailed information is available.
|
||||
*/
|
||||
const char *vpx_codec_error_detail(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/* REQUIRED FUNCTIONS
|
||||
*
|
||||
* The following functions are required to be implemented for all codecs.
|
||||
* They represent the base case functionality expected of all codecs.
|
||||
*/
|
||||
|
||||
/*!\brief Destroy a codec instance
|
||||
*
|
||||
* Destroys a codec context, freeing any associated memory buffers.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The codec algorithm initialized.
|
||||
* \retval #VPX_CODEC_MEM_ERROR
|
||||
* Memory allocation failed.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx);
|
||||
|
||||
|
||||
/*!\brief Get the capabilities of an algorithm.
|
||||
*
|
||||
* Retrieves the capabilities bitfield from the algorithm's interface.
|
||||
*
|
||||
* \param[in] iface Pointer to the algorithm interface
|
||||
*
|
||||
*/
|
||||
vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface);
|
||||
|
||||
|
||||
/*!\brief Control algorithm
|
||||
*
|
||||
* This function is used to exchange algorithm specific data with the codec
|
||||
* instance. This can be used to implement features specific to a particular
|
||||
* algorithm.
|
||||
*
|
||||
* This wrapper function dispatches the request to the helper function
|
||||
* associated with the given ctrl_id. It tries to call this function
|
||||
* transparently, but will return #VPX_CODEC_ERROR if the request could not
|
||||
* be dispatched.
|
||||
*
|
||||
* Note that this function should not be used directly. Call the
|
||||
* #vpx_codec_control wrapper macro instead.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] ctrl_id Algorithm specific control identifier
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The control request was processed.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* The control request was not processed.
|
||||
* \retval #VPX_CODEC_INVALID_PARAM
|
||||
* The data was not valid.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t *ctx,
|
||||
int ctrl_id,
|
||||
...);
|
||||
#if defined(VPX_DISABLE_CTRL_TYPECHECKS) && VPX_DISABLE_CTRL_TYPECHECKS
|
||||
# define vpx_codec_control(ctx,id,data) vpx_codec_control_(ctx,id,data)
|
||||
# define VPX_CTRL_USE_TYPE(id, typ)
|
||||
# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ)
|
||||
# define VPX_CTRL_VOID(id, typ)
|
||||
|
||||
#else
|
||||
/*!\brief vpx_codec_control wrapper macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_().
|
||||
*
|
||||
* \internal
|
||||
* It works by dispatching the call to the control function through a wrapper
|
||||
* function named with the id parameter.
|
||||
*/
|
||||
# define vpx_codec_control(ctx,id,data) vpx_codec_control_##id(ctx,id,data)\
|
||||
/**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control type definition macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_(). It defines the type of the argument for a given
|
||||
* control identifier.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function with
|
||||
* the correctly typed arguments as a wrapper to the type-unsafe internal
|
||||
* function.
|
||||
*/
|
||||
# define VPX_CTRL_USE_TYPE(id, typ) \
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) UNUSED;\
|
||||
\
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id, data);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control deprecated type definition macro
|
||||
*
|
||||
* Like #VPX_CTRL_USE_TYPE, but indicates that the specified control is
|
||||
* deprecated and should not be used. Consult the documentation for your
|
||||
* codec for more information.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function with the correctly typed arguments as a
|
||||
* wrapper to the type-unsafe internal function.
|
||||
*/
|
||||
# define VPX_CTRL_USE_TYPE_DEPRECATED(id, typ) \
|
||||
DECLSPEC_DEPRECATED static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int, typ) DEPRECATED UNUSED;\
|
||||
\
|
||||
DECLSPEC_DEPRECATED static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id, typ data) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id, data);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
/*!\brief vpx_codec_control void type definition macro
|
||||
*
|
||||
* This macro allows for type safe conversions across the variadic parameter
|
||||
* to vpx_codec_control_(). It indicates that a given control identifier takes
|
||||
* no argument.
|
||||
*
|
||||
* \internal
|
||||
* It defines a static function without a data argument as a wrapper to the
|
||||
* type-unsafe internal function.
|
||||
*/
|
||||
# define VPX_CTRL_VOID(id) \
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t*, int) UNUSED;\
|
||||
\
|
||||
static vpx_codec_err_t \
|
||||
vpx_codec_control_##id(vpx_codec_ctx_t *ctx, int ctrl_id) {\
|
||||
return vpx_codec_control_(ctx, ctrl_id);\
|
||||
} /**<\hideinitializer*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*!@} - end defgroup codec*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // VPX_VPX_CODEC_H_
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* GENERATED FILE: DO NOT EDIT! */
|
||||
|
||||
#ifndef VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
#define VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
|
||||
#if defined __x86_64__
|
||||
#define VPX_FRAMEWORK_TARGET "x86_64-darwin13-gcc"
|
||||
#include "vpx/vpx/x86_64-darwin13-gcc/vpx_config.h"
|
||||
#endif
|
||||
|
||||
#endif // VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_
|
||||
378
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_decoder.h
Normal file
378
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_decoder.h
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef VPX_VPX_DECODER_H_
|
||||
#define VPX_VPX_DECODER_H_
|
||||
|
||||
/*!\defgroup decoder Decoder Algorithm Interface
|
||||
* \ingroup codec
|
||||
* This abstraction allows applications using this decoder to easily support
|
||||
* multiple video formats with minimal code duplication. This section describes
|
||||
* the interface common to all decoders.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the decoder algorithm interface to applications.
|
||||
*
|
||||
* This file describes the interface between an application and a
|
||||
* video decoder algorithm.
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_codec.h"
|
||||
#include "./vpx_frame_buffer.h"
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_DECODER_ABI_VERSION (3 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
|
||||
|
||||
/*! \brief Decoder capabilities bitfield
|
||||
*
|
||||
* Each decoder advertises the capabilities it supports as part of its
|
||||
* ::vpx_codec_iface_t interface structure. Capabilities are extra interfaces
|
||||
* or functionality, and are not required to be supported by a decoder.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_CAP_* defines.
|
||||
*/
|
||||
#define VPX_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */
|
||||
#define VPX_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */
|
||||
#define VPX_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */
|
||||
#define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /**< Can conceal errors due to
|
||||
packet loss */
|
||||
#define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /**< Can receive encoded frames
|
||||
one fragment at a time */
|
||||
|
||||
/*! \brief Initialization-time Feature Enabling
|
||||
*
|
||||
* Certain codec features must be known at initialization time, to allow for
|
||||
* proper memory allocation.
|
||||
*
|
||||
* The available flags are specified by VPX_CODEC_USE_* defines.
|
||||
*/
|
||||
#define VPX_CODEC_CAP_FRAME_THREADING 0x200000 /**< Can support frame-based
|
||||
multi-threading */
|
||||
#define VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x400000 /**< Can support external
|
||||
frame buffers */
|
||||
|
||||
#define VPX_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */
|
||||
#define VPX_CODEC_USE_ERROR_CONCEALMENT 0x20000 /**< Conceal errors in decoded
|
||||
frames */
|
||||
#define VPX_CODEC_USE_INPUT_FRAGMENTS 0x40000 /**< The input frame should be
|
||||
passed to the decoder one
|
||||
fragment at a time */
|
||||
#define VPX_CODEC_USE_FRAME_THREADING 0x80000 /**< Enable frame-based
|
||||
multi-threading */
|
||||
|
||||
/*!\brief Stream properties
|
||||
*
|
||||
* This structure is used to query or set properties of the decoded
|
||||
* stream. Algorithms may extend this structure with data specific
|
||||
* to their bitstream by setting the sz member appropriately.
|
||||
*/
|
||||
typedef struct vpx_codec_stream_info {
|
||||
unsigned int sz; /**< Size of this structure */
|
||||
unsigned int w; /**< Width (or 0 for unknown/default) */
|
||||
unsigned int h; /**< Height (or 0 for unknown/default) */
|
||||
unsigned int is_kf; /**< Current frame is a keyframe */
|
||||
} vpx_codec_stream_info_t;
|
||||
|
||||
/* REQUIRED FUNCTIONS
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders.
|
||||
* They represent the base case functionality expected of all decoders.
|
||||
*/
|
||||
|
||||
|
||||
/*!\brief Initialization Configurations
|
||||
*
|
||||
* This structure is used to pass init time configuration options to the
|
||||
* decoder.
|
||||
*/
|
||||
typedef struct vpx_codec_dec_cfg {
|
||||
unsigned int threads; /**< Maximum number of threads to use, default 1 */
|
||||
unsigned int w; /**< Width */
|
||||
unsigned int h; /**< Height */
|
||||
} vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */
|
||||
|
||||
|
||||
/*!\brief Initialize a decoder instance
|
||||
*
|
||||
* Initializes a decoder context using the given interface. Applications
|
||||
* should call the vpx_codec_dec_init convenience macro instead of this
|
||||
* function directly, to ensure that the ABI version number parameter
|
||||
* is properly initialized.
|
||||
*
|
||||
* If the library was configured with --disable-multithread, this call
|
||||
* is not thread safe and should be guarded with a lock if being used
|
||||
* in a multithreaded context.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context.
|
||||
* \param[in] iface Pointer to the algorithm interface to use.
|
||||
* \param[in] cfg Configuration to use, if known. May be NULL.
|
||||
* \param[in] flags Bitfield of VPX_CODEC_USE_* flags
|
||||
* \param[in] ver ABI version number. Must be set to
|
||||
* VPX_DECODER_ABI_VERSION
|
||||
* \retval #VPX_CODEC_OK
|
||||
* The decoder algorithm initialized.
|
||||
* \retval #VPX_CODEC_MEM_ERROR
|
||||
* Memory allocation failed.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_iface_t *iface,
|
||||
const vpx_codec_dec_cfg_t *cfg,
|
||||
vpx_codec_flags_t flags,
|
||||
int ver);
|
||||
|
||||
/*!\brief Convenience macro for vpx_codec_dec_init_ver()
|
||||
*
|
||||
* Ensures the ABI version parameter is properly set.
|
||||
*/
|
||||
#define vpx_codec_dec_init(ctx, iface, cfg, flags) \
|
||||
vpx_codec_dec_init_ver(ctx, iface, cfg, flags, VPX_DECODER_ABI_VERSION)
|
||||
|
||||
|
||||
/*!\brief Parse stream info from a buffer
|
||||
*
|
||||
* Performs high level parsing of the bitstream. Construction of a decoder
|
||||
* context is not necessary. Can be used to determine if the bitstream is
|
||||
* of the proper format, and to extract information from the stream.
|
||||
*
|
||||
* \param[in] iface Pointer to the algorithm interface
|
||||
* \param[in] data Pointer to a block of data to parse
|
||||
* \param[in] data_sz Size of the data buffer
|
||||
* \param[in,out] si Pointer to stream info to update. The size member
|
||||
* \ref MUST be properly initialized, but \ref MAY be
|
||||
* clobbered by the algorithm. This parameter \ref MAY
|
||||
* be NULL.
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Bitstream is parsable and stream information updated
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_peek_stream_info(vpx_codec_iface_t *iface,
|
||||
const uint8_t *data,
|
||||
unsigned int data_sz,
|
||||
vpx_codec_stream_info_t *si);
|
||||
|
||||
|
||||
/*!\brief Return information about the current stream.
|
||||
*
|
||||
* Returns information about the stream that has been parsed during decoding.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in,out] si Pointer to stream info to update. The size member
|
||||
* \ref MUST be properly initialized, but \ref MAY be
|
||||
* clobbered by the algorithm. This parameter \ref MAY
|
||||
* be NULL.
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Bitstream is parsable and stream information updated
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_get_stream_info(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_stream_info_t *si);
|
||||
|
||||
|
||||
/*!\brief Decode data
|
||||
*
|
||||
* Processes a buffer of coded data. If the processing results in a new
|
||||
* decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be
|
||||
* generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode
|
||||
* time stamp) order. Frames produced will always be in PTS (presentation
|
||||
* time stamp) order.
|
||||
* If the decoder is configured with VPX_CODEC_USE_INPUT_FRAGMENTS enabled,
|
||||
* data and data_sz can contain a fragment of the encoded frame. Fragment
|
||||
* \#n must contain at least partition \#n, but can also contain subsequent
|
||||
* partitions (\#n+1 - \#n+i), and if so, fragments \#n+1, .., \#n+i must
|
||||
* be empty. When no more data is available, this function should be called
|
||||
* with NULL as data and 0 as data_sz. The memory passed to this function
|
||||
* must be available until the frame has been decoded.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] data Pointer to this block of new coded data. If
|
||||
* NULL, a VPX_CODEC_CB_PUT_FRAME event is posted
|
||||
* for the previously decoded frame.
|
||||
* \param[in] data_sz Size of the coded data, in bytes.
|
||||
* \param[in] user_priv Application specific data to associate with
|
||||
* this frame.
|
||||
* \param[in] deadline Soft deadline the decoder should attempt to meet,
|
||||
* in us. Set to zero for unlimited.
|
||||
*
|
||||
* \return Returns #VPX_CODEC_OK if the coded data was processed completely
|
||||
* and future pictures can be decoded without error. Otherwise,
|
||||
* see the descriptions of the other error codes in ::vpx_codec_err_t
|
||||
* for recoverability capabilities.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t *ctx,
|
||||
const uint8_t *data,
|
||||
unsigned int data_sz,
|
||||
void *user_priv,
|
||||
long deadline);
|
||||
|
||||
|
||||
/*!\brief Decoded frames iterator
|
||||
*
|
||||
* Iterates over a list of the frames available for display. The iterator
|
||||
* storage should be initialized to NULL to start the iteration. Iteration is
|
||||
* complete when this function returns NULL.
|
||||
*
|
||||
* The list of available frames becomes valid upon completion of the
|
||||
* vpx_codec_decode call, and remains valid until the next call to vpx_codec_decode.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in,out] iter Iterator storage, initialized to NULL
|
||||
*
|
||||
* \return Returns a pointer to an image, if one is ready for display. Frames
|
||||
* produced will always be in PTS (presentation time stamp) order.
|
||||
*/
|
||||
vpx_image_t *vpx_codec_get_frame(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_iter_t *iter);
|
||||
|
||||
|
||||
/*!\defgroup cap_put_frame Frame-Based Decoding Functions
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_PUT_FRAME capability. Calling these functions
|
||||
* for codecs that don't advertise this capability will result in an error
|
||||
* code being returned, usually VPX_CODEC_ERROR
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief put frame callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to notify the application of
|
||||
* the availability of decoded image data.
|
||||
*/
|
||||
typedef void (*vpx_codec_put_frame_cb_fn_t)(void *user_priv,
|
||||
const vpx_image_t *img);
|
||||
|
||||
|
||||
/*!\brief Register for notification of frame completion.
|
||||
*
|
||||
* Registers a given function to be called when a decoded frame is
|
||||
* available.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb Pointer to the callback function
|
||||
* \param[in] user_priv User's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Callback successfully registered.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* posting slice completion.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_register_put_frame_cb(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_put_frame_cb_fn_t cb,
|
||||
void *user_priv);
|
||||
|
||||
|
||||
/*!@} - end defgroup cap_put_frame */
|
||||
|
||||
/*!\defgroup cap_put_slice Slice-Based Decoding Functions
|
||||
*
|
||||
* The following functions are required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_PUT_SLICE capability. Calling these functions
|
||||
* for codecs that don't advertise this capability will result in an error
|
||||
* code being returned, usually VPX_CODEC_ERROR
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief put slice callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to notify the application of
|
||||
* the availability of partially decoded image data. The
|
||||
*/
|
||||
typedef void (*vpx_codec_put_slice_cb_fn_t)(void *user_priv,
|
||||
const vpx_image_t *img,
|
||||
const vpx_image_rect_t *valid,
|
||||
const vpx_image_rect_t *update);
|
||||
|
||||
|
||||
/*!\brief Register for notification of slice completion.
|
||||
*
|
||||
* Registers a given function to be called when a decoded slice is
|
||||
* available.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb Pointer to the callback function
|
||||
* \param[in] user_priv User's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* Callback successfully registered.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* posting slice completion.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_register_put_slice_cb(vpx_codec_ctx_t *ctx,
|
||||
vpx_codec_put_slice_cb_fn_t cb,
|
||||
void *user_priv);
|
||||
|
||||
|
||||
/*!@} - end defgroup cap_put_slice*/
|
||||
|
||||
/*!\defgroup cap_external_frame_buffer External Frame Buffer Functions
|
||||
*
|
||||
* The following section is required to be implemented for all decoders
|
||||
* that advertise the VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER capability.
|
||||
* Calling this function for codecs that don't advertise this capability
|
||||
* will result in an error code being returned, usually VPX_CODEC_ERROR.
|
||||
*
|
||||
* \note
|
||||
* Currently this only works with VP9.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!\brief Pass in external frame buffers for the decoder to use.
|
||||
*
|
||||
* Registers functions to be called when libvpx needs a frame buffer
|
||||
* to decode the current frame and a function to be called when libvpx does
|
||||
* not internally reference the frame buffer. This set function must
|
||||
* be called before the first call to decode or libvpx will assume the
|
||||
* default behavior of allocating frame buffers internally.
|
||||
*
|
||||
* \param[in] ctx Pointer to this instance's context
|
||||
* \param[in] cb_get Pointer to the get callback function
|
||||
* \param[in] cb_release Pointer to the release callback function
|
||||
* \param[in] cb_priv Callback's private data
|
||||
*
|
||||
* \retval #VPX_CODEC_OK
|
||||
* External frame buffers will be used by libvpx.
|
||||
* \retval #VPX_CODEC_INVALID_PARAM
|
||||
* One or more of the callbacks were NULL.
|
||||
* \retval #VPX_CODEC_ERROR
|
||||
* Decoder context not initialized, or algorithm not capable of
|
||||
* using external frame buffers.
|
||||
*
|
||||
* \note
|
||||
* When decoding VP9, the application may be required to pass in at least
|
||||
* #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS external frame
|
||||
* buffers.
|
||||
*/
|
||||
vpx_codec_err_t vpx_codec_set_frame_buffer_functions(
|
||||
vpx_codec_ctx_t *ctx,
|
||||
vpx_get_frame_buffer_cb_fn_t cb_get,
|
||||
vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv);
|
||||
|
||||
/*!@} - end defgroup cap_external_frame_buffer */
|
||||
|
||||
/*!@} - end defgroup decoder*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // VPX_VPX_DECODER_H_
|
||||
|
||||
1023
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_encoder.h
Normal file
1023
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_encoder.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef VPX_VPX_FRAME_BUFFER_H_
|
||||
#define VPX_VPX_FRAME_BUFFER_H_
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the decoder external frame buffer interface.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./vpx_integer.h"
|
||||
|
||||
/*!\brief The maximum number of work buffers used by libvpx.
|
||||
* Support maximum 4 threads to decode video in parallel.
|
||||
* Each thread will use one work buffer.
|
||||
* TODO(hkuang): Add support to set number of worker threads dynamically.
|
||||
*/
|
||||
#define VPX_MAXIMUM_WORK_BUFFERS 8
|
||||
|
||||
/*!\brief The maximum number of reference buffers that a VP9 encoder may use.
|
||||
*/
|
||||
#define VP9_MAXIMUM_REF_BUFFERS 8
|
||||
|
||||
/*!\brief External frame buffer
|
||||
*
|
||||
* This structure holds allocated frame buffers used by the decoder.
|
||||
*/
|
||||
typedef struct vpx_codec_frame_buffer {
|
||||
uint8_t *data; /**< Pointer to the data buffer */
|
||||
size_t size; /**< Size of data in bytes */
|
||||
void *priv; /**< Frame's private data */
|
||||
} vpx_codec_frame_buffer_t;
|
||||
|
||||
/*!\brief get frame buffer callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder to retrieve data for the frame
|
||||
* buffer in order for the decode call to complete. The callback must
|
||||
* allocate at least min_size in bytes and assign it to fb->data. The callback
|
||||
* must zero out all the data allocated. Then the callback must set fb->size
|
||||
* to the allocated size. The application does not need to align the allocated
|
||||
* data. The callback is triggered when the decoder needs a frame buffer to
|
||||
* decode a compressed image into. This function may be called more than once
|
||||
* for every call to vpx_codec_decode. The application may set fb->priv to
|
||||
* some data which will be passed back in the ximage and the release function
|
||||
* call. |fb| is guaranteed to not be NULL. On success the callback must
|
||||
* return 0. Any failure the callback must return a value less than 0.
|
||||
*
|
||||
* \param[in] priv Callback's private data
|
||||
* \param[in] new_size Size in bytes needed by the buffer
|
||||
* \param[in,out] fb Pointer to vpx_codec_frame_buffer_t
|
||||
*/
|
||||
typedef int (*vpx_get_frame_buffer_cb_fn_t)(
|
||||
void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
/*!\brief release frame buffer callback prototype
|
||||
*
|
||||
* This callback is invoked by the decoder when the frame buffer is not
|
||||
* referenced by any other buffers. |fb| is guaranteed to not be NULL. On
|
||||
* success the callback must return 0. Any failure the callback must return
|
||||
* a value less than 0.
|
||||
*
|
||||
* \param[in] priv Callback's private data
|
||||
* \param[in] fb Pointer to vpx_codec_frame_buffer_t
|
||||
*/
|
||||
typedef int (*vpx_release_frame_buffer_cb_fn_t)(
|
||||
void *priv, vpx_codec_frame_buffer_t *fb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_FRAME_BUFFER_H_
|
||||
224
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_image.h
Normal file
224
local_pod_repo/toxcore/osx/vpx.framework/Headers/vpx_image.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*!\file
|
||||
* \brief Describes the vpx image descriptor and associated operations
|
||||
*
|
||||
*/
|
||||
#ifndef VPX_VPX_IMAGE_H_
|
||||
#define VPX_VPX_IMAGE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!\brief Current ABI version number
|
||||
*
|
||||
* \internal
|
||||
* If this file is altered in any way that changes the ABI, this value
|
||||
* must be bumped. Examples include, but are not limited to, changing
|
||||
* types, removing or reassigning enums, adding/removing/rearranging
|
||||
* fields to structures
|
||||
*/
|
||||
#define VPX_IMAGE_ABI_VERSION (3) /**<\hideinitializer*/
|
||||
|
||||
|
||||
#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */
|
||||
#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */
|
||||
#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel. */
|
||||
#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */
|
||||
|
||||
/*!\brief List of supported image formats */
|
||||
typedef enum vpx_img_fmt {
|
||||
VPX_IMG_FMT_NONE,
|
||||
VPX_IMG_FMT_RGB24, /**< 24 bit per pixel packed RGB */
|
||||
VPX_IMG_FMT_RGB32, /**< 32 bit per pixel packed 0RGB */
|
||||
VPX_IMG_FMT_RGB565, /**< 16 bit per pixel, 565 */
|
||||
VPX_IMG_FMT_RGB555, /**< 16 bit per pixel, 555 */
|
||||
VPX_IMG_FMT_UYVY, /**< UYVY packed YUV */
|
||||
VPX_IMG_FMT_YUY2, /**< YUYV packed YUV */
|
||||
VPX_IMG_FMT_YVYU, /**< YVYU packed YUV */
|
||||
VPX_IMG_FMT_BGR24, /**< 24 bit per pixel packed BGR */
|
||||
VPX_IMG_FMT_RGB32_LE, /**< 32 bit packed BGR0 */
|
||||
VPX_IMG_FMT_ARGB, /**< 32 bit packed ARGB, alpha=255 */
|
||||
VPX_IMG_FMT_ARGB_LE, /**< 32 bit packed BGRA, alpha=255 */
|
||||
VPX_IMG_FMT_RGB565_LE, /**< 16 bit per pixel, gggbbbbb rrrrrggg */
|
||||
VPX_IMG_FMT_RGB555_LE, /**< 16 bit per pixel, gggbbbbb 0rrrrrgg */
|
||||
VPX_IMG_FMT_YV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 1, /**< planar YVU */
|
||||
VPX_IMG_FMT_I420 = VPX_IMG_FMT_PLANAR | 2,
|
||||
VPX_IMG_FMT_VPXYV12 = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_UV_FLIP | 3, /** < planar 4:2:0 format with vpx color space */
|
||||
VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4,
|
||||
VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5,
|
||||
VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6,
|
||||
VPX_IMG_FMT_I440 = VPX_IMG_FMT_PLANAR | 7,
|
||||
VPX_IMG_FMT_444A = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 6,
|
||||
VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH,
|
||||
VPX_IMG_FMT_I44016 = VPX_IMG_FMT_I440 | VPX_IMG_FMT_HIGHBITDEPTH
|
||||
} vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */
|
||||
|
||||
/*!\brief List of supported color spaces */
|
||||
typedef enum vpx_color_space {
|
||||
VPX_CS_UNKNOWN = 0, /**< Unknown */
|
||||
VPX_CS_BT_601 = 1, /**< BT.601 */
|
||||
VPX_CS_BT_709 = 2, /**< BT.709 */
|
||||
VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */
|
||||
VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */
|
||||
VPX_CS_BT_2020 = 5, /**< BT.2020 */
|
||||
VPX_CS_RESERVED = 6, /**< Reserved */
|
||||
VPX_CS_SRGB = 7 /**< sRGB */
|
||||
} vpx_color_space_t; /**< alias for enum vpx_color_space */
|
||||
|
||||
/**\brief Image Descriptor */
|
||||
typedef struct vpx_image {
|
||||
vpx_img_fmt_t fmt; /**< Image Format */
|
||||
vpx_color_space_t cs; /**< Color Space */
|
||||
|
||||
/* Image storage dimensions */
|
||||
unsigned int w; /**< Stored image width */
|
||||
unsigned int h; /**< Stored image height */
|
||||
unsigned int bit_depth; /**< Stored image bit-depth */
|
||||
|
||||
/* Image display dimensions */
|
||||
unsigned int d_w; /**< Displayed image width */
|
||||
unsigned int d_h; /**< Displayed image height */
|
||||
|
||||
/* Chroma subsampling info */
|
||||
unsigned int x_chroma_shift; /**< subsampling order, X */
|
||||
unsigned int y_chroma_shift; /**< subsampling order, Y */
|
||||
|
||||
/* Image data pointers. */
|
||||
#define VPX_PLANE_PACKED 0 /**< To be used for all packed formats */
|
||||
#define VPX_PLANE_Y 0 /**< Y (Luminance) plane */
|
||||
#define VPX_PLANE_U 1 /**< U (Chroma) plane */
|
||||
#define VPX_PLANE_V 2 /**< V (Chroma) plane */
|
||||
#define VPX_PLANE_ALPHA 3 /**< A (Transparency) plane */
|
||||
unsigned char *planes[4]; /**< pointer to the top left pixel for each plane */
|
||||
int stride[4]; /**< stride between rows for each plane */
|
||||
|
||||
int bps; /**< bits per sample (for packed formats) */
|
||||
|
||||
/* The following member may be set by the application to associate data
|
||||
* with this image.
|
||||
*/
|
||||
void *user_priv; /**< may be set by the application to associate data
|
||||
* with this image. */
|
||||
|
||||
/* The following members should be treated as private. */
|
||||
unsigned char *img_data; /**< private */
|
||||
int img_data_owner; /**< private */
|
||||
int self_allocd; /**< private */
|
||||
|
||||
void *fb_priv; /**< Frame buffer data associated with the image. */
|
||||
} vpx_image_t; /**< alias for struct vpx_image */
|
||||
|
||||
/**\brief Representation of a rectangle on a surface */
|
||||
typedef struct vpx_image_rect {
|
||||
unsigned int x; /**< leftmost column */
|
||||
unsigned int y; /**< topmost row */
|
||||
unsigned int w; /**< width */
|
||||
unsigned int h; /**< height */
|
||||
} vpx_image_rect_t; /**< alias for struct vpx_image_rect */
|
||||
|
||||
/*!\brief Open a descriptor, allocating storage for the underlying image
|
||||
*
|
||||
* Returns a descriptor for storing an image of the given format. The
|
||||
* storage for the descriptor is allocated on the heap.
|
||||
*
|
||||
* \param[in] img Pointer to storage for descriptor. If this parameter
|
||||
* is NULL, the storage for the descriptor will be
|
||||
* allocated on the heap.
|
||||
* \param[in] fmt Format for the image
|
||||
* \param[in] d_w Width of the image
|
||||
* \param[in] d_h Height of the image
|
||||
* \param[in] align Alignment, in bytes, of the image buffer and
|
||||
* each row in the image(stride).
|
||||
*
|
||||
* \return Returns a pointer to the initialized image descriptor. If the img
|
||||
* parameter is non-null, the value of the img parameter will be
|
||||
* returned.
|
||||
*/
|
||||
vpx_image_t *vpx_img_alloc(vpx_image_t *img,
|
||||
vpx_img_fmt_t fmt,
|
||||
unsigned int d_w,
|
||||
unsigned int d_h,
|
||||
unsigned int align);
|
||||
|
||||
/*!\brief Open a descriptor, using existing storage for the underlying image
|
||||
*
|
||||
* Returns a descriptor for storing an image of the given format. The
|
||||
* storage for descriptor has been allocated elsewhere, and a descriptor is
|
||||
* desired to "wrap" that storage.
|
||||
*
|
||||
* \param[in] img Pointer to storage for descriptor. If this parameter
|
||||
* is NULL, the storage for the descriptor will be
|
||||
* allocated on the heap.
|
||||
* \param[in] fmt Format for the image
|
||||
* \param[in] d_w Width of the image
|
||||
* \param[in] d_h Height of the image
|
||||
* \param[in] align Alignment, in bytes, of each row in the image.
|
||||
* \param[in] img_data Storage to use for the image
|
||||
*
|
||||
* \return Returns a pointer to the initialized image descriptor. If the img
|
||||
* parameter is non-null, the value of the img parameter will be
|
||||
* returned.
|
||||
*/
|
||||
vpx_image_t *vpx_img_wrap(vpx_image_t *img,
|
||||
vpx_img_fmt_t fmt,
|
||||
unsigned int d_w,
|
||||
unsigned int d_h,
|
||||
unsigned int align,
|
||||
unsigned char *img_data);
|
||||
|
||||
|
||||
/*!\brief Set the rectangle identifying the displayed portion of the image
|
||||
*
|
||||
* Updates the displayed rectangle (aka viewport) on the image surface to
|
||||
* match the specified coordinates and size.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
* \param[in] x leftmost column
|
||||
* \param[in] y topmost row
|
||||
* \param[in] w width
|
||||
* \param[in] h height
|
||||
*
|
||||
* \return 0 if the requested rectangle is valid, nonzero otherwise.
|
||||
*/
|
||||
int vpx_img_set_rect(vpx_image_t *img,
|
||||
unsigned int x,
|
||||
unsigned int y,
|
||||
unsigned int w,
|
||||
unsigned int h);
|
||||
|
||||
|
||||
/*!\brief Flip the image vertically (top for bottom)
|
||||
*
|
||||
* Adjusts the image descriptor's pointers and strides to make the image
|
||||
* be referenced upside-down.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
*/
|
||||
void vpx_img_flip(vpx_image_t *img);
|
||||
|
||||
/*!\brief Close an image descriptor
|
||||
*
|
||||
* Frees all allocated storage associated with an image descriptor.
|
||||
*
|
||||
* \param[in] img Image descriptor
|
||||
*/
|
||||
void vpx_img_free(vpx_image_t *img);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_IMAGE_H_
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VPX_VPX_INTEGER_H_
|
||||
#define VPX_VPX_INTEGER_H_
|
||||
|
||||
/* get ptrdiff_t, size_t, wchar_t, NULL */
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define VPX_FORCE_INLINE __forceinline
|
||||
#define VPX_INLINE __inline
|
||||
#else
|
||||
#define VPX_FORCE_INLINE __inline__ __attribute__(always_inline)
|
||||
// TODO(jbb): Allow a way to force inline off for older compilers.
|
||||
#define VPX_INLINE inline
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600)) || defined(VPX_EMULATE_INTTYPES)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT32_MIN _I32_MIN
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT16_MIN _I16_MIN
|
||||
#endif
|
||||
|
||||
#ifndef _UINTPTR_T_DEFINED
|
||||
typedef size_t uintptr_t;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* Most platforms have the C99 standard integer types. */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# if !defined(__STDC_FORMAT_MACROS)
|
||||
# define __STDC_FORMAT_MACROS
|
||||
# endif
|
||||
# if !defined(__STDC_LIMIT_MACROS)
|
||||
# define __STDC_LIMIT_MACROS
|
||||
# endif
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
||||
|
||||
/* VS2010 defines stdint.h, but not inttypes.h */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#define PRId64 "I64d"
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#endif // VPX_VPX_INTEGER_H_
|
||||
@@ -0,0 +1,7 @@
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 4
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_EXTRA ""
|
||||
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||
#define VERSION_STRING_NOSP "v1.4.0"
|
||||
#define VERSION_STRING " v1.4.0"
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2011 The WebM project authors. All Rights Reserved. */
|
||||
/* */
|
||||
/* Use of this source code is governed by a BSD-style license */
|
||||
/* that can be found in the LICENSE file in the root of the source */
|
||||
/* tree. An additional intellectual property rights grant can be found */
|
||||
/* in the file PATENTS. All contributing project authors may */
|
||||
/* be found in the AUTHORS file in the root of the source tree. */
|
||||
/* This file automatically generated by configure. Do not edit! */
|
||||
#ifndef VPX_CONFIG_H
|
||||
#define VPX_CONFIG_H
|
||||
#define RESTRICT
|
||||
#define INLINE inline
|
||||
#define ARCH_ARM 0
|
||||
#define ARCH_MIPS 0
|
||||
#define ARCH_X86 0
|
||||
#define ARCH_X86_64 1
|
||||
#define ARCH_PPC32 0
|
||||
#define ARCH_PPC64 0
|
||||
#define HAVE_EDSP 0
|
||||
#define HAVE_MEDIA 0
|
||||
#define HAVE_NEON 0
|
||||
#define HAVE_NEON_ASM 0
|
||||
#define HAVE_MIPS32 0
|
||||
#define HAVE_DSPR2 0
|
||||
#define HAVE_MIPS64 0
|
||||
#define HAVE_MMX 1
|
||||
#define HAVE_SSE 1
|
||||
#define HAVE_SSE2 1
|
||||
#define HAVE_SSE3 1
|
||||
#define HAVE_SSSE3 1
|
||||
#define HAVE_SSE4_1 1
|
||||
#define HAVE_AVX 1
|
||||
#define HAVE_AVX2 1
|
||||
#define HAVE_ALTIVEC 0
|
||||
#define HAVE_VPX_PORTS 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_ALT_TREE_LAYOUT 0
|
||||
#define HAVE_PTHREAD_H 1
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define CONFIG_DEPENDENCY_TRACKING 1
|
||||
#define CONFIG_EXTERNAL_BUILD 0
|
||||
#define CONFIG_INSTALL_DOCS 1
|
||||
#define CONFIG_INSTALL_BINS 1
|
||||
#define CONFIG_INSTALL_LIBS 1
|
||||
#define CONFIG_INSTALL_SRCS 0
|
||||
#define CONFIG_USE_X86INC 1
|
||||
#define CONFIG_DEBUG 0
|
||||
#define CONFIG_GPROF 0
|
||||
#define CONFIG_GCOV 0
|
||||
#define CONFIG_RVCT 0
|
||||
#define CONFIG_GCC 1
|
||||
#define CONFIG_MSVS 0
|
||||
#define CONFIG_PIC 0
|
||||
#define CONFIG_BIG_ENDIAN 0
|
||||
#define CONFIG_CODEC_SRCS 0
|
||||
#define CONFIG_DEBUG_LIBS 0
|
||||
#define CONFIG_FAST_UNALIGNED 1
|
||||
#define CONFIG_MEM_MANAGER 0
|
||||
#define CONFIG_MEM_TRACKER 0
|
||||
#define CONFIG_MEM_CHECKS 0
|
||||
#define CONFIG_DEQUANT_TOKENS 0
|
||||
#define CONFIG_DC_RECON 0
|
||||
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||
#define CONFIG_POSTPROC 1
|
||||
#define CONFIG_VP9_POSTPROC 0
|
||||
#define CONFIG_MULTITHREAD 1
|
||||
#define CONFIG_INTERNAL_STATS 0
|
||||
#define CONFIG_VP8_ENCODER 1
|
||||
#define CONFIG_VP8_DECODER 1
|
||||
#define CONFIG_VP9_ENCODER 1
|
||||
#define CONFIG_VP9_DECODER 1
|
||||
#define CONFIG_VP8 1
|
||||
#define CONFIG_VP9 1
|
||||
#define CONFIG_ENCODERS 1
|
||||
#define CONFIG_DECODERS 1
|
||||
#define CONFIG_STATIC_MSVCRT 0
|
||||
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||
#define CONFIG_REALTIME_ONLY 0
|
||||
#define CONFIG_ONTHEFLY_BITPACKING 0
|
||||
#define CONFIG_ERROR_CONCEALMENT 0
|
||||
#define CONFIG_SHARED 0
|
||||
#define CONFIG_STATIC 1
|
||||
#define CONFIG_SMALL 0
|
||||
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||
#define CONFIG_OS_SUPPORT 1
|
||||
#define CONFIG_UNIT_TESTS 0
|
||||
#define CONFIG_WEBM_IO 1
|
||||
#define CONFIG_LIBYUV 0
|
||||
#define CONFIG_DECODE_PERF_TESTS 0
|
||||
#define CONFIG_ENCODE_PERF_TESTS 0
|
||||
#define CONFIG_MULTI_RES_ENCODING 0
|
||||
#define CONFIG_TEMPORAL_DENOISING 1
|
||||
#define CONFIG_VP9_TEMPORAL_DENOISING 0
|
||||
#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
|
||||
#define CONFIG_VP9_HIGHBITDEPTH 0
|
||||
#define CONFIG_EXPERIMENTAL 0
|
||||
#define CONFIG_SIZE_LIMIT 0
|
||||
#define CONFIG_SPATIAL_SVC 0
|
||||
#define CONFIG_FP_MB_STATS 0
|
||||
#define CONFIG_EMULATE_HARDWARE 0
|
||||
#endif /* VPX_CONFIG_H */
|
||||
BIN
local_pod_repo/toxcore/osx/vpx.framework/vpx
Normal file
BIN
local_pod_repo/toxcore/osx/vpx.framework/vpx
Normal file
Binary file not shown.
43
local_pod_repo/toxcore/toxcore.podspec
Normal file
43
local_pod_repo/toxcore/toxcore.podspec
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# Be sure to run `pod lib lint toxcore.podspec' to ensure this is a
|
||||
# valid spec and remove all comments before submitting the spec.
|
||||
#
|
||||
# Any lines starting with a # are optional, but encouraged
|
||||
#
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
|
||||
#
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "toxcore"
|
||||
s.version = "0.2.18"
|
||||
s.summary = "Cocoapods wrapper for toxcore"
|
||||
s.homepage = "https://github.com/Zoxcore/toxcore"
|
||||
s.license = 'GPLv3'
|
||||
s.author = { "Dmytro Vorobiov" => "d@dvor.me" }
|
||||
s.source = {
|
||||
:git => "https://github.com/Zoxcore/toxcore.git",
|
||||
:tag => s.version.to_s,
|
||||
:submodules => true
|
||||
}
|
||||
|
||||
s.pod_target_xcconfig = { 'ENABLE_BITCODE' => 'NO', 'OTHER_LDFLAGS' => '-read_only_relocs suppress' }
|
||||
|
||||
s.ios.deployment_target = '7.0'
|
||||
s.osx.deployment_target = '10.9'
|
||||
s.requires_arc = true
|
||||
|
||||
# Preserve the layout of headers in the toxcore directory
|
||||
s.header_mappings_dir = 'toxcore'
|
||||
|
||||
s.source_files = 'toxcore/toxcore/*.{m,h}', 'toxcore/toxencryptsave/*.{m,h}', 'toxcore/toxav/*.{m,h}', 'toxcore/toxcore/events/*.{m,h}'
|
||||
|
||||
# s.dependency 'libopus-patched-config', '1.1'
|
||||
s.dependency 'libopus-static', '1.3.1'
|
||||
s.dependency 'libsodium', '~> 1.0.12'
|
||||
# s.dependency 'msgpack-c'
|
||||
|
||||
s.ios.vendored_frameworks = 'ios/vpx.framework'
|
||||
s.osx.vendored_frameworks = 'osx/vpx.framework'
|
||||
s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"${PODS_ROOT}"'}
|
||||
|
||||
end
|
||||
50
local_pod_repo/toxcore/toxcore/toxav/Makefile.inc
Normal file
50
local_pod_repo/toxcore/toxcore/toxav/Makefile.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
if BUILD_AV
|
||||
|
||||
lib_LTLIBRARIES += libtoxav.la
|
||||
libtoxav_la_include_HEADERS = ../toxav/toxav.h
|
||||
libtoxav_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxav_la_SOURCES = ../toxav/rtp.h \
|
||||
../toxav/rtp.c \
|
||||
../toxav/msi.h \
|
||||
../toxav/msi.c \
|
||||
../toxav/groupav.h \
|
||||
../toxav/groupav.c \
|
||||
../toxav/audio.h \
|
||||
../toxav/audio.c \
|
||||
../toxav/video.h \
|
||||
../toxav/video.c \
|
||||
../toxav/bwcontroller.h \
|
||||
../toxav/bwcontroller.c \
|
||||
../toxav/ring_buffer.h \
|
||||
../toxav/ring_buffer.c \
|
||||
../toxav/toxav.h \
|
||||
../toxav/toxav.c \
|
||||
../toxav/toxav_old.c
|
||||
|
||||
libtoxav_la_CFLAGS = -I../toxcore \
|
||||
-I../toxav \
|
||||
$(LIBSODIUM_CFLAGS) \
|
||||
$(NACL_CFLAGS) \
|
||||
$(AV_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS)
|
||||
|
||||
libtoxav_la_LDFLAGS = $(LT_LDFLAGS) \
|
||||
$(LIBSODIUM_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS) \
|
||||
$(WINSOCK2_LIBS)
|
||||
|
||||
libtoxav_la_LIBADD = libtoxcore.la \
|
||||
$(LIBSODIUM_LIBS) \
|
||||
$(NACL_LIBS) \
|
||||
$(PTHREAD_LIBS) \
|
||||
$(AV_LIBS)
|
||||
|
||||
if SET_SO_VERSION
|
||||
|
||||
EXTRA_libtoxav_la_DEPENDENCIES = ../so.version
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
73
local_pod_repo/toxcore/toxcore/toxav/audio.h
Normal file
73
local_pod_repo/toxcore/toxcore/toxav/audio.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_AUDIO_H
|
||||
#define C_TOXCORE_TOXAV_AUDIO_H
|
||||
|
||||
#include "opus.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include "toxav.h"
|
||||
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "rtp.h"
|
||||
|
||||
#define AUDIO_JITTERBUFFER_COUNT 3
|
||||
#define AUDIO_MAX_SAMPLE_RATE 48000
|
||||
#define AUDIO_MAX_CHANNEL_COUNT 2
|
||||
|
||||
#define AUDIO_START_SAMPLE_RATE 48000
|
||||
#define AUDIO_START_BITRATE 48000
|
||||
#define AUDIO_START_CHANNEL_COUNT 2
|
||||
#define AUDIO_OPUS_PACKET_LOSS_PERC 10
|
||||
#define AUDIO_OPUS_COMPLEXITY 10
|
||||
|
||||
#define AUDIO_DECODER_START_SAMPLE_RATE 48000
|
||||
#define AUDIO_DECODER_START_CHANNEL_COUNT 1
|
||||
|
||||
#define AUDIO_MAX_FRAME_DURATION_MS 120
|
||||
|
||||
// ((sampling_rate_in_hz * frame_duration_in_ms) / 1000) * 2 // because PCM16 needs 2 bytes for 1 sample
|
||||
// These are per frame and per channel.
|
||||
#define AUDIO_MAX_BUFFER_SIZE_PCM16 ((AUDIO_MAX_SAMPLE_RATE * AUDIO_MAX_FRAME_DURATION_MS) / 1000)
|
||||
#define AUDIO_MAX_BUFFER_SIZE_BYTES (AUDIO_MAX_BUFFER_SIZE_PCM16 * 2)
|
||||
|
||||
typedef struct ACSession {
|
||||
Mono_Time *mono_time;
|
||||
const Logger *log;
|
||||
|
||||
/* encoding */
|
||||
OpusEncoder *encoder;
|
||||
uint32_t le_sample_rate; /* Last encoder sample rate */
|
||||
uint8_t le_channel_count; /* Last encoder channel count */
|
||||
uint32_t le_bit_rate; /* Last encoder bit rate */
|
||||
|
||||
/* decoding */
|
||||
OpusDecoder *decoder;
|
||||
uint8_t lp_channel_count; /* Last packet channel count */
|
||||
uint32_t lp_sampling_rate; /* Last packet sample rate */
|
||||
uint32_t lp_frame_duration; /* Last packet frame duration */
|
||||
uint32_t ld_sample_rate; /* Last decoder sample rate */
|
||||
uint8_t ld_channel_count; /* Last decoder channel count */
|
||||
uint64_t ldrts; /* Last decoder reconfiguration time stamp */
|
||||
void *j_buf;
|
||||
|
||||
pthread_mutex_t queue_mutex[1];
|
||||
|
||||
ToxAV *av;
|
||||
uint32_t friend_number;
|
||||
/* Audio frame receive callback */
|
||||
toxav_audio_receive_frame_cb *acb;
|
||||
void *acb_user_data;
|
||||
} ACSession;
|
||||
|
||||
ACSession *ac_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number,
|
||||
toxav_audio_receive_frame_cb *cb, void *cb_data);
|
||||
void ac_kill(ACSession *ac);
|
||||
void ac_iterate(ACSession *ac);
|
||||
int ac_queue_message(Mono_Time *mono_time, void *acp, struct RTPMessage *msg);
|
||||
int ac_reconfigure_encoder(ACSession *ac, uint32_t bit_rate, uint32_t sampling_rate, uint8_t channels);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_AUDIO_H
|
||||
504
local_pod_repo/toxcore/toxcore/toxav/audio.m
Normal file
504
local_pod_repo/toxcore/toxcore/toxav/audio.m
Normal file
@@ -0,0 +1,504 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#include "audio.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rtp.h"
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
|
||||
static struct JitterBuffer *jbuf_new(uint32_t capacity);
|
||||
static void jbuf_clear(struct JitterBuffer *q);
|
||||
static void jbuf_free(struct JitterBuffer *q);
|
||||
static int jbuf_write(const Logger *log, struct JitterBuffer *q, struct RTPMessage *m);
|
||||
static struct RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
|
||||
static OpusEncoder *create_audio_encoder(const Logger *log, uint32_t bit_rate, uint32_t sampling_rate,
|
||||
uint8_t channel_count);
|
||||
static bool reconfigure_audio_encoder(const Logger *log, OpusEncoder **e, uint32_t new_br, uint32_t new_sr,
|
||||
uint8_t new_ch, uint32_t *old_br, uint32_t *old_sr, uint8_t *old_ch);
|
||||
static bool reconfigure_audio_decoder(ACSession *ac, uint32_t sampling_rate, uint8_t channels);
|
||||
|
||||
|
||||
|
||||
ACSession *ac_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number,
|
||||
toxav_audio_receive_frame_cb *cb, void *cb_data)
|
||||
{
|
||||
ACSession *ac = (ACSession *)calloc(1, sizeof(ACSession));
|
||||
|
||||
if (ac == nullptr) {
|
||||
LOGGER_WARNING(log, "Allocation failed! Application might misbehave!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (create_recursive_mutex(ac->queue_mutex) != 0) {
|
||||
LOGGER_WARNING(log, "Failed to create recursive mutex!");
|
||||
free(ac);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int status;
|
||||
ac->decoder = opus_decoder_create(AUDIO_DECODER_START_SAMPLE_RATE, AUDIO_DECODER_START_CHANNEL_COUNT, &status);
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while starting audio decoder: %s", opus_strerror(status));
|
||||
goto BASE_CLEANUP;
|
||||
}
|
||||
|
||||
ac->j_buf = jbuf_new(AUDIO_JITTERBUFFER_COUNT);
|
||||
|
||||
if (ac->j_buf == nullptr) {
|
||||
LOGGER_WARNING(log, "Jitter buffer creaton failed!");
|
||||
opus_decoder_destroy(ac->decoder);
|
||||
goto BASE_CLEANUP;
|
||||
}
|
||||
|
||||
ac->mono_time = mono_time;
|
||||
ac->log = log;
|
||||
|
||||
/* Initialize encoders with default values */
|
||||
ac->encoder = create_audio_encoder(log, AUDIO_START_BITRATE, AUDIO_START_SAMPLE_RATE, AUDIO_START_CHANNEL_COUNT);
|
||||
|
||||
if (ac->encoder == nullptr) {
|
||||
goto DECODER_CLEANUP;
|
||||
}
|
||||
|
||||
ac->le_bit_rate = AUDIO_START_BITRATE;
|
||||
ac->le_sample_rate = AUDIO_START_SAMPLE_RATE;
|
||||
ac->le_channel_count = AUDIO_START_CHANNEL_COUNT;
|
||||
|
||||
ac->ld_channel_count = AUDIO_DECODER_START_CHANNEL_COUNT;
|
||||
ac->ld_sample_rate = AUDIO_DECODER_START_SAMPLE_RATE;
|
||||
ac->ldrts = 0; /* Make it possible to reconfigure straight away */
|
||||
|
||||
/* These need to be set in order to properly
|
||||
* do error correction with opus */
|
||||
ac->lp_frame_duration = AUDIO_MAX_FRAME_DURATION_MS;
|
||||
ac->lp_sampling_rate = AUDIO_DECODER_START_SAMPLE_RATE;
|
||||
ac->lp_channel_count = AUDIO_DECODER_START_CHANNEL_COUNT;
|
||||
|
||||
ac->av = av;
|
||||
ac->friend_number = friend_number;
|
||||
ac->acb = cb;
|
||||
ac->acb_user_data = cb_data;
|
||||
|
||||
return ac;
|
||||
|
||||
DECODER_CLEANUP:
|
||||
opus_decoder_destroy(ac->decoder);
|
||||
jbuf_free((struct JitterBuffer *)ac->j_buf);
|
||||
BASE_CLEANUP:
|
||||
pthread_mutex_destroy(ac->queue_mutex);
|
||||
free(ac);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ac_kill(ACSession *ac)
|
||||
{
|
||||
if (ac == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
opus_encoder_destroy(ac->encoder);
|
||||
opus_decoder_destroy(ac->decoder);
|
||||
jbuf_free((struct JitterBuffer *)ac->j_buf);
|
||||
|
||||
pthread_mutex_destroy(ac->queue_mutex);
|
||||
|
||||
LOGGER_DEBUG(ac->log, "Terminated audio handler: %p", (void *)ac);
|
||||
free(ac);
|
||||
}
|
||||
|
||||
void ac_iterate(ACSession *ac)
|
||||
{
|
||||
if (ac == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: fix this and jitter buffering */
|
||||
|
||||
/* Enough space for the maximum frame size (120 ms 48 KHz stereo audio) */
|
||||
int16_t *temp_audio_buffer = (int16_t *)malloc(AUDIO_MAX_BUFFER_SIZE_PCM16 * AUDIO_MAX_CHANNEL_COUNT * sizeof(int16_t));
|
||||
|
||||
if (temp_audio_buffer == nullptr) {
|
||||
LOGGER_ERROR(ac->log, "Failed to allocate memory for audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(ac->queue_mutex);
|
||||
struct JitterBuffer *const j_buf = (struct JitterBuffer *)ac->j_buf;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
for (struct RTPMessage *msg = jbuf_read(j_buf, &rc); msg != nullptr || rc == 2; msg = jbuf_read(j_buf, &rc)) {
|
||||
pthread_mutex_unlock(ac->queue_mutex);
|
||||
|
||||
if (rc == 2) {
|
||||
LOGGER_DEBUG(ac->log, "OPUS correction");
|
||||
const int fs = (ac->lp_sampling_rate * ac->lp_frame_duration) / 1000;
|
||||
rc = opus_decode(ac->decoder, nullptr, 0, temp_audio_buffer, fs, 1);
|
||||
} else {
|
||||
assert(msg->len > 4);
|
||||
|
||||
/* Pick up sampling rate from packet */
|
||||
memcpy(&ac->lp_sampling_rate, msg->data, 4);
|
||||
ac->lp_sampling_rate = net_ntohl(ac->lp_sampling_rate);
|
||||
|
||||
ac->lp_channel_count = opus_packet_get_nb_channels(msg->data + 4);
|
||||
|
||||
/* NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa,
|
||||
* it didn't work quite well.
|
||||
*/
|
||||
if (!reconfigure_audio_decoder(ac, ac->lp_sampling_rate, ac->lp_channel_count)) {
|
||||
LOGGER_WARNING(ac->log, "Failed to reconfigure decoder!");
|
||||
free(msg);
|
||||
pthread_mutex_lock(ac->queue_mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
|
||||
* where
|
||||
* packet is the byte array containing the compressed data
|
||||
* len is the exact number of bytes contained in the packet
|
||||
* decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
|
||||
* max_size is the max duration of the frame in samples (per channel) that can fit
|
||||
* into the decoded_frame array
|
||||
*/
|
||||
rc = opus_decode(ac->decoder, msg->data + 4, msg->len - 4, temp_audio_buffer, 5760, 0);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
LOGGER_WARNING(ac->log, "Decoding error: %s", opus_strerror(rc));
|
||||
} else if (ac->acb != nullptr) {
|
||||
ac->lp_frame_duration = (rc * 1000) / ac->lp_sampling_rate;
|
||||
|
||||
ac->acb(ac->av, ac->friend_number, temp_audio_buffer, rc, ac->lp_channel_count,
|
||||
ac->lp_sampling_rate, ac->acb_user_data);
|
||||
}
|
||||
|
||||
free(temp_audio_buffer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(ac->queue_mutex);
|
||||
|
||||
free(temp_audio_buffer);
|
||||
}
|
||||
|
||||
int ac_queue_message(Mono_Time *mono_time, void *acp, struct RTPMessage *msg)
|
||||
{
|
||||
if (acp == nullptr || msg == nullptr) {
|
||||
free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ACSession *ac = (ACSession *)acp;
|
||||
|
||||
if ((msg->header.pt & 0x7f) == (RTP_TYPE_AUDIO + 2) % 128) {
|
||||
LOGGER_WARNING(ac->log, "Got dummy!");
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((msg->header.pt & 0x7f) != RTP_TYPE_AUDIO % 128) {
|
||||
LOGGER_WARNING(ac->log, "Invalid payload type!");
|
||||
free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(ac->queue_mutex);
|
||||
const int rc = jbuf_write(ac->log, (struct JitterBuffer *)ac->j_buf, msg);
|
||||
pthread_mutex_unlock(ac->queue_mutex);
|
||||
|
||||
if (rc == -1) {
|
||||
LOGGER_WARNING(ac->log, "Could not queue the message!");
|
||||
free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ac_reconfigure_encoder(ACSession *ac, uint32_t bit_rate, uint32_t sampling_rate, uint8_t channels)
|
||||
{
|
||||
if (ac == nullptr || !reconfigure_audio_encoder(
|
||||
ac->log, &ac->encoder, bit_rate,
|
||||
sampling_rate, channels,
|
||||
&ac->le_bit_rate,
|
||||
&ac->le_sample_rate,
|
||||
&ac->le_channel_count)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct JitterBuffer {
|
||||
struct RTPMessage **queue;
|
||||
uint32_t size;
|
||||
uint32_t capacity;
|
||||
uint16_t bottom;
|
||||
uint16_t top;
|
||||
};
|
||||
|
||||
static struct JitterBuffer *jbuf_new(uint32_t capacity)
|
||||
{
|
||||
unsigned int size = 1;
|
||||
|
||||
while (size <= (capacity * 4)) {
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
struct JitterBuffer *q = (struct JitterBuffer *)calloc(1, sizeof(struct JitterBuffer));
|
||||
|
||||
if (q == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
q->queue = (struct RTPMessage **)calloc(size, sizeof(struct RTPMessage *));
|
||||
|
||||
if (q->queue == nullptr) {
|
||||
free(q);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
q->size = size;
|
||||
q->capacity = capacity;
|
||||
return q;
|
||||
}
|
||||
static void jbuf_clear(struct JitterBuffer *q)
|
||||
{
|
||||
while (q->bottom != q->top) {
|
||||
free(q->queue[q->bottom % q->size]);
|
||||
q->queue[q->bottom % q->size] = nullptr;
|
||||
++q->bottom;
|
||||
}
|
||||
}
|
||||
static void jbuf_free(struct JitterBuffer *q)
|
||||
{
|
||||
if (q == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
jbuf_clear(q);
|
||||
free(q->queue);
|
||||
free(q);
|
||||
}
|
||||
static int jbuf_write(const Logger *log, struct JitterBuffer *q, struct RTPMessage *m)
|
||||
{
|
||||
const uint16_t sequnum = m->header.sequnum;
|
||||
|
||||
const unsigned int num = sequnum % q->size;
|
||||
|
||||
if ((uint32_t)(sequnum - q->bottom) > q->size) {
|
||||
LOGGER_DEBUG(log, "Clearing filled jitter buffer: %p", (void *)q);
|
||||
|
||||
jbuf_clear(q);
|
||||
q->bottom = sequnum - q->capacity;
|
||||
q->queue[num] = m;
|
||||
q->top = sequnum + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q->queue[num] != nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->queue[num] = m;
|
||||
|
||||
if ((sequnum - q->bottom) >= (q->top - q->bottom)) {
|
||||
q->top = sequnum + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static struct RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success)
|
||||
{
|
||||
if (q->top == q->bottom) {
|
||||
*success = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const unsigned int num = q->bottom % q->size;
|
||||
|
||||
if (q->queue[num] != nullptr) {
|
||||
struct RTPMessage *ret = q->queue[num];
|
||||
q->queue[num] = nullptr;
|
||||
++q->bottom;
|
||||
*success = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((uint32_t)(q->top - q->bottom) > q->capacity) {
|
||||
++q->bottom;
|
||||
*success = 2;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*success = 0;
|
||||
return nullptr;
|
||||
}
|
||||
static OpusEncoder *create_audio_encoder(const Logger *log, uint32_t bit_rate, uint32_t sampling_rate,
|
||||
uint8_t channel_count)
|
||||
{
|
||||
int status = OPUS_OK;
|
||||
/*
|
||||
* OPUS_APPLICATION_VOIP Process signal for improved speech intelligibility
|
||||
* OPUS_APPLICATION_AUDIO Favor faithfulness to the original input
|
||||
* OPUS_APPLICATION_RESTRICTED_LOWDELAY Configure the minimum possible coding delay
|
||||
*/
|
||||
OpusEncoder *rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_VOIP, &status);
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while starting audio encoder: %s", opus_strerror(status));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rates from 500 to 512000 bits per second are meaningful as well as the special
|
||||
* values OPUS_BITRATE_AUTO and OPUS_BITRATE_MAX. The value OPUS_BITRATE_MAX can
|
||||
* be used to cause the codec to use as much rate as it can, which is useful for
|
||||
* controlling the rate by adjusting the output buffer size.
|
||||
*
|
||||
* Parameters:
|
||||
* `[in]` `x` `opus_int32`: bitrate in bits per second.
|
||||
*/
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate));
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configures the encoder's use of inband forward error correction.
|
||||
* Note:
|
||||
* This is only applicable to the LPC layer
|
||||
* Parameters:
|
||||
* `[in]` `x` `int`: FEC flag, 0 (disabled) is default
|
||||
*/
|
||||
/* Enable in-band forward error correction in codec */
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_INBAND_FEC(1));
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configures the encoder's expected packet loss percentage.
|
||||
* Higher values with trigger progressively more loss resistant behavior in
|
||||
* the encoder at the expense of quality at a given bitrate in the lossless case,
|
||||
* but greater quality under loss.
|
||||
* Parameters:
|
||||
* `[in]` `x` `int`: Loss percentage in the range 0-100, inclusive.
|
||||
*/
|
||||
/* Make codec resistant to up to 10% packet loss
|
||||
* NOTE This could also be adjusted on the fly, rather than hard-coded,
|
||||
* with feedback from the receiving client.
|
||||
*/
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_PACKET_LOSS_PERC(AUDIO_OPUS_PACKET_LOSS_PERC));
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configures the encoder's computational complexity.
|
||||
*
|
||||
* The supported range is 0-10 inclusive with 10 representing the highest complexity.
|
||||
* The default value is 10.
|
||||
*
|
||||
* Parameters:
|
||||
* `[in]` `x` `int`: 0-10, inclusive
|
||||
*/
|
||||
/* Set algorithm to the highest complexity, maximizing compression */
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_COMPLEXITY(AUDIO_OPUS_COMPLEXITY));
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
FAILURE:
|
||||
opus_encoder_destroy(rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool reconfigure_audio_encoder(const Logger *log, OpusEncoder **e, uint32_t new_br, uint32_t new_sr,
|
||||
uint8_t new_ch, uint32_t *old_br, uint32_t *old_sr, uint8_t *old_ch)
|
||||
{
|
||||
/* Values are checked in toxav.c */
|
||||
if (*old_sr != new_sr || *old_ch != new_ch) {
|
||||
OpusEncoder *new_encoder = create_audio_encoder(log, new_br, new_sr, new_ch);
|
||||
|
||||
if (new_encoder == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
opus_encoder_destroy(*e);
|
||||
*e = new_encoder;
|
||||
} else if (*old_br == new_br) {
|
||||
return true; /* Nothing changed */
|
||||
}
|
||||
|
||||
const int status = opus_encoder_ctl(*e, OPUS_SET_BITRATE(new_br));
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
*old_br = new_br;
|
||||
*old_sr = new_sr;
|
||||
*old_ch = new_ch;
|
||||
|
||||
LOGGER_DEBUG(log, "Reconfigured audio encoder br: %d sr: %d cc:%d", new_br, new_sr, new_ch);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reconfigure_audio_decoder(ACSession *ac, uint32_t sampling_rate, uint8_t channels)
|
||||
{
|
||||
if (sampling_rate != ac->ld_sample_rate || channels != ac->ld_channel_count) {
|
||||
if (current_time_monotonic(ac->mono_time) - ac->ldrts < 500) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status;
|
||||
OpusDecoder *new_dec = opus_decoder_create(sampling_rate, channels, &status);
|
||||
|
||||
if (status != OPUS_OK) {
|
||||
LOGGER_ERROR(ac->log, "Error while starting audio decoder(%d %d): %s", sampling_rate, channels, opus_strerror(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
ac->ld_sample_rate = sampling_rate;
|
||||
ac->ld_channel_count = channels;
|
||||
ac->ldrts = current_time_monotonic(ac->mono_time);
|
||||
|
||||
opus_decoder_destroy(ac->decoder);
|
||||
ac->decoder = new_dec;
|
||||
|
||||
LOGGER_DEBUG(ac->log, "Reconfigured audio decoder sr: %d cc: %d", sampling_rate, channels);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
23
local_pod_repo/toxcore/toxcore/toxav/bwcontroller.h
Normal file
23
local_pod_repo/toxcore/toxcore/toxav/bwcontroller.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_BWCONTROLLER_H
|
||||
#define C_TOXCORE_TOXAV_BWCONTROLLER_H
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
typedef struct BWController BWController;
|
||||
|
||||
typedef void m_cb(BWController *bwc, uint32_t friend_number, float todo, void *user_data);
|
||||
|
||||
BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data,
|
||||
Mono_Time *bwc_mono_time);
|
||||
|
||||
void bwc_kill(BWController *bwc);
|
||||
|
||||
void bwc_add_lost(BWController *bwc, uint32_t bytes_lost);
|
||||
void bwc_add_recv(BWController *bwc, uint32_t recv_bytes);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_BWCONTROLLER_H
|
||||
222
local_pod_repo/toxcore/toxcore/toxav/bwcontroller.m
Normal file
222
local_pod_repo/toxcore/toxcore/toxav/bwcontroller.m
Normal file
@@ -0,0 +1,222 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#include "bwcontroller.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ring_buffer.h"
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
#define BWC_PACKET_ID 196
|
||||
#define BWC_SEND_INTERVAL_MS 950 // 0.95s
|
||||
#define BWC_AVG_PKT_COUNT 20
|
||||
#define BWC_AVG_LOSS_OVER_CYCLES_COUNT 30
|
||||
|
||||
typedef struct BWCCycle {
|
||||
uint32_t last_recv_timestamp; /* Last recv update time stamp */
|
||||
uint32_t last_sent_timestamp; /* Last sent update time stamp */
|
||||
uint32_t last_refresh_timestamp; /* Last refresh time stamp */
|
||||
|
||||
uint32_t lost;
|
||||
uint32_t recv;
|
||||
} BWCCycle;
|
||||
|
||||
typedef struct BWCRcvPkt {
|
||||
uint32_t packet_length_array[BWC_AVG_PKT_COUNT];
|
||||
RingBuffer *rb;
|
||||
} BWCRcvPkt;
|
||||
|
||||
struct BWController {
|
||||
m_cb *mcb;
|
||||
void *mcb_user_data;
|
||||
|
||||
Messenger *m;
|
||||
Tox *tox;
|
||||
uint32_t friend_number;
|
||||
|
||||
BWCCycle cycle;
|
||||
|
||||
BWCRcvPkt rcvpkt; /* To calculate average received packet (this means split parts, not the full message!) */
|
||||
|
||||
uint32_t packet_loss_counted_cycles;
|
||||
Mono_Time *bwc_mono_time;
|
||||
};
|
||||
|
||||
struct BWCMessage {
|
||||
uint32_t lost;
|
||||
uint32_t recv;
|
||||
};
|
||||
|
||||
static int bwc_handle_data(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object);
|
||||
static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length);
|
||||
static void send_update(BWController *bwc);
|
||||
|
||||
BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data,
|
||||
Mono_Time *bwc_mono_time)
|
||||
{
|
||||
BWController *retu = (BWController *)calloc(1, sizeof(BWController));
|
||||
|
||||
if (retu == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(m->log, "Creating bandwidth controller");
|
||||
retu->mcb = mcb;
|
||||
retu->mcb_user_data = mcb_user_data;
|
||||
retu->m = m;
|
||||
retu->friend_number = friendnumber;
|
||||
retu->bwc_mono_time = bwc_mono_time;
|
||||
const uint64_t now = current_time_monotonic(bwc_mono_time);
|
||||
retu->cycle.last_sent_timestamp = now;
|
||||
retu->cycle.last_refresh_timestamp = now;
|
||||
retu->tox = tox;
|
||||
retu->rcvpkt.rb = rb_new(BWC_AVG_PKT_COUNT);
|
||||
retu->cycle.lost = 0;
|
||||
retu->cycle.recv = 0;
|
||||
retu->packet_loss_counted_cycles = 0;
|
||||
|
||||
/* Fill with zeros */
|
||||
for (int i = 0; i < BWC_AVG_PKT_COUNT; ++i) {
|
||||
rb_write(retu->rcvpkt.rb, &retu->rcvpkt.packet_length_array[i]);
|
||||
}
|
||||
|
||||
m_callback_rtp_packet(m, friendnumber, BWC_PACKET_ID, bwc_handle_data, retu);
|
||||
return retu;
|
||||
}
|
||||
|
||||
void bwc_kill(BWController *bwc)
|
||||
{
|
||||
if (bwc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_callback_rtp_packet(bwc->m, bwc->friend_number, BWC_PACKET_ID, nullptr, nullptr);
|
||||
rb_kill(bwc->rcvpkt.rb);
|
||||
free(bwc);
|
||||
}
|
||||
|
||||
void bwc_add_lost(BWController *bwc, uint32_t bytes_lost)
|
||||
{
|
||||
if (bwc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_lost > 0) {
|
||||
LOGGER_DEBUG(bwc->m->log, "BWC lost(1): %d", (int)bytes_lost);
|
||||
bwc->cycle.lost += bytes_lost;
|
||||
send_update(bwc);
|
||||
}
|
||||
}
|
||||
|
||||
void bwc_add_recv(BWController *bwc, uint32_t recv_bytes)
|
||||
{
|
||||
if (bwc == nullptr || recv_bytes == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
++bwc->packet_loss_counted_cycles;
|
||||
bwc->cycle.recv += recv_bytes;
|
||||
send_update(bwc);
|
||||
}
|
||||
|
||||
static void send_update(BWController *bwc)
|
||||
{
|
||||
if (bwc->packet_loss_counted_cycles > BWC_AVG_LOSS_OVER_CYCLES_COUNT &&
|
||||
current_time_monotonic(bwc->bwc_mono_time) - bwc->cycle.last_sent_timestamp > BWC_SEND_INTERVAL_MS) {
|
||||
bwc->packet_loss_counted_cycles = 0;
|
||||
|
||||
if (bwc->cycle.lost != 0) {
|
||||
LOGGER_DEBUG(bwc->m->log, "%p Sent update rcv: %u lost: %u percent: %f %%",
|
||||
(void *)bwc, bwc->cycle.recv, bwc->cycle.lost,
|
||||
((double)bwc->cycle.lost / (bwc->cycle.recv + bwc->cycle.lost)) * 100.0);
|
||||
uint8_t bwc_packet[sizeof(struct BWCMessage) + 1];
|
||||
size_t offset = 0;
|
||||
|
||||
bwc_packet[offset] = BWC_PACKET_ID; // set packet ID
|
||||
++offset;
|
||||
|
||||
offset += net_pack_u32(bwc_packet + offset, bwc->cycle.lost);
|
||||
offset += net_pack_u32(bwc_packet + offset, bwc->cycle.recv);
|
||||
assert(offset == sizeof(bwc_packet));
|
||||
|
||||
if (bwc_send_custom_lossy_packet(bwc->tox, bwc->friend_number, bwc_packet, sizeof(bwc_packet)) == -1) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
char *stdstrerror = net_new_strerror(errno);
|
||||
LOGGER_WARNING(bwc->m->log, "BWC send failed (len: %u)! std error: %s, net error %s",
|
||||
(unsigned)sizeof(bwc_packet), stdstrerror, netstrerror);
|
||||
net_kill_strerror(stdstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
}
|
||||
|
||||
bwc->cycle.last_sent_timestamp = current_time_monotonic(bwc->bwc_mono_time);
|
||||
bwc->cycle.lost = 0;
|
||||
bwc->cycle.recv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int on_update(BWController *bwc, const struct BWCMessage *msg)
|
||||
{
|
||||
LOGGER_DEBUG(bwc->m->log, "%p Got update from peer", (void *)bwc);
|
||||
|
||||
/* Peers sent update too soon */
|
||||
if (bwc->cycle.last_recv_timestamp + BWC_SEND_INTERVAL_MS > current_time_monotonic(bwc->bwc_mono_time)) {
|
||||
LOGGER_INFO(bwc->m->log, "%p Rejecting extra update", (void *)bwc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bwc->cycle.last_recv_timestamp = current_time_monotonic(bwc->bwc_mono_time);
|
||||
|
||||
const uint32_t lost = msg->lost;
|
||||
|
||||
if (lost != 0 && bwc->mcb != nullptr) {
|
||||
const uint32_t recv = msg->recv;
|
||||
LOGGER_DEBUG(bwc->m->log, "recved: %u lost: %u percentage: %f %%", recv, lost,
|
||||
((double)lost / (recv + lost)) * 100.0);
|
||||
bwc->mcb(bwc, bwc->friend_number,
|
||||
(float)lost / (recv + lost),
|
||||
bwc->mcb_user_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* return -1 on failure, 0 on success
|
||||
*
|
||||
*/
|
||||
static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
Tox_Err_Friend_Custom_Packet error;
|
||||
tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error);
|
||||
|
||||
if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bwc_handle_data(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object)
|
||||
{
|
||||
if (length - 1 != sizeof(struct BWCMessage)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t offset = 1; // Ignore packet id.
|
||||
struct BWCMessage msg;
|
||||
offset += net_unpack_u32(data + offset, &msg.lost);
|
||||
offset += net_unpack_u32(data + offset, &msg.recv);
|
||||
assert(offset == length);
|
||||
|
||||
return on_update((BWController *)object, &msg);
|
||||
}
|
||||
64
local_pod_repo/toxcore/toxcore/toxav/groupav.h
Normal file
64
local_pod_repo/toxcore/toxcore/toxav/groupav.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_GROUPAV_H
|
||||
#define C_TOXCORE_TOXAV_GROUPAV_H
|
||||
|
||||
// Audio encoding/decoding
|
||||
#include "opus.h"
|
||||
|
||||
#include "../toxcore/group.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#define GROUP_AUDIO_PACKET_ID 192
|
||||
|
||||
// TODO(iphydf): Use this better typed one instead of the void-pointer one below.
|
||||
// typedef void audio_data_cb(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
|
||||
// uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata);
|
||||
typedef void audio_data_cb(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
|
||||
uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata);
|
||||
|
||||
/** @brief Create and connect to a new toxav group.
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int add_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/** @brief Join a AV group (you need to have been invited first).
|
||||
*
|
||||
* @return group number on success
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int join_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t friendnumber, const uint8_t *data,
|
||||
uint16_t length, audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
|
||||
/** @brief Send audio to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
/** @brief Enable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
|
||||
audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/** @brief Disable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int groupchat_disable_av(const Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
/** Return whether A/V is enabled in the groupchat. */
|
||||
bool groupchat_av_enabled(const Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_GROUPAV_H
|
||||
657
local_pod_repo/toxcore/toxcore/toxav/groupav.m
Normal file
657
local_pod_repo/toxcore/toxcore/toxav/groupav.m
Normal file
@@ -0,0 +1,657 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
#include "groupav.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "../toxcore/tox_struct.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
#define GROUP_JBUF_SIZE 6
|
||||
#define GROUP_JBUF_DEAD_SECONDS 4
|
||||
|
||||
typedef struct Group_Audio_Packet {
|
||||
uint16_t sequnum;
|
||||
uint16_t length;
|
||||
uint8_t *data;
|
||||
} Group_Audio_Packet;
|
||||
|
||||
typedef struct Group_JitterBuffer {
|
||||
Group_Audio_Packet **queue;
|
||||
uint32_t size;
|
||||
uint32_t capacity;
|
||||
uint16_t bottom;
|
||||
uint16_t top;
|
||||
uint64_t last_queued_time;
|
||||
} Group_JitterBuffer;
|
||||
|
||||
static void free_audio_packet(Group_Audio_Packet *pk)
|
||||
{
|
||||
if (pk == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(pk->data);
|
||||
free(pk);
|
||||
}
|
||||
|
||||
static Group_JitterBuffer *create_queue(unsigned int capacity)
|
||||
{
|
||||
unsigned int size = 1;
|
||||
|
||||
while (size <= capacity) {
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
Group_JitterBuffer *q = (Group_JitterBuffer *)calloc(1, sizeof(Group_JitterBuffer));
|
||||
|
||||
if (q == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
q->queue = (Group_Audio_Packet **)calloc(size, sizeof(Group_Audio_Packet *));
|
||||
|
||||
if (q->queue == nullptr) {
|
||||
free(q);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
q->size = size;
|
||||
q->capacity = capacity;
|
||||
return q;
|
||||
}
|
||||
|
||||
static void clear_queue(Group_JitterBuffer *q)
|
||||
{
|
||||
while (q->bottom != q->top) {
|
||||
const size_t idx = q->bottom % q->size;
|
||||
free_audio_packet(q->queue[idx]);
|
||||
q->queue[idx] = nullptr;
|
||||
++q->bottom;
|
||||
}
|
||||
}
|
||||
|
||||
static void terminate_queue(Group_JitterBuffer *q)
|
||||
{
|
||||
if (q == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
clear_queue(q);
|
||||
free(q->queue);
|
||||
free(q);
|
||||
}
|
||||
|
||||
/** @retval 0 if packet was queued
|
||||
* @retval -1 if it wasn't.
|
||||
*/
|
||||
static int queue(Group_JitterBuffer *q, const Mono_Time *mono_time, Group_Audio_Packet *pk)
|
||||
{
|
||||
const uint16_t sequnum = pk->sequnum;
|
||||
|
||||
const unsigned int num = sequnum % q->size;
|
||||
|
||||
if (!mono_time_is_timeout(mono_time, q->last_queued_time, GROUP_JBUF_DEAD_SECONDS)) {
|
||||
if ((uint32_t)(sequnum - q->bottom) > (1 << 15)) {
|
||||
/* Drop old packet. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((uint32_t)(sequnum - q->bottom) > q->size) {
|
||||
clear_queue(q);
|
||||
q->bottom = sequnum - q->capacity;
|
||||
q->queue[num] = pk;
|
||||
q->top = sequnum + 1;
|
||||
q->last_queued_time = mono_time_get(mono_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q->queue[num] != nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->queue[num] = pk;
|
||||
|
||||
if ((sequnum - q->bottom) >= (q->top - q->bottom)) {
|
||||
q->top = sequnum + 1;
|
||||
}
|
||||
|
||||
q->last_queued_time = mono_time_get(mono_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* success is:
|
||||
* - 0 when there is nothing to dequeue
|
||||
* - 1 when there's a good packet
|
||||
* - 2 when there's a lost packet
|
||||
*/
|
||||
static Group_Audio_Packet *dequeue(Group_JitterBuffer *q, int *success)
|
||||
{
|
||||
if (q->top == q->bottom) {
|
||||
*success = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const unsigned int num = q->bottom % q->size;
|
||||
|
||||
if (q->queue[num] != nullptr) {
|
||||
Group_Audio_Packet *ret = q->queue[num];
|
||||
q->queue[num] = nullptr;
|
||||
++q->bottom;
|
||||
*success = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((uint32_t)(q->top - q->bottom) > q->capacity) {
|
||||
++q->bottom;
|
||||
*success = 2;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*success = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef struct Group_AV {
|
||||
const Logger *log;
|
||||
Tox *tox;
|
||||
Group_Chats *g_c;
|
||||
OpusEncoder *audio_encoder;
|
||||
|
||||
unsigned int audio_channels;
|
||||
unsigned int audio_sample_rate;
|
||||
unsigned int audio_bitrate;
|
||||
|
||||
uint16_t audio_sequnum;
|
||||
|
||||
audio_data_cb *audio_data;
|
||||
void *userdata;
|
||||
} Group_AV;
|
||||
|
||||
typedef struct Group_Peer_AV {
|
||||
const Mono_Time *mono_time;
|
||||
Group_JitterBuffer *buffer;
|
||||
|
||||
OpusDecoder *audio_decoder;
|
||||
int decoder_channels;
|
||||
unsigned int last_packet_samples;
|
||||
} Group_Peer_AV;
|
||||
|
||||
static void kill_group_av(Group_AV *group_av)
|
||||
{
|
||||
if (group_av->audio_encoder != nullptr) {
|
||||
opus_encoder_destroy(group_av->audio_encoder);
|
||||
}
|
||||
|
||||
free(group_av);
|
||||
}
|
||||
|
||||
static int recreate_encoder(Group_AV *group_av)
|
||||
{
|
||||
if (group_av->audio_encoder != nullptr) {
|
||||
opus_encoder_destroy(group_av->audio_encoder);
|
||||
group_av->audio_encoder = nullptr;
|
||||
}
|
||||
|
||||
int rc = OPUS_OK;
|
||||
group_av->audio_encoder = opus_encoder_create(group_av->audio_sample_rate, group_av->audio_channels,
|
||||
OPUS_APPLICATION_AUDIO, &rc);
|
||||
|
||||
if (rc != OPUS_OK) {
|
||||
LOGGER_ERROR(group_av->log, "Error while starting audio encoder: %s", opus_strerror(rc));
|
||||
group_av->audio_encoder = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(group_av->audio_bitrate));
|
||||
|
||||
if (rc != OPUS_OK) {
|
||||
LOGGER_ERROR(group_av->log, "Error while setting encoder ctl: %s", opus_strerror(rc));
|
||||
opus_encoder_destroy(group_av->audio_encoder);
|
||||
group_av->audio_encoder = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_COMPLEXITY(10));
|
||||
|
||||
if (rc != OPUS_OK) {
|
||||
LOGGER_ERROR(group_av->log, "Error while setting encoder ctl: %s", opus_strerror(rc));
|
||||
opus_encoder_destroy(group_av->audio_encoder);
|
||||
group_av->audio_encoder = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Group_AV *new_group_av(const Logger *log, Tox *tox, Group_Chats *g_c, audio_data_cb *audio_callback,
|
||||
void *userdata)
|
||||
{
|
||||
if (g_c == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Group_AV *group_av = (Group_AV *)calloc(1, sizeof(Group_AV));
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
group_av->log = log;
|
||||
group_av->tox = tox;
|
||||
group_av->g_c = g_c;
|
||||
|
||||
group_av->audio_data = audio_callback;
|
||||
group_av->userdata = userdata;
|
||||
|
||||
return group_av;
|
||||
}
|
||||
|
||||
static void group_av_peer_new(void *object, uint32_t groupnumber, uint32_t friendgroupnumber)
|
||||
{
|
||||
const Group_AV *group_av = (const Group_AV *)object;
|
||||
Group_Peer_AV *peer_av = (Group_Peer_AV *)calloc(1, sizeof(Group_Peer_AV));
|
||||
|
||||
if (peer_av == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
peer_av->mono_time = g_mono_time(group_av->g_c);
|
||||
peer_av->buffer = create_queue(GROUP_JBUF_SIZE);
|
||||
|
||||
if (group_peer_set_object(group_av->g_c, groupnumber, friendgroupnumber, peer_av) == -1) {
|
||||
free(peer_av);
|
||||
}
|
||||
}
|
||||
|
||||
static void group_av_peer_delete(void *object, uint32_t groupnumber, void *peer_object)
|
||||
{
|
||||
Group_Peer_AV *peer_av = (Group_Peer_AV *)peer_object;
|
||||
|
||||
if (peer_av == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (peer_av->audio_decoder != nullptr) {
|
||||
opus_decoder_destroy(peer_av->audio_decoder);
|
||||
}
|
||||
|
||||
terminate_queue(peer_av->buffer);
|
||||
free(peer_object);
|
||||
}
|
||||
|
||||
static void group_av_groupchat_delete(void *object, uint32_t groupnumber)
|
||||
{
|
||||
if (object != nullptr) {
|
||||
kill_group_av((Group_AV *)object);
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, uint32_t groupnumber,
|
||||
uint32_t friendgroupnumber)
|
||||
{
|
||||
if (group_av == nullptr || peer_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int success;
|
||||
Group_Audio_Packet *pk = dequeue(peer_av->buffer, &success);
|
||||
|
||||
if (success == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int16_t *out_audio = nullptr;
|
||||
int out_audio_samples = 0;
|
||||
|
||||
const unsigned int sample_rate = 48000;
|
||||
|
||||
if (success == 1) {
|
||||
const int channels = opus_packet_get_nb_channels(pk->data);
|
||||
|
||||
if (channels == OPUS_INVALID_PACKET) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channels != 1 && channels != 2) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channels != peer_av->decoder_channels) {
|
||||
if (peer_av->audio_decoder != nullptr) {
|
||||
opus_decoder_destroy(peer_av->audio_decoder);
|
||||
peer_av->audio_decoder = nullptr;
|
||||
}
|
||||
|
||||
int rc;
|
||||
peer_av->audio_decoder = opus_decoder_create(sample_rate, channels, &rc);
|
||||
|
||||
if (rc != OPUS_OK) {
|
||||
LOGGER_ERROR(group_av->log, "Error while starting audio decoder: %s", opus_strerror(rc));
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
peer_av->decoder_channels = channels;
|
||||
}
|
||||
|
||||
const int num_samples = opus_decoder_get_nb_samples(peer_av->audio_decoder, pk->data, pk->length);
|
||||
|
||||
out_audio = (int16_t *)malloc(num_samples * peer_av->decoder_channels * sizeof(int16_t));
|
||||
|
||||
if (out_audio == nullptr) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_audio_samples = opus_decode(peer_av->audio_decoder, pk->data, pk->length, out_audio, num_samples, 0);
|
||||
free_audio_packet(pk);
|
||||
|
||||
if (out_audio_samples <= 0) {
|
||||
free(out_audio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
peer_av->last_packet_samples = out_audio_samples;
|
||||
} else {
|
||||
if (peer_av->audio_decoder == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (peer_av->last_packet_samples == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_audio = (int16_t *)malloc(peer_av->last_packet_samples * peer_av->decoder_channels * sizeof(int16_t));
|
||||
|
||||
if (out_audio == nullptr) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_audio_samples = opus_decode(peer_av->audio_decoder, nullptr, 0, out_audio, peer_av->last_packet_samples, 1);
|
||||
|
||||
if (out_audio_samples <= 0) {
|
||||
free(out_audio);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_audio != nullptr) {
|
||||
|
||||
if (group_av->audio_data != nullptr) {
|
||||
group_av->audio_data(group_av->tox, groupnumber, friendgroupnumber, out_audio, out_audio_samples,
|
||||
peer_av->decoder_channels, sample_rate, group_av->userdata);
|
||||
}
|
||||
|
||||
free(out_audio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int handle_group_audio_packet(void *object, uint32_t groupnumber, uint32_t friendgroupnumber, void *peer_object,
|
||||
const uint8_t *packet, uint16_t length)
|
||||
{
|
||||
if (peer_object == nullptr || object == nullptr || length <= sizeof(uint16_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Group_Peer_AV *peer_av = (Group_Peer_AV *)peer_object;
|
||||
|
||||
Group_Audio_Packet *pk = (Group_Audio_Packet *)calloc(1, sizeof(Group_Audio_Packet));
|
||||
|
||||
if (pk == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_unpack_u16(packet, &pk->sequnum);
|
||||
pk->length = length - sizeof(uint16_t);
|
||||
|
||||
pk->data = (uint8_t *)malloc(pk->length);
|
||||
|
||||
if (pk->data == nullptr) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(pk->data, packet + sizeof(uint16_t), pk->length);
|
||||
|
||||
if (queue(peer_av->buffer, peer_av->mono_time, pk) == -1) {
|
||||
free_audio_packet(pk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (decode_audio_packet((Group_AV *)object, peer_av, groupnumber, friendgroupnumber) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Enable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
|
||||
audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV
|
||||
|| group_get_object(g_c, groupnumber) != nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Group_AV *group_av = new_group_av(log, tox, g_c, audio_callback, userdata);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (group_set_object(g_c, groupnumber, group_av) == -1
|
||||
|| callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1
|
||||
|| callback_groupchat_peer_delete(g_c, groupnumber, group_av_peer_delete) == -1
|
||||
|| callback_groupchat_delete(g_c, groupnumber, group_av_groupchat_delete) == -1) {
|
||||
kill_group_av(group_av);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int numpeers = group_number_peers(g_c, groupnumber, false);
|
||||
|
||||
if (numpeers < 0) {
|
||||
kill_group_av(group_av);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < numpeers; ++i) {
|
||||
group_av_peer_new(group_av, groupnumber, i);
|
||||
}
|
||||
|
||||
group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Disable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int groupchat_disable_av(const Group_Chats *g_c, uint32_t groupnumber)
|
||||
{
|
||||
if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int numpeers = group_number_peers(g_c, groupnumber, false);
|
||||
|
||||
if (numpeers < 0) {
|
||||
kill_group_av(group_av);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < numpeers; ++i) {
|
||||
group_av_peer_delete(group_av, groupnumber, group_peer_get_object(g_c, groupnumber, i));
|
||||
group_peer_set_object(g_c, groupnumber, i, nullptr);
|
||||
}
|
||||
|
||||
kill_group_av(group_av);
|
||||
|
||||
if (group_set_object(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_peer_new(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_peer_delete(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_delete(g_c, groupnumber, nullptr) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return whether A/V is enabled in the groupchat. */
|
||||
bool groupchat_av_enabled(const Group_Chats *g_c, uint32_t groupnumber)
|
||||
{
|
||||
return group_get_object(g_c, groupnumber) != nullptr;
|
||||
}
|
||||
|
||||
/** @brief Create and connect to a new toxav group.
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int add_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
const int groupnumber = add_groupchat(g_c, &tox->rng, GROUPCHAT_TYPE_AV);
|
||||
|
||||
if (groupnumber == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (groupchat_enable_av(log, tox, g_c, groupnumber, audio_callback, userdata) == -1) {
|
||||
del_groupchat(g_c, groupnumber, true);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return groupnumber;
|
||||
}
|
||||
|
||||
/** @brief Join a AV group (you need to have been invited first).
|
||||
*
|
||||
* @return group number on success
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int join_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t friendnumber, const uint8_t *data,
|
||||
uint16_t length, audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
const int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length);
|
||||
|
||||
if (groupnumber == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (groupchat_enable_av(log, tox, g_c, groupnumber, audio_callback, userdata) == -1) {
|
||||
del_groupchat(g_c, groupnumber, true);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return groupnumber;
|
||||
}
|
||||
|
||||
/** @brief Send an encoded audio packet to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
static int send_audio_packet(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *packet, uint16_t length)
|
||||
{
|
||||
if (length == 0 || length > MAX_CRYPTO_DATA_SIZE - 1 - sizeof(uint16_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t plen = 1 + sizeof(uint16_t) + length;
|
||||
|
||||
Group_AV *const group_av = (Group_AV *)group_get_object(g_c, groupnumber);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t data[MAX_CRYPTO_DATA_SIZE];
|
||||
uint8_t *ptr = data;
|
||||
*ptr = GROUP_AUDIO_PACKET_ID;
|
||||
++ptr;
|
||||
|
||||
ptr += net_pack_u16(ptr, group_av->audio_sequnum);
|
||||
memcpy(ptr, packet, length);
|
||||
|
||||
if (send_group_lossy_packet(g_c, groupnumber, data, plen) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
++group_av->audio_sequnum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Send audio to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate)
|
||||
{
|
||||
Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channels != 1 && channels != 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sample_rate != 8000 && sample_rate != 12000 && sample_rate != 16000 && sample_rate != 24000
|
||||
&& sample_rate != 48000) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (group_av->audio_encoder == nullptr || group_av->audio_channels != channels
|
||||
|| group_av->audio_sample_rate != sample_rate) {
|
||||
group_av->audio_channels = channels;
|
||||
group_av->audio_sample_rate = sample_rate;
|
||||
|
||||
if (channels == 1) {
|
||||
group_av->audio_bitrate = 32000; // TODO(mannol): add way of adjusting bitrate
|
||||
} else {
|
||||
group_av->audio_bitrate = 64000; // TODO(mannol): add way of adjusting bitrate
|
||||
}
|
||||
|
||||
if (recreate_encoder(group_av) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t encoded[1024];
|
||||
const int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded));
|
||||
|
||||
if (size <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return send_audio_packet(g_c, groupnumber, encoded, size);
|
||||
}
|
||||
147
local_pod_repo/toxcore/toxcore/toxav/msi.h
Normal file
147
local_pod_repo/toxcore/toxcore/toxav/msi.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_MSI_H
|
||||
#define C_TOXCORE_TOXAV_MSI_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "video.h"
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/logger.h"
|
||||
|
||||
/**
|
||||
* Error codes.
|
||||
*/
|
||||
typedef enum MSIError {
|
||||
MSI_E_NONE,
|
||||
MSI_E_INVALID_MESSAGE,
|
||||
MSI_E_INVALID_PARAM,
|
||||
MSI_E_INVALID_STATE,
|
||||
MSI_E_STRAY_MESSAGE,
|
||||
MSI_E_SYSTEM,
|
||||
MSI_E_HANDLE,
|
||||
MSI_E_UNDISCLOSED, /* NOTE: must be last enum otherwise parsing will not work */
|
||||
} MSIError;
|
||||
|
||||
/**
|
||||
* Supported capabilities
|
||||
*/
|
||||
typedef enum MSICapabilities {
|
||||
MSI_CAP_S_AUDIO = 4, /* sending audio */
|
||||
MSI_CAP_S_VIDEO = 8, /* sending video */
|
||||
MSI_CAP_R_AUDIO = 16, /* receiving audio */
|
||||
MSI_CAP_R_VIDEO = 32, /* receiving video */
|
||||
} MSICapabilities;
|
||||
|
||||
|
||||
/**
|
||||
* Call state identifiers.
|
||||
*/
|
||||
typedef enum MSICallState {
|
||||
MSI_CALL_INACTIVE, /* Default */
|
||||
MSI_CALL_ACTIVE,
|
||||
MSI_CALL_REQUESTING, /* when sending call invite */
|
||||
MSI_CALL_REQUESTED, /* when getting call invite */
|
||||
} MSICallState;
|
||||
|
||||
/**
|
||||
* Callbacks ids that handle the states
|
||||
*/
|
||||
typedef enum MSICallbackID {
|
||||
MSI_ON_INVITE, /* Incoming call */
|
||||
MSI_ON_START, /* Call (RTP transmission) started */
|
||||
MSI_ON_END, /* Call that was active ended */
|
||||
MSI_ON_ERROR, /* On protocol error */
|
||||
MSI_ON_PEERTIMEOUT, /* Peer timed out; stop the call */
|
||||
MSI_ON_CAPABILITIES, /* Peer requested capabilities change */
|
||||
} MSICallbackID;
|
||||
|
||||
/**
|
||||
* The call struct. Please do not modify outside msi.c
|
||||
*/
|
||||
typedef struct MSICall {
|
||||
struct MSISession *session; /* Session pointer */
|
||||
|
||||
MSICallState state;
|
||||
uint8_t peer_capabilities; /* Peer capabilities */
|
||||
uint8_t self_capabilities; /* Self capabilities */
|
||||
uint16_t peer_vfpsz; /* Video frame piece size */
|
||||
uint32_t friend_number; /* Index of this call in MSISession */
|
||||
MSIError error; /* Last error */
|
||||
|
||||
struct ToxAVCall *av_call; /* Pointer to av call handler */
|
||||
|
||||
struct MSICall *next;
|
||||
struct MSICall *prev;
|
||||
} MSICall;
|
||||
|
||||
|
||||
/**
|
||||
* Expected return on success is 0, if any other number is
|
||||
* returned the call is considered errored and will be handled
|
||||
* as such which means it will be terminated without any notice.
|
||||
*/
|
||||
typedef int msi_action_cb(void *av, MSICall *call);
|
||||
|
||||
/**
|
||||
* Control session struct. Please do not modify outside msi.c
|
||||
*/
|
||||
typedef struct MSISession {
|
||||
/* Call handlers */
|
||||
MSICall **calls;
|
||||
uint32_t calls_tail;
|
||||
uint32_t calls_head;
|
||||
|
||||
void *av;
|
||||
Messenger *messenger;
|
||||
|
||||
pthread_mutex_t mutex[1];
|
||||
|
||||
msi_action_cb *invite_callback;
|
||||
msi_action_cb *start_callback;
|
||||
msi_action_cb *end_callback;
|
||||
msi_action_cb *error_callback;
|
||||
msi_action_cb *peertimeout_callback;
|
||||
msi_action_cb *capabilities_callback;
|
||||
} MSISession;
|
||||
|
||||
/**
|
||||
* Start the control session.
|
||||
*/
|
||||
MSISession *msi_new(Messenger *m);
|
||||
/**
|
||||
* Terminate control session. NOTE: all calls will be freed
|
||||
*/
|
||||
int msi_kill(MSISession *session, const Logger *log);
|
||||
/**
|
||||
* Callback setters.
|
||||
*/
|
||||
void msi_callback_invite(MSISession *session, msi_action_cb *callback);
|
||||
void msi_callback_start(MSISession *session, msi_action_cb *callback);
|
||||
void msi_callback_end(MSISession *session, msi_action_cb *callback);
|
||||
void msi_callback_error(MSISession *session, msi_action_cb *callback);
|
||||
void msi_callback_peertimeout(MSISession *session, msi_action_cb *callback);
|
||||
void msi_callback_capabilities(MSISession *session, msi_action_cb *callback);
|
||||
/**
|
||||
* Send invite request to friend_number.
|
||||
*/
|
||||
int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities);
|
||||
/**
|
||||
* Hangup call. NOTE: `call` will be freed
|
||||
*/
|
||||
int msi_hangup(MSICall *call);
|
||||
/**
|
||||
* Answer call request.
|
||||
*/
|
||||
int msi_answer(MSICall *call, uint8_t capabilities);
|
||||
/**
|
||||
* Change capabilities of the call.
|
||||
*/
|
||||
int msi_change_capabilities(MSICall *call, uint8_t capabilities);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_MSI_H
|
||||
903
local_pod_repo/toxcore/toxcore/toxav/msi.m
Normal file
903
local_pod_repo/toxcore/toxcore/toxav/msi.m
Normal file
@@ -0,0 +1,903 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#include "msi.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
#define MSI_MAXMSG_SIZE 256
|
||||
|
||||
/**
|
||||
* Protocol:
|
||||
*
|
||||
* `|id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|`
|
||||
*/
|
||||
|
||||
typedef enum MSIHeaderID {
|
||||
ID_REQUEST = 1,
|
||||
ID_ERROR,
|
||||
ID_CAPABILITIES,
|
||||
} MSIHeaderID;
|
||||
|
||||
|
||||
typedef enum MSIRequest {
|
||||
REQU_INIT,
|
||||
REQU_PUSH,
|
||||
REQU_POP,
|
||||
} MSIRequest;
|
||||
|
||||
|
||||
typedef struct MSIHeaderRequest {
|
||||
MSIRequest value;
|
||||
bool exists;
|
||||
} MSIHeaderRequest;
|
||||
|
||||
typedef struct MSIHeaderError {
|
||||
MSIError value;
|
||||
bool exists;
|
||||
} MSIHeaderError;
|
||||
|
||||
typedef struct MSIHeaderCapabilities {
|
||||
uint8_t value;
|
||||
bool exists;
|
||||
} MSIHeaderCapabilities;
|
||||
|
||||
|
||||
typedef struct MSIMessage {
|
||||
MSIHeaderRequest request;
|
||||
MSIHeaderError error;
|
||||
MSIHeaderCapabilities capabilities;
|
||||
} MSIMessage;
|
||||
|
||||
|
||||
static void msg_init(MSIMessage *dest, MSIRequest request);
|
||||
static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint16_t length);
|
||||
static uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len,
|
||||
uint16_t *length);
|
||||
static int send_message(Messenger *m, uint32_t friend_number, const MSIMessage *msg);
|
||||
static int send_error(Messenger *m, uint32_t friend_number, MSIError error);
|
||||
static bool invoke_callback(MSICall *call, MSICallbackID cb);
|
||||
static MSICall *get_call(MSISession *session, uint32_t friend_number);
|
||||
static MSICall *new_call(MSISession *session, uint32_t friend_number);
|
||||
static void kill_call(MSICall *call);
|
||||
static void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);
|
||||
static void handle_init(MSICall *call, const MSIMessage *msg);
|
||||
static void handle_push(MSICall *call, const MSIMessage *msg);
|
||||
static void handle_pop(MSICall *call, const MSIMessage *msg);
|
||||
static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object);
|
||||
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
void msi_callback_invite(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->invite_callback = callback;
|
||||
}
|
||||
void msi_callback_start(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->start_callback = callback;
|
||||
}
|
||||
void msi_callback_end(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->end_callback = callback;
|
||||
}
|
||||
void msi_callback_error(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->error_callback = callback;
|
||||
}
|
||||
void msi_callback_peertimeout(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->peertimeout_callback = callback;
|
||||
}
|
||||
void msi_callback_capabilities(MSISession *session, msi_action_cb *callback)
|
||||
{
|
||||
session->capabilities_callback = callback;
|
||||
}
|
||||
|
||||
MSISession *msi_new(Messenger *m)
|
||||
{
|
||||
if (m == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MSISession *retu = (MSISession *)calloc(1, sizeof(MSISession));
|
||||
|
||||
if (retu == nullptr) {
|
||||
LOGGER_ERROR(m->log, "Allocation failed! Program might misbehave!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (create_recursive_mutex(retu->mutex) != 0) {
|
||||
LOGGER_ERROR(m->log, "Failed to init mutex! Program might misbehave");
|
||||
free(retu);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
retu->messenger = m;
|
||||
|
||||
m_callback_msi_packet(m, handle_msi_packet, retu);
|
||||
|
||||
/* This is called when remote terminates session */
|
||||
m_callback_connectionstatus_internal_av(m, on_peer_status, retu);
|
||||
|
||||
LOGGER_DEBUG(m->log, "New msi session: %p ", (void *)retu);
|
||||
return retu;
|
||||
}
|
||||
int msi_kill(MSISession *session, const Logger *log)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
LOGGER_ERROR(log, "Tried to terminate non-existing session");
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_callback_msi_packet(session->messenger, nullptr, nullptr);
|
||||
|
||||
if (pthread_mutex_trylock(session->mutex) != 0) {
|
||||
LOGGER_ERROR(log, "Failed to acquire lock on msi mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->calls != nullptr) {
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_POP);
|
||||
|
||||
MSICall *it = get_call(session, session->calls_head);
|
||||
|
||||
while (it != nullptr) {
|
||||
send_message(session->messenger, it->friend_number, &msg);
|
||||
MSICall *temp_it = it;
|
||||
it = it->next;
|
||||
kill_call(temp_it); /* This will eventually free session->calls */
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
pthread_mutex_destroy(session->mutex);
|
||||
|
||||
LOGGER_DEBUG(log, "Terminated session: %p", (void *)session);
|
||||
free(session);
|
||||
return 0;
|
||||
}
|
||||
int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Session: %p Inviting friend: %u", (void *)session, friend_number);
|
||||
|
||||
if (pthread_mutex_trylock(session->mutex) != 0) {
|
||||
LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_call(session, friend_number) != nullptr) {
|
||||
LOGGER_ERROR(session->messenger->log, "Already in a call");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSICall *temp = new_call(session, friend_number);
|
||||
|
||||
if (temp == nullptr) {
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
temp->self_capabilities = capabilities;
|
||||
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_INIT);
|
||||
|
||||
msg.capabilities.exists = true;
|
||||
msg.capabilities.value = capabilities;
|
||||
|
||||
send_message(temp->session->messenger, temp->friend_number, &msg);
|
||||
|
||||
temp->state = MSI_CALL_REQUESTING;
|
||||
|
||||
*call = temp;
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Invite sent");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return 0;
|
||||
}
|
||||
int msi_hangup(MSICall *call)
|
||||
{
|
||||
if (call == nullptr || call->session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSISession *session = call->session;
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Session: %p Hanging up call with friend: %u", (void *)call->session,
|
||||
call->friend_number);
|
||||
|
||||
if (pthread_mutex_trylock(session->mutex) != 0) {
|
||||
LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (call->state == MSI_CALL_INACTIVE) {
|
||||
LOGGER_ERROR(session->messenger->log, "Call is in invalid state!");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_POP);
|
||||
|
||||
send_message(session->messenger, call->friend_number, &msg);
|
||||
|
||||
kill_call(call);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return 0;
|
||||
}
|
||||
int msi_answer(MSICall *call, uint8_t capabilities)
|
||||
{
|
||||
if (call == nullptr || call->session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSISession *session = call->session;
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Session: %p Answering call from: %u", (void *)call->session,
|
||||
call->friend_number);
|
||||
|
||||
if (pthread_mutex_trylock(session->mutex) != 0) {
|
||||
LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (call->state != MSI_CALL_REQUESTED) {
|
||||
/* Though sending in invalid state will not cause anything weird
|
||||
* Its better to not do it like a maniac */
|
||||
LOGGER_ERROR(session->messenger->log, "Call is in invalid state!");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
call->self_capabilities = capabilities;
|
||||
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_PUSH);
|
||||
|
||||
msg.capabilities.exists = true;
|
||||
msg.capabilities.value = capabilities;
|
||||
|
||||
send_message(session->messenger, call->friend_number, &msg);
|
||||
|
||||
call->state = MSI_CALL_ACTIVE;
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int msi_change_capabilities(MSICall *call, uint8_t capabilities)
|
||||
{
|
||||
if (call == nullptr || call->session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSISession *session = call->session;
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Session: %p Trying to change capabilities to friend %u", (void *)call->session,
|
||||
call->friend_number);
|
||||
|
||||
if (pthread_mutex_trylock(session->mutex) != 0) {
|
||||
LOGGER_ERROR(session->messenger->log, "Failed to acquire lock on msi mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (call->state != MSI_CALL_ACTIVE) {
|
||||
LOGGER_ERROR(session->messenger->log, "Call is in invalid state!");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
call->self_capabilities = capabilities;
|
||||
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_PUSH);
|
||||
|
||||
msg.capabilities.exists = true;
|
||||
msg.capabilities.value = capabilities;
|
||||
|
||||
send_message(call->session->messenger, call->friend_number, &msg);
|
||||
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Private functions
|
||||
*/
|
||||
static void msg_init(MSIMessage *dest, MSIRequest request)
|
||||
{
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->request.exists = true;
|
||||
dest->request.value = request;
|
||||
}
|
||||
|
||||
static bool check_size(const Logger *log, const uint8_t *bytes, int *constraint, uint8_t size)
|
||||
{
|
||||
*constraint -= 2 + size;
|
||||
|
||||
if (*constraint < 1) {
|
||||
LOGGER_ERROR(log, "Read over length!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bytes[1] != size) {
|
||||
LOGGER_ERROR(log, "Invalid data size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Assumes size == 1 */
|
||||
static bool check_enum_high(const Logger *log, const uint8_t *bytes, uint8_t enum_high)
|
||||
{
|
||||
if (bytes[2] > enum_high) {
|
||||
LOGGER_ERROR(log, "Failed enum high limit!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
/* Parse raw data received from socket into MSIMessage struct */
|
||||
|
||||
assert(dest != nullptr);
|
||||
|
||||
if (length == 0 || data[length - 1] != 0) { /* End byte must have value 0 */
|
||||
LOGGER_ERROR(log, "Invalid end byte");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
|
||||
const uint8_t *it = data;
|
||||
int size_constraint = length;
|
||||
|
||||
while (*it != 0) {/* until end byte is hit */
|
||||
switch (*it) {
|
||||
case ID_REQUEST: {
|
||||
if (!check_size(log, it, &size_constraint, 1) ||
|
||||
!check_enum_high(log, it, REQU_POP)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest->request.value = (MSIRequest)it[2];
|
||||
dest->request.exists = true;
|
||||
it += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_ERROR: {
|
||||
if (!check_size(log, it, &size_constraint, 1) ||
|
||||
!check_enum_high(log, it, MSI_E_UNDISCLOSED)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest->error.value = (MSIError)it[2];
|
||||
dest->error.exists = true;
|
||||
it += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_CAPABILITIES: {
|
||||
if (!check_size(log, it, &size_constraint, 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest->capabilities.value = it[2];
|
||||
dest->capabilities.exists = true;
|
||||
it += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
LOGGER_ERROR(log, "Invalid id byte");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dest->request.exists) {
|
||||
LOGGER_ERROR(log, "Invalid request field!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len,
|
||||
uint16_t *length)
|
||||
{
|
||||
/* Parse a single header for sending */
|
||||
assert(dest != nullptr);
|
||||
assert(value != nullptr);
|
||||
assert(value_len != 0);
|
||||
|
||||
*dest = id;
|
||||
++dest;
|
||||
*dest = value_len;
|
||||
++dest;
|
||||
|
||||
memcpy(dest, value, value_len);
|
||||
|
||||
*length += 2 + value_len;
|
||||
|
||||
return dest + value_len; /* Set to next position ready to be written */
|
||||
}
|
||||
static int send_message(Messenger *m, uint32_t friend_number, const MSIMessage *msg)
|
||||
{
|
||||
/* Parse and send message */
|
||||
assert(m != nullptr);
|
||||
|
||||
uint8_t parsed [MSI_MAXMSG_SIZE];
|
||||
|
||||
uint8_t *it = parsed;
|
||||
uint16_t size = 0;
|
||||
|
||||
if (msg->request.exists) {
|
||||
uint8_t cast = msg->request.value;
|
||||
it = msg_parse_header_out(ID_REQUEST, it, &cast,
|
||||
sizeof(cast), &size);
|
||||
} else {
|
||||
LOGGER_DEBUG(m->log, "Must have request field");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg->error.exists) {
|
||||
uint8_t cast = msg->error.value;
|
||||
it = msg_parse_header_out(ID_ERROR, it, &cast,
|
||||
sizeof(cast), &size);
|
||||
}
|
||||
|
||||
if (msg->capabilities.exists) {
|
||||
it = msg_parse_header_out(ID_CAPABILITIES, it, &msg->capabilities.value,
|
||||
sizeof(msg->capabilities.value), &size);
|
||||
}
|
||||
|
||||
if (it == parsed) {
|
||||
LOGGER_WARNING(m->log, "Parsing message failed; empty message");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*it = 0;
|
||||
++size;
|
||||
|
||||
if (m_msi_packet(m, friend_number, parsed, size)) {
|
||||
LOGGER_DEBUG(m->log, "Sent message");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static int send_error(Messenger *m, uint32_t friend_number, MSIError error)
|
||||
{
|
||||
/* Send error message */
|
||||
assert(m != nullptr);
|
||||
|
||||
LOGGER_DEBUG(m->log, "Sending error: %d to friend: %d", error, friend_number);
|
||||
|
||||
MSIMessage msg;
|
||||
msg_init(&msg, REQU_POP);
|
||||
|
||||
msg.error.exists = true;
|
||||
msg.error.value = error;
|
||||
|
||||
send_message(m, friend_number, &msg);
|
||||
return 0;
|
||||
}
|
||||
static int invoke_callback_inner(MSICall *call, MSICallbackID id)
|
||||
{
|
||||
MSISession *session = call->session;
|
||||
LOGGER_DEBUG(session->messenger->log, "invoking callback function: %d", id);
|
||||
|
||||
switch (id) {
|
||||
case MSI_ON_INVITE:
|
||||
return session->invite_callback(session->av, call);
|
||||
|
||||
case MSI_ON_START:
|
||||
return session->start_callback(session->av, call);
|
||||
|
||||
case MSI_ON_END:
|
||||
return session->end_callback(session->av, call);
|
||||
|
||||
case MSI_ON_ERROR:
|
||||
return session->error_callback(session->av, call);
|
||||
|
||||
case MSI_ON_PEERTIMEOUT:
|
||||
return session->peertimeout_callback(session->av, call);
|
||||
|
||||
case MSI_ON_CAPABILITIES:
|
||||
return session->capabilities_callback(session->av, call);
|
||||
}
|
||||
|
||||
LOGGER_FATAL(session->messenger->log, "invalid callback id: %d", id);
|
||||
return -1;
|
||||
}
|
||||
static bool invoke_callback(MSICall *call, MSICallbackID cb)
|
||||
{
|
||||
assert(call != nullptr);
|
||||
|
||||
if (invoke_callback_inner(call, cb) != 0) {
|
||||
LOGGER_WARNING(call->session->messenger->log,
|
||||
"Callback state handling failed, sending error");
|
||||
|
||||
/* If no callback present or error happened while handling,
|
||||
* an error message will be sent to friend
|
||||
*/
|
||||
if (call->error == MSI_E_NONE) {
|
||||
call->error = MSI_E_HANDLE;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static MSICall *get_call(MSISession *session, uint32_t friend_number)
|
||||
{
|
||||
assert(session != nullptr);
|
||||
|
||||
if (session->calls == nullptr || session->calls_tail < friend_number) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return session->calls[friend_number];
|
||||
}
|
||||
static MSICall *new_call(MSISession *session, uint32_t friend_number)
|
||||
{
|
||||
assert(session != nullptr);
|
||||
|
||||
MSICall *rc = (MSICall *)calloc(1, sizeof(MSICall));
|
||||
|
||||
if (rc == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rc->session = session;
|
||||
rc->friend_number = friend_number;
|
||||
|
||||
if (session->calls == nullptr) { /* Creating */
|
||||
session->calls = (MSICall **)calloc(friend_number + 1, sizeof(MSICall *));
|
||||
|
||||
if (session->calls == nullptr) {
|
||||
free(rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
session->calls_tail = friend_number;
|
||||
session->calls_head = friend_number;
|
||||
} else if (session->calls_tail < friend_number) { /* Appending */
|
||||
MSICall **tmp = (MSICall **)realloc(session->calls, sizeof(MSICall *) * (friend_number + 1));
|
||||
|
||||
if (tmp == nullptr) {
|
||||
free(rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
session->calls = tmp;
|
||||
|
||||
/* Set fields in between to null */
|
||||
for (uint32_t i = session->calls_tail + 1; i < friend_number; ++i) {
|
||||
session->calls[i] = nullptr;
|
||||
}
|
||||
|
||||
rc->prev = session->calls[session->calls_tail];
|
||||
session->calls[session->calls_tail]->next = rc;
|
||||
|
||||
session->calls_tail = friend_number;
|
||||
} else if (session->calls_head > friend_number) { /* Inserting at front */
|
||||
rc->next = session->calls[session->calls_head];
|
||||
session->calls[session->calls_head]->prev = rc;
|
||||
session->calls_head = friend_number;
|
||||
}
|
||||
|
||||
session->calls[friend_number] = rc;
|
||||
return rc;
|
||||
}
|
||||
static void kill_call(MSICall *call)
|
||||
{
|
||||
/* Assume that session mutex is locked */
|
||||
if (call == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
MSISession *session = call->session;
|
||||
|
||||
LOGGER_DEBUG(session->messenger->log, "Killing call: %p", (void *)call);
|
||||
|
||||
MSICall *prev = call->prev;
|
||||
MSICall *next = call->next;
|
||||
|
||||
if (prev != nullptr) {
|
||||
prev->next = next;
|
||||
} else if (next != nullptr) {
|
||||
session->calls_head = next->friend_number;
|
||||
} else {
|
||||
goto CLEAR_CONTAINER;
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
next->prev = prev;
|
||||
} else if (prev != nullptr) {
|
||||
session->calls_tail = prev->friend_number;
|
||||
} else {
|
||||
goto CLEAR_CONTAINER;
|
||||
}
|
||||
|
||||
session->calls[call->friend_number] = nullptr;
|
||||
free(call);
|
||||
return;
|
||||
|
||||
CLEAR_CONTAINER:
|
||||
session->calls_head = 0;
|
||||
session->calls_tail = 0;
|
||||
free(session->calls);
|
||||
free(call);
|
||||
session->calls = nullptr;
|
||||
}
|
||||
static void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data)
|
||||
{
|
||||
if (status != 0) {
|
||||
// Friend is online.
|
||||
return;
|
||||
}
|
||||
|
||||
MSISession *session = (MSISession *)data;
|
||||
LOGGER_DEBUG(m->log, "Friend %d is now offline", friend_number);
|
||||
|
||||
pthread_mutex_lock(session->mutex);
|
||||
MSICall *call = get_call(session, friend_number);
|
||||
|
||||
if (call == nullptr) {
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
invoke_callback(call, MSI_ON_PEERTIMEOUT); /* Failure is ignored */
|
||||
kill_call(call);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
}
|
||||
static bool try_handle_init(MSICall *call, const MSIMessage *msg)
|
||||
{
|
||||
assert(call != nullptr);
|
||||
LOGGER_DEBUG(call->session->messenger->log,
|
||||
"Session: %p Handling 'init' friend: %d", (void *)call->session, call->friend_number);
|
||||
|
||||
if (!msg->capabilities.exists) {
|
||||
LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'init'", (void *)call->session);
|
||||
call->error = MSI_E_INVALID_MESSAGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (call->state) {
|
||||
case MSI_CALL_INACTIVE: {
|
||||
/* Call requested */
|
||||
call->peer_capabilities = msg->capabilities.value;
|
||||
call->state = MSI_CALL_REQUESTED;
|
||||
|
||||
if (!invoke_callback(call, MSI_ON_INVITE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_ACTIVE: {
|
||||
/* If peer sent init while the call is already
|
||||
* active it's probable that he is trying to
|
||||
* re-call us while the call is not terminated
|
||||
* on our side. We can assume that in this case
|
||||
* we can automatically answer the re-call.
|
||||
*/
|
||||
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend is recalling us");
|
||||
|
||||
MSIMessage out_msg;
|
||||
msg_init(&out_msg, REQU_PUSH);
|
||||
|
||||
out_msg.capabilities.exists = true;
|
||||
out_msg.capabilities.value = call->self_capabilities;
|
||||
|
||||
send_message(call->session->messenger, call->friend_number, &out_msg);
|
||||
|
||||
/* If peer changed capabilities during re-call they will
|
||||
* be handled accordingly during the next step
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_REQUESTED: // fall-through
|
||||
case MSI_CALL_REQUESTING: {
|
||||
LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid state on 'init'", (void *)call->session);
|
||||
call->error = MSI_E_INVALID_STATE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static void handle_init(MSICall *call, const MSIMessage *msg)
|
||||
{
|
||||
assert(call != nullptr);
|
||||
LOGGER_DEBUG(call->session->messenger->log,
|
||||
"Session: %p Handling 'init' friend: %d", (void *)call->session, call->friend_number);
|
||||
|
||||
if (!try_handle_init(call, msg)) {
|
||||
send_error(call->session->messenger, call->friend_number, call->error);
|
||||
kill_call(call);
|
||||
}
|
||||
}
|
||||
static void handle_push(MSICall *call, const MSIMessage *msg)
|
||||
{
|
||||
assert(call != nullptr);
|
||||
|
||||
LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'push' friend: %d", (void *)call->session,
|
||||
call->friend_number);
|
||||
|
||||
if (!msg->capabilities.exists) {
|
||||
LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'push'", (void *)call->session);
|
||||
call->error = MSI_E_INVALID_MESSAGE;
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
switch (call->state) {
|
||||
case MSI_CALL_ACTIVE: {
|
||||
if (call->peer_capabilities != msg->capabilities.value) {
|
||||
/* Only act if capabilities changed */
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend is changing capabilities to: %u", msg->capabilities.value);
|
||||
|
||||
call->peer_capabilities = msg->capabilities.value;
|
||||
|
||||
if (!invoke_callback(call, MSI_ON_CAPABILITIES)) {
|
||||
goto FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_REQUESTING: {
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend answered our call");
|
||||
|
||||
/* Call started */
|
||||
call->peer_capabilities = msg->capabilities.value;
|
||||
call->state = MSI_CALL_ACTIVE;
|
||||
|
||||
if (!invoke_callback(call, MSI_ON_START)) {
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_INACTIVE: // fall-through
|
||||
case MSI_CALL_REQUESTED: {
|
||||
/* Pushes during initialization state are ignored */
|
||||
LOGGER_WARNING(call->session->messenger->log, "Ignoring invalid push");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
FAILURE:
|
||||
send_error(call->session->messenger, call->friend_number, call->error);
|
||||
kill_call(call);
|
||||
}
|
||||
static void handle_pop(MSICall *call, const MSIMessage *msg)
|
||||
{
|
||||
assert(call != nullptr);
|
||||
|
||||
LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'pop', friend id: %d", (void *)call->session,
|
||||
call->friend_number);
|
||||
|
||||
/* callback errors are ignored */
|
||||
|
||||
if (msg->error.exists) {
|
||||
LOGGER_WARNING(call->session->messenger->log, "Friend detected an error: %d", msg->error.value);
|
||||
call->error = msg->error.value;
|
||||
invoke_callback(call, MSI_ON_ERROR);
|
||||
} else {
|
||||
switch (call->state) {
|
||||
case MSI_CALL_INACTIVE: {
|
||||
LOGGER_FATAL(call->session->messenger->log, "Handling what should be impossible case");
|
||||
}
|
||||
|
||||
case MSI_CALL_ACTIVE: {
|
||||
/* Hangup */
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend hung up on us");
|
||||
invoke_callback(call, MSI_ON_END);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_REQUESTING: {
|
||||
/* Reject */
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend rejected our call");
|
||||
invoke_callback(call, MSI_ON_END);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSI_CALL_REQUESTED: {
|
||||
/* Cancel */
|
||||
LOGGER_INFO(call->session->messenger->log, "Friend canceled call invite");
|
||||
invoke_callback(call, MSI_ON_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kill_call(call);
|
||||
}
|
||||
static void handle_msi_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object)
|
||||
{
|
||||
LOGGER_DEBUG(m->log, "Got msi message");
|
||||
|
||||
MSISession *session = (MSISession *)object;
|
||||
MSIMessage msg;
|
||||
|
||||
if (msg_parse_in(m->log, &msg, data, length) == -1) {
|
||||
LOGGER_WARNING(m->log, "Error parsing message");
|
||||
send_error(m, friend_number, MSI_E_INVALID_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(m->log, "Successfully parsed message");
|
||||
|
||||
pthread_mutex_lock(session->mutex);
|
||||
MSICall *call = get_call(session, friend_number);
|
||||
|
||||
if (call == nullptr) {
|
||||
if (msg.request.value != REQU_INIT) {
|
||||
send_error(m, friend_number, MSI_E_STRAY_MESSAGE);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
call = new_call(session, friend_number);
|
||||
|
||||
if (call == nullptr) {
|
||||
send_error(m, friend_number, MSI_E_SYSTEM);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (msg.request.value) {
|
||||
case REQU_INIT: {
|
||||
handle_init(call, &msg);
|
||||
break;
|
||||
}
|
||||
|
||||
case REQU_PUSH: {
|
||||
handle_push(call, &msg);
|
||||
break;
|
||||
}
|
||||
|
||||
case REQU_POP: {
|
||||
handle_pop(call, &msg); /* always kills the call */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
}
|
||||
31
local_pod_repo/toxcore/toxcore/toxav/ring_buffer.h
Normal file
31
local_pod_repo/toxcore/toxcore/toxav/ring_buffer.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
* Copyright © 2013 plutooo
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_RING_BUFFER_H
|
||||
#define C_TOXCORE_TOXAV_RING_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Ring buffer */
|
||||
typedef struct RingBuffer RingBuffer;
|
||||
bool rb_full(const RingBuffer *b);
|
||||
bool rb_empty(const RingBuffer *b);
|
||||
void *rb_write(RingBuffer *b, void *p);
|
||||
bool rb_read(RingBuffer *b, void **p);
|
||||
RingBuffer *rb_new(int size);
|
||||
void rb_kill(RingBuffer *b);
|
||||
uint16_t rb_size(const RingBuffer *b);
|
||||
uint16_t rb_data(const RingBuffer *b, void **dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_RING_BUFFER_H
|
||||
115
local_pod_repo/toxcore/toxcore/toxav/ring_buffer.m
Normal file
115
local_pod_repo/toxcore/toxcore/toxav/ring_buffer.m
Normal file
@@ -0,0 +1,115 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
* Copyright © 2013 plutooo
|
||||
*/
|
||||
#include "ring_buffer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
|
||||
struct RingBuffer {
|
||||
uint16_t size; /* Max size */
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
void **data;
|
||||
};
|
||||
|
||||
bool rb_full(const RingBuffer *b)
|
||||
{
|
||||
return (b->end + 1) % b->size == b->start;
|
||||
}
|
||||
|
||||
bool rb_empty(const RingBuffer *b)
|
||||
{
|
||||
return b->end == b->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval NULL on success
|
||||
* @return input value "p" on failure, so caller can free on failed rb_write
|
||||
*/
|
||||
void *rb_write(RingBuffer *b, void *p)
|
||||
{
|
||||
if (b == nullptr) {
|
||||
return p;
|
||||
}
|
||||
|
||||
void *rc = nullptr;
|
||||
|
||||
if ((b->end + 1) % b->size == b->start) { /* full */
|
||||
rc = b->data[b->start];
|
||||
}
|
||||
|
||||
b->data[b->end] = p;
|
||||
b->end = (b->end + 1) % b->size;
|
||||
|
||||
if (b->end == b->start) {
|
||||
b->start = (b->start + 1) % b->size;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool rb_read(RingBuffer *b, void **p)
|
||||
{
|
||||
if (b->end == b->start) { /* Empty */
|
||||
*p = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
*p = b->data[b->start];
|
||||
b->start = (b->start + 1) % b->size;
|
||||
return true;
|
||||
}
|
||||
|
||||
RingBuffer *rb_new(int size)
|
||||
{
|
||||
RingBuffer *buf = (RingBuffer *)calloc(1, sizeof(RingBuffer));
|
||||
|
||||
if (buf == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buf->size = size + 1; /* include empty elem */
|
||||
buf->data = (void **)calloc(buf->size, sizeof(void *));
|
||||
|
||||
if (buf->data == nullptr) {
|
||||
free(buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void rb_kill(RingBuffer *b)
|
||||
{
|
||||
if (b != nullptr) {
|
||||
free(b->data);
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t rb_size(const RingBuffer *b)
|
||||
{
|
||||
if (rb_empty(b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return
|
||||
b->end > b->start ?
|
||||
b->end - b->start :
|
||||
(b->size - b->start) + b->end;
|
||||
}
|
||||
|
||||
uint16_t rb_data(const RingBuffer *b, void **dest)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < rb_size(b); ++i) {
|
||||
dest[i] = b->data[(b->start + i) % b->size];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
210
local_pod_repo/toxcore/toxcore/toxav/rtp.h
Normal file
210
local_pod_repo/toxcore/toxcore/toxav/rtp.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_RTP_H
|
||||
#define C_TOXCORE_TOXAV_RTP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bwcontroller.h"
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* RTPHeader serialised size in bytes.
|
||||
*/
|
||||
#define RTP_HEADER_SIZE 80
|
||||
|
||||
/**
|
||||
* Number of 32 bit padding fields between @ref RTPHeader::offset_lower and
|
||||
* everything before it.
|
||||
*/
|
||||
#define RTP_PADDING_FIELDS 11
|
||||
|
||||
/**
|
||||
* Payload type identifier. Also used as rtp callback prefix.
|
||||
*/
|
||||
typedef enum RTP_Type {
|
||||
RTP_TYPE_AUDIO = 192,
|
||||
RTP_TYPE_VIDEO = 193,
|
||||
} RTP_Type;
|
||||
|
||||
/**
|
||||
* A bit mask (up to 64 bits) specifying features of the current frame affecting
|
||||
* the behaviour of the decoder.
|
||||
*/
|
||||
typedef enum RTPFlags {
|
||||
/**
|
||||
* Support frames larger than 64KiB. The full 32 bit length and offset are
|
||||
* set in @ref RTPHeader::data_length_full and @ref RTPHeader::offset_full.
|
||||
*/
|
||||
RTP_LARGE_FRAME = 1 << 0,
|
||||
/**
|
||||
* Whether the packet is part of a key frame.
|
||||
*/
|
||||
RTP_KEY_FRAME = 1 << 1,
|
||||
} RTPFlags;
|
||||
|
||||
|
||||
struct RTPHeader {
|
||||
/* Standard RTP header */
|
||||
unsigned ve: 2; /* Version has only 2 bits! */
|
||||
unsigned pe: 1; /* Padding */
|
||||
unsigned xe: 1; /* Extra header */
|
||||
unsigned cc: 4; /* Contributing sources count */
|
||||
|
||||
unsigned ma: 1; /* Marker */
|
||||
unsigned pt: 7; /* Payload type */
|
||||
|
||||
uint16_t sequnum;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
|
||||
/* Non-standard Tox-specific fields */
|
||||
|
||||
/**
|
||||
* Bit mask of `RTPFlags` setting features of the current frame.
|
||||
*/
|
||||
uint64_t flags;
|
||||
|
||||
/**
|
||||
* The full 32 bit data offset of the current data chunk. The @ref
|
||||
* offset_lower data member contains the lower 16 bits of this value. For
|
||||
* frames smaller than 64KiB, @ref offset_full and @ref offset_lower are
|
||||
* equal.
|
||||
*/
|
||||
uint32_t offset_full;
|
||||
/**
|
||||
* The full 32 bit payload length without header and packet id.
|
||||
*/
|
||||
uint32_t data_length_full;
|
||||
/**
|
||||
* Only the receiver uses this field (why do we have this?).
|
||||
*/
|
||||
uint32_t received_length_full;
|
||||
|
||||
/**
|
||||
* Data offset of the current part (lower bits).
|
||||
*/
|
||||
uint16_t offset_lower;
|
||||
/**
|
||||
* Total message length (lower bits).
|
||||
*/
|
||||
uint16_t data_length_lower;
|
||||
};
|
||||
|
||||
|
||||
struct RTPMessage {
|
||||
/**
|
||||
* This is used in the old code that doesn't deal with large frames, i.e.
|
||||
* the audio code or receiving code for old 16 bit messages. We use it to
|
||||
* record the number of bytes received so far in a multi-part message. The
|
||||
* multi-part message in the old code is stored in `RTPSession::mp`.
|
||||
*/
|
||||
uint16_t len;
|
||||
|
||||
struct RTPHeader header;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
#define USED_RTP_WORKBUFFER_COUNT 3
|
||||
|
||||
/**
|
||||
* One slot in the work buffer list. Represents one frame that is currently
|
||||
* being assembled.
|
||||
*/
|
||||
struct RTPWorkBuffer {
|
||||
/**
|
||||
* Whether this slot contains a key frame. This is true iff
|
||||
* `buf->header.flags & RTP_KEY_FRAME`.
|
||||
*/
|
||||
bool is_keyframe;
|
||||
/**
|
||||
* The number of bytes received so far, regardless of which pieces. I.e. we
|
||||
* could have received the first 1000 bytes and the last 1000 bytes with
|
||||
* 4000 bytes in the middle still to come, and this number would be 2000.
|
||||
*/
|
||||
uint32_t received_len;
|
||||
/**
|
||||
* The message currently being assembled.
|
||||
*/
|
||||
struct RTPMessage *buf;
|
||||
};
|
||||
|
||||
struct RTPWorkBufferList {
|
||||
int8_t next_free_entry;
|
||||
struct RTPWorkBuffer work_buffer[USED_RTP_WORKBUFFER_COUNT];
|
||||
};
|
||||
|
||||
#define DISMISS_FIRST_LOST_VIDEO_PACKET_COUNT 10
|
||||
|
||||
typedef int rtp_m_cb(Mono_Time *mono_time, void *cs, struct RTPMessage *msg);
|
||||
|
||||
/**
|
||||
* RTP control session.
|
||||
*/
|
||||
typedef struct RTPSession {
|
||||
uint8_t payload_type;
|
||||
uint16_t sequnum; /* Sending sequence number */
|
||||
uint16_t rsequnum; /* Receiving sequence number */
|
||||
uint32_t rtimestamp;
|
||||
uint32_t ssrc; // this seems to be unused!?
|
||||
struct RTPMessage *mp; /* Expected parted message */
|
||||
struct RTPWorkBufferList *work_buffer_list;
|
||||
uint8_t first_packets_counter; /* dismiss first few lost video packets */
|
||||
Messenger *m;
|
||||
Tox *tox;
|
||||
uint32_t friend_number;
|
||||
BWController *bwc;
|
||||
void *cs;
|
||||
rtp_m_cb *mcb;
|
||||
} RTPSession;
|
||||
|
||||
|
||||
/**
|
||||
* Serialise an RTPHeader to bytes to be sent over the network.
|
||||
*
|
||||
* @param rdata A byte array of length RTP_HEADER_SIZE. Does not need to be
|
||||
* initialised. All RTP_HEADER_SIZE bytes will be initialised after a call
|
||||
* to this function.
|
||||
* @param header The RTPHeader to serialise.
|
||||
*/
|
||||
size_t rtp_header_pack(uint8_t *rdata, const struct RTPHeader *header);
|
||||
|
||||
/**
|
||||
* Deserialise an RTPHeader from bytes received over the network.
|
||||
*
|
||||
* @param data A byte array of length RTP_HEADER_SIZE.
|
||||
* @param header The RTPHeader to write the unpacked values to.
|
||||
*/
|
||||
size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header);
|
||||
|
||||
RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber,
|
||||
BWController *bwc, void *cs, rtp_m_cb *mcb);
|
||||
void rtp_kill(RTPSession *session);
|
||||
int rtp_allow_receiving(RTPSession *session);
|
||||
int rtp_stop_receiving(RTPSession *session);
|
||||
/**
|
||||
* Send a frame of audio or video data, chunked in @ref RTPMessage instances.
|
||||
*
|
||||
* @param session The A/V session to send the data for.
|
||||
* @param data A byte array of length @p length.
|
||||
* @param length The number of bytes to send from @p data.
|
||||
* @param is_keyframe Whether this video frame is a key frame. If it is an
|
||||
* audio frame, this parameter is ignored.
|
||||
*/
|
||||
int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
bool is_keyframe, const Logger *log);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_RTP_H
|
||||
871
local_pod_repo/toxcore/toxcore/toxav/rtp.m
Normal file
871
local_pod_repo/toxcore/toxcore/toxav/rtp.m
Normal file
@@ -0,0 +1,871 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#include "rtp.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bwcontroller.h"
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
/**
|
||||
* The number of milliseconds we want to keep a keyframe in the buffer for,
|
||||
* even though there are no free slots for incoming frames.
|
||||
*/
|
||||
#define VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS 15
|
||||
|
||||
|
||||
/**
|
||||
* return -1 on failure, 0 on success
|
||||
*
|
||||
*/
|
||||
static int rtp_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
Tox_Err_Friend_Custom_Packet error;
|
||||
tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error);
|
||||
|
||||
if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// allocate_len is NOT including header!
|
||||
static struct RTPMessage *new_message(const struct RTPHeader *header, size_t allocate_len, const uint8_t *data,
|
||||
uint16_t data_length)
|
||||
{
|
||||
assert(allocate_len >= data_length);
|
||||
struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + allocate_len);
|
||||
|
||||
if (msg == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
msg->len = data_length; // result without header
|
||||
msg->header = *header;
|
||||
memcpy(msg->data, data, msg->len);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the caller to clear slot 0.
|
||||
*/
|
||||
#define GET_SLOT_RESULT_DROP_OLDEST_SLOT (-1)
|
||||
|
||||
/**
|
||||
* Instruct the caller to drop the incoming packet.
|
||||
*/
|
||||
#define GET_SLOT_RESULT_DROP_INCOMING (-2)
|
||||
|
||||
/**
|
||||
* Find the next free slot in work_buffer for the incoming data packet.
|
||||
*
|
||||
* - If the data packet belongs to a frame that's already in the work_buffer then
|
||||
* use that slot.
|
||||
* - If there is no free slot return GET_SLOT_RESULT_DROP_OLDEST_SLOT.
|
||||
* - If the data packet is too old return GET_SLOT_RESULT_DROP_INCOMING.
|
||||
*
|
||||
* If there is a keyframe being assembled in slot 0, keep it a bit longer and
|
||||
* do not kick it out right away if all slots are full instead kick out the new
|
||||
* incoming interframe.
|
||||
*/
|
||||
static int8_t get_slot(const Logger *log, struct RTPWorkBufferList *wkbl, bool is_keyframe,
|
||||
const struct RTPHeader *header, bool is_multipart)
|
||||
{
|
||||
if (is_multipart) {
|
||||
// This RTP message is part of a multipart frame, so we try to find an
|
||||
// existing slot with the previous parts of the frame in it.
|
||||
for (uint8_t i = 0; i < wkbl->next_free_entry; ++i) {
|
||||
const struct RTPWorkBuffer *slot = &wkbl->work_buffer[i];
|
||||
|
||||
if ((slot->buf->header.sequnum == header->sequnum) && (slot->buf->header.timestamp == header->timestamp)) {
|
||||
// Sequence number and timestamp match, so this slot belongs to
|
||||
// the same frame.
|
||||
//
|
||||
// In reality, these will almost certainly either both match or
|
||||
// both not match. Only if somehow there were 65535 frames
|
||||
// between, the timestamp will matter.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The message may or may not be part of a multipart frame.
|
||||
//
|
||||
// If it is part of a multipart frame, then this is an entirely new frame
|
||||
// for which we did not have a slot *or* the frame is so old that its slot
|
||||
// has been evicted by now.
|
||||
//
|
||||
// |----------- time ----------->
|
||||
// _________________
|
||||
// slot 0 | |
|
||||
// -----------------
|
||||
// _________________
|
||||
// slot 1 | |
|
||||
// -----------------
|
||||
// ____________
|
||||
// slot 2 | | -> frame too old, drop
|
||||
// ------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// |----------- time ----------->
|
||||
// _________________
|
||||
// slot 0 | |
|
||||
// -----------------
|
||||
// _________________
|
||||
// slot 1 | |
|
||||
// -----------------
|
||||
// ____________
|
||||
// slot 2 | | -> ok, start filling in a new slot
|
||||
// ------------
|
||||
|
||||
// If there is a free slot:
|
||||
if (wkbl->next_free_entry < USED_RTP_WORKBUFFER_COUNT) {
|
||||
// If there is at least one filled slot:
|
||||
if (wkbl->next_free_entry > 0) {
|
||||
// Get the most recently filled slot.
|
||||
const struct RTPWorkBuffer *slot = &wkbl->work_buffer[wkbl->next_free_entry - 1];
|
||||
|
||||
// If the incoming packet is older than our newest slot, drop it.
|
||||
// This is the first situation in the above diagram.
|
||||
if (slot->buf->header.timestamp > header->timestamp) {
|
||||
LOGGER_DEBUG(log, "workbuffer:2:timestamp too old");
|
||||
return GET_SLOT_RESULT_DROP_INCOMING;
|
||||
}
|
||||
}
|
||||
|
||||
// Not all slots are filled, and the packet is newer than our most
|
||||
// recent slot, so it's a new frame we want to start assembling. This is
|
||||
// the second situation in the above diagram.
|
||||
return wkbl->next_free_entry;
|
||||
}
|
||||
|
||||
// If the incoming frame is a key frame, then stop assembling the oldest
|
||||
// slot, regardless of whether there was a keyframe in that or not.
|
||||
if (is_keyframe) {
|
||||
return GET_SLOT_RESULT_DROP_OLDEST_SLOT;
|
||||
}
|
||||
|
||||
// The incoming slot is not a key frame, so we look at slot 0 to see what to
|
||||
// do next.
|
||||
const struct RTPWorkBuffer *slot = &wkbl->work_buffer[0];
|
||||
|
||||
// The incoming frame is not a key frame, but the existing slot 0 is also
|
||||
// not a keyframe, so we stop assembling the existing frame and make space
|
||||
// for the new one.
|
||||
if (!slot->is_keyframe) {
|
||||
return GET_SLOT_RESULT_DROP_OLDEST_SLOT;
|
||||
}
|
||||
|
||||
// If this key frame is fully received, we also stop assembling and clear
|
||||
// slot 0. This also means sending the frame to the decoder.
|
||||
if (slot->received_len == slot->buf->header.data_length_full) {
|
||||
return GET_SLOT_RESULT_DROP_OLDEST_SLOT;
|
||||
}
|
||||
|
||||
// This is a key frame, not fully received yet, but it's already much older
|
||||
// than the incoming frame, so we stop assembling it and send whatever part
|
||||
// we did receive to the decoder.
|
||||
if (slot->buf->header.timestamp + VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS <= header->timestamp) {
|
||||
return GET_SLOT_RESULT_DROP_OLDEST_SLOT;
|
||||
}
|
||||
|
||||
// This is a key frame, it's not too old yet, so we keep it in its slot for
|
||||
// a little longer.
|
||||
LOGGER_INFO(log, "keep KEYFRAME in workbuffer");
|
||||
return GET_SLOT_RESULT_DROP_INCOMING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an assembled frame (as much data as we currently have for this frame,
|
||||
* some pieces may be missing)
|
||||
*
|
||||
* If there are no frames ready, we return NULL. If this function returns
|
||||
* non-NULL, it transfers ownership of the message to the caller, i.e. the
|
||||
* caller is responsible for storing it elsewhere or calling `free()`.
|
||||
*/
|
||||
static struct RTPMessage *process_frame(const Logger *log, struct RTPWorkBufferList *wkbl, uint8_t slot_id)
|
||||
{
|
||||
assert(wkbl->next_free_entry >= 0);
|
||||
|
||||
if (wkbl->next_free_entry == 0) {
|
||||
// There are no frames in any slot.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Slot 0 contains a key frame, slot_id points at an interframe that is
|
||||
// relative to that key frame, so we don't use it yet.
|
||||
if (wkbl->work_buffer[0].is_keyframe && slot_id != 0) {
|
||||
LOGGER_DEBUG(log, "process_frame:KEYFRAME waiting in slot 0");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Either slot_id is 0 and slot 0 is a key frame, or there is no key frame
|
||||
// in slot 0 (and slot_id is anything).
|
||||
struct RTPWorkBuffer *const slot = &wkbl->work_buffer[slot_id];
|
||||
|
||||
// Move ownership of the frame out of the slot into m_new.
|
||||
struct RTPMessage *const m_new = slot->buf;
|
||||
slot->buf = nullptr;
|
||||
|
||||
assert(wkbl->next_free_entry >= 1 && wkbl->next_free_entry <= USED_RTP_WORKBUFFER_COUNT);
|
||||
|
||||
if (slot_id != wkbl->next_free_entry - 1) {
|
||||
// The slot is not the last slot, so we created a gap. We move all the
|
||||
// entries after it one step up.
|
||||
for (uint8_t i = slot_id; i < wkbl->next_free_entry - 1; ++i) {
|
||||
// Move entry (i+1) into entry (i).
|
||||
wkbl->work_buffer[i] = wkbl->work_buffer[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// We now have a free entry at the end of the array.
|
||||
--wkbl->next_free_entry;
|
||||
|
||||
// Clear the newly freed entry.
|
||||
const struct RTPWorkBuffer empty = {0};
|
||||
wkbl->work_buffer[wkbl->next_free_entry] = empty;
|
||||
|
||||
// Move ownership of the frame to the caller.
|
||||
return m_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log A logger.
|
||||
* @param wkbl The list of in-progress frames, i.e. all the slots.
|
||||
* @param slot_id The slot we want to fill the data into.
|
||||
* @param is_keyframe Whether the data is part of a key frame.
|
||||
* @param header The RTP header from the incoming packet.
|
||||
* @param incoming_data The pure payload without header.
|
||||
* @param incoming_data_length The length in bytes of the incoming data payload.
|
||||
*/
|
||||
static bool fill_data_into_slot(const Logger *log, struct RTPWorkBufferList *wkbl, const uint8_t slot_id,
|
||||
bool is_keyframe, const struct RTPHeader *header,
|
||||
const uint8_t *incoming_data, uint16_t incoming_data_length)
|
||||
{
|
||||
// We're either filling the data into an existing slot, or in a new one that
|
||||
// is the next free entry.
|
||||
assert(slot_id <= wkbl->next_free_entry);
|
||||
struct RTPWorkBuffer *const slot = &wkbl->work_buffer[slot_id];
|
||||
|
||||
assert(header != nullptr);
|
||||
assert(is_keyframe == (bool)((header->flags & RTP_KEY_FRAME) != 0));
|
||||
|
||||
if (slot->received_len == 0) {
|
||||
assert(slot->buf == nullptr);
|
||||
|
||||
// No data for this slot has been received, yet, so we create a new
|
||||
// message for it with enough memory for the entire frame.
|
||||
struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + header->data_length_full);
|
||||
|
||||
if (msg == nullptr) {
|
||||
LOGGER_ERROR(log, "Out of memory while trying to allocate for frame of size %u",
|
||||
(unsigned)header->data_length_full);
|
||||
// Out of memory: throw away the incoming data.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unused in the new video receiving code, as it's 16 bit and can't hold
|
||||
// the full length of large frames. Instead, we use slot->received_len.
|
||||
msg->len = 0;
|
||||
msg->header = *header;
|
||||
|
||||
slot->buf = msg;
|
||||
slot->is_keyframe = is_keyframe;
|
||||
slot->received_len = 0;
|
||||
|
||||
assert(wkbl->next_free_entry < USED_RTP_WORKBUFFER_COUNT);
|
||||
++wkbl->next_free_entry;
|
||||
}
|
||||
|
||||
// We already checked this when we received the packet, but we rely on it
|
||||
// here, so assert again.
|
||||
assert(header->offset_full < header->data_length_full);
|
||||
|
||||
// Copy the incoming chunk of data into the correct position in the full
|
||||
// frame data array.
|
||||
memcpy(
|
||||
slot->buf->data + header->offset_full,
|
||||
incoming_data,
|
||||
incoming_data_length
|
||||
);
|
||||
|
||||
// Update the total received length of this slot.
|
||||
slot->received_len += incoming_data_length;
|
||||
|
||||
// Update received length also in the header of the message, for later use.
|
||||
slot->buf->header.received_length_full = slot->received_len;
|
||||
|
||||
return slot->received_len == header->data_length_full;
|
||||
}
|
||||
|
||||
static void update_bwc_values(const Logger *log, RTPSession *session, const struct RTPMessage *msg)
|
||||
{
|
||||
if (session->first_packets_counter < DISMISS_FIRST_LOST_VIDEO_PACKET_COUNT) {
|
||||
++session->first_packets_counter;
|
||||
} else {
|
||||
const uint32_t data_length_full = msg->header.data_length_full; // without header
|
||||
const uint32_t received_length_full = msg->header.received_length_full; // without header
|
||||
bwc_add_recv(session->bwc, data_length_full);
|
||||
|
||||
if (received_length_full < data_length_full) {
|
||||
LOGGER_DEBUG(log, "BWC: full length=%u received length=%d", data_length_full, received_length_full);
|
||||
bwc_add_lost(session->bwc, data_length_full - received_length_full);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a single RTP video packet.
|
||||
*
|
||||
* The packet may or may not be part of a multipart frame. This function will
|
||||
* find out and handle it appropriately.
|
||||
*
|
||||
* @param session The current RTP session with:
|
||||
* <code>
|
||||
* session->mcb == vc_queue_message() // this function is called from here
|
||||
* session->mp == struct RTPMessage *
|
||||
* session->cs == call->video.second // == VCSession created by vc_new() call
|
||||
* </code>
|
||||
* @param header The RTP header deserialised from the packet.
|
||||
* @param incoming_data The packet data *not* header, i.e. this is the actual
|
||||
* payload.
|
||||
* @param incoming_data_length The packet length *not* including header, i.e.
|
||||
* this is the actual payload length.
|
||||
* @param log A logger.
|
||||
*
|
||||
* @retval -1 on error.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
static int handle_video_packet(RTPSession *session, const struct RTPHeader *header,
|
||||
const uint8_t *incoming_data, uint16_t incoming_data_length, const Logger *log)
|
||||
{
|
||||
// Full frame length in bytes. The frame may be split into multiple packets,
|
||||
// but this value is the complete assembled frame size.
|
||||
const uint32_t full_frame_length = header->data_length_full;
|
||||
|
||||
// Current offset in the frame. If this is the first packet of a multipart
|
||||
// frame or it's not a multipart frame, then this value is 0.
|
||||
const uint32_t offset = header->offset_full; // without header
|
||||
|
||||
// The sender tells us whether this is a key frame.
|
||||
const bool is_keyframe = (header->flags & RTP_KEY_FRAME) != 0;
|
||||
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- full lens=%u len=%u offset=%u is_keyframe=%s",
|
||||
(unsigned)incoming_data_length, (unsigned)full_frame_length, (unsigned)offset, is_keyframe ? "K" : ".");
|
||||
LOGGER_DEBUG(log, "wkbl->next_free_entry:003=%d", session->work_buffer_list->next_free_entry);
|
||||
|
||||
const bool is_multipart = full_frame_length != incoming_data_length;
|
||||
|
||||
/* The message was sent in single part */
|
||||
int8_t slot_id = get_slot(log, session->work_buffer_list, is_keyframe, header, is_multipart);
|
||||
LOGGER_DEBUG(log, "slot num=%d", slot_id);
|
||||
|
||||
// get_slot told us to drop the packet, so we ignore it.
|
||||
if (slot_id == GET_SLOT_RESULT_DROP_INCOMING) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get_slot said there is no free slot.
|
||||
if (slot_id == GET_SLOT_RESULT_DROP_OLDEST_SLOT) {
|
||||
LOGGER_DEBUG(log, "there was no free slot, so we process the oldest frame");
|
||||
// We now own the frame.
|
||||
struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, 0);
|
||||
|
||||
// The process_frame function returns NULL if there is no slot 0, i.e.
|
||||
// the work buffer list is completely empty. It can't be empty, because
|
||||
// get_slot just told us it's full, so process_frame must return non-null.
|
||||
assert(m_new != nullptr);
|
||||
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]);
|
||||
update_bwc_values(log, session, m_new);
|
||||
// Pass ownership of m_new to the callback.
|
||||
session->mcb(session->m->mono_time, session->cs, m_new);
|
||||
// Now we no longer own m_new.
|
||||
m_new = nullptr;
|
||||
|
||||
// Now we must have a free slot, so we either get that slot, i.e. >= 0,
|
||||
// or get told to drop the incoming packet if it's too old.
|
||||
slot_id = get_slot(log, session->work_buffer_list, is_keyframe, header, /* is_multipart */false);
|
||||
|
||||
if (slot_id == GET_SLOT_RESULT_DROP_INCOMING) {
|
||||
// The incoming frame is too old, so we drop it.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// We must have a valid slot here.
|
||||
assert(slot_id >= 0);
|
||||
|
||||
LOGGER_DEBUG(log, "fill_data_into_slot.1");
|
||||
|
||||
// fill in this part into the slot buffer at the correct offset
|
||||
if (!fill_data_into_slot(
|
||||
log,
|
||||
session->work_buffer_list,
|
||||
slot_id,
|
||||
is_keyframe,
|
||||
header,
|
||||
incoming_data,
|
||||
incoming_data_length)) {
|
||||
// Memory allocation failed. Return error.
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, slot_id);
|
||||
|
||||
if (m_new != nullptr) {
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]);
|
||||
update_bwc_values(log, session, m_new);
|
||||
session->mcb(session->m->mono_time, session->cs, m_new);
|
||||
|
||||
m_new = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval -1 on error.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
static int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object)
|
||||
{
|
||||
RTPSession *session = (RTPSession *)object;
|
||||
|
||||
if (session == nullptr || length < RTP_HEADER_SIZE + 1) {
|
||||
LOGGER_WARNING(m->log, "No session or invalid length of received buffer!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the packet type.
|
||||
const uint8_t packet_type = data[0];
|
||||
++data;
|
||||
--length;
|
||||
|
||||
// Unpack the header.
|
||||
struct RTPHeader header;
|
||||
rtp_header_unpack(data, &header);
|
||||
|
||||
if (header.pt != packet_type % 128) {
|
||||
LOGGER_WARNING(m->log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d",
|
||||
header.pt, packet_type % 128);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header.pt != session->payload_type % 128) {
|
||||
LOGGER_WARNING(m->log, "RTPHeader packet type does not match this session's payload type: %d != %d",
|
||||
header.pt, session->payload_type % 128);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((header.flags & RTP_LARGE_FRAME) != 0 && header.offset_full >= header.data_length_full) {
|
||||
LOGGER_ERROR(m->log, "Invalid video packet: frame offset (%u) >= full frame length (%u)",
|
||||
(unsigned)header.offset_full, (unsigned)header.data_length_full);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header.offset_lower >= header.data_length_lower) {
|
||||
LOGGER_ERROR(m->log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)",
|
||||
(unsigned)header.offset_lower, (unsigned)header.data_length_lower);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(m->log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128);
|
||||
|
||||
// The sender uses the new large-frame capable protocol and is sending a
|
||||
// video packet.
|
||||
if ((header.flags & RTP_LARGE_FRAME) != 0 && header.pt == (RTP_TYPE_VIDEO % 128)) {
|
||||
return handle_video_packet(session, &header, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE, m->log);
|
||||
}
|
||||
|
||||
// everything below here is for the old 16 bit protocol ------------------
|
||||
|
||||
if (header.data_length_lower == length - RTP_HEADER_SIZE) {
|
||||
/* The message is sent in single part */
|
||||
|
||||
/* Message is not late; pick up the latest parameters */
|
||||
session->rsequnum = header.sequnum;
|
||||
session->rtimestamp = header.timestamp;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
|
||||
/* Invoke processing of active multiparted message */
|
||||
if (session->mp != nullptr) {
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
session->mp = nullptr;
|
||||
}
|
||||
|
||||
/* The message came in the allowed time;
|
||||
*/
|
||||
|
||||
return session->mcb(session->m->mono_time, session->cs, new_message(&header, length - RTP_HEADER_SIZE,
|
||||
data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE));
|
||||
}
|
||||
|
||||
/* The message is sent in multiple parts */
|
||||
|
||||
if (session->mp != nullptr) {
|
||||
/* There are 2 possible situations in this case:
|
||||
* 1) being that we got the part of already processing message.
|
||||
* 2) being that we got the part of a new/old message.
|
||||
*
|
||||
* We handle them differently as we only allow a single multiparted
|
||||
* processing message
|
||||
*/
|
||||
if (session->mp->header.sequnum == header.sequnum &&
|
||||
session->mp->header.timestamp == header.timestamp) {
|
||||
/* First case */
|
||||
|
||||
/* Make sure we have enough allocated memory */
|
||||
if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE ||
|
||||
session->mp->header.data_length_lower <= header.offset_lower) {
|
||||
/* There happened to be some corruption on the stream;
|
||||
* continue wihtout this part
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE,
|
||||
length - RTP_HEADER_SIZE);
|
||||
session->mp->len += length - RTP_HEADER_SIZE;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
|
||||
if (session->mp->len == session->mp->header.data_length_lower) {
|
||||
/* Received a full message; now push it for the further
|
||||
* processing.
|
||||
*/
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
session->mp = nullptr;
|
||||
}
|
||||
} else {
|
||||
/* Second case */
|
||||
if (session->mp->header.timestamp > header.timestamp) {
|
||||
/* The received message part is from the old message;
|
||||
* discard it.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push the previous message for processing */
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
|
||||
session->mp = nullptr;
|
||||
goto NEW_MULTIPARTED;
|
||||
}
|
||||
} else {
|
||||
/* In this case threat the message as if it was received in order
|
||||
*/
|
||||
/* This is also a point for new multiparted messages */
|
||||
NEW_MULTIPARTED:
|
||||
|
||||
/* Message is not late; pick up the latest parameters */
|
||||
session->rsequnum = header.sequnum;
|
||||
session->rtimestamp = header.timestamp;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
|
||||
/* Store message.
|
||||
*/
|
||||
session->mp = new_message(&header, header.data_length_lower, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE);
|
||||
|
||||
if (session->mp != nullptr) {
|
||||
memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len);
|
||||
} else {
|
||||
LOGGER_WARNING(m->log, "new_message() returned a null pointer");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header)
|
||||
{
|
||||
uint8_t *p = rdata;
|
||||
*p = (header->ve & 3) << 6
|
||||
| (header->pe & 1) << 5
|
||||
| (header->xe & 1) << 4
|
||||
| (header->cc & 0xf);
|
||||
++p;
|
||||
*p = (header->ma & 1) << 7
|
||||
| (header->pt & 0x7f);
|
||||
++p;
|
||||
|
||||
p += net_pack_u16(p, header->sequnum);
|
||||
p += net_pack_u32(p, header->timestamp);
|
||||
p += net_pack_u32(p, header->ssrc);
|
||||
p += net_pack_u64(p, header->flags);
|
||||
p += net_pack_u32(p, header->offset_full);
|
||||
p += net_pack_u32(p, header->data_length_full);
|
||||
p += net_pack_u32(p, header->received_length_full);
|
||||
|
||||
for (size_t i = 0; i < RTP_PADDING_FIELDS; ++i) {
|
||||
p += net_pack_u32(p, 0);
|
||||
}
|
||||
|
||||
p += net_pack_u16(p, header->offset_lower);
|
||||
p += net_pack_u16(p, header->data_length_lower);
|
||||
assert(p == rdata + RTP_HEADER_SIZE);
|
||||
return p - rdata;
|
||||
}
|
||||
|
||||
size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header)
|
||||
{
|
||||
const uint8_t *p = data;
|
||||
header->ve = (*p >> 6) & 3;
|
||||
header->pe = (*p >> 5) & 1;
|
||||
header->xe = (*p >> 4) & 1;
|
||||
header->cc = *p & 0xf;
|
||||
++p;
|
||||
|
||||
header->ma = (*p >> 7) & 1;
|
||||
header->pt = *p & 0x7f;
|
||||
++p;
|
||||
|
||||
p += net_unpack_u16(p, &header->sequnum);
|
||||
p += net_unpack_u32(p, &header->timestamp);
|
||||
p += net_unpack_u32(p, &header->ssrc);
|
||||
p += net_unpack_u64(p, &header->flags);
|
||||
p += net_unpack_u32(p, &header->offset_full);
|
||||
p += net_unpack_u32(p, &header->data_length_full);
|
||||
p += net_unpack_u32(p, &header->received_length_full);
|
||||
|
||||
p += sizeof(uint32_t) * RTP_PADDING_FIELDS;
|
||||
|
||||
p += net_unpack_u16(p, &header->offset_lower);
|
||||
p += net_unpack_u16(p, &header->data_length_lower);
|
||||
assert(p == data + RTP_HEADER_SIZE);
|
||||
return p - data;
|
||||
}
|
||||
|
||||
RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber,
|
||||
BWController *bwc, void *cs, rtp_m_cb *mcb)
|
||||
{
|
||||
assert(mcb != nullptr);
|
||||
assert(cs != nullptr);
|
||||
assert(m != nullptr);
|
||||
|
||||
RTPSession *session = (RTPSession *)calloc(1, sizeof(RTPSession));
|
||||
|
||||
if (session == nullptr) {
|
||||
LOGGER_WARNING(m->log, "Alloc failed! Program might misbehave!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
session->work_buffer_list = (struct RTPWorkBufferList *)calloc(1, sizeof(struct RTPWorkBufferList));
|
||||
|
||||
if (session->work_buffer_list == nullptr) {
|
||||
LOGGER_ERROR(m->log, "out of memory while allocating work buffer list");
|
||||
free(session);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// First entry is free.
|
||||
session->work_buffer_list->next_free_entry = 0;
|
||||
|
||||
session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : random_u32(m->rng);
|
||||
session->payload_type = payload_type;
|
||||
session->m = m;
|
||||
session->tox = tox;
|
||||
session->friend_number = friendnumber;
|
||||
|
||||
// set NULL just in case
|
||||
session->mp = nullptr;
|
||||
session->first_packets_counter = 1;
|
||||
|
||||
/* Also set payload type as prefix */
|
||||
session->bwc = bwc;
|
||||
session->cs = cs;
|
||||
session->mcb = mcb;
|
||||
|
||||
if (-1 == rtp_allow_receiving(session)) {
|
||||
LOGGER_WARNING(m->log, "Failed to start rtp receiving mode");
|
||||
free(session->work_buffer_list);
|
||||
free(session);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void rtp_kill(RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Terminated RTP session: %p", (void *)session);
|
||||
rtp_stop_receiving(session);
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d",
|
||||
(int)session->work_buffer_list->next_free_entry);
|
||||
|
||||
for (int8_t i = 0; i < session->work_buffer_list->next_free_entry; ++i) {
|
||||
free(session->work_buffer_list->work_buffer[i].buf);
|
||||
}
|
||||
free(session->work_buffer_list);
|
||||
free(session);
|
||||
}
|
||||
|
||||
int rtp_allow_receiving(RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m_callback_rtp_packet(session->m, session->friend_number, session->payload_type,
|
||||
handle_rtp_packet, session) == -1) {
|
||||
LOGGER_WARNING(session->m->log, "Failed to register rtp receive handler");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Started receiving on session: %p", (void *)session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtp_stop_receiving(RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, nullptr, nullptr);
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Stopped receiving on session: %p", (void *)session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a frame of audio or video data, chunked in @ref RTPMessage instances.
|
||||
*
|
||||
* @param session The A/V session to send the data for.
|
||||
* @param data A byte array of length @p length.
|
||||
* @param length The number of bytes to send from @p data.
|
||||
* @param is_keyframe Whether this video frame is a key frame. If it is an
|
||||
* audio frame, this parameter is ignored.
|
||||
*/
|
||||
int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
bool is_keyframe, const Logger *log)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
LOGGER_ERROR(log, "No session!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct RTPHeader header = {0};
|
||||
|
||||
header.ve = 2; // this is unused in toxav
|
||||
|
||||
header.pe = 0;
|
||||
|
||||
header.xe = 0;
|
||||
|
||||
header.cc = 0;
|
||||
|
||||
header.ma = 0;
|
||||
|
||||
header.pt = session->payload_type % 128;
|
||||
|
||||
header.sequnum = session->sequnum;
|
||||
|
||||
header.timestamp = current_time_monotonic(session->m->mono_time);
|
||||
|
||||
header.ssrc = session->ssrc;
|
||||
|
||||
header.offset_lower = 0;
|
||||
|
||||
// here the highest bits gets stripped anyway, no need to do keyframe bit magic here!
|
||||
header.data_length_lower = length;
|
||||
|
||||
if (session->payload_type == RTP_TYPE_VIDEO) {
|
||||
header.flags = RTP_LARGE_FRAME;
|
||||
}
|
||||
|
||||
uint16_t length_safe = (uint16_t)length;
|
||||
|
||||
if (length > UINT16_MAX) {
|
||||
length_safe = UINT16_MAX;
|
||||
}
|
||||
|
||||
header.data_length_lower = length_safe;
|
||||
header.data_length_full = length; // without header
|
||||
header.offset_lower = 0;
|
||||
header.offset_full = 0;
|
||||
|
||||
if (is_keyframe) {
|
||||
header.flags |= RTP_KEY_FRAME;
|
||||
}
|
||||
|
||||
VLA(uint8_t, rdata, length + RTP_HEADER_SIZE + 1);
|
||||
memset(rdata, 0, SIZEOF_VLA(rdata));
|
||||
rdata[0] = session->payload_type; // packet id == payload_type
|
||||
|
||||
if (MAX_CRYPTO_DATA_SIZE > (length + RTP_HEADER_SIZE + 1)) {
|
||||
/*
|
||||
* The length is lesser than the maximum allowed length (including header)
|
||||
* Send the packet in single piece.
|
||||
*/
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, SIZEOF_VLA(rdata))) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! net error: %s",
|
||||
(unsigned)SIZEOF_VLA(rdata), netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The length is greater than the maximum allowed length (including header)
|
||||
* Send the packet in multiple pieces.
|
||||
*/
|
||||
uint32_t sent = 0;
|
||||
uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1);
|
||||
|
||||
while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) {
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number,
|
||||
rdata, piece + RTP_HEADER_SIZE + 1)) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s",
|
||||
piece + RTP_HEADER_SIZE + 1, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
|
||||
sent += piece;
|
||||
header.offset_lower = sent;
|
||||
header.offset_full = sent; // raw data offset, without any header
|
||||
}
|
||||
|
||||
/* Send remaining */
|
||||
piece = length - sent;
|
||||
|
||||
if (piece != 0) {
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata,
|
||||
piece + RTP_HEADER_SIZE + 1)) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s",
|
||||
piece + RTP_HEADER_SIZE + 1, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++session->sequnum;
|
||||
return 0;
|
||||
}
|
||||
849
local_pod_repo/toxcore/toxcore/toxav/toxav.h
Normal file
849
local_pod_repo/toxcore/toxcore/toxav/toxav.h
Normal file
@@ -0,0 +1,849 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Public audio/video API for Tox clients.
|
||||
*
|
||||
* This API can handle multiple calls. Each call has its state, in very rare
|
||||
* occasions the library can change the state of the call without apps knowledge.
|
||||
*
|
||||
* @section av_events Events and callbacks
|
||||
*
|
||||
* As in Core API, events are handled by callbacks. One callback can be
|
||||
* registered per event. All events have a callback function type named
|
||||
* `toxav_{event}_cb` and a function to register it named `toxav_callback_{event}`.
|
||||
* Passing a NULL callback will result in no callback being registered for that
|
||||
* event. Only one callback per event can be registered, so if a client needs
|
||||
* multiple event listeners, it needs to implement the dispatch functionality
|
||||
* itself. Unlike Core API, lack of some event handlers will cause the the
|
||||
* library to drop calls before they are started. Hanging up call from a
|
||||
* callback causes undefined behaviour.
|
||||
*
|
||||
* @section av_threading Threading implications
|
||||
*
|
||||
* Only toxav_iterate is thread-safe, all other functions must run from the
|
||||
* tox thread.
|
||||
*
|
||||
* Important exceptions are the `*_iterate` and `*_iterate_interval`
|
||||
* functions. You have to choose either the single thread or the multi thread
|
||||
* functions and read their documentation.
|
||||
*
|
||||
* A common way to run ToxAV (multiple or single instance) is to have a thread,
|
||||
* separate from tox instance thread, running a simple toxav_iterate loop,
|
||||
* sleeping for `toxav_iteration_interval * milliseconds` on each iteration.
|
||||
*
|
||||
* An important thing to note is that events are triggered from both tox and
|
||||
* toxav thread (see above). Audio and video receive frame events are triggered
|
||||
* from toxav thread while all the other events are triggered from tox thread.
|
||||
*
|
||||
* Tox thread has priority with mutex mechanisms. Any api function can
|
||||
* fail if mutexes are held by tox thread in which case they will set SYNC
|
||||
* error code.
|
||||
*
|
||||
* @subsection av_multi_threading Separate audio and video threads
|
||||
*
|
||||
* ToxAV supports either a single thread for audio and video or decoding and
|
||||
* encoding them in separate threads. You have to choose one mode and can not
|
||||
* mix function calls to those different modes.
|
||||
*
|
||||
* For best results use the multi-threaded mode and run the audio thread with
|
||||
* higher priority than the video thread. This prioritizes audio over video.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_TOXAV_H
|
||||
#define C_TOXCORE_TOXAV_TOXAV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* External Tox type.
|
||||
*/
|
||||
#ifndef TOX_DEFINED
|
||||
#define TOX_DEFINED
|
||||
typedef struct Tox Tox;
|
||||
#endif /* TOX_DEFINED */
|
||||
|
||||
/**
|
||||
* @brief The ToxAV instance type.
|
||||
*
|
||||
* Each ToxAV instance can be bound to only one Tox instance, and Tox instance
|
||||
* can have only one ToxAV instance. One must make sure to close ToxAV instance
|
||||
* prior closing Tox instance otherwise undefined behaviour occurs. Upon
|
||||
* closing of ToxAV instance, all active calls will be forcibly terminated
|
||||
* without notifying peers.
|
||||
*/
|
||||
typedef struct ToxAV ToxAV;
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief Creation and destruction
|
||||
*/
|
||||
|
||||
typedef enum Toxav_Err_New {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_NEW_OK,
|
||||
|
||||
/**
|
||||
* One of the arguments to the function was NULL when it was not expected.
|
||||
*/
|
||||
TOXAV_ERR_NEW_NULL,
|
||||
|
||||
/**
|
||||
* Memory allocation failure while trying to allocate structures required for
|
||||
* the A/V session.
|
||||
*/
|
||||
TOXAV_ERR_NEW_MALLOC,
|
||||
|
||||
/**
|
||||
* Attempted to create a second session for the same Tox instance.
|
||||
*/
|
||||
TOXAV_ERR_NEW_MULTIPLE,
|
||||
|
||||
} Toxav_Err_New;
|
||||
|
||||
|
||||
/**
|
||||
* Start new A/V session. There can only be only one session per Tox instance.
|
||||
*/
|
||||
ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error);
|
||||
|
||||
/**
|
||||
* Releases all resources associated with the A/V session.
|
||||
*
|
||||
* If any calls were ongoing, these will be forcibly terminated without
|
||||
* notifying peers. After calling this function, no other functions may be
|
||||
* called and the av pointer becomes invalid.
|
||||
*/
|
||||
void toxav_kill(ToxAV *av);
|
||||
|
||||
/**
|
||||
* Returns the Tox instance the A/V object was created for.
|
||||
*/
|
||||
Tox *toxav_get_tox(const ToxAV *av);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief A/V event loop, single thread
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the interval in milliseconds when the next toxav_iterate call should
|
||||
* be. If no call is active at the moment, this function returns 200.
|
||||
* This function MUST be called from the same thread as toxav_iterate.
|
||||
*/
|
||||
uint32_t toxav_iteration_interval(const ToxAV *av);
|
||||
|
||||
/**
|
||||
* Main loop for the session. This function needs to be called in intervals of
|
||||
* `toxav_iteration_interval()` milliseconds. It is best called in the separate
|
||||
* thread from tox_iterate.
|
||||
*/
|
||||
void toxav_iterate(ToxAV *av);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief A/V event loop, multiple threads
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the interval in milliseconds when the next toxav_audio_iterate call
|
||||
* should be. If no call is active at the moment, this function returns 200.
|
||||
* This function MUST be called from the same thread as toxav_audio_iterate.
|
||||
*/
|
||||
uint32_t toxav_audio_iteration_interval(const ToxAV *av);
|
||||
|
||||
/**
|
||||
* Main loop for the session. This function needs to be called in intervals of
|
||||
* `toxav_audio_iteration_interval()` milliseconds. It is best called in a
|
||||
* separate thread from tox_iterate and toxav_video_iterate. The thread calling
|
||||
* this function should have higher priority than the one calling
|
||||
* toxav_video_iterate to prioritize audio over video.
|
||||
*/
|
||||
void toxav_audio_iterate(ToxAV *av);
|
||||
|
||||
/**
|
||||
* Returns the interval in milliseconds when the next toxav_video_iterate call
|
||||
* should be. If no call is active at the moment, this function returns 200.
|
||||
* This function MUST be called from the same thread as toxav_video_iterate.
|
||||
*/
|
||||
uint32_t toxav_video_iteration_interval(const ToxAV *av);
|
||||
|
||||
/**
|
||||
* Main loop for the session. This function needs to be called in intervals of
|
||||
* `toxav_video_iteration_interval()` milliseconds. It is best called in a
|
||||
* separate thread from tox_iterate and toxav_audio_iterate. The thread calling
|
||||
* this function should have lower priority than the one calling
|
||||
* toxav_audio_iterate to prioritize audio over video.
|
||||
*/
|
||||
void toxav_video_iterate(ToxAV *av);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief Call setup
|
||||
*/
|
||||
|
||||
typedef enum Toxav_Err_Call {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_CALL_OK,
|
||||
|
||||
/**
|
||||
* A resource allocation error occurred while trying to create the structures
|
||||
* required for the call.
|
||||
*/
|
||||
TOXAV_ERR_CALL_MALLOC,
|
||||
|
||||
/**
|
||||
* Synchronization error occurred.
|
||||
*/
|
||||
TOXAV_ERR_CALL_SYNC,
|
||||
|
||||
/**
|
||||
* The friend number did not designate a valid friend.
|
||||
*/
|
||||
TOXAV_ERR_CALL_FRIEND_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* The friend was valid, but not currently connected.
|
||||
*/
|
||||
TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED,
|
||||
|
||||
/**
|
||||
* Attempted to call a friend while already in an audio or video call with
|
||||
* them.
|
||||
*/
|
||||
TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL,
|
||||
|
||||
/**
|
||||
* Audio or video bit rate is invalid.
|
||||
*/
|
||||
TOXAV_ERR_CALL_INVALID_BIT_RATE,
|
||||
|
||||
} Toxav_Err_Call;
|
||||
|
||||
|
||||
/**
|
||||
* Call a friend. This will start ringing the friend.
|
||||
*
|
||||
* It is the client's responsibility to stop ringing after a certain timeout,
|
||||
* if such behaviour is desired. If the client does not stop ringing, the
|
||||
* library will not stop until the friend is disconnected. Audio and video
|
||||
* receiving are both enabled by default.
|
||||
*
|
||||
* @param friend_number The friend number of the friend that should be called.
|
||||
* @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable
|
||||
* audio sending.
|
||||
* @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable
|
||||
* video sending.
|
||||
*/
|
||||
bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,
|
||||
Toxav_Err_Call *error);
|
||||
|
||||
/**
|
||||
* The function type for the call callback.
|
||||
*
|
||||
* @param friend_number The friend number from which the call is incoming.
|
||||
* @param audio_enabled True if friend is sending audio.
|
||||
* @param video_enabled True if friend is sending video.
|
||||
*/
|
||||
typedef void toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `call` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_call(ToxAV *av, toxav_call_cb *callback, void *user_data);
|
||||
|
||||
typedef enum Toxav_Err_Answer {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_OK,
|
||||
|
||||
/**
|
||||
* Synchronization error occurred.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_SYNC,
|
||||
|
||||
/**
|
||||
* Failed to initialize codecs for call session. Note that codec initiation
|
||||
* will fail if there is no receive callback registered for either audio or
|
||||
* video.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_CODEC_INITIALIZATION,
|
||||
|
||||
/**
|
||||
* The friend number did not designate a valid friend.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* The friend was valid, but they are not currently trying to initiate a call.
|
||||
* This is also returned if this client is already in a call with the friend.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING,
|
||||
|
||||
/**
|
||||
* Audio or video bit rate is invalid.
|
||||
*/
|
||||
TOXAV_ERR_ANSWER_INVALID_BIT_RATE,
|
||||
|
||||
} Toxav_Err_Answer;
|
||||
|
||||
|
||||
/**
|
||||
* Accept an incoming call.
|
||||
*
|
||||
* If answering fails for any reason, the call will still be pending and it is
|
||||
* possible to try and answer it later. Audio and video receiving are both
|
||||
* enabled by default.
|
||||
*
|
||||
* @param friend_number The friend number of the friend that is calling.
|
||||
* @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable
|
||||
* audio sending.
|
||||
* @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable
|
||||
* video sending.
|
||||
*/
|
||||
bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,
|
||||
Toxav_Err_Answer *error);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief Call state graph
|
||||
*/
|
||||
|
||||
enum Toxav_Friend_Call_State {
|
||||
|
||||
/**
|
||||
* The empty bit mask. None of the bits specified below are set.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_NONE = 0,
|
||||
|
||||
/**
|
||||
* Set by the AV core if an error occurred on the remote end or if friend
|
||||
* timed out. This is the final state after which no more state
|
||||
* transitions can occur for the call. This call state will never be triggered
|
||||
* in combination with other call states.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_ERROR = 1,
|
||||
|
||||
/**
|
||||
* The call has finished. This is the final state after which no more state
|
||||
* transitions can occur for the call. This call state will never be
|
||||
* triggered in combination with other call states.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_FINISHED = 2,
|
||||
|
||||
/**
|
||||
* The flag that marks that friend is sending audio.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_SENDING_A = 4,
|
||||
|
||||
/**
|
||||
* The flag that marks that friend is sending video.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_SENDING_V = 8,
|
||||
|
||||
/**
|
||||
* The flag that marks that friend is receiving audio.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_ACCEPTING_A = 16,
|
||||
|
||||
/**
|
||||
* The flag that marks that friend is receiving video.
|
||||
*/
|
||||
TOXAV_FRIEND_CALL_STATE_ACCEPTING_V = 32,
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The function type for the call_state callback.
|
||||
*
|
||||
* @param friend_number The friend number for which the call state changed.
|
||||
* @param state The bitmask of the new call state which is guaranteed to be
|
||||
* different than the previous state. The state is set to 0 when the call is
|
||||
* paused. The bitmask represents all the activities currently performed by the
|
||||
* friend.
|
||||
*/
|
||||
typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `call_state` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *user_data);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief Call control
|
||||
*/
|
||||
|
||||
typedef enum Toxav_Call_Control {
|
||||
|
||||
/**
|
||||
* Resume a previously paused call. Only valid if the pause was caused by this
|
||||
* client, if not, this control is ignored. Not valid before the call is accepted.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_RESUME,
|
||||
|
||||
/**
|
||||
* Put a call on hold. Not valid before the call is accepted.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_PAUSE,
|
||||
|
||||
/**
|
||||
* Reject a call if it was not answered, yet. Cancel a call after it was
|
||||
* answered.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_CANCEL,
|
||||
|
||||
/**
|
||||
* Request that the friend stops sending audio. Regardless of the friend's
|
||||
* compliance, this will cause the audio_receive_frame event to stop being
|
||||
* triggered on receiving an audio frame from the friend.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_MUTE_AUDIO,
|
||||
|
||||
/**
|
||||
* Calling this control will notify client to start sending audio again.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_UNMUTE_AUDIO,
|
||||
|
||||
/**
|
||||
* Request that the friend stops sending video. Regardless of the friend's
|
||||
* compliance, this will cause the video_receive_frame event to stop being
|
||||
* triggered on receiving a video frame from the friend.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_HIDE_VIDEO,
|
||||
|
||||
/**
|
||||
* Calling this control will notify client to start sending video again.
|
||||
*/
|
||||
TOXAV_CALL_CONTROL_SHOW_VIDEO,
|
||||
|
||||
} Toxav_Call_Control;
|
||||
|
||||
|
||||
typedef enum Toxav_Err_Call_Control {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_CALL_CONTROL_OK,
|
||||
|
||||
/**
|
||||
* Synchronization error occurred.
|
||||
*/
|
||||
TOXAV_ERR_CALL_CONTROL_SYNC,
|
||||
|
||||
/**
|
||||
* The friend_number passed did not designate a valid friend.
|
||||
*/
|
||||
TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* This client is currently not in a call with the friend. Before the call is
|
||||
* answered, only CANCEL is a valid control.
|
||||
*/
|
||||
TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL,
|
||||
|
||||
/**
|
||||
* Happens if user tried to pause an already paused call or if trying to
|
||||
* resume a call that is not paused.
|
||||
*/
|
||||
TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION,
|
||||
|
||||
} Toxav_Err_Call_Control;
|
||||
|
||||
|
||||
/**
|
||||
* Sends a call control command to a friend.
|
||||
*
|
||||
* @param friend_number The friend number of the friend this client is in a call
|
||||
* with.
|
||||
* @param control The control command to send.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
bool toxav_call_control(ToxAV *av, uint32_t friend_number, Toxav_Call_Control control, Toxav_Err_Call_Control *error);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief Controlling bit rates
|
||||
*/
|
||||
|
||||
typedef enum Toxav_Err_Bit_Rate_Set {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_BIT_RATE_SET_OK,
|
||||
|
||||
/**
|
||||
* Synchronization error occurred.
|
||||
*/
|
||||
TOXAV_ERR_BIT_RATE_SET_SYNC,
|
||||
|
||||
/**
|
||||
* The bit rate passed was not one of the supported values.
|
||||
*/
|
||||
TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE,
|
||||
|
||||
/**
|
||||
* The friend_number passed did not designate a valid friend.
|
||||
*/
|
||||
TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* This client is currently not in a call with the friend.
|
||||
*/
|
||||
TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL,
|
||||
|
||||
} Toxav_Err_Bit_Rate_Set;
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief A/V sending
|
||||
*/
|
||||
|
||||
typedef enum Toxav_Err_Send_Frame {
|
||||
|
||||
/**
|
||||
* The function returned successfully.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_OK,
|
||||
|
||||
/**
|
||||
* In case of video, one of Y, U, or V was NULL. In case of audio, the samples
|
||||
* data pointer was NULL.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_NULL,
|
||||
|
||||
/**
|
||||
* The friend_number passed did not designate a valid friend.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* This client is currently not in a call with the friend.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL,
|
||||
|
||||
/**
|
||||
* Synchronization error occurred.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_SYNC,
|
||||
|
||||
/**
|
||||
* One of the frame parameters was invalid. E.g. the resolution may be too
|
||||
* small or too large, or the audio sampling rate may be unsupported.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_INVALID,
|
||||
|
||||
/**
|
||||
* Either friend turned off audio or video receiving or we turned off sending
|
||||
* for the said payload.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED,
|
||||
|
||||
/**
|
||||
* Failed to push frame through rtp interface.
|
||||
*/
|
||||
TOXAV_ERR_SEND_FRAME_RTP_FAILED,
|
||||
|
||||
} Toxav_Err_Send_Frame;
|
||||
|
||||
|
||||
/**
|
||||
* Send an audio frame to a friend.
|
||||
*
|
||||
* The expected format of the PCM data is: `[s1c1][s1c2][...][s2c1][s2c2][...]...`
|
||||
* Meaning: sample 1 for channel 1, sample 1 for channel 2, ...
|
||||
* For mono audio, this has no meaning, every sample is subsequent. For stereo,
|
||||
* this means the expected format is LRLRLR... with samples for left and right
|
||||
* alternating.
|
||||
*
|
||||
* @param friend_number The friend number of the friend to which to send an
|
||||
* audio frame.
|
||||
* @param pcm An array of audio samples. The size of this array must be
|
||||
* `sample_count * channels`.
|
||||
* @param sample_count Number of samples in this frame. Valid numbers here are
|
||||
* `((sample rate) * (audio length) / 1000)`, where audio length can be
|
||||
* 2.5, 5, 10, 20, 40 or 60 millseconds.
|
||||
* @param channels Number of audio channels. Supported values are 1 and 2.
|
||||
* @param sampling_rate Audio sampling rate used in this frame. Valid sampling
|
||||
* rates are 8000, 12000, 16000, 24000, or 48000.
|
||||
*/
|
||||
bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count,
|
||||
uint8_t channels, uint32_t sampling_rate, Toxav_Err_Send_Frame *error);
|
||||
|
||||
/**
|
||||
* Set the bit rate to be used in subsequent video frames.
|
||||
*
|
||||
* @param friend_number The friend number of the friend for which to set the
|
||||
* bit rate.
|
||||
* @param bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_rate, Toxav_Err_Bit_Rate_Set *error);
|
||||
|
||||
/**
|
||||
* The function type for the audio_bit_rate callback. The event is triggered
|
||||
* when the network becomes too saturated for current bit rates at which
|
||||
* point core suggests new bit rates.
|
||||
*
|
||||
* @param friend_number The friend number of the friend for which to set the
|
||||
* bit rate.
|
||||
* @param audio_bit_rate Suggested maximum audio bit rate in Kb/sec.
|
||||
*/
|
||||
typedef void toxav_audio_bit_rate_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `audio_bit_rate` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_audio_bit_rate(ToxAV *av, toxav_audio_bit_rate_cb *callback, void *user_data);
|
||||
|
||||
/**
|
||||
* Send a video frame to a friend.
|
||||
*
|
||||
* Y - plane should be of size: `height * width`
|
||||
* U - plane should be of size: `(height/2) * (width/2)`
|
||||
* V - plane should be of size: `(height/2) * (width/2)`
|
||||
*
|
||||
* @param friend_number The friend number of the friend to which to send a video
|
||||
* frame.
|
||||
* @param width Width of the frame in pixels.
|
||||
* @param height Height of the frame in pixels.
|
||||
* @param y Y (Luminance) plane data.
|
||||
* @param u U (Chroma) plane data.
|
||||
* @param v V (Chroma) plane data.
|
||||
*/
|
||||
bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y,
|
||||
const uint8_t *u, const uint8_t *v, Toxav_Err_Send_Frame *error);
|
||||
|
||||
/**
|
||||
* Set the bit rate to be used in subsequent video frames.
|
||||
*
|
||||
* @param friend_number The friend number of the friend for which to set the
|
||||
* bit rate.
|
||||
* @param bit_rate The new video bit rate in Kb/sec. Set to 0 to disable.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t bit_rate, Toxav_Err_Bit_Rate_Set *error);
|
||||
|
||||
/**
|
||||
* The function type for the video_bit_rate callback. The event is triggered
|
||||
* when the network becomes too saturated for current bit rates at which
|
||||
* point core suggests new bit rates.
|
||||
*
|
||||
* @param friend_number The friend number of the friend for which to set the
|
||||
* bit rate.
|
||||
* @param video_bit_rate Suggested maximum video bit rate in Kb/sec.
|
||||
*/
|
||||
typedef void toxav_video_bit_rate_cb(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `video_bit_rate` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_video_bit_rate(ToxAV *av, toxav_video_bit_rate_cb *callback, void *user_data);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @{
|
||||
* @brief A/V receiving
|
||||
*/
|
||||
|
||||
/**
|
||||
* The function type for the audio_receive_frame callback. The callback can be
|
||||
* called multiple times per single iteration depending on the amount of queued
|
||||
* frames in the buffer. The received format is the same as in send function.
|
||||
*
|
||||
* @param friend_number The friend number of the friend who sent an audio frame.
|
||||
* @param pcm An array of audio samples (`sample_count * channels` elements).
|
||||
* @param sample_count The number of audio samples per channel in the PCM array.
|
||||
* @param channels Number of audio channels.
|
||||
* @param sampling_rate Sampling rate used in this frame.
|
||||
*
|
||||
*/
|
||||
typedef void toxav_audio_receive_frame_cb(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count,
|
||||
uint8_t channels, uint32_t sampling_rate, void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `audio_receive_frame` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb *callback, void *user_data);
|
||||
|
||||
/**
|
||||
* The function type for the video_receive_frame callback.
|
||||
*
|
||||
* The size of plane data is derived from width and height as documented
|
||||
* below.
|
||||
*
|
||||
* Strides represent padding for each plane that may or may not be present.
|
||||
* You must handle strides in your image processing code. Strides are
|
||||
* negative if the image is bottom-up hence why you MUST `abs()` it when
|
||||
* calculating plane buffer size.
|
||||
*
|
||||
* @param friend_number The friend number of the friend who sent a video frame.
|
||||
* @param width Width of the frame in pixels.
|
||||
* @param height Height of the frame in pixels.
|
||||
* @param y Luminosity plane. `Size = MAX(width, abs(ystride)) * height`.
|
||||
* @param u U chroma plane. `Size = MAX(width/2, abs(ustride)) * (height/2)`.
|
||||
* @param v V chroma plane. `Size = MAX(width/2, abs(vstride)) * (height/2)`.
|
||||
*
|
||||
* @param ystride Luminosity plane stride.
|
||||
* @param ustride U chroma plane stride.
|
||||
* @param vstride V chroma plane stride.
|
||||
*/
|
||||
typedef void toxav_video_receive_frame_cb(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height,
|
||||
const uint8_t *y, const uint8_t *u, const uint8_t *v, int32_t ystride, int32_t ustride, int32_t vstride,
|
||||
void *user_data);
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback for the `video_receive_frame` event. Pass NULL to unset.
|
||||
*
|
||||
*/
|
||||
void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb *callback, void *user_data);
|
||||
|
||||
/***
|
||||
* NOTE Compatibility with old toxav group calls. TODO(iphydf): remove
|
||||
*
|
||||
* TODO(iphydf): Use proper new API guidelines for these. E.g. don't use inline
|
||||
* function types, don't have per-callback userdata, especially don't have one
|
||||
* userdata per group.
|
||||
*/
|
||||
|
||||
// TODO(iphydf): Use this better typed one instead of the void-pointer one below.
|
||||
typedef void toxav_group_audio_cb(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
|
||||
uint32_t samples, uint8_t channels, uint32_t sample_rate, void *user_data);
|
||||
|
||||
typedef void toxav_audio_data_cb(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
|
||||
uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata);
|
||||
|
||||
/** @brief Create a new toxav group.
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*/
|
||||
int toxav_add_av_groupchat(Tox *tox, toxav_audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/** @brief Join a AV group (you need to have been invited first).
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*/
|
||||
int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data, uint16_t length,
|
||||
toxav_audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/** @brief Send audio to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*
|
||||
* Valid number of samples are `(sample rate) * (audio length) / 1000`
|
||||
* (Valid values for audio length are: 2.5, 5, 10, 20, 40 or 60 ms)
|
||||
* Valid number of channels are 1 or 2.
|
||||
* Valid sample rates are 8000, 12000, 16000, 24000, or 48000.
|
||||
*
|
||||
* Recommended values are: samples = 960, channels = 1, sample_rate = 48000
|
||||
*/
|
||||
int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
/** @brief Enable A/V in a groupchat.
|
||||
*
|
||||
* A/V must be enabled on a groupchat for audio to be sent to it and for
|
||||
* received audio to be handled.
|
||||
*
|
||||
* An A/V group created with `toxav_add_av_groupchat` or `toxav_join_av_groupchat`
|
||||
* will start with A/V enabled.
|
||||
*
|
||||
* An A/V group loaded from a savefile will start with A/V disabled.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*/
|
||||
int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber,
|
||||
toxav_audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/** @brief Disable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber);
|
||||
|
||||
/** @brief Return whether A/V is enabled in the groupchat. */
|
||||
bool toxav_groupchat_av_enabled(Tox *tox, uint32_t groupnumber);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//!TOKSTYLE-
|
||||
#ifndef DOXYGEN_IGNORE
|
||||
|
||||
typedef Toxav_Err_Call TOXAV_ERR_CALL;
|
||||
typedef Toxav_Err_New TOXAV_ERR_NEW;
|
||||
typedef Toxav_Err_Answer TOXAV_ERR_ANSWER;
|
||||
typedef Toxav_Err_Call_Control TOXAV_ERR_CALL_CONTROL;
|
||||
typedef Toxav_Err_Bit_Rate_Set TOXAV_ERR_BIT_RATE_SET;
|
||||
typedef Toxav_Err_Send_Frame TOXAV_ERR_SEND_FRAME;
|
||||
typedef Toxav_Call_Control TOXAV_CALL_CONTROL;
|
||||
typedef enum Toxav_Friend_Call_State TOXAV_FRIEND_CALL_STATE;
|
||||
|
||||
#endif
|
||||
//!TOKSTYLE+
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_TOXAV_H
|
||||
1503
local_pod_repo/toxcore/toxcore/toxav/toxav.m
Normal file
1503
local_pod_repo/toxcore/toxcore/toxav/toxav.m
Normal file
File diff suppressed because it is too large
Load Diff
86
local_pod_repo/toxcore/toxcore/toxav/toxav_old.m
Normal file
86
local_pod_repo/toxcore/toxcore/toxav/toxav_old.m
Normal file
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file contains the group chats code for the backwards compatibility.
|
||||
*/
|
||||
#include "toxav.h"
|
||||
|
||||
#include "../toxcore/tox_struct.h"
|
||||
#include "groupav.h"
|
||||
|
||||
int toxav_add_av_groupchat(Tox *tox, audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
return add_av_groupchat(tox->m->log, tox, tox->m->conferences_object, audio_callback, userdata);
|
||||
}
|
||||
|
||||
/** @brief Join a AV group (you need to have been invited first).
|
||||
*
|
||||
* @return group number on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*/
|
||||
int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data, uint16_t length,
|
||||
audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
return join_av_groupchat(tox->m->log, tox, tox->m->conferences_object, friendnumber, data, length, audio_callback, userdata);
|
||||
}
|
||||
|
||||
/** @brief Send audio to the group chat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*
|
||||
* Valid number of samples are `(sample rate) * (audio length) / 1000`
|
||||
* (Valid values for audio length are: 2.5, 5, 10, 20, 40 or 60 ms)
|
||||
* Valid number of channels are 1 or 2.
|
||||
* Valid sample rates are 8000, 12000, 16000, 24000, or 48000.
|
||||
*
|
||||
* Recommended values are: samples = 960, channels = 1, sample_rate = 48000
|
||||
*/
|
||||
int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate)
|
||||
{
|
||||
return group_send_audio(tox->m->conferences_object, groupnumber, pcm, samples, channels, sample_rate);
|
||||
}
|
||||
|
||||
/** @brief Enable A/V in a groupchat.
|
||||
*
|
||||
* A/V must be enabled on a groupchat for audio to be sent to it and for
|
||||
* received audio to be handled.
|
||||
*
|
||||
* An A/V group created with `toxav_add_av_groupchat` or `toxav_join_av_groupchat`
|
||||
* will start with A/V enabled.
|
||||
*
|
||||
* An A/V group loaded from a savefile will start with A/V disabled.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to `samples * channels * sizeof(int16_t)`.
|
||||
*/
|
||||
int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber, audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
return groupchat_enable_av(tox->m->log, tox, tox->m->conferences_object, groupnumber, audio_callback, userdata);
|
||||
}
|
||||
|
||||
/** @brief Disable A/V in a groupchat.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber)
|
||||
{
|
||||
return groupchat_disable_av(tox->m->conferences_object, groupnumber);
|
||||
}
|
||||
|
||||
/** @brief Return whether A/V is enabled in the groupchat. */
|
||||
bool toxav_groupchat_av_enabled(Tox *tox, uint32_t groupnumber)
|
||||
{
|
||||
return groupchat_av_enabled(tox->m->conferences_object, groupnumber);
|
||||
}
|
||||
54
local_pod_repo/toxcore/toxcore/toxav/video.h
Normal file
54
local_pod_repo/toxcore/toxcore/toxav/video.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXAV_VIDEO_H
|
||||
#define C_TOXCORE_TOXAV_VIDEO_H
|
||||
|
||||
#include <vpx/vpx_decoder.h>
|
||||
#include <vpx/vpx_encoder.h>
|
||||
#include <vpx/vpx_image.h>
|
||||
|
||||
#include <vpx/vp8cx.h>
|
||||
#include <vpx/vp8dx.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "toxav.h"
|
||||
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "rtp.h"
|
||||
|
||||
typedef struct VCSession {
|
||||
/* encoding */
|
||||
vpx_codec_ctx_t encoder[1];
|
||||
uint32_t frame_counter;
|
||||
|
||||
/* decoding */
|
||||
vpx_codec_ctx_t decoder[1];
|
||||
struct RingBuffer *vbuf_raw; /* Un-decoded data */
|
||||
|
||||
uint64_t linfts; /* Last received frame time stamp */
|
||||
uint32_t lcfd; /* Last calculated frame duration for incoming video payload */
|
||||
|
||||
const Logger *log;
|
||||
ToxAV *av;
|
||||
uint32_t friend_number;
|
||||
|
||||
/* Video frame receive callback */
|
||||
toxav_video_receive_frame_cb *vcb;
|
||||
void *vcb_user_data;
|
||||
|
||||
pthread_mutex_t queue_mutex[1];
|
||||
} VCSession;
|
||||
|
||||
VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number,
|
||||
toxav_video_receive_frame_cb *cb, void *cb_data);
|
||||
void vc_kill(VCSession *vc);
|
||||
void vc_iterate(VCSession *vc);
|
||||
int vc_queue_message(Mono_Time *mono_time, void *vcp, struct RTPMessage *msg);
|
||||
int vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height, int16_t kf_max_dist);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_VIDEO_H
|
||||
446
local_pod_repo/toxcore/toxcore/toxav/video.m
Normal file
446
local_pod_repo/toxcore/toxcore/toxav/video.m
Normal file
@@ -0,0 +1,446 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013-2015 Tox project.
|
||||
*/
|
||||
#include "video.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "msi.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "rtp.h"
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "../toxcore/network.h"
|
||||
|
||||
/**
|
||||
* Soft deadline the decoder should attempt to meet, in "us" (microseconds).
|
||||
* Set to zero for unlimited.
|
||||
*
|
||||
* By convention, the value 1 is used to mean "return as fast as possible."
|
||||
*/
|
||||
// TODO(zoff99): don't hardcode this, let the application choose it
|
||||
#define WANTED_MAX_DECODER_FPS 40
|
||||
|
||||
/**
|
||||
* VPX_DL_REALTIME (1)
|
||||
* deadline parameter analogous to VPx REALTIME mode.
|
||||
*
|
||||
* VPX_DL_GOOD_QUALITY (1000000)
|
||||
* deadline parameter analogous to VPx GOOD QUALITY mode.
|
||||
*
|
||||
* VPX_DL_BEST_QUALITY (0)
|
||||
* deadline parameter analogous to VPx BEST QUALITY mode.
|
||||
*/
|
||||
#define MAX_DECODE_TIME_US (1000000 / WANTED_MAX_DECODER_FPS) // to allow x fps
|
||||
|
||||
/**
|
||||
* Codec control function to set encoder internal speed settings. Changes in
|
||||
* this value influences, among others, the encoder's selection of motion
|
||||
* estimation methods. Values greater than 0 will increase encoder speed at the
|
||||
* expense of quality.
|
||||
*
|
||||
* Note Valid range for VP8: `-16..16`
|
||||
*/
|
||||
#define VP8E_SET_CPUUSED_VALUE 16
|
||||
|
||||
/**
|
||||
* Initialize encoder with this value.
|
||||
*
|
||||
* Target bandwidth to use for this stream, in kilobits per second.
|
||||
*/
|
||||
#define VIDEO_BITRATE_INITIAL_VALUE 5000
|
||||
#define VIDEO_DECODE_BUFFER_SIZE 5 // this buffer has normally max. 1 entry
|
||||
|
||||
static vpx_codec_iface_t *video_codec_decoder_interface(void)
|
||||
{
|
||||
return vpx_codec_vp8_dx();
|
||||
}
|
||||
static vpx_codec_iface_t *video_codec_encoder_interface(void)
|
||||
{
|
||||
return vpx_codec_vp8_cx();
|
||||
}
|
||||
|
||||
#define VIDEO_CODEC_DECODER_MAX_WIDTH 800 // its a dummy value, because the struct needs a value there
|
||||
#define VIDEO_CODEC_DECODER_MAX_HEIGHT 600 // its a dummy value, because the struct needs a value there
|
||||
|
||||
#define VPX_MAX_DIST_START 40
|
||||
|
||||
#define VPX_MAX_ENCODER_THREADS 4
|
||||
#define VPX_MAX_DECODER_THREADS 4
|
||||
#define VIDEO_VP8_DECODER_POST_PROCESSING_ENABLED 0
|
||||
|
||||
static void vc_init_encoder_cfg(const Logger *log, vpx_codec_enc_cfg_t *cfg, int16_t kf_max_dist)
|
||||
{
|
||||
const vpx_codec_err_t rc = vpx_codec_enc_config_default(video_codec_encoder_interface(), cfg, 0);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(log, "vc_init_encoder_cfg:Failed to get config: %s", vpx_codec_err_to_string(rc));
|
||||
}
|
||||
|
||||
/* Target bandwidth to use for this stream, in kilobits per second */
|
||||
cfg->rc_target_bitrate = VIDEO_BITRATE_INITIAL_VALUE;
|
||||
cfg->g_w = VIDEO_CODEC_DECODER_MAX_WIDTH;
|
||||
cfg->g_h = VIDEO_CODEC_DECODER_MAX_HEIGHT;
|
||||
cfg->g_pass = VPX_RC_ONE_PASS;
|
||||
cfg->g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
|
||||
cfg->g_lag_in_frames = 0;
|
||||
|
||||
/* Allow lagged encoding
|
||||
*
|
||||
* If set, this value allows the encoder to consume a number of input
|
||||
* frames before producing output frames. This allows the encoder to
|
||||
* base decisions for the current frame on future frames. This does
|
||||
* increase the latency of the encoding pipeline, so it is not appropriate
|
||||
* in all situations (ex: realtime encoding).
|
||||
*
|
||||
* Note that this is a maximum value -- the encoder may produce frames
|
||||
* sooner than the given limit. Set this value to 0 to disable this
|
||||
* feature.
|
||||
*/
|
||||
cfg->kf_min_dist = 0;
|
||||
cfg->kf_mode = VPX_KF_AUTO; // Encoder determines optimal placement automatically
|
||||
cfg->rc_end_usage = VPX_VBR; // what quality mode?
|
||||
|
||||
/*
|
||||
* VPX_VBR Variable Bit Rate (VBR) mode
|
||||
* VPX_CBR Constant Bit Rate (CBR) mode
|
||||
* VPX_CQ Constrained Quality (CQ) mode -> give codec a hint that we may be on low bandwidth connection
|
||||
* VPX_Q Constant Quality (Q) mode
|
||||
*/
|
||||
if (kf_max_dist > 1) {
|
||||
cfg->kf_max_dist = kf_max_dist; // a full frame every x frames minimum (can be more often, codec decides automatically)
|
||||
LOGGER_DEBUG(log, "kf_max_dist=%d (1)", cfg->kf_max_dist);
|
||||
} else {
|
||||
cfg->kf_max_dist = VPX_MAX_DIST_START;
|
||||
LOGGER_DEBUG(log, "kf_max_dist=%d (2)", cfg->kf_max_dist);
|
||||
}
|
||||
|
||||
cfg->g_threads = VPX_MAX_ENCODER_THREADS; // Maximum number of threads to use
|
||||
/* TODO: set these to something reasonable */
|
||||
// cfg->g_timebase.num = 1;
|
||||
// cfg->g_timebase.den = 60; // 60 fps
|
||||
cfg->rc_resize_allowed = 1; // allow encoder to resize to smaller resolution
|
||||
cfg->rc_resize_up_thresh = 40;
|
||||
cfg->rc_resize_down_thresh = 5;
|
||||
|
||||
/* TODO: make quality setting an API call, but start with normal quality */
|
||||
#if 0
|
||||
/* Highest-resolution encoder settings */
|
||||
cfg->rc_dropframe_thresh = 0;
|
||||
cfg->rc_resize_allowed = 0;
|
||||
cfg->rc_min_quantizer = 2;
|
||||
cfg->rc_max_quantizer = 56;
|
||||
cfg->rc_undershoot_pct = 100;
|
||||
cfg->rc_overshoot_pct = 15;
|
||||
cfg->rc_buf_initial_sz = 500;
|
||||
cfg->rc_buf_optimal_sz = 600;
|
||||
cfg->rc_buf_sz = 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
VCSession *vc_new(Mono_Time *mono_time, const Logger *log, ToxAV *av, uint32_t friend_number,
|
||||
toxav_video_receive_frame_cb *cb, void *cb_data)
|
||||
{
|
||||
VCSession *vc = (VCSession *)calloc(1, sizeof(VCSession));
|
||||
vpx_codec_err_t rc;
|
||||
|
||||
if (vc == nullptr) {
|
||||
LOGGER_WARNING(log, "Allocation failed! Application might misbehave!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (create_recursive_mutex(vc->queue_mutex) != 0) {
|
||||
LOGGER_WARNING(log, "Failed to create recursive mutex!");
|
||||
free(vc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int cpu_used_value = VP8E_SET_CPUUSED_VALUE;
|
||||
|
||||
vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE);
|
||||
|
||||
if (vc->vbuf_raw == nullptr) {
|
||||
goto BASE_CLEANUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* VPX_CODEC_USE_FRAME_THREADING
|
||||
* Enable frame-based multi-threading
|
||||
*
|
||||
* VPX_CODEC_USE_ERROR_CONCEALMENT
|
||||
* Conceal errors in decoded frames
|
||||
*/
|
||||
vpx_codec_dec_cfg_t dec_cfg;
|
||||
dec_cfg.threads = VPX_MAX_DECODER_THREADS; // Maximum number of threads to use
|
||||
dec_cfg.w = VIDEO_CODEC_DECODER_MAX_WIDTH;
|
||||
dec_cfg.h = VIDEO_CODEC_DECODER_MAX_HEIGHT;
|
||||
|
||||
LOGGER_DEBUG(log, "Using VP8 codec for decoder (0)");
|
||||
rc = vpx_codec_dec_init(vc->decoder, video_codec_decoder_interface(), &dec_cfg,
|
||||
VPX_CODEC_USE_FRAME_THREADING | VPX_CODEC_USE_POSTPROC);
|
||||
|
||||
if (rc == VPX_CODEC_INCAPABLE) {
|
||||
LOGGER_WARNING(log, "Postproc not supported by this decoder (0)");
|
||||
rc = vpx_codec_dec_init(vc->decoder, video_codec_decoder_interface(), &dec_cfg, VPX_CODEC_USE_FRAME_THREADING);
|
||||
}
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(log, "Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
|
||||
goto BASE_CLEANUP;
|
||||
}
|
||||
|
||||
if (VIDEO_VP8_DECODER_POST_PROCESSING_ENABLED == 1) {
|
||||
vp8_postproc_cfg_t pp = {VP8_DEBLOCK, 1, 0};
|
||||
const vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp);
|
||||
|
||||
if (cc_res != VPX_CODEC_OK) {
|
||||
LOGGER_WARNING(log, "Failed to turn on postproc");
|
||||
} else {
|
||||
LOGGER_DEBUG(log, "turn on postproc: OK");
|
||||
}
|
||||
} else {
|
||||
vp8_postproc_cfg_t pp = {0, 0, 0};
|
||||
vpx_codec_err_t cc_res = vpx_codec_control(vc->decoder, VP8_SET_POSTPROC, &pp);
|
||||
|
||||
if (cc_res != VPX_CODEC_OK) {
|
||||
LOGGER_WARNING(log, "Failed to turn OFF postproc");
|
||||
} else {
|
||||
LOGGER_DEBUG(log, "Disable postproc: OK");
|
||||
}
|
||||
}
|
||||
|
||||
/* Set encoder to some initial values
|
||||
*/
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
vc_init_encoder_cfg(log, &cfg, 1);
|
||||
|
||||
LOGGER_DEBUG(log, "Using VP8 codec for encoder (0.1)");
|
||||
rc = vpx_codec_enc_init(vc->encoder, video_codec_encoder_interface(), &cfg, VPX_CODEC_USE_FRAME_THREADING);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
|
||||
goto BASE_CLEANUP_1;
|
||||
}
|
||||
|
||||
rc = vpx_codec_control(vc->encoder, VP8E_SET_CPUUSED, cpu_used_value);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
|
||||
vpx_codec_destroy(vc->encoder);
|
||||
goto BASE_CLEANUP_1;
|
||||
}
|
||||
|
||||
/*
|
||||
* VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int)
|
||||
* control function to set noise sensitivity
|
||||
* 0: off, 1: OnYOnly, 2: OnYUV, 3: OnYUVAggressive, 4: Adaptive
|
||||
*/
|
||||
#if 0
|
||||
rc = vpx_codec_control(vc->encoder, VP8E_SET_NOISE_SENSITIVITY, 2);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
|
||||
vpx_codec_destroy(vc->encoder);
|
||||
goto BASE_CLEANUP_1;
|
||||
}
|
||||
|
||||
#endif
|
||||
vc->linfts = current_time_monotonic(mono_time);
|
||||
vc->lcfd = 60;
|
||||
vc->vcb = cb;
|
||||
vc->vcb_user_data = cb_data;
|
||||
vc->friend_number = friend_number;
|
||||
vc->av = av;
|
||||
vc->log = log;
|
||||
return vc;
|
||||
BASE_CLEANUP_1:
|
||||
vpx_codec_destroy(vc->decoder);
|
||||
BASE_CLEANUP:
|
||||
pthread_mutex_destroy(vc->queue_mutex);
|
||||
rb_kill(vc->vbuf_raw);
|
||||
free(vc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void vc_kill(VCSession *vc)
|
||||
{
|
||||
if (vc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
vpx_codec_destroy(vc->encoder);
|
||||
vpx_codec_destroy(vc->decoder);
|
||||
void *p;
|
||||
|
||||
while (rb_read(vc->vbuf_raw, &p)) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
rb_kill(vc->vbuf_raw);
|
||||
pthread_mutex_destroy(vc->queue_mutex);
|
||||
LOGGER_DEBUG(vc->log, "Terminated video handler: %p", (void *)vc);
|
||||
free(vc);
|
||||
}
|
||||
|
||||
void vc_iterate(VCSession *vc)
|
||||
{
|
||||
if (vc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(vc->queue_mutex);
|
||||
|
||||
struct RTPMessage *p;
|
||||
|
||||
if (!rb_read(vc->vbuf_raw, (void **)&p)) {
|
||||
LOGGER_TRACE(vc->log, "no Video frame data available");
|
||||
pthread_mutex_unlock(vc->queue_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t log_rb_size = rb_size(vc->vbuf_raw);
|
||||
pthread_mutex_unlock(vc->queue_mutex);
|
||||
const struct RTPHeader *const header = &p->header;
|
||||
|
||||
uint32_t full_data_len;
|
||||
|
||||
if ((header->flags & RTP_LARGE_FRAME) != 0) {
|
||||
full_data_len = header->data_length_full;
|
||||
LOGGER_DEBUG(vc->log, "vc_iterate:001:full_data_len=%d", (int)full_data_len);
|
||||
} else {
|
||||
full_data_len = p->len;
|
||||
LOGGER_DEBUG(vc->log, "vc_iterate:002");
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(vc->log, "vc_iterate: rb_read p->len=%d p->header.xe=%d", (int)full_data_len, p->header.xe);
|
||||
LOGGER_DEBUG(vc->log, "vc_iterate: rb_read rb size=%d", (int)log_rb_size);
|
||||
const vpx_codec_err_t rc = vpx_codec_decode(vc->decoder, p->data, full_data_len, nullptr, MAX_DECODE_TIME_US);
|
||||
free(p);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(vc->log, "Error decoding video: %d %s", (int)rc, vpx_codec_err_to_string(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Play decoded images */
|
||||
vpx_codec_iter_t iter = nullptr;
|
||||
|
||||
for (vpx_image_t *dest = vpx_codec_get_frame(vc->decoder, &iter);
|
||||
dest != nullptr;
|
||||
dest = vpx_codec_get_frame(vc->decoder, &iter)) {
|
||||
if (vc->vcb != nullptr) {
|
||||
vc->vcb(vc->av, vc->friend_number, dest->d_w, dest->d_h,
|
||||
dest->planes[0], dest->planes[1], dest->planes[2],
|
||||
dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb_user_data);
|
||||
}
|
||||
|
||||
vpx_img_free(dest); // is this needed? none of the VPx examples show that
|
||||
}
|
||||
}
|
||||
|
||||
int vc_queue_message(Mono_Time *mono_time, void *vcp, struct RTPMessage *msg)
|
||||
{
|
||||
/* This function is called with complete messages
|
||||
* they have already been assembled.
|
||||
* this function gets called from handle_rtp_packet() and handle_rtp_packet_v3()
|
||||
*/
|
||||
if (vcp == nullptr || msg == nullptr) {
|
||||
free(msg);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
VCSession *vc = (VCSession *)vcp;
|
||||
const struct RTPHeader *const header = &msg->header;
|
||||
|
||||
if (msg->header.pt == (RTP_TYPE_VIDEO + 2) % 128) {
|
||||
LOGGER_WARNING(vc->log, "Got dummy!");
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msg->header.pt != RTP_TYPE_VIDEO % 128) {
|
||||
LOGGER_WARNING(vc->log, "Invalid payload type! pt=%d", (int)msg->header.pt);
|
||||
free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(vc->queue_mutex);
|
||||
|
||||
if ((header->flags & RTP_LARGE_FRAME) != 0 && header->pt == RTP_TYPE_VIDEO % 128) {
|
||||
LOGGER_DEBUG(vc->log, "rb_write msg->len=%d b0=%d b1=%d", (int)msg->len, (int)msg->data[0], (int)msg->data[1]);
|
||||
}
|
||||
|
||||
free(rb_write(vc->vbuf_raw, msg));
|
||||
|
||||
/* Calculate time it took for peer to send us this frame */
|
||||
const uint32_t t_lcfd = current_time_monotonic(mono_time) - vc->linfts;
|
||||
vc->lcfd = t_lcfd > 100 ? vc->lcfd : t_lcfd;
|
||||
vc->linfts = current_time_monotonic(mono_time);
|
||||
pthread_mutex_unlock(vc->queue_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height, int16_t kf_max_dist)
|
||||
{
|
||||
if (vc == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
vpx_codec_enc_cfg_t cfg2 = *vc->encoder->config.enc;
|
||||
|
||||
if (cfg2.rc_target_bitrate == bit_rate && cfg2.g_w == width && cfg2.g_h == height && kf_max_dist == -1) {
|
||||
return 0; /* Nothing changed */
|
||||
}
|
||||
|
||||
if (cfg2.g_w == width && cfg2.g_h == height && kf_max_dist == -1) {
|
||||
/* Only bit rate changed */
|
||||
LOGGER_INFO(vc->log, "bitrate change from: %u to: %u", (uint32_t)cfg2.rc_target_bitrate, (uint32_t)bit_rate);
|
||||
cfg2.rc_target_bitrate = bit_rate;
|
||||
const vpx_codec_err_t rc = vpx_codec_enc_config_set(vc->encoder, &cfg2);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Resolution is changed, must reinitialize encoder since libvpx v1.4 doesn't support
|
||||
* reconfiguring encoder to use resolutions greater than initially set.
|
||||
*/
|
||||
LOGGER_DEBUG(vc->log, "Have to reinitialize vpx encoder on session %p", (void *)vc);
|
||||
vpx_codec_ctx_t new_c;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
vc_init_encoder_cfg(vc->log, &cfg, kf_max_dist);
|
||||
cfg.rc_target_bitrate = bit_rate;
|
||||
cfg.g_w = width;
|
||||
cfg.g_h = height;
|
||||
|
||||
LOGGER_DEBUG(vc->log, "Using VP8 codec for encoder");
|
||||
vpx_codec_err_t rc = vpx_codec_enc_init(&new_c, video_codec_encoder_interface(), &cfg, VPX_CODEC_USE_FRAME_THREADING);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(vc->log, "Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int cpu_used_value = VP8E_SET_CPUUSED_VALUE;
|
||||
|
||||
rc = vpx_codec_control(&new_c, VP8E_SET_CPUUSED, cpu_used_value);
|
||||
|
||||
if (rc != VPX_CODEC_OK) {
|
||||
LOGGER_ERROR(vc->log, "Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
|
||||
vpx_codec_destroy(&new_c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vpx_codec_destroy(vc->encoder);
|
||||
memcpy(vc->encoder, &new_c, sizeof(new_c));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
555
local_pod_repo/toxcore/toxcore/toxcore/DHT.h
Normal file
555
local_pod_repo/toxcore/toxcore/toxcore/DHT.h
Normal file
@@ -0,0 +1,555 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief An implementation of the DHT as seen in docs/updates/DHT.md
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_DHT_H
|
||||
#define C_TOXCORE_TOXCORE_DHT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "attributes.h"
|
||||
#include "crypto_core.h"
|
||||
#include "logger.h"
|
||||
#include "mono_time.h"
|
||||
#include "network.h"
|
||||
#include "ping_array.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Maximum size of a signature (may be smaller) */
|
||||
#define SIGNATURE_SIZE CRYPTO_SIGNATURE_SIZE
|
||||
/** Maximum number of clients stored per friend. */
|
||||
#define MAX_FRIEND_CLIENTS 8
|
||||
|
||||
#define LCLIENT_NODES MAX_FRIEND_CLIENTS
|
||||
#define LCLIENT_LENGTH 128
|
||||
|
||||
/** A list of the clients mathematically closest to ours. */
|
||||
#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES)
|
||||
|
||||
#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8
|
||||
|
||||
/** The max number of nodes to send with send nodes. */
|
||||
#define MAX_SENT_NODES 4
|
||||
|
||||
/** Ping timeout in seconds */
|
||||
#define PING_TIMEOUT 5
|
||||
|
||||
/** size of DHT ping arrays. */
|
||||
#define DHT_PING_ARRAY_SIZE 512
|
||||
|
||||
/** Ping interval in seconds for each node in our lists. */
|
||||
#define PING_INTERVAL 60
|
||||
|
||||
/** The number of seconds for a non responsive node to become bad. */
|
||||
#define PINGS_MISSED_NODE_GOES_BAD 1
|
||||
#define PING_ROUNDTRIP 2
|
||||
#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP))
|
||||
|
||||
/**
|
||||
* The number of "fake" friends to add.
|
||||
*
|
||||
* (for optimization purposes and so our paths for the onion part are more random)
|
||||
*/
|
||||
#define DHT_FAKE_FRIEND_NUMBER 2
|
||||
|
||||
/** Maximum packet size for a DHT request packet. */
|
||||
#define MAX_CRYPTO_REQUEST_SIZE 1024
|
||||
|
||||
#define CRYPTO_PACKET_FRIEND_REQ 32 // Friend request crypto packet ID.
|
||||
#define CRYPTO_PACKET_DHTPK 156
|
||||
#define CRYPTO_PACKET_NAT_PING 254 // NAT ping crypto packet ID.
|
||||
|
||||
/* Max size of a packed node for IPV4 and IPV6 respectively */
|
||||
#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
|
||||
#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* This define can eventually be removed; it is necessary if a significant
|
||||
* proportion of dht nodes do not implement the dht announcements protocol.
|
||||
*/
|
||||
#define CHECK_ANNOUNCE_NODE
|
||||
|
||||
/**
|
||||
* @brief Create a request to peer.
|
||||
*
|
||||
* Packs the data and sender public key and encrypts the packet.
|
||||
*
|
||||
* @param[in] send_public_key public key of the sender.
|
||||
* @param[in] send_secret_key secret key of the sender.
|
||||
* @param[out] packet an array of @ref MAX_CRYPTO_REQUEST_SIZE big.
|
||||
* @param[in] recv_public_key public key of the receiver.
|
||||
* @param[in] data represents the data we send with the request.
|
||||
* @param[in] data_length the length of the data.
|
||||
* @param[in] request_id the id of the request (32 = friend request, 254 = ping request).
|
||||
*
|
||||
* @attention Constraints:
|
||||
* @code
|
||||
* sizeof(packet) >= MAX_CRYPTO_REQUEST_SIZE
|
||||
* @endcode
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @return the length of the created packet on success.
|
||||
*/
|
||||
non_null()
|
||||
int create_request(const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key,
|
||||
uint8_t *packet, const uint8_t *recv_public_key,
|
||||
const uint8_t *data, uint32_t data_length, uint8_t request_id);
|
||||
|
||||
/**
|
||||
* @brief Decrypts and unpacks a DHT request packet.
|
||||
*
|
||||
* Puts the senders public key in the request in @p public_key, the data from
|
||||
* the request in @p data.
|
||||
*
|
||||
* @param[in] self_public_key public key of the receiver (us).
|
||||
* @param[in] self_secret_key secret key of the receiver (us).
|
||||
* @param[out] public_key public key of the sender, copied from the input packet.
|
||||
* @param[out] data decrypted request data, copied from the input packet, must
|
||||
* have room for @ref MAX_CRYPTO_REQUEST_SIZE bytes.
|
||||
* @param[in] packet is the request packet.
|
||||
* @param[in] packet_length length of the packet.
|
||||
*
|
||||
* @attention Constraints:
|
||||
* @code
|
||||
* sizeof(data) >= MAX_CRYPTO_REQUEST_SIZE
|
||||
* @endcode
|
||||
*
|
||||
* @retval -1 if not valid request.
|
||||
* @return the length of the unpacked data.
|
||||
*/
|
||||
non_null()
|
||||
int handle_request(
|
||||
const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
|
||||
uint8_t *request_id, const uint8_t *packet, uint16_t packet_length);
|
||||
|
||||
typedef struct IPPTs {
|
||||
IP_Port ip_port;
|
||||
uint64_t timestamp;
|
||||
} IPPTs;
|
||||
|
||||
typedef struct IPPTsPng {
|
||||
IP_Port ip_port;
|
||||
uint64_t timestamp;
|
||||
uint64_t last_pinged;
|
||||
|
||||
/* Returned by this node */
|
||||
IP_Port ret_ip_port;
|
||||
uint64_t ret_timestamp;
|
||||
/* true if this ip_port is ours */
|
||||
bool ret_ip_self;
|
||||
} IPPTsPng;
|
||||
|
||||
typedef struct Client_data {
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
IPPTsPng assoc4;
|
||||
IPPTsPng assoc6;
|
||||
|
||||
#ifdef CHECK_ANNOUNCE_NODE
|
||||
/* Responded to data search? */
|
||||
bool announce_node;
|
||||
#endif
|
||||
} Client_data;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct NAT {
|
||||
/* true if currently hole punching */
|
||||
bool hole_punching;
|
||||
uint32_t punching_index;
|
||||
uint32_t tries;
|
||||
uint32_t punching_index2;
|
||||
|
||||
uint64_t punching_timestamp;
|
||||
uint64_t recv_nat_ping_timestamp;
|
||||
uint64_t nat_ping_id;
|
||||
uint64_t nat_ping_timestamp;
|
||||
} NAT;
|
||||
|
||||
#define DHT_FRIEND_MAX_LOCKS 32
|
||||
|
||||
typedef struct Node_format {
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
IP_Port ip_port;
|
||||
} Node_format;
|
||||
|
||||
extern const Node_format empty_node_format;
|
||||
|
||||
typedef struct DHT_Friend DHT_Friend;
|
||||
|
||||
non_null() const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend);
|
||||
non_null() const Client_data *dht_friend_client(const DHT_Friend *dht_friend, size_t index);
|
||||
|
||||
/** @return packet size of packed node with ip_family on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
int packed_node_size(Family ip_family);
|
||||
|
||||
/** @brief Pack an IP_Port structure into data of max size length.
|
||||
*
|
||||
* Packed_length is the offset of data currently packed.
|
||||
*
|
||||
* @return size of packed IP_Port data on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_Port *ip_port);
|
||||
|
||||
/** @brief Encrypt plain and write resulting DHT packet into packet with max size length.
|
||||
*
|
||||
* @return size of packet on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int dht_create_packet(const Random *rng,
|
||||
const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
|
||||
const uint8_t *shared_key, const uint8_t type,
|
||||
const uint8_t *plain, size_t plain_length,
|
||||
uint8_t *packet, size_t length);
|
||||
|
||||
/** @brief Unpack IP_Port structure from data of max size length into ip_port.
|
||||
*
|
||||
* len_processed is the offset of data currently unpacked.
|
||||
*
|
||||
* @return size of unpacked ip_port on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled);
|
||||
|
||||
/** @brief Pack number of nodes into data of maxlength length.
|
||||
*
|
||||
* @return length of packed nodes on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int pack_nodes(const Logger *logger, uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number);
|
||||
|
||||
/** @brief Unpack data of length into nodes of size max_num_nodes.
|
||||
* Put the length of the data processed in processed_data_len.
|
||||
* tcp_enabled sets if TCP nodes are expected (true) or not (false).
|
||||
*
|
||||
* @return number of unpacked nodes on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null(1, 4) nullable(3)
|
||||
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
|
||||
uint16_t length, bool tcp_enabled);
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
/* struct to store some shared keys so we don't have to regenerate them for each request. */
|
||||
#define MAX_KEYS_PER_SLOT 4
|
||||
#define KEYS_TIMEOUT 600
|
||||
|
||||
typedef struct Shared_Key {
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||
uint32_t times_requested;
|
||||
bool stored;
|
||||
uint64_t time_last_requested;
|
||||
} Shared_Key;
|
||||
|
||||
typedef struct Shared_Keys {
|
||||
Shared_Key keys[256 * MAX_KEYS_PER_SLOT];
|
||||
} Shared_Keys;
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
typedef int cryptopacket_handler_cb(void *object, const IP_Port *ip_port, const uint8_t *source_pubkey,
|
||||
const uint8_t *data, uint16_t len, void *userdata);
|
||||
|
||||
typedef struct DHT DHT;
|
||||
|
||||
non_null() const uint8_t *dht_get_self_public_key(const DHT *dht);
|
||||
non_null() const uint8_t *dht_get_self_secret_key(const DHT *dht);
|
||||
non_null() void dht_set_self_public_key(DHT *dht, const uint8_t *key);
|
||||
non_null() void dht_set_self_secret_key(DHT *dht, const uint8_t *key);
|
||||
|
||||
non_null() Networking_Core *dht_get_net(const DHT *dht);
|
||||
non_null() struct Ping *dht_get_ping(const DHT *dht);
|
||||
non_null() const Client_data *dht_get_close_clientlist(const DHT *dht);
|
||||
non_null() const Client_data *dht_get_close_client(const DHT *dht, uint32_t client_num);
|
||||
non_null() uint16_t dht_get_num_friends(const DHT *dht);
|
||||
|
||||
non_null() DHT_Friend *dht_get_friend(DHT *dht, uint32_t friend_num);
|
||||
non_null() const uint8_t *dht_get_friend_public_key(const DHT *dht, uint32_t friend_num);
|
||||
|
||||
/*----------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Shared key generations are costly, it is therefore smart to store commonly used
|
||||
* ones so that they can be re-used later without being computed again.
|
||||
*
|
||||
* If a shared key is already in shared_keys, copy it to shared_key.
|
||||
* Otherwise generate it into shared_key and copy it to shared_keys
|
||||
*/
|
||||
non_null()
|
||||
void get_shared_key(
|
||||
const Mono_Time *mono_time, Shared_Keys *shared_keys, uint8_t *shared_key,
|
||||
const uint8_t *secret_key, const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||
* for packets that we receive.
|
||||
*/
|
||||
non_null()
|
||||
void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||
* for packets that we send.
|
||||
*/
|
||||
non_null()
|
||||
void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* Sends a getnodes request to `ip_port` with the public key `public_key` for nodes
|
||||
* that are close to `client_id`.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id);
|
||||
|
||||
typedef void dht_ip_cb(void *object, int32_t number, const IP_Port *ip_port);
|
||||
|
||||
typedef void dht_get_nodes_response_cb(const DHT *dht, const Node_format *node, void *user_data);
|
||||
|
||||
/** Sets the callback to be triggered on a getnodes response. */
|
||||
non_null(1) nullable(2)
|
||||
void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function);
|
||||
|
||||
/** @brief Add a new friend to the friends list.
|
||||
* public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
*
|
||||
* ip_callback is the callback of a function that will be called when the ip address
|
||||
* is found along with arguments data and number.
|
||||
*
|
||||
* lock_count will be set to a non zero number that must be passed to `dht_delfriend()`
|
||||
* to properly remove the callback.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure (friends list is full).
|
||||
*/
|
||||
non_null(1, 2) nullable(3, 4, 6)
|
||||
int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
|
||||
void *data, int32_t number, uint16_t *lock_count);
|
||||
|
||||
/** @brief Delete a friend from the friends list.
|
||||
* public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure (public_key not in friends list).
|
||||
*/
|
||||
non_null()
|
||||
int dht_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count);
|
||||
|
||||
/** @brief Get ip of friend.
|
||||
*
|
||||
* @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long.
|
||||
*
|
||||
* @retval -1 if public_key does NOT refer to a friend
|
||||
* @retval 0 if public_key refers to a friend and we failed to find the friend (yet)
|
||||
* @retval 1 if public_key refers to a friend and we found him
|
||||
*/
|
||||
non_null()
|
||||
int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port);
|
||||
|
||||
/** @brief Compares pk1 and pk2 with pk.
|
||||
*
|
||||
* @retval 0 if both are same distance.
|
||||
* @retval 1 if pk1 is closer.
|
||||
* @retval 2 if pk2 is closer.
|
||||
*/
|
||||
non_null()
|
||||
int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2);
|
||||
|
||||
/** Return index of first unequal bit number between public keys pk1 and pk2. */
|
||||
non_null()
|
||||
unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2);
|
||||
|
||||
/**
|
||||
* Add node to the node list making sure only the nodes closest to cmp_pk are in the list.
|
||||
*
|
||||
* @return true iff the node was added to the list.
|
||||
*/
|
||||
non_null()
|
||||
bool add_to_list(
|
||||
Node_format *nodes_list, uint32_t length, const uint8_t *pk, const IP_Port *ip_port, const uint8_t *cmp_pk);
|
||||
|
||||
/** Return 1 if node can be added to close list, 0 if it can't. */
|
||||
non_null()
|
||||
bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port);
|
||||
|
||||
#ifdef CHECK_ANNOUNCE_NODE
|
||||
/** Set node as announce node. */
|
||||
non_null()
|
||||
void set_announce_node(DHT *dht, const uint8_t *public_key);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know
|
||||
* and put them in nodes_list (must be MAX_SENT_NODES big).
|
||||
*
|
||||
* sa_family = family (IPv4 or IPv6) (0 if we don't care)?
|
||||
* is_LAN = return some LAN ips (true or false)
|
||||
* want_announce: return only nodes which implement the dht announcements protocol.
|
||||
*
|
||||
* @return the number of nodes returned.
|
||||
*/
|
||||
non_null()
|
||||
int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family,
|
||||
bool is_LAN, bool want_announce);
|
||||
|
||||
|
||||
/** @brief Put up to max_num nodes in nodes from the random friends.
|
||||
*
|
||||
* Important: this function relies on the first two DHT friends *not* being real
|
||||
* friends to avoid leaking information about real friends into the onion paths.
|
||||
*
|
||||
* @return the number of nodes.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t randfriends_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num);
|
||||
|
||||
/** @brief Put up to max_num nodes in nodes from the closelist.
|
||||
*
|
||||
* @return the number of nodes.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t closelist_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num);
|
||||
|
||||
/** Run this function at least a couple times per second (It's the main loop). */
|
||||
non_null()
|
||||
void do_dht(DHT *dht);
|
||||
|
||||
/*
|
||||
* Use these two functions to bootstrap the client.
|
||||
*/
|
||||
/**
|
||||
* @brief Sends a "get nodes" request to the given node with ip, port and public_key
|
||||
* to setup connections
|
||||
*/
|
||||
non_null()
|
||||
bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Resolves address into an IP address.
|
||||
*
|
||||
* If successful, sends a "get nodes" request to the given node with ip, port
|
||||
* and public_key to setup connections
|
||||
*
|
||||
* @param address can be a hostname or an IP address (IPv4 or IPv6).
|
||||
* @param ipv6enabled if false, the resolving sticks STRICTLY to IPv4 addresses.
|
||||
* Otherwise, the resolving looks for IPv6 addresses first, then IPv4 addresses.
|
||||
*
|
||||
* @retval 1 if the address could be converted into an IP address
|
||||
* @retval 0 otherwise
|
||||
*/
|
||||
non_null()
|
||||
int dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled,
|
||||
uint16_t port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Start sending packets after DHT loaded_friends_list and loaded_clients_list are set.
|
||||
*
|
||||
* @retval 0 if successful
|
||||
* @retval -1 otherwise
|
||||
*/
|
||||
non_null()
|
||||
int dht_connect_after_load(DHT *dht);
|
||||
|
||||
/* ROUTING FUNCTIONS */
|
||||
|
||||
/** @brief Send the given packet to node with public_key.
|
||||
*
|
||||
* @return number of bytes sent.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length);
|
||||
|
||||
/**
|
||||
* Send the following packet to everyone who tells us they are connected to friend_id.
|
||||
*
|
||||
* @return ip for friend.
|
||||
* @return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
|
||||
*/
|
||||
non_null()
|
||||
uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet *packet);
|
||||
|
||||
/** Function to handle crypto packets. */
|
||||
non_null(1) nullable(3, 4)
|
||||
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_cb *cb, void *object);
|
||||
|
||||
/* SAVE/LOAD functions */
|
||||
|
||||
/** Get the size of the DHT (for saving). */
|
||||
non_null()
|
||||
uint32_t dht_size(const DHT *dht);
|
||||
|
||||
/** Save the DHT in data where data is an array of size `dht_size()`. */
|
||||
non_null()
|
||||
void dht_save(const DHT *dht, uint8_t *data);
|
||||
|
||||
/** @brief Load the DHT from data of size size.
|
||||
*
|
||||
* @retval -1 if failure.
|
||||
* @retval 0 if success.
|
||||
*/
|
||||
non_null()
|
||||
int dht_load(DHT *dht, const uint8_t *data, uint32_t length);
|
||||
|
||||
/** Initialize DHT. */
|
||||
non_null()
|
||||
DHT *new_dht(const Logger *log, const Random *rng, const Network *ns, Mono_Time *mono_time, Networking_Core *net,
|
||||
bool hole_punching_enabled, bool lan_discovery_enabled);
|
||||
|
||||
nullable(1)
|
||||
void kill_dht(DHT *dht);
|
||||
|
||||
/**
|
||||
* @retval false if we are not connected to the DHT.
|
||||
* @retval true if we are.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_isconnected(const DHT *dht);
|
||||
|
||||
/**
|
||||
* @retval false if we are not connected or only connected to lan peers with the DHT.
|
||||
* @retval true if we are.
|
||||
*/
|
||||
non_null()
|
||||
bool dht_non_lan_connected(const DHT *dht);
|
||||
|
||||
/** @brief Attempt to add client with ip_port and public_key to the friends client list
|
||||
* and close_clientlist.
|
||||
*
|
||||
* @return 1+ if the item is used in any list, 0 else
|
||||
*/
|
||||
non_null()
|
||||
uint32_t addto_lists(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key);
|
||||
|
||||
/** @brief Copies our own ip_port structure to `dest`.
|
||||
*
|
||||
* WAN addresses take priority over LAN addresses.
|
||||
*
|
||||
* This function will zero the `dest` buffer before use.
|
||||
*
|
||||
* @retval 0 if our ip port can't be found (this usually means we're not connected to the DHT).
|
||||
* @retval 1 if IP is a WAN address.
|
||||
* @retval 2 if IP is a LAN address.
|
||||
*/
|
||||
non_null()
|
||||
unsigned int ipport_self_copy(const DHT *dht, IP_Port *dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
3119
local_pod_repo/toxcore/toxcore/toxcore/DHT.m
Normal file
3119
local_pod_repo/toxcore/toxcore/toxcore/DHT.m
Normal file
File diff suppressed because it is too large
Load Diff
55
local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.h
Normal file
55
local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LAN discovery implementation.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
||||
#define C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
||||
|
||||
#include "network.h"
|
||||
|
||||
/**
|
||||
* Interval in seconds between LAN discovery packet sending.
|
||||
*/
|
||||
#define LAN_DISCOVERY_INTERVAL 10
|
||||
|
||||
typedef struct Broadcast_Info Broadcast_Info;
|
||||
|
||||
/**
|
||||
* Send a LAN discovery pcaket to the broadcast address with port port.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
non_null()
|
||||
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, uint16_t port);
|
||||
|
||||
/**
|
||||
* Discovers broadcast devices and IP addresses.
|
||||
*/
|
||||
non_null()
|
||||
Broadcast_Info *lan_discovery_init(const Network *ns);
|
||||
|
||||
/**
|
||||
* Free all resources associated with the broadcast info.
|
||||
*/
|
||||
nullable(1)
|
||||
void lan_discovery_kill(Broadcast_Info *broadcast);
|
||||
|
||||
/**
|
||||
* Is IP a local ip or not.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_is_local(const IP *ip);
|
||||
|
||||
/**
|
||||
* Checks if a given IP isn't routable.
|
||||
*
|
||||
* @return true if ip is a LAN ip, false if it is not.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_is_lan(const IP *ip);
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_LAN_DISCOVERY_H
|
||||
386
local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.m
Normal file
386
local_pod_repo/toxcore/toxcore/toxcore/LAN_discovery.m
Normal file
@@ -0,0 +1,386 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LAN discovery implementation.
|
||||
*/
|
||||
#include "LAN_discovery.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
// The mingw32/64 Windows library warns about including winsock2.h after
|
||||
// windows.h even though with the above it's a valid thing to do. So, to make
|
||||
// mingw32 headers happy, we include winsock2.h first.
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/netdevice.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#include "ccompat.h"
|
||||
#include "crypto_core.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_INTERFACES 16
|
||||
|
||||
|
||||
struct Broadcast_Info {
|
||||
uint32_t count;
|
||||
IP ips[MAX_INTERFACES];
|
||||
};
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
|
||||
if (broadcast == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
|
||||
unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
if (pAdapterInfo == nullptr) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAdapterInfo);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||
|
||||
if (pAdapterInfo == nullptr) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const int ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
|
||||
if (ret == NO_ERROR) {
|
||||
IP_ADAPTER_INFO *pAdapter = pAdapterInfo;
|
||||
|
||||
while (pAdapter != nullptr) {
|
||||
IP gateway = {0};
|
||||
IP subnet_mask = {0};
|
||||
|
||||
if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask)
|
||||
&& addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) {
|
||||
if (net_family_is_ipv4(gateway.family) && net_family_is_ipv4(subnet_mask.family)) {
|
||||
IP *ip = &broadcast->ips[broadcast->count];
|
||||
ip->family = net_family_ipv4();
|
||||
const uint32_t gateway_ip = net_ntohl(gateway.ip.v4.uint32);
|
||||
const uint32_t subnet_ip = net_ntohl(subnet_mask.ip.v4.uint32);
|
||||
const uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1;
|
||||
ip->ip.v4.uint32 = net_htonl(broadcast_ip);
|
||||
++broadcast->count;
|
||||
|
||||
if (broadcast->count >= MAX_INTERFACES) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
}
|
||||
|
||||
if (pAdapterInfo != nullptr) {
|
||||
free(pAdapterInfo);
|
||||
}
|
||||
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
#elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
|
||||
if (broadcast == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Not sure how many platforms this will run on,
|
||||
* so it's wrapped in `__linux__` for now.
|
||||
* Definitely won't work like this on Windows...
|
||||
*/
|
||||
const Socket sock = net_socket(ns, net_family_ipv4(), TOX_SOCK_STREAM, 0);
|
||||
|
||||
if (!sock_valid(sock)) {
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Configure ifconf for the ioctl call. */
|
||||
struct ifreq i_faces[MAX_INTERFACES];
|
||||
memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES);
|
||||
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_buf = (char *)i_faces;
|
||||
ifc.ifc_len = sizeof(i_faces);
|
||||
|
||||
if (ioctl(sock.sock, SIOCGIFCONF, &ifc) < 0) {
|
||||
kill_sock(ns, sock);
|
||||
free(broadcast);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* `ifc.ifc_len` is set by the `ioctl()` to the actual length used.
|
||||
* On usage of the complete array the call should be repeated with
|
||||
* a larger array, not done (640kB and 16 interfaces shall be
|
||||
* enough, for everybody!)
|
||||
*/
|
||||
const int n = ifc.ifc_len / sizeof(struct ifreq);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
/* there are interfaces with are incapable of broadcast */
|
||||
if (ioctl(sock.sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* moot check: only AF_INET returned (backwards compat.) */
|
||||
if (i_faces[i].ifr_broadaddr.sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const struct sockaddr_in *sock4 = (const struct sockaddr_in *)(void *)&i_faces[i].ifr_broadaddr;
|
||||
|
||||
if (broadcast->count >= MAX_INTERFACES) {
|
||||
break;
|
||||
}
|
||||
|
||||
IP *ip = &broadcast->ips[broadcast->count];
|
||||
ip->family = net_family_ipv4();
|
||||
ip->ip.v4.uint32 = sock4->sin_addr.s_addr;
|
||||
|
||||
if (ip->ip.v4.uint32 == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++broadcast->count;
|
||||
}
|
||||
|
||||
kill_sock(ns, sock);
|
||||
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
#else // TODO(irungentoo): Other platforms?
|
||||
|
||||
non_null()
|
||||
static Broadcast_Info *fetch_broadcast_info(const Network *ns)
|
||||
{
|
||||
return (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** @brief Send packet to all IPv4 broadcast addresses
|
||||
*
|
||||
* @retval true if sent to at least one broadcast target.
|
||||
* @retval false on failure to find any valid broadcast target.
|
||||
*/
|
||||
non_null()
|
||||
static bool send_broadcasts(const Networking_Core *net, const Broadcast_Info *broadcast, uint16_t port,
|
||||
const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if (broadcast->count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < broadcast->count; ++i) {
|
||||
IP_Port ip_port;
|
||||
ip_port.ip = broadcast->ips[i];
|
||||
ip_port.port = port;
|
||||
sendpacket(net, &ip_port, data, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Return the broadcast ip. */
|
||||
static IP broadcast_ip(Family family_socket, Family family_broadcast)
|
||||
{
|
||||
IP ip;
|
||||
ip_reset(&ip);
|
||||
|
||||
if (net_family_is_ipv6(family_socket)) {
|
||||
if (net_family_is_ipv6(family_broadcast)) {
|
||||
ip.family = net_family_ipv6();
|
||||
/* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
/* `FE80::*:` MUST be exact, for that we would need to look over all
|
||||
* interfaces and check in which status they are */
|
||||
ip.ip.v6.uint8[ 0] = 0xFF;
|
||||
ip.ip.v6.uint8[ 1] = 0x02;
|
||||
ip.ip.v6.uint8[15] = 0x01;
|
||||
} else if (net_family_is_ipv4(family_broadcast)) {
|
||||
ip.family = net_family_ipv6();
|
||||
ip.ip.v6 = ip6_broadcast;
|
||||
}
|
||||
} else if (net_family_is_ipv4(family_socket) && net_family_is_ipv4(family_broadcast)) {
|
||||
ip.family = net_family_ipv4();
|
||||
ip.ip.v4 = ip4_broadcast;
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool ip4_is_local(const IP4 *ip4)
|
||||
{
|
||||
/* Loopback. */
|
||||
return ip4->uint8[0] == 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is IP a local ip or not.
|
||||
*/
|
||||
bool ip_is_local(const IP *ip)
|
||||
{
|
||||
if (net_family_is_ipv4(ip->family)) {
|
||||
return ip4_is_local(&ip->ip.v4);
|
||||
}
|
||||
|
||||
/* embedded IPv4-in-IPv6 */
|
||||
if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
|
||||
IP4 ip4;
|
||||
ip4.uint32 = ip->ip.v6.uint32[3];
|
||||
return ip4_is_local(&ip4);
|
||||
}
|
||||
|
||||
/* localhost in IPv6 (::1) */
|
||||
return ip->ip.v6.uint64[0] == 0 && ip->ip.v6.uint32[2] == 0 && ip->ip.v6.uint32[3] == net_htonl(1);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool ip4_is_lan(const IP4 *ip4)
|
||||
{
|
||||
/* 10.0.0.0 to 10.255.255.255 range. */
|
||||
if (ip4->uint8[0] == 10) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 172.16.0.0 to 172.31.255.255 range. */
|
||||
if (ip4->uint8[0] == 172 && ip4->uint8[1] >= 16 && ip4->uint8[1] <= 31) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 192.168.0.0 to 192.168.255.255 range. */
|
||||
if (ip4->uint8[0] == 192 && ip4->uint8[1] == 168) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 169.254.1.0 to 169.254.254.255 range. */
|
||||
if (ip4->uint8[0] == 169 && ip4->uint8[1] == 254 && ip4->uint8[2] != 0
|
||||
&& ip4->uint8[2] != 255) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
|
||||
* (shared address space to stack another layer of NAT) */
|
||||
return (ip4->uint8[0] == 100) && ((ip4->uint8[1] & 0xC0) == 0x40);
|
||||
}
|
||||
|
||||
bool ip_is_lan(const IP *ip)
|
||||
{
|
||||
if (ip_is_local(ip)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (net_family_is_ipv4(ip->family)) {
|
||||
return ip4_is_lan(&ip->ip.v4);
|
||||
}
|
||||
|
||||
if (net_family_is_ipv6(ip->family)) {
|
||||
/* autogenerated for each interface: `FE80::*` (up to `FEBF::*`)
|
||||
* `FF02::1` is - according to RFC 4291 - multicast all-nodes link-local */
|
||||
if (((ip->ip.v6.uint8[0] == 0xFF) && (ip->ip.v6.uint8[1] < 3) && (ip->ip.v6.uint8[15] == 1)) ||
|
||||
((ip->ip.v6.uint8[0] == 0xFE) && ((ip->ip.v6.uint8[1] & 0xC0) == 0x80))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* embedded IPv4-in-IPv6 */
|
||||
if (ipv6_ipv4_in_v6(&ip->ip.v6)) {
|
||||
IP4 ip4;
|
||||
ip4.uint32 = ip->ip.v6.uint32[3];
|
||||
return ip4_is_lan(&ip4);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadcast, const uint8_t *dht_pk, uint16_t port)
|
||||
{
|
||||
if (broadcast == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1];
|
||||
data[0] = NET_PACKET_LAN_DISCOVERY;
|
||||
pk_copy(data + 1, dht_pk);
|
||||
|
||||
send_broadcasts(net, broadcast, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
bool res = false;
|
||||
IP_Port ip_port;
|
||||
ip_port.port = port;
|
||||
|
||||
/* IPv6 multicast */
|
||||
if (net_family_is_ipv6(net_family(net))) {
|
||||
ip_port.ip = broadcast_ip(net_family_ipv6(), net_family_ipv6());
|
||||
|
||||
if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is IPv6 */
|
||||
ip_port.ip = broadcast_ip(net_family(net), net_family_ipv4());
|
||||
|
||||
if (ip_isset(&ip_port.ip) && sendpacket(net, &ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Broadcast_Info *lan_discovery_init(const Network *ns)
|
||||
{
|
||||
return fetch_broadcast_info(ns);
|
||||
}
|
||||
|
||||
void lan_discovery_kill(Broadcast_Info *broadcast)
|
||||
{
|
||||
free(broadcast);
|
||||
}
|
||||
132
local_pod_repo/toxcore/toxcore/toxcore/Makefile.inc
Normal file
132
local_pod_repo/toxcore/toxcore/toxcore/Makefile.inc
Normal file
@@ -0,0 +1,132 @@
|
||||
lib_LTLIBRARIES += libtoxcore.la
|
||||
|
||||
libtoxcore_la_include_HEADERS = \
|
||||
../toxcore/tox.h
|
||||
|
||||
libtoxcore_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
|
||||
../third_party/cmp/cmp.h \
|
||||
../toxcore/attributes.h \
|
||||
../toxcore/bin_pack.c \
|
||||
../toxcore/bin_pack.h \
|
||||
../toxcore/bin_unpack.c \
|
||||
../toxcore/bin_unpack.h \
|
||||
../toxcore/ccompat.c \
|
||||
../toxcore/ccompat.h \
|
||||
../toxcore/events/conference_connected.c \
|
||||
../toxcore/events/conference_invite.c \
|
||||
../toxcore/events/conference_message.c \
|
||||
../toxcore/events/conference_peer_list_changed.c \
|
||||
../toxcore/events/conference_peer_name.c \
|
||||
../toxcore/events/conference_title.c \
|
||||
../toxcore/events/file_chunk_request.c \
|
||||
../toxcore/events/file_recv.c \
|
||||
../toxcore/events/file_recv_chunk.c \
|
||||
../toxcore/events/file_recv_control.c \
|
||||
../toxcore/events/friend_connection_status.c \
|
||||
../toxcore/events/friend_lossless_packet.c \
|
||||
../toxcore/events/friend_lossy_packet.c \
|
||||
../toxcore/events/friend_message.c \
|
||||
../toxcore/events/friend_name.c \
|
||||
../toxcore/events/friend_read_receipt.c \
|
||||
../toxcore/events/friend_request.c \
|
||||
../toxcore/events/friend_status.c \
|
||||
../toxcore/events/friend_status_message.c \
|
||||
../toxcore/events/friend_typing.c \
|
||||
../toxcore/events/events_alloc.c \
|
||||
../toxcore/events/events_alloc.h \
|
||||
../toxcore/events/self_connection_status.c \
|
||||
../toxcore/DHT.h \
|
||||
../toxcore/DHT.c \
|
||||
../toxcore/mono_time.h \
|
||||
../toxcore/mono_time.c \
|
||||
../toxcore/network.h \
|
||||
../toxcore/network.c \
|
||||
../toxcore/crypto_core.h \
|
||||
../toxcore/crypto_core.c \
|
||||
../toxcore/timed_auth.h \
|
||||
../toxcore/timed_auth.c \
|
||||
../toxcore/ping_array.h \
|
||||
../toxcore/ping_array.c \
|
||||
../toxcore/net_crypto.h \
|
||||
../toxcore/net_crypto.c \
|
||||
../toxcore/friend_requests.h \
|
||||
../toxcore/friend_requests.c \
|
||||
../toxcore/LAN_discovery.h \
|
||||
../toxcore/LAN_discovery.c \
|
||||
../toxcore/friend_connection.h \
|
||||
../toxcore/friend_connection.c \
|
||||
../toxcore/Messenger.h \
|
||||
../toxcore/Messenger.c \
|
||||
../toxcore/ping.h \
|
||||
../toxcore/ping.c \
|
||||
../toxcore/state.h \
|
||||
../toxcore/state.c \
|
||||
../toxcore/tox.h \
|
||||
../toxcore/tox.c \
|
||||
../toxcore/tox_dispatch.h \
|
||||
../toxcore/tox_dispatch.c \
|
||||
../toxcore/tox_events.h \
|
||||
../toxcore/tox_events.c \
|
||||
../toxcore/tox_unpack.h \
|
||||
../toxcore/tox_unpack.c \
|
||||
../toxcore/tox_private.c \
|
||||
../toxcore/tox_private.h \
|
||||
../toxcore/tox_struct.h \
|
||||
../toxcore/tox_api.c \
|
||||
../toxcore/util.h \
|
||||
../toxcore/util.c \
|
||||
../toxcore/group.h \
|
||||
../toxcore/group.c \
|
||||
../toxcore/onion.h \
|
||||
../toxcore/onion.c \
|
||||
../toxcore/logger.h \
|
||||
../toxcore/logger.c \
|
||||
../toxcore/onion_announce.h \
|
||||
../toxcore/onion_announce.c \
|
||||
../toxcore/onion_client.h \
|
||||
../toxcore/onion_client.c \
|
||||
../toxcore/announce.h \
|
||||
../toxcore/announce.c \
|
||||
../toxcore/forwarding.h \
|
||||
../toxcore/forwarding.c \
|
||||
../toxcore/TCP_client.h \
|
||||
../toxcore/TCP_client.c \
|
||||
../toxcore/TCP_common.h \
|
||||
../toxcore/TCP_common.c \
|
||||
../toxcore/TCP_server.h \
|
||||
../toxcore/TCP_server.c \
|
||||
../toxcore/TCP_connection.h \
|
||||
../toxcore/TCP_connection.c \
|
||||
../toxcore/list.c \
|
||||
../toxcore/list.h
|
||||
|
||||
libtoxcore_la_CFLAGS = -I$(top_srcdir) \
|
||||
-I$(top_srcdir)/toxcore \
|
||||
$(LIBSODIUM_CFLAGS) \
|
||||
$(NACL_CFLAGS) \
|
||||
$(MSGPACK_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS) \
|
||||
-DCMP_NO_FLOAT=1
|
||||
|
||||
libtoxcore_la_LDFLAGS = $(LT_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS) \
|
||||
$(LIBSODIUM_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(MSGPACK_LDFLAGS) \
|
||||
$(MATH_LDFLAGS) \
|
||||
$(RT_LIBS) \
|
||||
$(WINSOCK2_LIBS)
|
||||
|
||||
libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \
|
||||
$(NACL_OBJECTS) \
|
||||
$(NACL_LIBS) \
|
||||
$(MSGPACK_LIBS) \
|
||||
$(PTHREAD_LIBS)
|
||||
|
||||
if SET_SO_VERSION
|
||||
|
||||
EXTRA_libtoxcore_la_DEPENDENCIES = ../so.version
|
||||
|
||||
endif
|
||||
869
local_pod_repo/toxcore/toxcore/toxcore/Messenger.h
Normal file
869
local_pod_repo/toxcore/toxcore/toxcore/Messenger.h
Normal file
@@ -0,0 +1,869 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of a simple text chat only messenger on the tox network
|
||||
* core.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_MESSENGER_H
|
||||
#define C_TOXCORE_TOXCORE_MESSENGER_H
|
||||
|
||||
#include "TCP_server.h"
|
||||
#include "announce.h"
|
||||
#include "forwarding.h"
|
||||
#include "friend_connection.h"
|
||||
#include "friend_requests.h"
|
||||
#include "logger.h"
|
||||
#include "net_crypto.h"
|
||||
#include "state.h"
|
||||
|
||||
#define MAX_NAME_LENGTH 128
|
||||
/* TODO(irungentoo): this must depend on other variable. */
|
||||
#define MAX_STATUSMESSAGE_LENGTH 1007
|
||||
/* Used for TCP relays in Messenger struct (may need to be `% 2 == 0`)*/
|
||||
#define NUM_SAVED_TCP_RELAYS 8
|
||||
/* This cannot be bigger than 256 */
|
||||
#define MAX_CONCURRENT_FILE_PIPES 256
|
||||
|
||||
|
||||
#define FRIEND_ADDRESS_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
|
||||
|
||||
typedef enum Message_Type {
|
||||
MESSAGE_NORMAL = 0,
|
||||
MESSAGE_ACTION = 1,
|
||||
MESSAGE_HIGH_LEVEL_ACK = 2,
|
||||
} Message_Type;
|
||||
|
||||
typedef struct Messenger Messenger;
|
||||
|
||||
// Returns the size of the data
|
||||
typedef uint32_t m_state_size_cb(const Messenger *m);
|
||||
|
||||
// Returns the new pointer to data
|
||||
typedef uint8_t *m_state_save_cb(const Messenger *m, uint8_t *data);
|
||||
|
||||
// Returns if there were any erros during loading
|
||||
typedef State_Load_Status m_state_load_cb(Messenger *m, const uint8_t *data, uint32_t length);
|
||||
|
||||
typedef struct Messenger_State_Plugin {
|
||||
State_Type type;
|
||||
m_state_size_cb *size;
|
||||
m_state_save_cb *save;
|
||||
m_state_load_cb *load;
|
||||
} Messenger_State_Plugin;
|
||||
|
||||
typedef struct Messenger_Options {
|
||||
bool ipv6enabled;
|
||||
bool udp_disabled;
|
||||
TCP_Proxy_Info proxy_info;
|
||||
uint16_t port_range[2];
|
||||
uint16_t tcp_server_port;
|
||||
|
||||
bool hole_punching_enabled;
|
||||
bool local_discovery_enabled;
|
||||
bool dht_announcements_enabled;
|
||||
|
||||
logger_cb *log_callback;
|
||||
void *log_context;
|
||||
void *log_user_data;
|
||||
|
||||
Messenger_State_Plugin *state_plugins;
|
||||
uint8_t state_plugins_length;
|
||||
} Messenger_Options;
|
||||
|
||||
/* this means no special capabilities, in other words clients that are older
|
||||
* and did not implement this feature yet
|
||||
*/
|
||||
#define TOX_CAPABILITY_BASIC 0
|
||||
/* ATTENTION: if you are adding new flags in your fork or toxcore,
|
||||
* or in c-toxcore master,
|
||||
* please coordinate with us first!
|
||||
* thank you, the Tox Devs.
|
||||
*/
|
||||
#define TOX_CAPABILITY_CAPABILITIES ((uint64_t)1) << 0
|
||||
#define TOX_CAPABILITY_MSGV2 ((uint64_t)1) << 1
|
||||
#define TOX_CAPABILITY_TOXAV_H264 ((uint64_t)1) << 2
|
||||
#define TOX_CAPABILITY_MSGV3 ((uint64_t)1) << 3
|
||||
/* add new flags/bits here */
|
||||
/* if the TOX_CAPABILITY_NEXT_IMPLEMENTATION flag is set it means
|
||||
* we are using a different system for indicating capabilities now,
|
||||
* and TOX_CAPABILITIES_* should be ignored and just the new (not yet known)
|
||||
* system should be used
|
||||
*/
|
||||
#define TOX_CAPABILITY_NEXT_IMPLEMENTATION ((uint64_t)1) << 63
|
||||
/* hardcoded capabilities of this version/branch of toxcore */
|
||||
#define TOX_CAPABILITIES_CURRENT (uint64_t)(TOX_CAPABILITY_CAPABILITIES | TOX_CAPABILITY_MSGV3)
|
||||
/* size of the FLAGS in bytes */
|
||||
#define TOX_CAPABILITIES_SIZE sizeof(uint64_t)
|
||||
|
||||
struct Receipts {
|
||||
uint32_t packet_num;
|
||||
uint32_t msg_id;
|
||||
struct Receipts *next;
|
||||
};
|
||||
|
||||
/** Status definitions. */
|
||||
typedef enum Friend_Status {
|
||||
NOFRIEND,
|
||||
FRIEND_ADDED,
|
||||
FRIEND_REQUESTED,
|
||||
FRIEND_CONFIRMED,
|
||||
FRIEND_ONLINE,
|
||||
} Friend_Status;
|
||||
|
||||
/** @brief Errors for m_addfriend
|
||||
*
|
||||
* FAERR - Friend Add Error
|
||||
*/
|
||||
typedef enum Friend_Add_Error {
|
||||
FAERR_TOOLONG = -1,
|
||||
FAERR_NOMESSAGE = -2,
|
||||
FAERR_OWNKEY = -3,
|
||||
FAERR_ALREADYSENT = -4,
|
||||
FAERR_BADCHECKSUM = -6,
|
||||
FAERR_SETNEWNOSPAM = -7,
|
||||
FAERR_NOMEM = -8,
|
||||
} Friend_Add_Error;
|
||||
|
||||
|
||||
/** Default start timeout in seconds between friend requests. */
|
||||
#define FRIENDREQUEST_TIMEOUT 5
|
||||
|
||||
typedef enum Connection_Status {
|
||||
CONNECTION_NONE,
|
||||
CONNECTION_TCP,
|
||||
CONNECTION_UDP,
|
||||
} Connection_Status;
|
||||
|
||||
/**
|
||||
* Represents userstatuses someone can have.
|
||||
*/
|
||||
typedef enum Userstatus {
|
||||
USERSTATUS_NONE,
|
||||
USERSTATUS_AWAY,
|
||||
USERSTATUS_BUSY,
|
||||
USERSTATUS_INVALID,
|
||||
} Userstatus;
|
||||
|
||||
#define FILE_ID_LENGTH 32
|
||||
|
||||
struct File_Transfers {
|
||||
uint64_t size;
|
||||
uint64_t transferred;
|
||||
uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */
|
||||
uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */
|
||||
uint32_t last_packet_number; /* number of the last packet sent. */
|
||||
uint64_t requested; /* total data requested by the request chunk callback */
|
||||
uint8_t id[FILE_ID_LENGTH];
|
||||
};
|
||||
typedef enum Filestatus {
|
||||
FILESTATUS_NONE,
|
||||
FILESTATUS_NOT_ACCEPTED,
|
||||
FILESTATUS_TRANSFERRING,
|
||||
// FILESTATUS_BROKEN,
|
||||
FILESTATUS_FINISHED,
|
||||
} Filestatus;
|
||||
|
||||
typedef enum File_Pause {
|
||||
FILE_PAUSE_NOT,
|
||||
FILE_PAUSE_US,
|
||||
FILE_PAUSE_OTHER,
|
||||
FILE_PAUSE_BOTH,
|
||||
} File_Pause;
|
||||
|
||||
typedef enum Filecontrol {
|
||||
FILECONTROL_ACCEPT,
|
||||
FILECONTROL_PAUSE,
|
||||
FILECONTROL_KILL,
|
||||
FILECONTROL_SEEK,
|
||||
} Filecontrol;
|
||||
|
||||
typedef enum Filekind {
|
||||
FILEKIND_DATA,
|
||||
FILEKIND_AVATAR,
|
||||
} Filekind;
|
||||
|
||||
|
||||
typedef void m_self_connection_status_cb(Messenger *m, Onion_Connection_Status connection_status, void *user_data);
|
||||
typedef void m_friend_status_cb(Messenger *m, uint32_t friend_number, unsigned int status, void *user_data);
|
||||
typedef void m_friend_connection_status_cb(Messenger *m, uint32_t friend_number, unsigned int connection_status,
|
||||
void *user_data);
|
||||
typedef void m_friend_message_cb(Messenger *m, uint32_t friend_number, unsigned int message_type,
|
||||
const uint8_t *message, size_t length, void *user_data);
|
||||
typedef void m_file_recv_control_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, unsigned int control,
|
||||
void *user_data);
|
||||
typedef void m_friend_request_cb(Messenger *m, const uint8_t *public_key, const uint8_t *message, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_name_cb(Messenger *m, uint32_t friend_number, const uint8_t *name, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_status_message_cb(Messenger *m, uint32_t friend_number, const uint8_t *message, size_t length,
|
||||
void *user_data);
|
||||
typedef void m_friend_typing_cb(Messenger *m, uint32_t friend_number, bool is_typing, void *user_data);
|
||||
typedef void m_friend_read_receipt_cb(Messenger *m, uint32_t friend_number, uint32_t message_id, void *user_data);
|
||||
typedef void m_file_recv_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint32_t kind,
|
||||
uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data);
|
||||
typedef void m_file_chunk_request_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
size_t length, void *user_data);
|
||||
typedef void m_file_recv_chunk_cb(Messenger *m, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *user_data);
|
||||
typedef void m_friend_lossy_packet_cb(Messenger *m, uint32_t friend_number, uint8_t packet_id, const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void m_friend_lossless_packet_cb(Messenger *m, uint32_t friend_number, uint8_t packet_id, const uint8_t *data,
|
||||
size_t length, void *user_data);
|
||||
typedef void m_friend_connectionstatuschange_internal_cb(Messenger *m, uint32_t friend_number,
|
||||
uint8_t connection_status, void *user_data);
|
||||
typedef void m_conference_invite_cb(Messenger *m, uint32_t friend_number, const uint8_t *cookie, uint16_t length,
|
||||
void *user_data);
|
||||
typedef void m_msi_packet_cb(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length,
|
||||
void *user_data);
|
||||
typedef int m_lossy_rtp_packet_cb(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object);
|
||||
|
||||
typedef struct RTP_Packet_Handler {
|
||||
m_lossy_rtp_packet_cb *function;
|
||||
void *object;
|
||||
} RTP_Packet_Handler;
|
||||
|
||||
typedef struct Friend {
|
||||
uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
int friendcon_id;
|
||||
|
||||
uint64_t friendrequest_lastsent; // Time at which the last friend request was sent.
|
||||
uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts.
|
||||
uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online.
|
||||
uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do.
|
||||
uint8_t name[MAX_NAME_LENGTH];
|
||||
uint16_t name_length;
|
||||
bool name_sent; // false if we didn't send our name to this friend, true if we have.
|
||||
uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmessage_length;
|
||||
bool statusmessage_sent;
|
||||
Userstatus userstatus;
|
||||
bool userstatus_sent;
|
||||
bool user_istyping;
|
||||
bool user_istyping_sent;
|
||||
bool is_typing;
|
||||
uint16_t info_size; // Length of the info.
|
||||
uint32_t message_id; // a semi-unique id used in read receipts.
|
||||
uint32_t friendrequest_nospam; // The nospam number used in the friend request.
|
||||
uint64_t last_seen_time;
|
||||
Connection_Status last_connection_udp_tcp;
|
||||
struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];
|
||||
uint32_t num_sending_files;
|
||||
struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];
|
||||
|
||||
RTP_Packet_Handler lossy_rtp_packethandlers[PACKET_ID_RANGE_LOSSY_AV_SIZE];
|
||||
|
||||
struct Receipts *receipts_start;
|
||||
struct Receipts *receipts_end;
|
||||
uint64_t toxcore_capabilities;
|
||||
} Friend;
|
||||
|
||||
struct Messenger {
|
||||
Logger *log;
|
||||
Mono_Time *mono_time;
|
||||
const Random *rng;
|
||||
const Network *ns;
|
||||
|
||||
Networking_Core *net;
|
||||
Net_Crypto *net_crypto;
|
||||
DHT *dht;
|
||||
|
||||
Forwarding *forwarding;
|
||||
Announcements *announce;
|
||||
|
||||
Onion *onion;
|
||||
Onion_Announce *onion_a;
|
||||
Onion_Client *onion_c;
|
||||
|
||||
Friend_Connections *fr_c;
|
||||
|
||||
TCP_Server *tcp_server;
|
||||
Friend_Requests *fr;
|
||||
uint8_t name[MAX_NAME_LENGTH];
|
||||
uint16_t name_length;
|
||||
|
||||
uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmessage_length;
|
||||
|
||||
Userstatus userstatus;
|
||||
|
||||
Friend *friendlist;
|
||||
uint32_t numfriends;
|
||||
|
||||
uint64_t lastdump;
|
||||
uint8_t is_receiving_file;
|
||||
|
||||
bool has_added_relays; // If the first connection has occurred in do_messenger
|
||||
|
||||
uint16_t num_loaded_relays;
|
||||
Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config
|
||||
|
||||
m_friend_request_cb *friend_request;
|
||||
m_friend_message_cb *friend_message;
|
||||
m_friend_name_cb *friend_namechange;
|
||||
m_friend_status_message_cb *friend_statusmessagechange;
|
||||
m_friend_status_cb *friend_userstatuschange;
|
||||
m_friend_typing_cb *friend_typingchange;
|
||||
m_friend_read_receipt_cb *read_receipt;
|
||||
m_friend_connection_status_cb *friend_connectionstatuschange;
|
||||
m_friend_connectionstatuschange_internal_cb *friend_connectionstatuschange_internal;
|
||||
void *friend_connectionstatuschange_internal_userdata;
|
||||
|
||||
struct Group_Chats *conferences_object; /* Set by new_groupchats()*/
|
||||
m_conference_invite_cb *conference_invite;
|
||||
|
||||
m_file_recv_cb *file_sendrequest;
|
||||
m_file_recv_control_cb *file_filecontrol;
|
||||
m_file_recv_chunk_cb *file_filedata;
|
||||
m_file_chunk_request_cb *file_reqchunk;
|
||||
|
||||
m_msi_packet_cb *msi_packet;
|
||||
void *msi_packet_userdata;
|
||||
|
||||
m_friend_lossy_packet_cb *lossy_packethandler;
|
||||
m_friend_lossless_packet_cb *lossless_packethandler;
|
||||
|
||||
m_self_connection_status_cb *core_connection_change;
|
||||
Onion_Connection_Status last_connection_status;
|
||||
|
||||
Messenger_Options options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format: `[real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]`
|
||||
*
|
||||
* @param[out] address FRIEND_ADDRESS_SIZE byte address to give to others.
|
||||
*/
|
||||
non_null()
|
||||
void getaddress(const Messenger *m, uint8_t *address);
|
||||
|
||||
/**
|
||||
* Add a friend.
|
||||
*
|
||||
* Set the data that will be sent along with friend request.
|
||||
*
|
||||
* @param address is the address of the friend (returned by getaddress of the friend
|
||||
* you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.
|
||||
* TODO(irungentoo): add checksum.
|
||||
* @param data is the data.
|
||||
* @param length is the length.
|
||||
*
|
||||
* @return the friend number if success.
|
||||
* @retval FA_TOOLONG if message length is too long.
|
||||
* @retval FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
|
||||
* @retval FAERR_OWNKEY if user's own key.
|
||||
* @retval FAERR_ALREADYSENT if friend request already sent or already a friend.
|
||||
* @retval FAERR_BADCHECKSUM if bad checksum in address.
|
||||
* @retval FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
|
||||
* (the nospam for that friend was set to the new one).
|
||||
* @retval FAERR_NOMEM if increasing the friend list size fails.
|
||||
*/
|
||||
non_null()
|
||||
int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length);
|
||||
|
||||
|
||||
/** @brief Add a friend without sending a friendrequest.
|
||||
* @return the friend number if success.
|
||||
* @retval -3 if user's own key.
|
||||
* @retval -4 if friend request already sent or already a friend.
|
||||
* @retval -6 if bad checksum in address.
|
||||
* @retval -8 if increasing the friend list size fails.
|
||||
*/
|
||||
non_null()
|
||||
int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk);
|
||||
|
||||
/** @return the friend number associated to that public key.
|
||||
* @retval -1 if no such friend.
|
||||
*/
|
||||
non_null()
|
||||
int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk);
|
||||
|
||||
/** @brief Copies the public key associated to that friend id into real_pk buffer.
|
||||
*
|
||||
* Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk);
|
||||
|
||||
/** @return friend connection id on success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int getfriendcon_id(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Remove a friend.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_delfriend(Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Checks friend's connection status.
|
||||
*
|
||||
* @retval CONNECTION_UDP (2) if friend is directly connected to us (Online UDP).
|
||||
* @retval CONNECTION_TCP (1) if friend is connected to us (Online TCP).
|
||||
* @retval CONNECTION_NONE (0) if friend is not connected to us (Offline).
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/**
|
||||
* Checks if there exists a friend with given friendnumber.
|
||||
*
|
||||
* @param friendnumber The index in the friend list.
|
||||
*
|
||||
* @retval true if friend exists.
|
||||
* @retval false if friend doesn't exist.
|
||||
*/
|
||||
non_null()
|
||||
bool m_friend_exists(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Send a message of type to an online friend.
|
||||
*
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if too large.
|
||||
* @retval -3 if friend not online.
|
||||
* @retval -4 if send failed (because queue is full).
|
||||
* @retval -5 if bad type.
|
||||
* @retval 0 if success.
|
||||
*
|
||||
* The value in message_id will be passed to your read_receipt callback when the other receives the message.
|
||||
*/
|
||||
non_null(1, 4) nullable(6)
|
||||
int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,
|
||||
uint32_t *message_id);
|
||||
|
||||
|
||||
/** @brief Set the name and name_length of a friend.
|
||||
*
|
||||
* name must be a string of maximum MAX_NAME_LENGTH length.
|
||||
* length must be at least 1 byte.
|
||||
* length is the length of name with the NULL terminator.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length);
|
||||
|
||||
/** @brief Set our nickname.
|
||||
*
|
||||
* name must be a string of maximum MAX_NAME_LENGTH length.
|
||||
* length must be at least 1 byte.
|
||||
* length is the length of name with the NULL terminator.
|
||||
*
|
||||
* @retval 0 if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int setname(Messenger *m, const uint8_t *name, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Get your nickname.
|
||||
*
|
||||
* m - The messenger context to use.
|
||||
* name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
|
||||
*
|
||||
* @return length of the name.
|
||||
* @retval 0 on error.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t getself_name(const Messenger *m, uint8_t *name);
|
||||
|
||||
/** @brief Get name of friendnumber and put it in name.
|
||||
*
|
||||
* name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
|
||||
*
|
||||
* @return length of name if success.
|
||||
* @retval -1 if failure.
|
||||
*/
|
||||
non_null()
|
||||
int getname(const Messenger *m, int32_t friendnumber, uint8_t *name);
|
||||
|
||||
/** @return the length of name, including null on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_get_name_size(const Messenger *m, int32_t friendnumber);
|
||||
non_null() int m_get_self_name_size(const Messenger *m);
|
||||
|
||||
/** @brief Set our user status.
|
||||
* You are responsible for freeing status after.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length);
|
||||
non_null() int m_set_userstatus(Messenger *m, uint8_t status);
|
||||
|
||||
/**
|
||||
* Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
|
||||
*
|
||||
* @return the length of friendnumber's status message, including null on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber);
|
||||
non_null() int m_get_self_statusmessage_size(const Messenger *m);
|
||||
|
||||
/** @brief Copy friendnumber's status message into buf, truncating if size is over maxlen.
|
||||
*
|
||||
* Get the size you need to allocate from m_get_statusmessage_size.
|
||||
* The self variant will copy our own status message.
|
||||
*
|
||||
* @return the length of the copied data on success
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null() int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen);
|
||||
non_null() int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf);
|
||||
|
||||
/** @brief return one of Userstatus values.
|
||||
*
|
||||
* Values unknown to your application should be represented as USERSTATUS_NONE.
|
||||
* As above, the self variant will return our own Userstatus.
|
||||
* If friendnumber is invalid, this shall return USERSTATUS_INVALID.
|
||||
*/
|
||||
non_null() uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);
|
||||
non_null() uint8_t m_get_self_userstatus(const Messenger *m);
|
||||
|
||||
/* get capabilities of friend's toxcore
|
||||
* return TOX_CAPABILITY_BASIC on any error
|
||||
*/
|
||||
uint64_t m_get_friend_toxcore_capabilities(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief returns timestamp of last time friendnumber was seen online or 0 if never seen.
|
||||
* if friendnumber is invalid this function will return UINT64_MAX.
|
||||
*/
|
||||
non_null() uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** @brief Set our typing status for a friend.
|
||||
* You are responsible for turning it on or off.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int m_set_usertyping(Messenger *m, int32_t friendnumber, bool is_typing);
|
||||
|
||||
/** @brief Get the typing status of a friend.
|
||||
*
|
||||
* @retval -1 if friend number is invalid.
|
||||
* @retval 0 if friend is not typing.
|
||||
* @retval 1 if friend is typing.
|
||||
*/
|
||||
non_null()
|
||||
int m_get_istyping(const Messenger *m, int32_t friendnumber);
|
||||
|
||||
/** Set the function that will be executed when a friend request is received. */
|
||||
non_null(1) nullable(2)
|
||||
void m_callback_friendrequest(Messenger *m, m_friend_request_cb *function);
|
||||
|
||||
/** Set the function that will be executed when a message from a friend is received. */
|
||||
non_null() void m_callback_friendmessage(Messenger *m, m_friend_message_cb *function);
|
||||
|
||||
/** @brief Set the callback for name changes.
|
||||
* You are not responsible for freeing newname.
|
||||
*/
|
||||
non_null() void m_callback_namechange(Messenger *m, m_friend_name_cb *function);
|
||||
|
||||
/** @brief Set the callback for status message changes.
|
||||
*
|
||||
* You are not responsible for freeing newstatus
|
||||
*/
|
||||
non_null() void m_callback_statusmessage(Messenger *m, m_friend_status_message_cb *function);
|
||||
|
||||
/** @brief Set the callback for status type changes. */
|
||||
non_null() void m_callback_userstatus(Messenger *m, m_friend_status_cb *function);
|
||||
|
||||
/** @brief Set the callback for typing changes. */
|
||||
non_null() void m_callback_typingchange(Messenger *m, m_friend_typing_cb *function);
|
||||
|
||||
/** @brief Set the callback for read receipts.
|
||||
*
|
||||
* If you are keeping a record of returns from m_sendmessage,
|
||||
* receipt might be one of those values, meaning the message
|
||||
* has been received on the other side.
|
||||
* Since core doesn't track ids for you, receipt may not correspond to any message.
|
||||
* In that case, you should discard it.
|
||||
*/
|
||||
non_null() void m_callback_read_receipt(Messenger *m, m_friend_read_receipt_cb *function);
|
||||
|
||||
/** @brief Set the callback for connection status changes.
|
||||
*
|
||||
* Status:
|
||||
* - 0: friend went offline after being previously online.
|
||||
* - 1: friend went online.
|
||||
*
|
||||
* Note that this callback is not called when adding friends, thus the
|
||||
* "after being previously online" part.
|
||||
* It's assumed that when adding friends, their connection status is offline.
|
||||
*/
|
||||
non_null() void m_callback_connectionstatus(Messenger *m, m_friend_connection_status_cb *function);
|
||||
|
||||
/** Same as previous but for internal A/V core usage only */
|
||||
non_null() void m_callback_connectionstatus_internal_av(
|
||||
Messenger *m, m_friend_connectionstatuschange_internal_cb *function, void *userdata);
|
||||
|
||||
|
||||
/** @brief Set the callback for typing changes. */
|
||||
non_null() void m_callback_core_connection(Messenger *m, m_self_connection_status_cb *function);
|
||||
|
||||
/*** CONFERENCES */
|
||||
|
||||
/** @brief Set the callback for conference invites. */
|
||||
non_null(1) nullable(2)
|
||||
void m_callback_conference_invite(Messenger *m, m_conference_invite_cb *function);
|
||||
|
||||
/** @brief Send a conference invite packet.
|
||||
*
|
||||
* return true on success
|
||||
* return false on failure
|
||||
*/
|
||||
non_null()
|
||||
bool send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
/*** FILE SENDING */
|
||||
|
||||
|
||||
/** @brief Set the callback for file send requests. */
|
||||
non_null() void callback_file_sendrequest(Messenger *m, m_file_recv_cb *function);
|
||||
|
||||
|
||||
/** @brief Set the callback for file control requests. */
|
||||
non_null() void callback_file_control(Messenger *m, m_file_recv_control_cb *function);
|
||||
|
||||
/** @brief Set the callback for file data. */
|
||||
non_null() void callback_file_data(Messenger *m, m_file_recv_chunk_cb *function);
|
||||
|
||||
/** @brief Set the callback for file request chunk. */
|
||||
non_null() void callback_file_reqchunk(Messenger *m, m_file_chunk_request_cb *function);
|
||||
|
||||
|
||||
/** @brief Copy the file transfer file id to file_id
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if filenumber not valid
|
||||
*/
|
||||
non_null()
|
||||
int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id);
|
||||
|
||||
/** @brief Send a file send request.
|
||||
*
|
||||
* Maximum filename length is 255 bytes.
|
||||
*
|
||||
* @return file number on success
|
||||
* @retval -1 if friend not found.
|
||||
* @retval -2 if filename length invalid.
|
||||
* @retval -3 if no more file sending slots left.
|
||||
* @retval -4 if could not send packet (friend offline).
|
||||
*/
|
||||
non_null()
|
||||
long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
|
||||
const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length);
|
||||
|
||||
/** @brief Send a file control request.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if file number invalid.
|
||||
* @retval -4 if file control is bad.
|
||||
* @retval -5 if file already paused.
|
||||
* @retval -6 if resume file failed because it was only paused by the other.
|
||||
* @retval -7 if resume file failed because it wasn't paused.
|
||||
* @retval -8 if packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control);
|
||||
|
||||
/** @brief Send a seek file control request.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if file number invalid.
|
||||
* @retval -4 if not receiving file.
|
||||
* @retval -5 if file status wrong.
|
||||
* @retval -6 if position bad.
|
||||
* @retval -8 if packet failed to send.
|
||||
*/
|
||||
non_null()
|
||||
int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position);
|
||||
|
||||
/** @brief Send file data.
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -1 if friend not valid.
|
||||
* @retval -2 if friend not online.
|
||||
* @retval -3 if filenumber invalid.
|
||||
* @retval -4 if file transfer not transferring.
|
||||
* @retval -5 if bad data size.
|
||||
* @retval -6 if packet queue full.
|
||||
* @retval -7 if wrong position.
|
||||
*/
|
||||
non_null(1) nullable(5)
|
||||
int send_file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, uint16_t length);
|
||||
|
||||
/*** A/V related */
|
||||
|
||||
/** @brief Set the callback for msi packets. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void m_callback_msi_packet(Messenger *m, m_msi_packet_cb *function, void *userdata);
|
||||
|
||||
/** @brief Send an msi packet.
|
||||
*
|
||||
* @retval true on success
|
||||
* @retval false on failure
|
||||
*/
|
||||
non_null()
|
||||
bool m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length);
|
||||
|
||||
/** @brief Set handlers for lossy rtp packets.
|
||||
*
|
||||
* @retval -1 on failure.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
non_null(1) nullable(4, 5)
|
||||
int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte,
|
||||
m_lossy_rtp_packet_cb *function, void *object);
|
||||
|
||||
/*** CUSTOM PACKETS */
|
||||
|
||||
/** @brief Set handlers for custom lossy packets. */
|
||||
non_null() void custom_lossy_packet_registerhandler(Messenger *m, m_friend_lossy_packet_cb *lossy_packethandler);
|
||||
|
||||
/** @brief High level function to send custom lossy packets.
|
||||
*
|
||||
* TODO(oxij): this name is confusing, because this function sends both av and custom lossy packets.
|
||||
* Meanwhile, m_handle_lossy_packet routes custom packets to custom_lossy_packet_registerhandler
|
||||
* as you would expect from its name.
|
||||
*
|
||||
* I.e. custom_lossy_packet_registerhandler's "custom lossy packet" and this "custom lossy packet"
|
||||
* are not the same set of packets.
|
||||
*
|
||||
* @retval -1 if friend invalid.
|
||||
* @retval -2 if length wrong.
|
||||
* @retval -3 if first byte invalid.
|
||||
* @retval -4 if friend offline.
|
||||
* @retval -5 if packet failed to send because of other error.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);
|
||||
|
||||
|
||||
/** @brief Set handlers for custom lossless packets. */
|
||||
non_null()
|
||||
void custom_lossless_packet_registerhandler(Messenger *m, m_friend_lossless_packet_cb *lossless_packethandler);
|
||||
|
||||
/** @brief High level function to send custom lossless packets.
|
||||
*
|
||||
* @retval -1 if friend invalid.
|
||||
* @retval -2 if length wrong.
|
||||
* @retval -3 if first byte invalid.
|
||||
* @retval -4 if friend offline.
|
||||
* @retval -5 if packet failed to send because of other error.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);
|
||||
|
||||
/*** Messenger constructor/destructor/operations. */
|
||||
|
||||
typedef enum Messenger_Error {
|
||||
MESSENGER_ERROR_NONE,
|
||||
MESSENGER_ERROR_PORT,
|
||||
MESSENGER_ERROR_TCP_SERVER,
|
||||
MESSENGER_ERROR_OTHER,
|
||||
} Messenger_Error;
|
||||
|
||||
/** @brief Run this at startup.
|
||||
*
|
||||
* @return allocated instance of Messenger on success.
|
||||
* @retval 0 if there are problems.
|
||||
*
|
||||
* if error is not NULL it will be set to one of the values in the enum above.
|
||||
*/
|
||||
non_null()
|
||||
Messenger *new_messenger(Mono_Time *mono_time, const Random *rng, const Network *ns, Messenger_Options *options, Messenger_Error *error);
|
||||
|
||||
/** @brief Run this before closing shop.
|
||||
*
|
||||
* Free all datastructures.
|
||||
*/
|
||||
nullable(1)
|
||||
void kill_messenger(Messenger *m);
|
||||
|
||||
/** @brief The main loop that needs to be run at least 20 times per second. */
|
||||
non_null(1) nullable(2)
|
||||
void do_messenger(Messenger *m, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Return the time in milliseconds before `do_messenger()` should be called again
|
||||
* for optimal performance.
|
||||
*
|
||||
* @return time (in ms) before the next `do_messenger()` needs to be run on success.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t messenger_run_interval(const Messenger *m);
|
||||
|
||||
/* SAVING AND LOADING FUNCTIONS: */
|
||||
|
||||
/** @brief Registers a state plugin for saving, loading, and getting the size of a section of the save.
|
||||
*
|
||||
* @retval true on success
|
||||
* @retval false on error
|
||||
*/
|
||||
non_null()
|
||||
bool m_register_state_plugin(Messenger *m, State_Type type,
|
||||
m_state_size_cb *size_callback,
|
||||
m_state_load_cb *load_callback,
|
||||
m_state_save_cb *save_callback);
|
||||
|
||||
/** return size of the messenger data (for saving). */
|
||||
non_null()
|
||||
uint32_t messenger_size(const Messenger *m);
|
||||
|
||||
/** Save the messenger in data (must be allocated memory of size at least `Messenger_size()`) */
|
||||
non_null()
|
||||
uint8_t *messenger_save(const Messenger *m, uint8_t *data);
|
||||
|
||||
/** @brief Load a state section.
|
||||
*
|
||||
* @param data Data to load.
|
||||
* @param length Length of data.
|
||||
* @param type Type of section (`STATE_TYPE_*`).
|
||||
* @param status Result of loading section is stored here if the section is handled.
|
||||
* @return true iff section handled.
|
||||
*/
|
||||
non_null()
|
||||
bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
|
||||
State_Load_Status *status);
|
||||
|
||||
/** @brief Return the number of friends in the instance m.
|
||||
*
|
||||
* You should use this to determine how much memory to allocate
|
||||
* for copy_friendlist.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t count_friendlist(const Messenger *m);
|
||||
|
||||
/** @brief Copy a list of valid friend IDs into the array out_list.
|
||||
* If out_list is NULL, returns 0.
|
||||
* Otherwise, returns the number of elements copied.
|
||||
* If the array was too small, the contents
|
||||
* of out_list will be truncated to list_size.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size);
|
||||
|
||||
non_null()
|
||||
bool m_is_receiving_file(Messenger *m);
|
||||
|
||||
#endif
|
||||
3414
local_pod_repo/toxcore/toxcore/toxcore/Messenger.m
Normal file
3414
local_pod_repo/toxcore/toxcore/toxcore/Messenger.m
Normal file
File diff suppressed because it is too large
Load Diff
154
local_pod_repo/toxcore/toxcore/toxcore/TCP_client.h
Normal file
154
local_pod_repo/toxcore/toxcore/toxcore/TCP_client.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the TCP relay client part of Tox.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_CLIENT_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_CLIENT_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "forwarding.h"
|
||||
#include "mono_time.h"
|
||||
#include "network.h"
|
||||
|
||||
#define TCP_CONNECTION_TIMEOUT 10
|
||||
|
||||
typedef enum TCP_Proxy_Type {
|
||||
TCP_PROXY_NONE,
|
||||
TCP_PROXY_HTTP,
|
||||
TCP_PROXY_SOCKS5,
|
||||
} TCP_Proxy_Type;
|
||||
|
||||
typedef struct TCP_Proxy_Info {
|
||||
IP_Port ip_port;
|
||||
uint8_t proxy_type; // a value from TCP_PROXY_TYPE
|
||||
} TCP_Proxy_Info;
|
||||
|
||||
typedef enum TCP_Client_Status {
|
||||
TCP_CLIENT_NO_STATUS,
|
||||
TCP_CLIENT_PROXY_HTTP_CONNECTING,
|
||||
TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
|
||||
TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
|
||||
TCP_CLIENT_CONNECTING,
|
||||
TCP_CLIENT_UNCONFIRMED,
|
||||
TCP_CLIENT_CONFIRMED,
|
||||
TCP_CLIENT_DISCONNECTED,
|
||||
} TCP_Client_Status;
|
||||
|
||||
typedef struct TCP_Client_Connection TCP_Client_Connection;
|
||||
|
||||
non_null()
|
||||
const uint8_t *tcp_con_public_key(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
IP_Port tcp_con_ip_port(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con);
|
||||
|
||||
non_null()
|
||||
void *tcp_con_custom_object(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con);
|
||||
non_null()
|
||||
void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object);
|
||||
non_null()
|
||||
void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value);
|
||||
|
||||
/** Create new TCP connection to ip_port/public_key */
|
||||
non_null(1, 2, 3, 4, 5, 6, 7, 8) nullable(9)
|
||||
TCP_Client_Connection *new_TCP_connection(
|
||||
const Logger *logger, const Mono_Time *mono_time, const Random *rng, const Network *ns, const IP_Port *ip_port,
|
||||
const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key,
|
||||
const TCP_Proxy_Info *proxy_info);
|
||||
|
||||
/** Run the TCP connection */
|
||||
non_null(1, 2, 3) nullable(4)
|
||||
void do_TCP_connection(const Logger *logger, const Mono_Time *mono_time,
|
||||
TCP_Client_Connection *tcp_connection, void *userdata);
|
||||
|
||||
/** Kill the TCP connection */
|
||||
nullable(1)
|
||||
void kill_TCP_connection(TCP_Client_Connection *tcp_connection);
|
||||
|
||||
typedef int tcp_onion_response_cb(void *object, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_onion_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *data, uint16_t length);
|
||||
non_null()
|
||||
void onion_response_handler(TCP_Client_Connection *con, tcp_onion_response_cb *onion_callback, void *object);
|
||||
|
||||
non_null()
|
||||
int send_forward_request_tcp(const Logger *logger, TCP_Client_Connection *con, const IP_Port *dest, const uint8_t *data,
|
||||
uint16_t length);
|
||||
non_null()
|
||||
void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwarded_response_callback, void *object);
|
||||
|
||||
typedef int tcp_routing_response_cb(void *object, uint8_t connection_id, const uint8_t *public_key);
|
||||
typedef int tcp_routing_status_cb(void *object, uint32_t number, uint8_t connection_id, uint8_t status);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_routing_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key);
|
||||
non_null()
|
||||
void routing_response_handler(TCP_Client_Connection *con, tcp_routing_response_cb *response_callback, void *object);
|
||||
non_null()
|
||||
void routing_status_handler(TCP_Client_Connection *con, tcp_routing_status_cb *status_callback, void *object);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int send_disconnect_request(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id);
|
||||
|
||||
/** @brief Set the number that will be used as an argument in the callbacks related to con_id.
|
||||
*
|
||||
* When not set by this function, the number is -1.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number);
|
||||
|
||||
typedef int tcp_routing_data_cb(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data,
|
||||
uint16_t length, void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int send_data(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length);
|
||||
non_null()
|
||||
void routing_data_handler(TCP_Client_Connection *con, tcp_routing_data_cb *data_callback, void *object);
|
||||
|
||||
typedef int tcp_oob_data_cb(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int send_oob_packet(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data,
|
||||
uint16_t length);
|
||||
non_null()
|
||||
void oob_data_handler(TCP_Client_Connection *con, tcp_oob_data_cb *oob_data_callback, void *object);
|
||||
|
||||
|
||||
#endif
|
||||
1005
local_pod_repo/toxcore/toxcore/toxcore/TCP_client.m
Normal file
1005
local_pod_repo/toxcore/toxcore/toxcore/TCP_client.m
Normal file
File diff suppressed because it is too large
Load Diff
109
local_pod_repo/toxcore/toxcore/toxcore/TCP_common.h
Normal file
109
local_pod_repo/toxcore/toxcore/toxcore/TCP_common.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_COMMON_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_COMMON_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "network.h"
|
||||
|
||||
typedef struct TCP_Priority_List TCP_Priority_List;
|
||||
struct TCP_Priority_List {
|
||||
TCP_Priority_List *next;
|
||||
uint16_t size;
|
||||
uint16_t sent;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
nullable(1)
|
||||
void wipe_priority_list(TCP_Priority_List *p);
|
||||
|
||||
#define NUM_RESERVED_PORTS 16
|
||||
#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS)
|
||||
|
||||
#define TCP_PACKET_ROUTING_REQUEST 0
|
||||
#define TCP_PACKET_ROUTING_RESPONSE 1
|
||||
#define TCP_PACKET_CONNECTION_NOTIFICATION 2
|
||||
#define TCP_PACKET_DISCONNECT_NOTIFICATION 3
|
||||
#define TCP_PACKET_PING 4
|
||||
#define TCP_PACKET_PONG 5
|
||||
#define TCP_PACKET_OOB_SEND 6
|
||||
#define TCP_PACKET_OOB_RECV 7
|
||||
#define TCP_PACKET_ONION_REQUEST 8
|
||||
#define TCP_PACKET_ONION_RESPONSE 9
|
||||
#define TCP_PACKET_FORWARD_REQUEST 10
|
||||
#define TCP_PACKET_FORWARDING 11
|
||||
|
||||
#define TCP_HANDSHAKE_PLAIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE)
|
||||
#define TCP_SERVER_HANDSHAKE_SIZE (CRYPTO_NONCE_SIZE + TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE)
|
||||
#define TCP_CLIENT_HANDSHAKE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + TCP_SERVER_HANDSHAKE_SIZE)
|
||||
#define TCP_MAX_OOB_DATA_LENGTH 1024
|
||||
|
||||
/** frequency to ping connected nodes and timeout in seconds */
|
||||
#define TCP_PING_FREQUENCY 30
|
||||
#define TCP_PING_TIMEOUT 10
|
||||
|
||||
#define MAX_PACKET_SIZE 2048
|
||||
|
||||
typedef struct TCP_Connection {
|
||||
const Random *rng;
|
||||
const Network *ns;
|
||||
Socket sock;
|
||||
IP_Port ip_port; // for debugging.
|
||||
uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */
|
||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||
uint8_t last_packet[2 + MAX_PACKET_SIZE];
|
||||
uint16_t last_packet_length;
|
||||
uint16_t last_packet_sent;
|
||||
|
||||
TCP_Priority_List *priority_queue_start;
|
||||
TCP_Priority_List *priority_queue_end;
|
||||
} TCP_Connection;
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
non_null()
|
||||
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con);
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
non_null()
|
||||
int send_pending_data(const Logger *logger, TCP_Connection *con);
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int write_packet_TCP_secure_connection(
|
||||
const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
|
||||
bool priority);
|
||||
|
||||
/** @brief Read length bytes from socket.
|
||||
*
|
||||
* return length on success
|
||||
* return -1 on failure/no data in buffer.
|
||||
*/
|
||||
non_null()
|
||||
int read_TCP_packet(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port);
|
||||
|
||||
/**
|
||||
* @return length of received packet on success.
|
||||
* @retval 0 if could not read any packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
non_null()
|
||||
int read_packet_TCP_secure_connection(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint16_t *next_packet_length,
|
||||
const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
|
||||
uint16_t max_len, const IP_Port *ip_port);
|
||||
|
||||
#endif
|
||||
305
local_pod_repo/toxcore/toxcore/toxcore/TCP_common.m
Normal file
305
local_pod_repo/toxcore/toxcore/toxcore/TCP_common.m
Normal file
@@ -0,0 +1,305 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
#include "TCP_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccompat.h"
|
||||
|
||||
void wipe_priority_list(TCP_Priority_List *p)
|
||||
{
|
||||
while (p != nullptr) {
|
||||
TCP_Priority_List *pp = p;
|
||||
p = p->next;
|
||||
free(pp->data);
|
||||
free(pp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con)
|
||||
{
|
||||
if (con->last_packet_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint16_t left = con->last_packet_length - con->last_packet_sent;
|
||||
const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port);
|
||||
|
||||
if (len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == left) {
|
||||
con->last_packet_length = 0;
|
||||
con->last_packet_sent = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
con->last_packet_sent += len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 0 if pending data was sent completely
|
||||
* @retval -1 if it wasn't
|
||||
*/
|
||||
int send_pending_data(const Logger *logger, TCP_Connection *con)
|
||||
{
|
||||
/* finish sending current non-priority packet */
|
||||
if (send_pending_data_nonpriority(logger, con) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TCP_Priority_List *p = con->priority_queue_start;
|
||||
|
||||
while (p != nullptr) {
|
||||
const uint16_t left = p->size - p->sent;
|
||||
const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port);
|
||||
|
||||
if (len != left) {
|
||||
if (len > 0) {
|
||||
p->sent += len;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TCP_Priority_List *pp = p;
|
||||
p = p->next;
|
||||
free(pp->data);
|
||||
free(pp);
|
||||
}
|
||||
|
||||
con->priority_queue_start = p;
|
||||
|
||||
if (p == nullptr) {
|
||||
con->priority_queue_end = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval false on failure (only if calloc fails)
|
||||
* @retval true on success
|
||||
*/
|
||||
non_null()
|
||||
static bool add_priority(TCP_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent)
|
||||
{
|
||||
TCP_Priority_List *p = con->priority_queue_end;
|
||||
TCP_Priority_List *new_list = (TCP_Priority_List *)calloc(1, sizeof(TCP_Priority_List));
|
||||
|
||||
if (new_list == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new_list->next = nullptr;
|
||||
new_list->size = size;
|
||||
new_list->sent = sent;
|
||||
new_list->data = (uint8_t *)malloc(size);
|
||||
|
||||
if (new_list->data == nullptr) {
|
||||
free(new_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(new_list->data, packet, size);
|
||||
|
||||
if (p != nullptr) {
|
||||
p->next = new_list;
|
||||
} else {
|
||||
con->priority_queue_start = new_list;
|
||||
}
|
||||
|
||||
con->priority_queue_end = new_list;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval 1 on success.
|
||||
* @retval 0 if could not send packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
int write_packet_TCP_secure_connection(const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
|
||||
bool priority)
|
||||
{
|
||||
if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool sendpriority = true;
|
||||
|
||||
if (send_pending_data(logger, con) == -1) {
|
||||
if (priority) {
|
||||
sendpriority = false;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE);
|
||||
|
||||
uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
|
||||
memcpy(packet, &c_length, sizeof(uint16_t));
|
||||
int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
|
||||
|
||||
if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
len = sendpriority ? net_send(con->ns, logger, con->sock, packet, SIZEOF_VLA(packet), &con->ip_port) : 0;
|
||||
|
||||
if (len <= 0) {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
increment_nonce(con->sent_nonce);
|
||||
|
||||
if ((unsigned int)len == SIZEOF_VLA(packet)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return add_priority(con, packet, SIZEOF_VLA(packet), len) ? 1 : 0;
|
||||
}
|
||||
|
||||
len = net_send(con->ns, logger, con->sock, packet, SIZEOF_VLA(packet), &con->ip_port);
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
increment_nonce(con->sent_nonce);
|
||||
|
||||
if ((unsigned int)len == SIZEOF_VLA(packet)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(con->last_packet, packet, SIZEOF_VLA(packet));
|
||||
con->last_packet_length = SIZEOF_VLA(packet);
|
||||
con->last_packet_sent = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @brief Read length bytes from socket.
|
||||
*
|
||||
* return length on success
|
||||
* return -1 on failure/no data in buffer.
|
||||
*/
|
||||
int read_TCP_packet(const Logger *logger, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port)
|
||||
{
|
||||
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
|
||||
|
||||
if (count < length) {
|
||||
LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int len = net_recv(ns, logger, sock, data, length, ip_port);
|
||||
|
||||
if (len != length) {
|
||||
LOGGER_ERROR(logger, "FAIL recv packet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** @brief Read the next two bytes in TCP stream then convert them to
|
||||
* length (host byte order).
|
||||
*
|
||||
* return length on success
|
||||
* return 0 if nothing has been read from socket.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
static uint16_t read_TCP_length(const Logger *logger, const Network *ns, Socket sock, const IP_Port *ip_port)
|
||||
{
|
||||
const uint16_t count = net_socket_data_recv_buffer(ns, sock);
|
||||
|
||||
if (count >= sizeof(uint16_t)) {
|
||||
uint8_t length_buf[sizeof(uint16_t)];
|
||||
const int len = net_recv(ns, logger, sock, length_buf, sizeof(length_buf), ip_port);
|
||||
|
||||
if (len != sizeof(uint16_t)) {
|
||||
LOGGER_ERROR(logger, "FAIL recv packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t length;
|
||||
net_unpack_u16(length_buf, &length);
|
||||
|
||||
if (length > MAX_PACKET_SIZE) {
|
||||
LOGGER_ERROR(logger, "TCP packet too large: %d > %d", length, MAX_PACKET_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return length of received packet on success.
|
||||
* @retval 0 if could not read any packet.
|
||||
* @retval -1 on failure (connection must be killed).
|
||||
*/
|
||||
int read_packet_TCP_secure_connection(
|
||||
const Logger *logger, const Network *ns, Socket sock, uint16_t *next_packet_length,
|
||||
const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
|
||||
uint16_t max_len, const IP_Port *ip_port)
|
||||
{
|
||||
if (*next_packet_length == 0) {
|
||||
const uint16_t len = read_TCP_length(logger, ns, sock, ip_port);
|
||||
|
||||
if (len == (uint16_t) -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*next_packet_length = len;
|
||||
}
|
||||
|
||||
if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) {
|
||||
LOGGER_DEBUG(logger, "packet too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, data_encrypted, *next_packet_length);
|
||||
const int len_packet = read_TCP_packet(logger, ns, sock, data_encrypted, *next_packet_length, ip_port);
|
||||
|
||||
if (len_packet == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len_packet != *next_packet_length) {
|
||||
LOGGER_ERROR(logger, "invalid packet length: %d, expected %d", len_packet, *next_packet_length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*next_packet_length = 0;
|
||||
|
||||
const int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data);
|
||||
|
||||
if (len + CRYPTO_MAC_SIZE != len_packet) {
|
||||
LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
increment_nonce(recv_nonce);
|
||||
|
||||
return len;
|
||||
}
|
||||
310
local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.h
Normal file
310
local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.h
Normal file
@@ -0,0 +1,310 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2015 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles TCP relay connections between two Tox clients.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_CONNECTION_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_CONNECTION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "DHT.h" // for Node_format
|
||||
#include "TCP_client.h"
|
||||
#include "TCP_common.h"
|
||||
|
||||
#define TCP_CONN_NONE 0
|
||||
#define TCP_CONN_VALID 1
|
||||
|
||||
/** NOTE: only used by TCP_con */
|
||||
#define TCP_CONN_CONNECTED 2
|
||||
|
||||
/** Connection is not connected but can be quickly reconnected in case it is needed. */
|
||||
#define TCP_CONN_SLEEPING 3
|
||||
|
||||
#define TCP_CONNECTIONS_STATUS_NONE 0
|
||||
#define TCP_CONNECTIONS_STATUS_REGISTERED 1
|
||||
#define TCP_CONNECTIONS_STATUS_ONLINE 2
|
||||
|
||||
#define MAX_FRIEND_TCP_CONNECTIONS 6
|
||||
|
||||
/** Time until connection to friend gets killed (if it doesn't get locked within that time) */
|
||||
#define TCP_CONNECTION_ANNOUNCE_TIMEOUT TCP_CONNECTION_TIMEOUT
|
||||
|
||||
/** @brief The amount of recommended connections for each friend
|
||||
* NOTE: Must be at most (MAX_FRIEND_TCP_CONNECTIONS / 2)
|
||||
*/
|
||||
#define RECOMMENDED_FRIEND_TCP_CONNECTIONS (MAX_FRIEND_TCP_CONNECTIONS / 2)
|
||||
|
||||
/** Number of TCP connections used for onion purposes. */
|
||||
#define NUM_ONION_TCP_CONNECTIONS RECOMMENDED_FRIEND_TCP_CONNECTIONS
|
||||
|
||||
typedef struct TCP_Conn_to {
|
||||
uint32_t tcp_connection;
|
||||
uint8_t status;
|
||||
uint8_t connection_id;
|
||||
} TCP_Conn_to;
|
||||
|
||||
typedef struct TCP_Connection_to {
|
||||
uint8_t status;
|
||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */
|
||||
|
||||
TCP_Conn_to connections[MAX_FRIEND_TCP_CONNECTIONS];
|
||||
|
||||
int id; /* id used in callbacks. */
|
||||
} TCP_Connection_to;
|
||||
|
||||
typedef struct TCP_con {
|
||||
uint8_t status;
|
||||
TCP_Client_Connection *connection;
|
||||
uint64_t connected_time;
|
||||
uint32_t lock_count;
|
||||
uint32_t sleep_count;
|
||||
bool onion;
|
||||
|
||||
/* Only used when connection is sleeping. */
|
||||
IP_Port ip_port;
|
||||
uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
bool unsleep; /* set to 1 to unsleep connection. */
|
||||
} TCP_con;
|
||||
|
||||
typedef struct TCP_Connections TCP_Connections;
|
||||
|
||||
non_null()
|
||||
const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c);
|
||||
|
||||
non_null()
|
||||
uint32_t tcp_connections_count(const TCP_Connections *tcp_c);
|
||||
|
||||
/** Returns the number of connected TCP relays */
|
||||
non_null()
|
||||
uint32_t tcp_connected_relays_count(const TCP_Connections *tcp_c);
|
||||
|
||||
/** @brief Send a packet to the TCP connection.
|
||||
*
|
||||
* return -1 on failure.
|
||||
* return 0 on success.
|
||||
*/
|
||||
non_null()
|
||||
int send_packet_tcp_connection(const TCP_Connections *tcp_c, int connections_number, const uint8_t *packet,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Return a TCP connection number for use in send_tcp_onion_request.
|
||||
*
|
||||
* TODO(irungentoo): This number is just the index of an array that the elements
|
||||
* can change without warning.
|
||||
*
|
||||
* return TCP connection number on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int get_random_tcp_onion_conn_number(const TCP_Connections *tcp_c);
|
||||
|
||||
/** @brief Put IP_Port of a random onion TCP connection in ip_port.
|
||||
*
|
||||
* return true on success.
|
||||
* return false on failure.
|
||||
*/
|
||||
non_null()
|
||||
bool tcp_get_random_conn_ip_port(const TCP_Connections *tcp_c, IP_Port *ip_port);
|
||||
|
||||
/** @brief Send an onion packet via the TCP relay corresponding to tcp_connections_number.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data,
|
||||
uint16_t length);
|
||||
|
||||
/** @brief Set if we want TCP_connection to allocate some connection for onion use.
|
||||
*
|
||||
* If status is 1, allocate some connections. if status is 0, don't.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_onion_status(TCP_Connections *tcp_c, bool status);
|
||||
|
||||
/**
|
||||
* Send a forward request to the TCP relay with IP_Port tcp_forwarder,
|
||||
* requesting to forward data via a chain of dht nodes starting with dht_node.
|
||||
* A chain_length of 0 means that dht_node is the final destination of data.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_forward_request(const Logger *logger, TCP_Connections *tcp_c, const IP_Port *tcp_forwarder,
|
||||
const IP_Port *dht_node,
|
||||
const uint8_t *chain_keys, uint16_t chain_length,
|
||||
const uint8_t *data, uint16_t data_length);
|
||||
|
||||
/** @brief Send an oob packet via the TCP relay corresponding to tcp_connections_number.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int tcp_send_oob_packet(const TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key,
|
||||
const uint8_t *packet, uint16_t length);
|
||||
|
||||
typedef int tcp_data_cb(void *object, int id, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
non_null()
|
||||
int tcp_send_oob_packet_using_relay(const TCP_Connections *tcp_c, const uint8_t *relay_pk, const uint8_t *public_key,
|
||||
const uint8_t *packet, uint16_t length);
|
||||
|
||||
/** @brief Set the callback for TCP data packets. */
|
||||
non_null()
|
||||
void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_data_cb *tcp_data_callback, void *object);
|
||||
|
||||
typedef int tcp_onion_cb(void *object, const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/** @brief Set the callback for TCP onion packets. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_onion_cb *tcp_onion_callback, void *object);
|
||||
|
||||
/** @brief Set the callback for TCP forwarding packets. */
|
||||
non_null(1) nullable(2, 3)
|
||||
void set_forwarding_packet_tcp_connection_callback(TCP_Connections *tcp_c,
|
||||
forwarded_response_cb *tcp_forwarded_response_callback,
|
||||
void *object);
|
||||
|
||||
|
||||
typedef int tcp_oob_cb(void *object, const uint8_t *public_key, unsigned int tcp_connections_number,
|
||||
const uint8_t *data, uint16_t length, void *userdata);
|
||||
|
||||
/** @brief Set the callback for TCP oob data packets. */
|
||||
non_null()
|
||||
void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, tcp_oob_cb *tcp_oob_callback, void *object);
|
||||
|
||||
/** @brief Encode tcp_connections_number as a custom ip_port.
|
||||
*
|
||||
* return ip_port.
|
||||
*/
|
||||
IP_Port tcp_connections_number_to_ip_port(unsigned int tcp_connections_number);
|
||||
|
||||
/** @brief Decode ip_port created by tcp_connections_number_to_ip_port to tcp_connections_number.
|
||||
*
|
||||
* return true on success.
|
||||
* return false if ip_port is invalid.
|
||||
*/
|
||||
non_null()
|
||||
bool ip_port_to_tcp_connections_number(const IP_Port *ip_port, unsigned int *tcp_connections_number);
|
||||
|
||||
/** @brief Create a new TCP connection to public_key.
|
||||
*
|
||||
* public_key must be the counterpart to the secret key that the other peer used with `new_tcp_connections()`.
|
||||
*
|
||||
* id is the id in the callbacks for that connection.
|
||||
*
|
||||
* return connections_number on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id);
|
||||
|
||||
/**
|
||||
* @retval 0 on success.
|
||||
* @retval -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number);
|
||||
|
||||
/** @brief Set connection status.
|
||||
*
|
||||
* status of 1 means we are using the connection.
|
||||
* status of 0 means we are not using it.
|
||||
*
|
||||
* Unused tcp connections will be disconnected from but kept in case they are needed.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int set_tcp_connection_to_status(const TCP_Connections *tcp_c, int connections_number, bool status);
|
||||
|
||||
/**
|
||||
* @return number of online tcp relays tied to the connection on success.
|
||||
* @retval 0 on failure.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_connection_to_online_tcp_relays(const TCP_Connections *tcp_c, int connections_number);
|
||||
|
||||
/** @brief Add a TCP relay tied to a connection.
|
||||
*
|
||||
* NOTE: This can only be used during the tcp_oob_callback.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_number_relay_connection(const TCP_Connections *tcp_c, int connections_number,
|
||||
unsigned int tcp_connections_number);
|
||||
|
||||
/** @brief Add a TCP relay tied to a connection.
|
||||
*
|
||||
* This should be called with the same relay by two peers who want to create a TCP connection with each other.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, const IP_Port *ip_port,
|
||||
const uint8_t *relay_pk);
|
||||
|
||||
/** @brief Add a TCP relay to the TCP_Connections instance.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
non_null()
|
||||
int add_tcp_relay_global(TCP_Connections *tcp_c, const IP_Port *ip_port, const uint8_t *relay_pk);
|
||||
|
||||
/** @brief Copy a maximum of max_num TCP relays we are connected to to tcp_relays.
|
||||
*
|
||||
* NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
|
||||
*
|
||||
* return number of relays copied to tcp_relays on success.
|
||||
* return 0 on failure.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_copy_connected_relays(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num);
|
||||
|
||||
/** @brief Copy a maximum of `max_num` TCP relays we are connected to starting at idx.
|
||||
*
|
||||
* @param idx is the index in the TCP relay array for `tcp_c` designated.
|
||||
* If idx is greater than the array length a modulo operation is performed.
|
||||
*
|
||||
* Returns the number of relays successfully copied.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t tcp_copy_connected_relays_index(const TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num,
|
||||
uint32_t idx);
|
||||
|
||||
/** @brief Returns a new TCP_Connections object associated with the secret_key.
|
||||
*
|
||||
* In order for others to connect to this instance `new_tcp_connection_to()` must be called with the
|
||||
* public_key associated with secret_key.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
non_null()
|
||||
TCP_Connections *new_tcp_connections(
|
||||
const Logger *logger, const Random *rng, const Network *ns, Mono_Time *mono_time,
|
||||
const uint8_t *secret_key, const TCP_Proxy_Info *proxy_info);
|
||||
|
||||
non_null()
|
||||
int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number);
|
||||
|
||||
non_null(1, 2) nullable(3)
|
||||
void do_tcp_connections(const Logger *logger, TCP_Connections *tcp_c, void *userdata);
|
||||
|
||||
nullable(1)
|
||||
void kill_tcp_connections(TCP_Connections *tcp_c);
|
||||
|
||||
#endif
|
||||
1709
local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.m
Normal file
1709
local_pod_repo/toxcore/toxcore/toxcore/TCP_connection.m
Normal file
File diff suppressed because it is too large
Load Diff
51
local_pod_repo/toxcore/toxcore/toxcore/TCP_server.h
Normal file
51
local_pod_repo/toxcore/toxcore/toxcore/TCP_server.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2014 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the TCP relay server part of Tox.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_TCP_SERVER_H
|
||||
#define C_TOXCORE_TOXCORE_TCP_SERVER_H
|
||||
|
||||
#include "crypto_core.h"
|
||||
#include "forwarding.h"
|
||||
#include "onion.h"
|
||||
|
||||
#define MAX_INCOMING_CONNECTIONS 256
|
||||
|
||||
#define TCP_MAX_BACKLOG MAX_INCOMING_CONNECTIONS
|
||||
|
||||
#define ARRAY_ENTRY_SIZE 6
|
||||
|
||||
typedef enum TCP_Status {
|
||||
TCP_STATUS_NO_STATUS,
|
||||
TCP_STATUS_CONNECTED,
|
||||
TCP_STATUS_UNCONFIRMED,
|
||||
TCP_STATUS_CONFIRMED,
|
||||
} TCP_Status;
|
||||
|
||||
typedef struct TCP_Server TCP_Server;
|
||||
|
||||
non_null()
|
||||
const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server);
|
||||
non_null()
|
||||
size_t tcp_server_listen_count(const TCP_Server *tcp_server);
|
||||
|
||||
/** Create new TCP server instance. */
|
||||
non_null(1, 2, 3, 6, 7) nullable(8, 9)
|
||||
TCP_Server *new_TCP_server(const Logger *logger, const Random *rng, const Network *ns,
|
||||
bool ipv6_enabled, uint16_t num_sockets, const uint16_t *ports,
|
||||
const uint8_t *secret_key, Onion *onion, Forwarding *forwarding);
|
||||
|
||||
/** Run the TCP_server */
|
||||
non_null()
|
||||
void do_TCP_server(TCP_Server *tcp_server, const Mono_Time *mono_time);
|
||||
|
||||
/** Kill the TCP server */
|
||||
nullable(1)
|
||||
void kill_TCP_server(TCP_Server *tcp_server);
|
||||
|
||||
|
||||
#endif
|
||||
1408
local_pod_repo/toxcore/toxcore/toxcore/TCP_server.m
Normal file
1408
local_pod_repo/toxcore/toxcore/toxcore/TCP_server.m
Normal file
File diff suppressed because it is too large
Load Diff
67
local_pod_repo/toxcore/toxcore/toxcore/announce.h
Normal file
67
local_pod_repo/toxcore/toxcore/toxcore/announce.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2020-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_ANNOUNCE_H
|
||||
#define C_TOXCORE_TOXCORE_ANNOUNCE_H
|
||||
|
||||
#include "forwarding.h"
|
||||
|
||||
#define MAX_ANNOUNCEMENT_SIZE 512
|
||||
|
||||
typedef void announce_on_retrieve_cb(void *object, const uint8_t *data, uint16_t length);
|
||||
|
||||
uint8_t announce_response_of_request_type(uint8_t request_type);
|
||||
|
||||
typedef struct Announcements Announcements;
|
||||
|
||||
non_null()
|
||||
Announcements *new_announcements(const Logger *log, const Random *rng, const Mono_Time *mono_time, Forwarding *forwarding);
|
||||
|
||||
/**
|
||||
* @brief If data is stored, run `on_retrieve_callback` on it.
|
||||
*
|
||||
* @return true if data is stored, false otherwise.
|
||||
*/
|
||||
non_null(1, 2) nullable(3, 4)
|
||||
bool announce_on_stored(const Announcements *announce, const uint8_t *data_public_key,
|
||||
announce_on_retrieve_cb *on_retrieve_callback, void *object);
|
||||
|
||||
non_null()
|
||||
void announce_set_synch_offset(Announcements *announce, int32_t synch_offset);
|
||||
|
||||
nullable(1)
|
||||
void kill_announcements(Announcements *announce);
|
||||
|
||||
|
||||
/* The declarations below are not public, they are exposed only for tests. */
|
||||
|
||||
/** @private
|
||||
* Return xor of first ANNOUNCE_BUCKET_PREFIX_LENGTH bits from one bit after
|
||||
* base and pk first differ
|
||||
*/
|
||||
non_null()
|
||||
uint16_t announce_get_bucketnum(const uint8_t *base, const uint8_t *pk);
|
||||
|
||||
/** @private */
|
||||
non_null(1, 2) nullable(3)
|
||||
bool announce_store_data(Announcements *announce, const uint8_t *data_public_key,
|
||||
const uint8_t *data, uint32_t length, uint32_t timeout);
|
||||
|
||||
/** @private */
|
||||
#define MAX_MAX_ANNOUNCEMENT_TIMEOUT 900
|
||||
#define MIN_MAX_ANNOUNCEMENT_TIMEOUT 10
|
||||
#define MAX_ANNOUNCEMENT_TIMEOUT_UPTIME_RATIO 4
|
||||
|
||||
/** @private
|
||||
* For efficient lookup and updating, entries are stored as a hash table keyed
|
||||
* to the first ANNOUNCE_BUCKET_PREFIX_LENGTH bits starting from one bit after
|
||||
* the first bit in which data public key first differs from the dht key, with
|
||||
* (2-adically) closest keys preferentially stored within a given bucket. A
|
||||
* given key appears at most once (even if timed out).
|
||||
*/
|
||||
#define ANNOUNCE_BUCKET_SIZE 8
|
||||
#define ANNOUNCE_BUCKET_PREFIX_LENGTH 5
|
||||
#define ANNOUNCE_BUCKETS 32 // ANNOUNCE_BUCKETS = 2 ** ANNOUNCE_BUCKET_PREFIX_LENGTH
|
||||
|
||||
#endif
|
||||
689
local_pod_repo/toxcore/toxcore/toxcore/announce.m
Normal file
689
local_pod_repo/toxcore/toxcore/toxcore/announce.m
Normal file
@@ -0,0 +1,689 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2020-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* "Server side" of the DHT announcements protocol.
|
||||
*/
|
||||
|
||||
#include "announce.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LAN_discovery.h"
|
||||
#include "ccompat.h"
|
||||
#include "timed_auth.h"
|
||||
#include "util.h"
|
||||
|
||||
uint8_t announce_response_of_request_type(uint8_t request_type)
|
||||
{
|
||||
switch (request_type) {
|
||||
case NET_PACKET_DATA_SEARCH_REQUEST:
|
||||
return NET_PACKET_DATA_SEARCH_RESPONSE;
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_REQUEST:
|
||||
return NET_PACKET_DATA_RETRIEVE_RESPONSE;
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_REQUEST:
|
||||
return NET_PACKET_STORE_ANNOUNCE_RESPONSE;
|
||||
|
||||
default: {
|
||||
assert(false);
|
||||
return NET_PACKET_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Announce_Entry {
|
||||
uint64_t store_until;
|
||||
uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||
uint8_t *data;
|
||||
uint32_t length;
|
||||
} Announce_Entry;
|
||||
|
||||
struct Announcements {
|
||||
const Logger *log;
|
||||
const Random *rng;
|
||||
Forwarding *forwarding;
|
||||
const Mono_Time *mono_time;
|
||||
DHT *dht;
|
||||
Networking_Core *net;
|
||||
const uint8_t *public_key;
|
||||
const uint8_t *secret_key;
|
||||
|
||||
Shared_Keys shared_keys;
|
||||
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
||||
|
||||
int32_t synch_offset;
|
||||
|
||||
uint64_t start_time;
|
||||
|
||||
Announce_Entry entries[ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE];
|
||||
};
|
||||
|
||||
void announce_set_synch_offset(Announcements *announce, int32_t synch_offset)
|
||||
{
|
||||
announce->synch_offset = synch_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry is considered to be "deleted" for the purposes of the protocol
|
||||
* once it has timed out.
|
||||
*/
|
||||
non_null()
|
||||
static bool entry_is_empty(const Announcements *announce, const Announce_Entry *entry)
|
||||
{
|
||||
return mono_time_get(announce->mono_time) >= entry->store_until;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void delete_entry(Announce_Entry *entry)
|
||||
{
|
||||
entry->store_until = 0;
|
||||
}
|
||||
|
||||
/** Return bits (at most 8) from pk starting at index as uint8_t */
|
||||
non_null()
|
||||
static uint8_t truncate_pk_at_index(const uint8_t *pk, uint16_t index, uint16_t bits)
|
||||
{
|
||||
assert(bits < 8);
|
||||
const uint8_t i = index / 8;
|
||||
const uint8_t j = index % 8;
|
||||
return ((uint8_t)((i < CRYPTO_PUBLIC_KEY_SIZE ? pk[i] : 0) << j) >> (8 - bits)) |
|
||||
((i + 1 < CRYPTO_PUBLIC_KEY_SIZE ? pk[i + 1] : 0) >> (16 - bits - j));
|
||||
}
|
||||
|
||||
uint16_t announce_get_bucketnum(const uint8_t *base, const uint8_t *pk)
|
||||
{
|
||||
const uint16_t index = bit_by_bit_cmp(base, pk);
|
||||
|
||||
return truncate_pk_at_index(base, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH) ^
|
||||
truncate_pk_at_index(pk, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static Announce_Entry *bucket_of_key(Announcements *announce, const uint8_t *pk)
|
||||
{
|
||||
return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
|
||||
}
|
||||
|
||||
non_null()
|
||||
static Announce_Entry *get_stored(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
return &bucket[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static const Announce_Entry *bucket_of_key_const(const Announcements *announce, const uint8_t *pk)
|
||||
{
|
||||
return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
|
||||
}
|
||||
|
||||
non_null()
|
||||
static const Announce_Entry *get_stored_const(const Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
const Announce_Entry *const bucket = bucket_of_key_const(announce, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
return &bucket[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool announce_on_stored(const Announcements *announce, const uint8_t *data_public_key,
|
||||
announce_on_retrieve_cb *on_retrieve_callback, void *object)
|
||||
{
|
||||
const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr || entry->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (on_retrieve_callback != nullptr) {
|
||||
on_retrieve_callback(object, entry->data, entry->length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return existing entry for this key if it exists, else an empty
|
||||
* slot in the key's bucket if one exists, else an entry in the key's bucket
|
||||
* of greatest 2-adic distance greater than that of the key bucket if one
|
||||
* exists, else nullptr.
|
||||
*/
|
||||
non_null()
|
||||
static Announce_Entry *find_entry_slot(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
|
||||
|
||||
Announce_Entry *slot = nullptr;
|
||||
uint16_t min_index = bit_by_bit_cmp(announce->public_key, data_public_key);
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (pk_equal(bucket[i].data_public_key, data_public_key)) {
|
||||
return &bucket[i];
|
||||
}
|
||||
|
||||
if (entry_is_empty(announce, &bucket[i])) {
|
||||
slot = &bucket[i];
|
||||
min_index = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t index = bit_by_bit_cmp(announce->public_key, bucket[i].data_public_key);
|
||||
|
||||
if (index < min_index) {
|
||||
slot = &bucket[i];
|
||||
min_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool would_accept_store_request(Announcements *announce, const uint8_t *data_public_key)
|
||||
{
|
||||
return find_entry_slot(announce, data_public_key) != nullptr;
|
||||
}
|
||||
|
||||
bool announce_store_data(Announcements *announce, const uint8_t *data_public_key,
|
||||
const uint8_t *data, uint32_t length, uint32_t timeout)
|
||||
{
|
||||
if (length > MAX_ANNOUNCEMENT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Announce_Entry *entry = find_entry_slot(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
assert(data != nullptr);
|
||||
|
||||
if (entry->data != nullptr) {
|
||||
free(entry->data);
|
||||
}
|
||||
|
||||
entry->data = (uint8_t *)malloc(length);
|
||||
|
||||
if (entry->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(entry->data, data, length);
|
||||
}
|
||||
|
||||
entry->length = length;
|
||||
memcpy(entry->data_public_key, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
entry->store_until = mono_time_get(announce->mono_time) + timeout;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint32_t calculate_timeout(const Announcements *announce, uint32_t requested_timeout)
|
||||
{
|
||||
const uint64_t uptime = mono_time_get(announce->mono_time) - announce->start_time;
|
||||
const uint32_t max_announcement_timeout = max_u32(
|
||||
(uint32_t)min_u64(
|
||||
MAX_MAX_ANNOUNCEMENT_TIMEOUT,
|
||||
uptime / MAX_ANNOUNCEMENT_TIMEOUT_UPTIME_RATIO),
|
||||
MIN_MAX_ANNOUNCEMENT_TIMEOUT);
|
||||
|
||||
return min_u32(max_announcement_timeout, requested_timeout);
|
||||
}
|
||||
|
||||
#define DATA_SEARCH_TO_AUTH_MAX_SIZE (CRYPTO_PUBLIC_KEY_SIZE * 2 + MAX_PACKED_IPPORT_SIZE + MAX_SENDBACK_SIZE)
|
||||
|
||||
non_null(1, 2, 3, 4, 7) nullable(5)
|
||||
static int create_data_search_to_auth(const Logger *logger, const uint8_t *data_public_key,
|
||||
const uint8_t *requester_key,
|
||||
const IP_Port *source, const uint8_t *sendback, uint16_t sendback_length,
|
||||
uint8_t *dest, uint16_t max_length)
|
||||
{
|
||||
if (max_length < DATA_SEARCH_TO_AUTH_MAX_SIZE
|
||||
|| sendback_length > MAX_SENDBACK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dest, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE, requester_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
|
||||
const int ipport_length = pack_ip_port(logger, dest + CRYPTO_PUBLIC_KEY_SIZE * 2, MAX_PACKED_IPPORT_SIZE, source);
|
||||
|
||||
if (ipport_length == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sendback_length > 0) {
|
||||
assert(sendback != nullptr);
|
||||
memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length, sendback, sendback_length);
|
||||
}
|
||||
|
||||
return CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length + sendback_length;
|
||||
}
|
||||
|
||||
#define DATA_SEARCH_TIMEOUT 60
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_data_search_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
if (length != CRYPTO_PUBLIC_KEY_SIZE &&
|
||||
length != CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
const uint8_t *previous_hash = nullptr;
|
||||
|
||||
if (length == CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
|
||||
previous_hash = data + CRYPTO_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
const int nodes_max_length = (int)reply_max_length -
|
||||
(CRYPTO_PUBLIC_KEY_SIZE + 1 + CRYPTO_SHA256_SIZE + TIMED_AUTH_SIZE + 1 + 1);
|
||||
|
||||
if (nodes_max_length < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *p = reply;
|
||||
|
||||
memcpy(p, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
p += CRYPTO_PUBLIC_KEY_SIZE;
|
||||
|
||||
const Announce_Entry *const stored = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (stored == nullptr) {
|
||||
*p = 0;
|
||||
++p;
|
||||
} else {
|
||||
*p = 1;
|
||||
++p;
|
||||
crypto_sha256(p, stored->data, stored->length);
|
||||
p += CRYPTO_SHA256_SIZE;
|
||||
}
|
||||
|
||||
generate_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, p);
|
||||
p += TIMED_AUTH_SIZE;
|
||||
|
||||
*p = would_accept_store_request(announce, data_public_key);
|
||||
++p;
|
||||
|
||||
Node_format nodes_list[MAX_SENT_NODES];
|
||||
const int num_nodes = get_close_nodes(announce->dht, data_public_key, nodes_list,
|
||||
net_family_unspec(), ip_is_lan(&source->ip), true);
|
||||
|
||||
if (num_nodes < 0 || num_nodes > MAX_SENT_NODES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p = num_nodes;
|
||||
++p;
|
||||
|
||||
p += pack_nodes(announce->log, p, nodes_max_length, nodes_list, num_nodes);
|
||||
|
||||
const uint32_t reply_len = p - reply;
|
||||
|
||||
if (previous_hash != nullptr) {
|
||||
uint8_t hash[CRYPTO_SHA256_SIZE];
|
||||
|
||||
crypto_sha256(hash, reply, reply_len);
|
||||
|
||||
if (crypto_sha256_eq(hash, previous_hash)) {
|
||||
return CRYPTO_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_data_retrieve_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
if (length != CRYPTO_PUBLIC_KEY_SIZE + 1 + TIMED_AUTH_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[CRYPTO_PUBLIC_KEY_SIZE] != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
const uint8_t *const auth = data + CRYPTO_PUBLIC_KEY_SIZE + 1;
|
||||
|
||||
if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, auth)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
|
||||
|
||||
if (entry == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + 1 + entry->length;
|
||||
|
||||
if (reply_max_length < reply_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
reply[CRYPTO_PUBLIC_KEY_SIZE] = 1;
|
||||
memcpy(reply + CRYPTO_PUBLIC_KEY_SIZE + 1, entry->data, entry->length);
|
||||
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static int create_reply_plain_store_announce_request(Announcements *announce,
|
||||
const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length,
|
||||
uint8_t *to_auth, uint16_t to_auth_length)
|
||||
{
|
||||
const int plain_len = (int)length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
|
||||
const int announcement_len = (int)plain_len - (TIMED_AUTH_SIZE + sizeof(uint32_t) + 1);
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
if (announcement_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, plain, plain_len);
|
||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||
|
||||
get_shared_key(announce->mono_time, &announce->shared_keys, shared_key,
|
||||
announce->secret_key, data_public_key);
|
||||
|
||||
if (decrypt_data_symmetric(shared_key,
|
||||
data + CRYPTO_PUBLIC_KEY_SIZE,
|
||||
data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
||||
plain_len + CRYPTO_MAC_SIZE,
|
||||
plain) != plain_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const auth = plain;
|
||||
uint32_t requested_timeout;
|
||||
net_unpack_u32(plain + TIMED_AUTH_SIZE, &requested_timeout);
|
||||
const uint32_t timeout = calculate_timeout(announce, requested_timeout);
|
||||
const uint8_t announcement_type = plain[TIMED_AUTH_SIZE + sizeof(uint32_t)];
|
||||
const uint8_t *announcement = plain + TIMED_AUTH_SIZE + sizeof(uint32_t) + 1;
|
||||
|
||||
if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
|
||||
to_auth, to_auth_length, auth)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announcement_type > 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (announcement_type == 1) {
|
||||
if (announcement_len != CRYPTO_SHA256_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Announce_Entry *stored = get_stored(announce, data_public_key);
|
||||
|
||||
if (stored == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t stored_hash[CRYPTO_SHA256_SIZE];
|
||||
crypto_sha256(stored_hash, stored->data, stored->length);
|
||||
|
||||
if (!crypto_sha256_eq(announcement, stored_hash)) {
|
||||
delete_entry(stored);
|
||||
return -1;
|
||||
} else {
|
||||
stored->store_until = mono_time_get(announce->mono_time) + timeout;
|
||||
}
|
||||
} else {
|
||||
if (!announce_store_data(announce, data_public_key, announcement, announcement_len, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint64_t);
|
||||
|
||||
if (reply_max_length < reply_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
net_pack_u32(reply + CRYPTO_PUBLIC_KEY_SIZE, timeout);
|
||||
net_pack_u64(reply + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t),
|
||||
mono_time_get(announce->mono_time) + announce->synch_offset);
|
||||
return reply_len;
|
||||
}
|
||||
|
||||
non_null(1, 2, 3, 7, 9) nullable(5)
|
||||
static int create_reply_plain(Announcements *announce,
|
||||
const uint8_t *requester_key, const IP_Port *source, uint8_t type,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length)
|
||||
{
|
||||
if (length < CRYPTO_PUBLIC_KEY_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint8_t *const data_public_key = data;
|
||||
|
||||
uint8_t to_auth[DATA_SEARCH_TO_AUTH_MAX_SIZE];
|
||||
const int to_auth_length = create_data_search_to_auth(announce->log, data_public_key, requester_key, source,
|
||||
sendback, sendback_length, to_auth, DATA_SEARCH_TO_AUTH_MAX_SIZE);
|
||||
|
||||
if (to_auth_length == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NET_PACKET_DATA_SEARCH_REQUEST:
|
||||
return create_reply_plain_data_search_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_REQUEST:
|
||||
return create_reply_plain_data_retrieve_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_REQUEST:
|
||||
return create_reply_plain_store_announce_request(announce, source, data, length, reply, reply_max_length, to_auth,
|
||||
(uint16_t)to_auth_length);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
non_null(1, 2, 5, 7) nullable(3)
|
||||
static int create_reply(Announcements *announce, const IP_Port *source,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length,
|
||||
uint8_t *reply, uint16_t reply_max_length)
|
||||
{
|
||||
const int plain_len = (int)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
|
||||
|
||||
if (plain_len < (int)sizeof(uint64_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, plain, plain_len);
|
||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||
|
||||
dht_get_shared_key_recv(announce->dht, shared_key, data + 1);
|
||||
|
||||
if (decrypt_data_symmetric(shared_key,
|
||||
data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||
data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
||||
plain_len + CRYPTO_MAC_SIZE,
|
||||
plain) != plain_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int plain_reply_max_len = (int)reply_max_length -
|
||||
(1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
|
||||
|
||||
if (plain_reply_max_len < sizeof(uint64_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
VLA(uint8_t, plain_reply, plain_reply_max_len);
|
||||
|
||||
const int plain_reply_noping_len = create_reply_plain(announce,
|
||||
data + 1, source, data[0],
|
||||
sendback, sendback_length,
|
||||
plain, plain_len - sizeof(uint64_t),
|
||||
plain_reply, plain_reply_max_len - sizeof(uint64_t));
|
||||
|
||||
if (plain_reply_noping_len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(plain_reply + plain_reply_noping_len,
|
||||
plain + (plain_len - sizeof(uint64_t)), sizeof(uint64_t));
|
||||
|
||||
const uint16_t plain_reply_len = plain_reply_noping_len + sizeof(uint64_t);
|
||||
|
||||
const uint8_t response_type = announce_response_of_request_type(data[0]);
|
||||
|
||||
return dht_create_packet(announce->rng, announce->public_key, shared_key, response_type,
|
||||
plain_reply, plain_reply_len, reply, reply_max_length);
|
||||
}
|
||||
|
||||
non_null(1, 2, 3, 5) nullable(7)
|
||||
static void forwarded_request_callback(void *object, const IP_Port *forwarder,
|
||||
const uint8_t *sendback, uint16_t sendback_length,
|
||||
const uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
Announcements *announce = (Announcements *) object;
|
||||
|
||||
uint8_t reply[MAX_FORWARD_DATA_SIZE];
|
||||
|
||||
const int len = create_reply(announce, forwarder,
|
||||
sendback, sendback_length,
|
||||
data, length, reply, sizeof(reply));
|
||||
|
||||
if (len == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
forward_reply(announce->net, forwarder, sendback, sendback_length, reply, len);
|
||||
}
|
||||
|
||||
non_null(1, 2, 3) nullable(5)
|
||||
static int handle_dht_announce_request(void *object, const IP_Port *source,
|
||||
const uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
Announcements *announce = (Announcements *) object;
|
||||
|
||||
uint8_t reply[MAX_FORWARD_DATA_SIZE];
|
||||
|
||||
const int len = create_reply(announce, source,
|
||||
nullptr, 0,
|
||||
data, length, reply, sizeof(reply));
|
||||
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sendpacket(announce->net, source, reply, len) == len ? 0 : -1;
|
||||
}
|
||||
|
||||
Announcements *new_announcements(const Logger *log, const Random *rng, const Mono_Time *mono_time,
|
||||
Forwarding *forwarding)
|
||||
{
|
||||
if (log == nullptr || mono_time == nullptr || forwarding == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Announcements *announce = (Announcements *)calloc(1, sizeof(Announcements));
|
||||
|
||||
if (announce == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
announce->log = log;
|
||||
announce->rng = rng;
|
||||
announce->forwarding = forwarding;
|
||||
announce->mono_time = mono_time;
|
||||
announce->dht = forwarding_get_dht(forwarding);
|
||||
announce->net = dht_get_net(announce->dht);
|
||||
announce->public_key = dht_get_self_public_key(announce->dht);
|
||||
announce->secret_key = dht_get_self_secret_key(announce->dht);
|
||||
new_hmac_key(announce->rng, announce->hmac_key);
|
||||
|
||||
announce->start_time = mono_time_get(announce->mono_time);
|
||||
|
||||
set_callback_forwarded_request(forwarding, forwarded_request_callback, announce);
|
||||
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, handle_dht_announce_request, announce);
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, handle_dht_announce_request, announce);
|
||||
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, handle_dht_announce_request, announce);
|
||||
|
||||
return announce;
|
||||
}
|
||||
|
||||
void kill_announcements(Announcements *announce)
|
||||
{
|
||||
if (announce == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_callback_forwarded_request(announce->forwarding, nullptr, nullptr);
|
||||
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, nullptr, nullptr);
|
||||
networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, nullptr, nullptr);
|
||||
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
|
||||
|
||||
crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
||||
crypto_memzero(&announce->shared_keys, sizeof(Shared_Keys));
|
||||
|
||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||
if (announce->entries[i].data != nullptr) {
|
||||
free(announce->entries[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
free(announce);
|
||||
}
|
||||
31
local_pod_repo/toxcore/toxcore/toxcore/attributes.h
Normal file
31
local_pod_repo/toxcore/toxcore/toxcore/attributes.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* printf and nonnull attributes for GCC/Clang and Cimple.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
||||
#define C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
||||
|
||||
/* No declarations here. */
|
||||
|
||||
//!TOKSTYLE-
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define GNU_PRINTF(f, a)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(_DEBUG) && !defined(__OPTIMIZE__)
|
||||
#define non_null(...) __attribute__((__nonnull__(__VA_ARGS__)))
|
||||
#else
|
||||
#define non_null(...)
|
||||
#endif
|
||||
|
||||
#define nullable(...)
|
||||
|
||||
//!TOKSTYLE+
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_ATTRIBUTES_H
|
||||
122
local_pod_repo/toxcore/toxcore/toxcore/bin_pack.h
Normal file
122
local_pod_repo/toxcore/toxcore/toxcore/bin_pack.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_BIN_PACK_H
|
||||
#define C_TOXCORE_TOXCORE_BIN_PACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Binary serialisation object.
|
||||
*/
|
||||
typedef struct Bin_Pack Bin_Pack;
|
||||
|
||||
/** @brief Function used to pack an object.
|
||||
*
|
||||
* This function would typically cast the `void *` to the actual object pointer type and then call
|
||||
* more appropriately typed packing functions.
|
||||
*/
|
||||
typedef bool bin_pack_cb(Bin_Pack *bp, const void *obj);
|
||||
|
||||
/** @brief Determine the serialised size of an object.
|
||||
*
|
||||
* @param callback The function called on the created packer and packed object.
|
||||
* @param obj The object to be packed, passed as `obj` to the callback.
|
||||
*
|
||||
* @return The packed size of the passed object according to the callback. UINT32_MAX in case of
|
||||
* errors such as buffer overflow.
|
||||
*/
|
||||
non_null(1) nullable(2)
|
||||
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj);
|
||||
|
||||
/** @brief Pack an object into a buffer of a given size.
|
||||
*
|
||||
* This function creates and initialises a `Bin_Pack` packer object, calls the callback with the
|
||||
* packer object and the to-be-packed object, and then cleans up the packer object.
|
||||
*
|
||||
* You can use `bin_pack_obj_size` to determine the minimum required size of `buf`. If packing
|
||||
* overflows `uint32_t`, this function returns `false`.
|
||||
*
|
||||
* @param callback The function called on the created packer and packed object.
|
||||
* @param obj The object to be packed, passed as `obj` to the callback.
|
||||
* @param buf A byte array large enough to hold the serialised representation of `obj`.
|
||||
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
|
||||
*
|
||||
* @retval false if an error occurred (e.g. buffer overflow).
|
||||
*/
|
||||
non_null(1, 3) nullable(2)
|
||||
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Allocate a new packer object.
|
||||
*
|
||||
* This is the only function that allocates memory in this module.
|
||||
*
|
||||
* @param buf A byte array large enough to hold the serialised representation of `obj`.
|
||||
* @param buf_size The size of the byte array. Can be `UINT32_MAX` to disable bounds checking.
|
||||
*
|
||||
* @retval nullptr on allocation failure.
|
||||
*/
|
||||
non_null()
|
||||
Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Deallocates a packer object.
|
||||
*
|
||||
* Does not deallocate the buffer inside.
|
||||
*/
|
||||
nullable(1)
|
||||
void bin_pack_free(Bin_Pack *bp);
|
||||
|
||||
/** @brief Start packing a MessagePack array.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` calls to other functions below.
|
||||
*/
|
||||
non_null()
|
||||
bool bin_pack_array(Bin_Pack *bp, uint32_t size);
|
||||
|
||||
/** @brief Pack a MessagePack bool. */
|
||||
non_null() bool bin_pack_bool(Bin_Pack *bp, bool val);
|
||||
/** @brief Pack a `uint8_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u08(Bin_Pack *bp, uint8_t val);
|
||||
/** @brief Pack a `uint16_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u16(Bin_Pack *bp, uint16_t val);
|
||||
/** @brief Pack a `uint32_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u32(Bin_Pack *bp, uint32_t val);
|
||||
/** @brief Pack a `uint64_t` as MessagePack positive integer. */
|
||||
non_null() bool bin_pack_u64(Bin_Pack *bp, uint64_t val);
|
||||
/** @brief Pack a byte array as MessagePack bin. */
|
||||
non_null() bool bin_pack_bin(Bin_Pack *bp, const uint8_t *data, uint32_t length);
|
||||
|
||||
/** @brief Start packing a custom binary representation.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` bytes packed by functions below.
|
||||
*/
|
||||
non_null() bool bin_pack_bin_marker(Bin_Pack *bp, uint32_t size);
|
||||
|
||||
/** @brief Write a `uint8_t` directly to the packer in 1 byte. */
|
||||
non_null() bool bin_pack_u08_b(Bin_Pack *bp, uint8_t val);
|
||||
/** @brief Write a `uint16_t` as big endian 16 bit int in 2 bytes. */
|
||||
non_null() bool bin_pack_u16_b(Bin_Pack *bp, uint16_t val);
|
||||
/** @brief Write a `uint32_t` as big endian 32 bit int in 4 bytes. */
|
||||
non_null() bool bin_pack_u32_b(Bin_Pack *bp, uint32_t val);
|
||||
/** @brief Write a `uint64_t` as big endian 64 bit int in 8 bytes. */
|
||||
non_null() bool bin_pack_u64_b(Bin_Pack *bp, uint64_t val);
|
||||
|
||||
/** @brief Write a byte array directly to the packer in `length` bytes.
|
||||
*
|
||||
* Note that unless you prepend the array length manually, there is no record of it in the resulting
|
||||
* serialised representation.
|
||||
*/
|
||||
non_null() bool bin_pack_bin_b(Bin_Pack *bp, const uint8_t *data, uint32_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_BIN_PACK_H
|
||||
161
local_pod_repo/toxcore/toxcore/toxcore/bin_pack.m
Normal file
161
local_pod_repo/toxcore/toxcore/toxcore/bin_pack.m
Normal file
@@ -0,0 +1,161 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "bin_pack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmp.h"
|
||||
#include "ccompat.h"
|
||||
|
||||
struct Bin_Pack {
|
||||
uint8_t *bytes;
|
||||
uint32_t bytes_size;
|
||||
uint32_t bytes_pos;
|
||||
cmp_ctx_t ctx;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static bool null_reader(cmp_ctx_t *ctx, void *data, size_t limit)
|
||||
{
|
||||
assert(limit == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool null_skipper(cmp_ctx_t *ctx, size_t limit)
|
||||
{
|
||||
assert(limit == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static size_t buf_writer(cmp_ctx_t *ctx, const void *data, size_t count)
|
||||
{
|
||||
Bin_Pack *bp = (Bin_Pack *)ctx->buf;
|
||||
assert(bp != nullptr);
|
||||
const uint32_t new_pos = bp->bytes_pos + count;
|
||||
if (new_pos < bp->bytes_pos) {
|
||||
// 32 bit overflow.
|
||||
return 0;
|
||||
}
|
||||
if (bp->bytes != nullptr) {
|
||||
if (new_pos > bp->bytes_size) {
|
||||
// Buffer too small.
|
||||
return 0;
|
||||
}
|
||||
memcpy(bp->bytes + bp->bytes_pos, data, count);
|
||||
}
|
||||
bp->bytes_pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
non_null(1) nullable(2)
|
||||
static void bin_pack_init(Bin_Pack *bp, uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
bp->bytes = buf;
|
||||
bp->bytes_size = buf_size;
|
||||
bp->bytes_pos = 0;
|
||||
cmp_init(&bp->ctx, bp, null_reader, null_skipper, buf_writer);
|
||||
}
|
||||
|
||||
bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Pack bp;
|
||||
bin_pack_init(&bp, buf, buf_size);
|
||||
return callback(&bp, obj);
|
||||
}
|
||||
|
||||
uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj)
|
||||
{
|
||||
Bin_Pack bp;
|
||||
bin_pack_init(&bp, nullptr, 0);
|
||||
callback(&bp, obj);
|
||||
return bp.bytes_pos;
|
||||
}
|
||||
|
||||
Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Pack *bp = (Bin_Pack *)calloc(1, sizeof(Bin_Pack));
|
||||
if (bp == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
bin_pack_init(bp, buf, buf_size);
|
||||
return bp;
|
||||
}
|
||||
|
||||
void bin_pack_free(Bin_Pack *bp)
|
||||
{
|
||||
free(bp);
|
||||
}
|
||||
|
||||
bool bin_pack_array(Bin_Pack *bp, uint32_t size)
|
||||
{
|
||||
return cmp_write_array(&bp->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_pack_bool(Bin_Pack *bp, bool val)
|
||||
{
|
||||
return cmp_write_bool(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u08(Bin_Pack *bp, uint8_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u16(Bin_Pack *bp, uint16_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u32(Bin_Pack *bp, uint32_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_u64(Bin_Pack *bp, uint64_t val)
|
||||
{
|
||||
return cmp_write_uinteger(&bp->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_pack_bin(Bin_Pack *bp, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
return cmp_write_bin(&bp->ctx, data, length);
|
||||
}
|
||||
|
||||
bool bin_pack_bin_marker(Bin_Pack *bp, uint32_t size)
|
||||
{
|
||||
return cmp_write_bin_marker(&bp->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_pack_u08_b(Bin_Pack *bp, uint8_t val)
|
||||
{
|
||||
return bp->ctx.write(&bp->ctx, &val, 1) == 1;
|
||||
}
|
||||
|
||||
bool bin_pack_u16_b(Bin_Pack *bp, uint16_t val)
|
||||
{
|
||||
return bin_pack_u08_b(bp, (val >> 8) & 0xff)
|
||||
&& bin_pack_u08_b(bp, val & 0xff);
|
||||
}
|
||||
|
||||
bool bin_pack_u32_b(Bin_Pack *bp, uint32_t val)
|
||||
{
|
||||
return bin_pack_u16_b(bp, (val >> 16) & 0xffff)
|
||||
&& bin_pack_u16_b(bp, val & 0xffff);
|
||||
}
|
||||
|
||||
bool bin_pack_u64_b(Bin_Pack *bp, uint64_t val)
|
||||
{
|
||||
return bin_pack_u32_b(bp, (val >> 32) & 0xffffffff)
|
||||
&& bin_pack_u32_b(bp, val & 0xffffffff);
|
||||
}
|
||||
|
||||
bool bin_pack_bin_b(Bin_Pack *bp, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
return bp->ctx.write(&bp->ctx, data, length) == length;
|
||||
}
|
||||
100
local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.h
Normal file
100
local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
||||
#define C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Binary deserialisation object.
|
||||
*/
|
||||
typedef struct Bin_Unpack Bin_Unpack;
|
||||
|
||||
/** @brief Allocate a new unpacker object.
|
||||
*
|
||||
* @param buf The byte array to unpack values from.
|
||||
* @param buf_size The size of the byte array.
|
||||
*
|
||||
* @retval nullptr on allocation failure.
|
||||
*/
|
||||
non_null()
|
||||
Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size);
|
||||
|
||||
/** @brief Deallocates an unpacker object.
|
||||
*
|
||||
* Does not deallocate the buffer inside.
|
||||
*/
|
||||
nullable(1)
|
||||
void bin_unpack_free(Bin_Unpack *bu);
|
||||
|
||||
/** @brief Start unpacking a MessagePack array.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` calls to other functions below.
|
||||
*
|
||||
* @param size Will contain the number of array elements following the array marker.
|
||||
*/
|
||||
non_null() bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size);
|
||||
|
||||
/** @brief Start unpacking a fixed size MessagePack array.
|
||||
*
|
||||
* @retval false if the packed array size is not exactly the required size.
|
||||
*/
|
||||
non_null() bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size);
|
||||
|
||||
/** @brief Unpack a MessagePack bool. */
|
||||
non_null() bool bin_unpack_bool(Bin_Unpack *bu, bool *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint8_t`. */
|
||||
non_null() bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint16_t`. */
|
||||
non_null() bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint32_t`. */
|
||||
non_null() bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val);
|
||||
/** @brief Unpack a MessagePack positive int into a `uint64_t`. */
|
||||
non_null() bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val);
|
||||
/** @brief Unpack a MessagePack bin into a newly allocated byte array.
|
||||
*
|
||||
* Allocates a new byte array and stores it into `data_ptr` with its length stored in
|
||||
* `data_length_ptr`. This function requires that the unpacking buffer has at least as many bytes
|
||||
* remaining to be unpacked as the bin claims to need, so it's not possible to cause an arbitrarily
|
||||
* large allocation unless the input array was already that large.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr);
|
||||
/** @brief Unpack a MessagePack bin of a fixed length into a pre-allocated byte array.
|
||||
*
|
||||
* Unlike the function above, this function does not allocate any memory, but requires the size to
|
||||
* be known up front.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length);
|
||||
|
||||
/** @brief Start unpacking a custom binary representation.
|
||||
*
|
||||
* A call to this function must be followed by exactly `size` bytes packed by functions below.
|
||||
*/
|
||||
non_null() bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size);
|
||||
|
||||
/** @brief Read a `uint8_t` directly from the unpacker, consuming 1 byte. */
|
||||
non_null() bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val);
|
||||
/** @brief Read a `uint16_t` as big endian 16 bit int, consuming 2 bytes. */
|
||||
non_null() bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val);
|
||||
/** @brief Read a `uint32_t` as big endian 32 bit int, consuming 4 bytes. */
|
||||
non_null() bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val);
|
||||
/** @brief Read a `uint64_t` as big endian 64 bit int, consuming 8 bytes. */
|
||||
non_null() bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val);
|
||||
|
||||
/** @brief Read a byte array directly from the packer, consuming `length` bytes. */
|
||||
non_null() bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_BIN_UNPACK_H
|
||||
185
local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.m
Normal file
185
local_pod_repo/toxcore/toxcore/toxcore/bin_unpack.m
Normal file
@@ -0,0 +1,185 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "bin_unpack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmp.h"
|
||||
#include "ccompat.h"
|
||||
|
||||
struct Bin_Unpack {
|
||||
const uint8_t *bytes;
|
||||
uint32_t bytes_size;
|
||||
cmp_ctx_t ctx;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static bool buf_reader(cmp_ctx_t *ctx, void *data, size_t limit)
|
||||
{
|
||||
Bin_Unpack *reader = (Bin_Unpack *)ctx->buf;
|
||||
assert(reader != nullptr && reader->bytes != nullptr);
|
||||
if (limit > reader->bytes_size) {
|
||||
return false;
|
||||
}
|
||||
memcpy(data, reader->bytes, limit);
|
||||
reader->bytes += limit;
|
||||
reader->bytes_size -= limit;
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool buf_skipper(cmp_ctx_t *ctx, size_t limit)
|
||||
{
|
||||
Bin_Unpack *reader = (Bin_Unpack *)ctx->buf;
|
||||
assert(reader != nullptr && reader->bytes != nullptr);
|
||||
if (limit > reader->bytes_size) {
|
||||
return false;
|
||||
}
|
||||
reader->bytes += limit;
|
||||
reader->bytes_size -= limit;
|
||||
return true;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static size_t null_writer(cmp_ctx_t *ctx, const void *data, size_t count)
|
||||
{
|
||||
assert(count == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size)
|
||||
{
|
||||
Bin_Unpack *bu = (Bin_Unpack *)calloc(1, sizeof(Bin_Unpack));
|
||||
if (bu == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
bu->bytes = buf;
|
||||
bu->bytes_size = buf_size;
|
||||
cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer);
|
||||
return bu;
|
||||
}
|
||||
|
||||
void bin_unpack_free(Bin_Unpack *bu)
|
||||
{
|
||||
free(bu);
|
||||
}
|
||||
|
||||
bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size)
|
||||
{
|
||||
return cmp_read_array(&bu->ctx, size) && *size <= bu->bytes_size;
|
||||
}
|
||||
|
||||
bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size)
|
||||
{
|
||||
uint32_t size;
|
||||
return cmp_read_array(&bu->ctx, &size) && size == required_size;
|
||||
}
|
||||
|
||||
bool bin_unpack_bool(Bin_Unpack *bu, bool *val)
|
||||
{
|
||||
return cmp_read_bool(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val)
|
||||
{
|
||||
return cmp_read_uchar(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val)
|
||||
{
|
||||
return cmp_read_ushort(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val)
|
||||
{
|
||||
return cmp_read_uint(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val)
|
||||
{
|
||||
return cmp_read_ulong(&bu->ctx, val);
|
||||
}
|
||||
|
||||
bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr)
|
||||
{
|
||||
uint32_t bin_size;
|
||||
if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > bu->bytes_size) {
|
||||
// There aren't as many bytes as this bin claims to want to allocate.
|
||||
return false;
|
||||
}
|
||||
uint8_t *const data = (uint8_t *)malloc(bin_size);
|
||||
|
||||
if (!bin_unpack_bin_b(bu, data, bin_size)) {
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
*data_ptr = data;
|
||||
*data_length_ptr = bin_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
uint32_t bin_size;
|
||||
if (!bin_unpack_bin_size(bu, &bin_size) || bin_size != data_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_bin_b(bu, data, bin_size);
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size)
|
||||
{
|
||||
return cmp_read_bin_size(&bu->ctx, size);
|
||||
}
|
||||
|
||||
bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val)
|
||||
{
|
||||
return bin_unpack_bin_b(bu, val, 1);
|
||||
}
|
||||
|
||||
bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val)
|
||||
{
|
||||
uint8_t hi = 0;
|
||||
uint8_t lo = 0;
|
||||
if (!(bin_unpack_u08_b(bu, &hi)
|
||||
&& bin_unpack_u08_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint16_t)hi << 8) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val)
|
||||
{
|
||||
uint16_t hi = 0;
|
||||
uint16_t lo = 0;
|
||||
if (!(bin_unpack_u16_b(bu, &hi)
|
||||
&& bin_unpack_u16_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint32_t)hi << 16) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val)
|
||||
{
|
||||
uint32_t hi = 0;
|
||||
uint32_t lo = 0;
|
||||
if (!(bin_unpack_u32_b(bu, &hi)
|
||||
&& bin_unpack_u32_b(bu, &lo))) {
|
||||
return false;
|
||||
}
|
||||
*val = ((uint64_t)hi << 32) | lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length)
|
||||
{
|
||||
return bu->ctx.read(&bu->ctx, data, length);
|
||||
}
|
||||
87
local_pod_repo/toxcore/toxcore/toxcore/ccompat.h
Normal file
87
local_pod_repo/toxcore/toxcore/toxcore/ccompat.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2021 The TokTok team.
|
||||
*/
|
||||
|
||||
/**
|
||||
* C language compatibility macros for varying compiler support.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_CCOMPAT_H
|
||||
#define C_TOXCORE_TOXCORE_CCOMPAT_H
|
||||
|
||||
#include <stddef.h> // NULL, size_t
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
//!TOKSTYLE-
|
||||
|
||||
// Variable length arrays.
|
||||
// VLA(type, name, size) allocates a variable length array with automatic
|
||||
// storage duration. VLA_SIZE(name) evaluates to the runtime size of that array
|
||||
// in bytes.
|
||||
//
|
||||
// If C99 VLAs are not available, an emulation using alloca (stack allocation
|
||||
// "function") is used. Note the semantic difference: alloca'd memory does not
|
||||
// get freed at the end of the declaration's scope. Do not use VLA() in loops or
|
||||
// you may run out of stack space.
|
||||
#if !defined(DISABLE_VLA) && !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
// C99 VLAs.
|
||||
#define ALLOC_VLA(type, name, size) type name[size]
|
||||
#define SIZEOF_VLA sizeof
|
||||
#else
|
||||
|
||||
// Emulation using alloca.
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h>
|
||||
#elif defined(__COMPCERT__)
|
||||
// TODO(iphydf): This leaks memory like crazy, so compcert is useless for now.
|
||||
// Once we're rid of VLAs, we can remove this and compcert becomes useful.
|
||||
#define alloca malloc
|
||||
#include <stdlib.h>
|
||||
#elif defined(__linux__)
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#if !defined(alloca) && defined(__GNUC__)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ALLOC_VLA(type, name, size) \
|
||||
const size_t name##_vla_size = (size) * sizeof(type); \
|
||||
type *const name = (type *)alloca(name##_vla_size)
|
||||
#define SIZEOF_VLA(name) name##_vla_size
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MAX_VLA_SIZE
|
||||
#include <assert.h>
|
||||
#define VLA(type, name, size) \
|
||||
ALLOC_VLA(type, name, size); \
|
||||
assert((size_t)(size) * sizeof(type) <= MAX_VLA_SIZE)
|
||||
#else
|
||||
#define VLA ALLOC_VLA
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) || __cplusplus < 201103L
|
||||
#define nullptr NULL
|
||||
#ifndef static_assert
|
||||
#ifdef __GNUC__
|
||||
// We'll just assume gcc and clang support C11 _Static_assert.
|
||||
#define static_assert _Static_assert
|
||||
#else // !__GNUC__
|
||||
#define STATIC_ASSERT_(cond, msg, line) typedef int static_assert_##line[(cond) ? 1 : -1]
|
||||
#define STATIC_ASSERT(cond, msg, line) STATIC_ASSERT_(cond, msg, line)
|
||||
#define static_assert(cond, msg) STATIC_ASSERT(cond, msg, __LINE__)
|
||||
#endif // !__GNUC__
|
||||
#endif // !static_assert
|
||||
#endif // !__cplusplus
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define GNU_PRINTF(f, a)
|
||||
#endif
|
||||
|
||||
//!TOKSTYLE+
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_CCOMPAT_H
|
||||
4
local_pod_repo/toxcore/toxcore/toxcore/ccompat.m
Normal file
4
local_pod_repo/toxcore/toxcore/toxcore/ccompat.m
Normal file
@@ -0,0 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
#include "ccompat.h"
|
||||
461
local_pod_repo/toxcore/toxcore/toxcore/crypto_core.h
Normal file
461
local_pod_repo/toxcore/toxcore/toxcore/crypto_core.h
Normal file
@@ -0,0 +1,461 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Functions for the core crypto.
|
||||
*/
|
||||
#ifndef C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
||||
#define C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The number of bytes in a signature.
|
||||
*/
|
||||
#define CRYPTO_SIGNATURE_SIZE 64
|
||||
|
||||
/**
|
||||
* The number of bytes in a Tox public key used for signatures.
|
||||
*/
|
||||
#define CRYPTO_SIGN_PUBLIC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* The number of bytes in a Tox secret key used for signatures.
|
||||
*/
|
||||
#define CRYPTO_SIGN_SECRET_KEY_SIZE 64
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a Tox public key used for encryption.
|
||||
*/
|
||||
#define CRYPTO_PUBLIC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a Tox secret key used for encryption.
|
||||
*/
|
||||
#define CRYPTO_SECRET_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a shared key computed from public and secret keys.
|
||||
*/
|
||||
#define CRYPTO_SHARED_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a symmetric key.
|
||||
*/
|
||||
#define CRYPTO_SYMMETRIC_KEY_SIZE CRYPTO_SHARED_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes needed for the MAC (message authentication code) in an
|
||||
* encrypted message.
|
||||
*/
|
||||
#define CRYPTO_MAC_SIZE 16
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a nonce used for encryption/decryption.
|
||||
*/
|
||||
#define CRYPTO_NONCE_SIZE 24
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a SHA256 hash.
|
||||
*/
|
||||
#define CRYPTO_SHA256_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a SHA512 hash.
|
||||
*/
|
||||
#define CRYPTO_SHA512_SIZE 64
|
||||
|
||||
typedef void crypto_random_bytes_cb(void *obj, uint8_t *bytes, size_t length);
|
||||
typedef uint32_t crypto_random_uniform_cb(void *obj, uint32_t upper_bound);
|
||||
|
||||
typedef struct Random_Funcs {
|
||||
crypto_random_bytes_cb *random_bytes;
|
||||
crypto_random_uniform_cb *random_uniform;
|
||||
} Random_Funcs;
|
||||
|
||||
typedef struct Random {
|
||||
const Random_Funcs *funcs;
|
||||
void *obj;
|
||||
} Random;
|
||||
|
||||
const Random *system_random(void);
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an encryption public key used by DHT group chats.
|
||||
*/
|
||||
#define ENC_PUBLIC_KEY_SIZE CRYPTO_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an encryption secret key used by DHT group chats.
|
||||
*/
|
||||
#define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a signature public key.
|
||||
*/
|
||||
#define SIG_PUBLIC_KEY_SIZE CRYPTO_SIGN_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a signature secret key.
|
||||
*/
|
||||
#define SIG_SECRET_KEY_SIZE CRYPTO_SIGN_SECRET_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in a DHT group chat public key identifier.
|
||||
*/
|
||||
#define CHAT_ID_SIZE SIG_PUBLIC_KEY_SIZE
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an extended public key used by DHT group chats.
|
||||
*/
|
||||
#define EXT_PUBLIC_KEY_SIZE (ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an extended secret key used by DHT group chats.
|
||||
*/
|
||||
#define EXT_SECRET_KEY_SIZE (ENC_SECRET_KEY_SIZE + SIG_SECRET_KEY_SIZE)
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an HMAC authenticator.
|
||||
*/
|
||||
#define CRYPTO_HMAC_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief The number of bytes in an HMAC secret key.
|
||||
*/
|
||||
#define CRYPTO_HMAC_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief A `bzero`-like function which won't be optimised away by the compiler.
|
||||
*
|
||||
* Some compilers will inline `bzero` or `memset` if they can prove that there
|
||||
* will be no reads to the written data. Use this function if you want to be
|
||||
* sure the memory is indeed zeroed.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_memzero(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute a SHA256 hash (32 bytes).
|
||||
*/
|
||||
non_null()
|
||||
void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute a SHA512 hash (64 bytes).
|
||||
*/
|
||||
non_null()
|
||||
void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute an HMAC authenticator (32 bytes).
|
||||
*
|
||||
* @param auth Resulting authenticator.
|
||||
* @param key Secret key, as generated by `new_hmac_key()`.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data,
|
||||
size_t length);
|
||||
|
||||
/**
|
||||
* @brief Verify an HMAC authenticator.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE],
|
||||
const uint8_t *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 public keys of length @ref CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @retval true if both mem locations of length are equal
|
||||
* @retval false if they are not
|
||||
*/
|
||||
non_null()
|
||||
bool pk_equal(const uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Copy a public key from `src` to `dest`.
|
||||
*/
|
||||
non_null()
|
||||
void pk_copy(uint8_t dest[CRYPTO_PUBLIC_KEY_SIZE], const uint8_t src[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 SHA512 checksums of length CRYPTO_SHA512_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @return true if both mem locations of length are equal, false if they are not.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2);
|
||||
|
||||
/**
|
||||
* @brief Compare 2 SHA256 checksums of length CRYPTO_SHA256_SIZE, not vulnerable to
|
||||
* timing attacks.
|
||||
*
|
||||
* @return true if both mem locations of length are equal, false if they are not.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2);
|
||||
|
||||
/**
|
||||
* @brief Return a random 8 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint8_t random_u08(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 16 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint16_t random_u16(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 32 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t random_u32(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 64 bit integer.
|
||||
*/
|
||||
non_null()
|
||||
uint64_t random_u64(const Random *rng);
|
||||
|
||||
/**
|
||||
* @brief Return a random 32 bit integer between 0 and upper_bound (excluded).
|
||||
*
|
||||
* On libsodium builds this function guarantees a uniform distribution of possible outputs.
|
||||
* On vanilla NACL builds this function is equivalent to `random() % upper_bound`.
|
||||
*/
|
||||
non_null()
|
||||
uint32_t random_range_u32(const Random *rng, uint32_t upper_bound);
|
||||
|
||||
/** @brief Cryptographically signs a message using the supplied secret key and puts the resulting signature
|
||||
* in the supplied buffer.
|
||||
*
|
||||
* @param signature The buffer for the resulting signature, which must have room for at
|
||||
* least CRYPTO_SIGNATURE_SIZE bytes.
|
||||
* @param message The message being signed.
|
||||
* @param message_length The length in bytes of the message being signed.
|
||||
* @param secret_key The secret key used to create the signature. The key should be
|
||||
* produced by either `create_extended_keypair` or the libsodium function `crypto_sign_keypair`.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_signature_create(uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *secret_key);
|
||||
|
||||
/** @brief Verifies that the given signature was produced by a given message and public key.
|
||||
*
|
||||
* @param signature The signature we wish to verify.
|
||||
* @param message The message we wish to verify.
|
||||
* @param message_length The length of the message.
|
||||
* @param public_key The public key counterpart of the secret key that was used to
|
||||
* create the signature.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_signature_verify(const uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *public_key);
|
||||
|
||||
/**
|
||||
* @brief Fill the given nonce with random bytes.
|
||||
*/
|
||||
non_null()
|
||||
void random_nonce(const Random *rng, uint8_t *nonce);
|
||||
|
||||
/**
|
||||
* @brief Fill an array of bytes with random values.
|
||||
*/
|
||||
non_null()
|
||||
void random_bytes(const Random *rng, uint8_t *bytes, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not.
|
||||
*
|
||||
* This should only be used for input validation.
|
||||
*
|
||||
* @return false if it isn't, true if it is.
|
||||
*/
|
||||
non_null()
|
||||
bool public_key_valid(const uint8_t *public_key);
|
||||
|
||||
/** @brief Creates an extended keypair: curve25519 and ed25519 for encryption and signing
|
||||
* respectively. The Encryption keys are derived from the signature keys.
|
||||
*
|
||||
* @param pk The buffer where the public key will be stored. Must have room for EXT_PUBLIC_KEY_SIZE bytes.
|
||||
* @param sk The buffer where the secret key will be stored. Must have room for EXT_SECRET_KEY_SIZE bytes.
|
||||
*
|
||||
* @retval true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool create_extended_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
/** Functions for groupchat extended keys */
|
||||
non_null() const uint8_t *get_enc_key(const uint8_t *key);
|
||||
non_null() const uint8_t *get_sig_pk(const uint8_t *key);
|
||||
non_null() void set_sig_pk(uint8_t *key, const uint8_t *sig_pk);
|
||||
non_null() const uint8_t *get_sig_sk(const uint8_t *key);
|
||||
non_null() const uint8_t *get_chat_id(const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Generate a new random keypair.
|
||||
*
|
||||
* Every call to this function is likely to generate a different keypair.
|
||||
*/
|
||||
non_null()
|
||||
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key);
|
||||
|
||||
/**
|
||||
* @brief Derive the public key from a given secret key.
|
||||
*/
|
||||
non_null()
|
||||
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key);
|
||||
|
||||
/**
|
||||
* @brief Encrypt message to send from secret key to public key.
|
||||
*
|
||||
* Encrypt plain text of the given length to encrypted of
|
||||
* `length + CRYPTO_MAC_SIZE` using the public key (@ref CRYPTO_PUBLIC_KEY_SIZE
|
||||
* bytes) of the receiver and the secret key of the sender and a
|
||||
* @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem.
|
||||
* @return length of encrypted data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain,
|
||||
size_t length, uint8_t *encrypted);
|
||||
|
||||
/**
|
||||
* @brief Decrypt message from public key to secret key.
|
||||
*
|
||||
* Decrypt encrypted text of the given @p length to plain text of the given
|
||||
* `length - CRYPTO_MAC_SIZE` using the public key (@ref CRYPTO_PUBLIC_KEY_SIZE
|
||||
* bytes) of the sender, the secret key of the receiver and a
|
||||
* @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem (decryption failed).
|
||||
* @return length of plain text data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain);
|
||||
|
||||
/**
|
||||
* @brief Fast encrypt/decrypt operations.
|
||||
*
|
||||
* Use if this is not a one-time communication. @ref encrypt_precompute does the
|
||||
* shared-key generation once so it does not have to be performed on every
|
||||
* encrypt/decrypt.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key);
|
||||
|
||||
/**
|
||||
* @brief Encrypt message with precomputed shared key.
|
||||
*
|
||||
* Encrypts plain of length length to encrypted of length + @ref CRYPTO_MAC_SIZE
|
||||
* using a shared key @ref CRYPTO_SYMMETRIC_KEY_SIZE big and a @ref CRYPTO_NONCE_SIZE
|
||||
* byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem.
|
||||
* @return length of encrypted data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *plain, size_t length,
|
||||
uint8_t *encrypted);
|
||||
|
||||
/**
|
||||
* @brief Decrypt message with precomputed shared key.
|
||||
*
|
||||
* Decrypts encrypted of length length to plain of length
|
||||
* `length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
|
||||
* big and a @ref CRYPTO_NONCE_SIZE byte nonce.
|
||||
*
|
||||
* @retval -1 if there was a problem (decryption failed).
|
||||
* @return length of plain data if everything was fine.
|
||||
*/
|
||||
non_null()
|
||||
int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length,
|
||||
uint8_t *plain);
|
||||
|
||||
/**
|
||||
* @brief Increment the given nonce by 1 in big endian (rightmost byte incremented
|
||||
* first).
|
||||
*/
|
||||
non_null()
|
||||
void increment_nonce(uint8_t *nonce);
|
||||
|
||||
/**
|
||||
* @brief Increment the given nonce by a given number.
|
||||
*
|
||||
* The number should be in host byte order.
|
||||
*/
|
||||
non_null()
|
||||
void increment_nonce_number(uint8_t *nonce, uint32_t increment);
|
||||
|
||||
/**
|
||||
* @brief Fill a key @ref CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes.
|
||||
*
|
||||
* This does the same as `new_symmetric_key` but without giving the Random object implicitly.
|
||||
* It is as safe as `new_symmetric_key`.
|
||||
*/
|
||||
non_null()
|
||||
void new_symmetric_key_implicit_random(uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Fill a key @ref CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes.
|
||||
*/
|
||||
non_null()
|
||||
void new_symmetric_key(const Random *rng, uint8_t *key);
|
||||
|
||||
/**
|
||||
* @brief Locks `length` bytes of memory pointed to by `data`.
|
||||
*
|
||||
* This will attempt to prevent the specified memory region from being swapped
|
||||
* to disk.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_memlock(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Unlocks `length` bytes of memory pointed to by `data`.
|
||||
*
|
||||
* This allows the specified memory region to be swapped to disk.
|
||||
*
|
||||
* This function call has the side effect of zeroing the specified memory region
|
||||
* whether or not it succeeds. Therefore it should only be used once the memory
|
||||
* is no longer in use.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
non_null()
|
||||
bool crypto_memunlock(void *data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Generate a random secret HMAC key.
|
||||
*/
|
||||
non_null()
|
||||
void new_hmac_key(const Random *rng, uint8_t key[CRYPTO_HMAC_KEY_SIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_CRYPTO_CORE_H
|
||||
578
local_pod_repo/toxcore/toxcore/toxcore/crypto_core.m
Normal file
578
local_pod_repo/toxcore/toxcore/toxcore/crypto_core.m
Normal file
@@ -0,0 +1,578 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functions for the core crypto.
|
||||
*
|
||||
* NOTE: This code has to be perfect. We don't mess around with encryption.
|
||||
*/
|
||||
#include "crypto_core.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
// We use libsodium by default.
|
||||
#include "sodium.h"
|
||||
#else
|
||||
#include <crypto_auth.h>
|
||||
#include <crypto_box.h>
|
||||
#include <crypto_hash_sha256.h>
|
||||
#include <crypto_hash_sha512.h>
|
||||
#include <crypto_scalarmult_curve25519.h>
|
||||
#include <crypto_verify_16.h>
|
||||
#include <crypto_verify_32.h>
|
||||
#include <randombytes.h>
|
||||
#endif
|
||||
|
||||
#include "ccompat.h"
|
||||
|
||||
#ifndef crypto_box_MACBYTES
|
||||
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
|
||||
#endif
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
// Need dht because of ENC_SECRET_KEY_SIZE and ENC_PUBLIC_KEY_SIZE
|
||||
#define ENC_PUBLIC_KEY_SIZE CRYPTO_PUBLIC_KEY_SIZE
|
||||
#define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE
|
||||
#endif
|
||||
|
||||
static_assert(CRYPTO_PUBLIC_KEY_SIZE == crypto_box_PUBLICKEYBYTES,
|
||||
"CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES");
|
||||
static_assert(CRYPTO_SECRET_KEY_SIZE == crypto_box_SECRETKEYBYTES,
|
||||
"CRYPTO_SECRET_KEY_SIZE should be equal to crypto_box_SECRETKEYBYTES");
|
||||
static_assert(CRYPTO_SHARED_KEY_SIZE == crypto_box_BEFORENMBYTES,
|
||||
"CRYPTO_SHARED_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES");
|
||||
static_assert(CRYPTO_SYMMETRIC_KEY_SIZE == crypto_box_BEFORENMBYTES,
|
||||
"CRYPTO_SYMMETRIC_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES");
|
||||
static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES,
|
||||
"CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES");
|
||||
static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES,
|
||||
"CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES");
|
||||
static_assert(CRYPTO_HMAC_SIZE == crypto_auth_BYTES,
|
||||
"CRYPTO_HMAC_SIZE should be equal to crypto_auth_BYTES");
|
||||
static_assert(CRYPTO_HMAC_KEY_SIZE == crypto_auth_KEYBYTES,
|
||||
"CRYPTO_HMAC_KEY_SIZE should be equal to crypto_auth_KEYBYTES");
|
||||
static_assert(CRYPTO_SHA256_SIZE == crypto_hash_sha256_BYTES,
|
||||
"CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES");
|
||||
static_assert(CRYPTO_SHA512_SIZE == crypto_hash_sha512_BYTES,
|
||||
"CRYPTO_SHA512_SIZE should be equal to crypto_hash_sha512_BYTES");
|
||||
static_assert(CRYPTO_PUBLIC_KEY_SIZE == 32,
|
||||
"CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for pk_equal to work");
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
static_assert(CRYPTO_SIGNATURE_SIZE == crypto_sign_BYTES,
|
||||
"CRYPTO_SIGNATURE_SIZE should be equal to crypto_sign_BYTES");
|
||||
static_assert(CRYPTO_SIGN_PUBLIC_KEY_SIZE == crypto_sign_PUBLICKEYBYTES,
|
||||
"CRYPTO_SIGN_PUBLIC_KEY_SIZE should be equal to crypto_sign_PUBLICKEYBYTES");
|
||||
static_assert(CRYPTO_SIGN_SECRET_KEY_SIZE == crypto_sign_SECRETKEYBYTES,
|
||||
"CRYPTO_SIGN_SECRET_KEY_SIZE should be equal to crypto_sign_SECRETKEYBYTES");
|
||||
#endif /* VANILLA_NACL */
|
||||
|
||||
bool create_extended_keypair(uint8_t *pk, uint8_t *sk)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
/* create signature key pair */
|
||||
crypto_sign_keypair(pk + ENC_PUBLIC_KEY_SIZE, sk + ENC_SECRET_KEY_SIZE);
|
||||
|
||||
/* convert public signature key to public encryption key */
|
||||
const int res1 = crypto_sign_ed25519_pk_to_curve25519(pk, pk + ENC_PUBLIC_KEY_SIZE);
|
||||
|
||||
/* convert secret signature key to secret encryption key */
|
||||
const int res2 = crypto_sign_ed25519_sk_to_curve25519(sk, sk + ENC_SECRET_KEY_SIZE);
|
||||
|
||||
return res1 == 0 && res2 == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint8_t *get_enc_key(const uint8_t *key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
const uint8_t *get_sig_pk(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
void set_sig_pk(uint8_t *key, const uint8_t *sig_pk)
|
||||
{
|
||||
memcpy(key + ENC_PUBLIC_KEY_SIZE, sig_pk, SIG_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
const uint8_t *get_sig_sk(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_SECRET_KEY_SIZE;
|
||||
}
|
||||
|
||||
const uint8_t *get_chat_id(const uint8_t *key)
|
||||
{
|
||||
return key + ENC_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
static uint8_t *crypto_malloc(size_t bytes)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)malloc(bytes);
|
||||
|
||||
if (ptr != nullptr) {
|
||||
crypto_memlock(ptr, bytes);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
nullable(1)
|
||||
static void crypto_free(uint8_t *ptr, size_t bytes)
|
||||
{
|
||||
if (ptr != nullptr) {
|
||||
crypto_memzero(ptr, bytes);
|
||||
crypto_memunlock(ptr, bytes);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
#endif // !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
|
||||
void crypto_memzero(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
memset(data, 0, length);
|
||||
#else
|
||||
sodium_memzero(data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_memlock(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if (sodium_mlock(data, length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_memunlock(void *data, size_t length)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if (sodium_munlock(data, length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool pk_equal(const uint8_t *pk1, const uint8_t *pk2)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(pk1, pk2, CRYPTO_PUBLIC_KEY_SIZE) == 0;
|
||||
#else
|
||||
return crypto_verify_32(pk1, pk2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pk_copy(uint8_t *dest, const uint8_t *src)
|
||||
{
|
||||
memcpy(dest, src, CRYPTO_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2)
|
||||
{
|
||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(cksum1, cksum2, CRYPTO_SHA512_SIZE) == 0;
|
||||
#elif defined(VANILLA_NACL)
|
||||
const int lo = crypto_verify_32(cksum1, cksum2) == 0 ? 1 : 0;
|
||||
const int hi = crypto_verify_32(cksum1 + 8, cksum2 + 8) == 0 ? 1 : 0;
|
||||
return (lo & hi) == 1;
|
||||
#else
|
||||
return crypto_verify_64(cksum1, cksum2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Hope that this is better for the fuzzer
|
||||
return memcmp(cksum1, cksum2, CRYPTO_SHA256_SIZE) == 0;
|
||||
#else
|
||||
return crypto_verify_32(cksum1, cksum2) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t random_u08(const Random *rng)
|
||||
{
|
||||
uint8_t randnum;
|
||||
random_bytes(rng, &randnum, 1);
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint16_t random_u16(const Random *rng)
|
||||
{
|
||||
uint16_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint32_t random_u32(const Random *rng)
|
||||
{
|
||||
uint32_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint64_t random_u64(const Random *rng)
|
||||
{
|
||||
uint64_t randnum;
|
||||
random_bytes(rng, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum;
|
||||
}
|
||||
|
||||
uint32_t random_range_u32(const Random *rng, uint32_t upper_bound)
|
||||
{
|
||||
return rng->funcs->random_uniform(rng->obj, upper_bound);
|
||||
}
|
||||
|
||||
bool crypto_signature_create(uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *secret_key)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
return crypto_sign_detached(signature, nullptr, message, message_length, secret_key) == 0;
|
||||
#endif // VANILLA_NACL
|
||||
}
|
||||
|
||||
bool crypto_signature_verify(const uint8_t *signature, const uint8_t *message, uint64_t message_length,
|
||||
const uint8_t *public_key)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
return false;
|
||||
#else
|
||||
return crypto_sign_verify_detached(signature, message, message_length, public_key) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool public_key_valid(const uint8_t *public_key)
|
||||
{
|
||||
/* Last bit of key is always zero. */
|
||||
return public_key[31] < 128;
|
||||
}
|
||||
|
||||
int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key,
|
||||
uint8_t *shared_key)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memcpy(shared_key, public_key, CRYPTO_SHARED_KEY_SIZE);
|
||||
return 0;
|
||||
#else
|
||||
return crypto_box_beforenm(shared_key, public_key, secret_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
|
||||
const uint8_t *plain, size_t length, uint8_t *encrypted)
|
||||
{
|
||||
if (length == 0 || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
// Don't encrypt anything.
|
||||
memcpy(encrypted, plain, length);
|
||||
// Zero MAC to avoid uninitialized memory reads.
|
||||
memset(encrypted + length, 0, crypto_box_MACBYTES);
|
||||
#else
|
||||
|
||||
const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
|
||||
const size_t size_temp_encrypted = length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES;
|
||||
|
||||
uint8_t *temp_plain = crypto_malloc(size_temp_plain);
|
||||
uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
|
||||
|
||||
if (temp_plain == nullptr || temp_encrypted == nullptr) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// crypto_box_afternm requires the entire range of the output array be
|
||||
// initialised with something. It doesn't matter what it's initialised with,
|
||||
// so we'll pick 0x00.
|
||||
memset(temp_encrypted, 0, size_temp_encrypted);
|
||||
|
||||
memset(temp_plain, 0, crypto_box_ZEROBYTES);
|
||||
// Pad the message with 32 0 bytes.
|
||||
memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length);
|
||||
|
||||
if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce,
|
||||
shared_key) != 0) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unpad the encrypted message.
|
||||
memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);
|
||||
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
#endif
|
||||
assert(length < INT32_MAX - crypto_box_MACBYTES);
|
||||
return (int32_t)(length + crypto_box_MACBYTES);
|
||||
}
|
||||
|
||||
int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain)
|
||||
{
|
||||
if (length <= crypto_box_BOXZEROBYTES || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
|
||||
|| plain == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
assert(length >= crypto_box_MACBYTES);
|
||||
memcpy(plain, encrypted, length - crypto_box_MACBYTES); // Don't encrypt anything
|
||||
#else
|
||||
|
||||
const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
|
||||
const size_t size_temp_encrypted = length + crypto_box_BOXZEROBYTES;
|
||||
|
||||
uint8_t *temp_plain = crypto_malloc(size_temp_plain);
|
||||
uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
|
||||
|
||||
if (temp_plain == nullptr || temp_encrypted == nullptr) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// crypto_box_open_afternm requires the entire range of the output array be
|
||||
// initialised with something. It doesn't matter what it's initialised with,
|
||||
// so we'll pick 0x00.
|
||||
memset(temp_plain, 0, size_temp_plain);
|
||||
|
||||
memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES);
|
||||
// Pad the message with 16 0 bytes.
|
||||
memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length);
|
||||
|
||||
if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce,
|
||||
shared_key) != 0) {
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);
|
||||
|
||||
crypto_free(temp_plain, size_temp_plain);
|
||||
crypto_free(temp_encrypted, size_temp_encrypted);
|
||||
#endif
|
||||
assert(length > crypto_box_MACBYTES);
|
||||
assert(length < INT32_MAX);
|
||||
return (int32_t)(length - crypto_box_MACBYTES);
|
||||
}
|
||||
|
||||
int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *plain, size_t length, uint8_t *encrypted)
|
||||
{
|
||||
if (public_key == nullptr || secret_key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t k[crypto_box_BEFORENMBYTES];
|
||||
encrypt_precompute(public_key, secret_key, k);
|
||||
const int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted);
|
||||
crypto_memzero(k, sizeof(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
|
||||
const uint8_t *encrypted, size_t length, uint8_t *plain)
|
||||
{
|
||||
if (public_key == nullptr || secret_key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t k[crypto_box_BEFORENMBYTES];
|
||||
encrypt_precompute(public_key, secret_key, k);
|
||||
const int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain);
|
||||
crypto_memzero(k, sizeof(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void increment_nonce(uint8_t *nonce)
|
||||
{
|
||||
/* TODO(irungentoo): use `increment_nonce_number(nonce, 1)` or
|
||||
* sodium_increment (change to little endian).
|
||||
*
|
||||
* NOTE don't use breaks inside this loop.
|
||||
* In particular, make sure, as far as possible,
|
||||
* that loop bounds and their potential underflow or overflow
|
||||
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
|
||||
*/
|
||||
uint_fast16_t carry = 1U;
|
||||
|
||||
for (uint32_t i = crypto_box_NONCEBYTES; i != 0; --i) {
|
||||
carry += (uint_fast16_t)nonce[i - 1];
|
||||
nonce[i - 1] = (uint8_t)carry;
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void increment_nonce_number(uint8_t *nonce, uint32_t increment)
|
||||
{
|
||||
/* NOTE don't use breaks inside this loop
|
||||
* In particular, make sure, as far as possible,
|
||||
* that loop bounds and their potential underflow or overflow
|
||||
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
|
||||
*/
|
||||
uint8_t num_as_nonce[crypto_box_NONCEBYTES] = {0};
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 4] = increment >> 24;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 3] = increment >> 16;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 2] = increment >> 8;
|
||||
num_as_nonce[crypto_box_NONCEBYTES - 1] = increment;
|
||||
|
||||
uint_fast16_t carry = 0U;
|
||||
|
||||
for (uint32_t i = crypto_box_NONCEBYTES; i != 0; --i) {
|
||||
carry += (uint_fast16_t)nonce[i - 1] + (uint_fast16_t)num_as_nonce[i - 1];
|
||||
nonce[i - 1] = (uint8_t)carry;
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void random_nonce(const Random *rng, uint8_t *nonce)
|
||||
{
|
||||
random_bytes(rng, nonce, crypto_box_NONCEBYTES);
|
||||
}
|
||||
|
||||
void new_symmetric_key_implicit_random(uint8_t *key)
|
||||
{
|
||||
randombytes(key, CRYPTO_SYMMETRIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
void new_symmetric_key(const Random *rng, uint8_t *key)
|
||||
{
|
||||
random_bytes(rng, key, CRYPTO_SYMMETRIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
|
||||
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
|
||||
crypto_scalarmult_curve25519_base(public_key, secret_key);
|
||||
return 0;
|
||||
#else
|
||||
return crypto_box_keypair(public_key, secret_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)
|
||||
{
|
||||
crypto_scalarmult_curve25519_base(public_key, secret_key);
|
||||
}
|
||||
|
||||
void new_hmac_key(const Random *rng, uint8_t *key)
|
||||
{
|
||||
random_bytes(rng, key, CRYPTO_HMAC_KEY_SIZE);
|
||||
}
|
||||
|
||||
void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data,
|
||||
size_t length)
|
||||
{
|
||||
crypto_auth(auth, data, length, key);
|
||||
}
|
||||
|
||||
bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE],
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
return crypto_auth_verify(auth, data, length, key) == 0;
|
||||
}
|
||||
|
||||
void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memset(hash, 0, CRYPTO_SHA256_SIZE);
|
||||
memcpy(hash, data, length < CRYPTO_SHA256_SIZE ? length : CRYPTO_SHA256_SIZE);
|
||||
#else
|
||||
crypto_hash_sha256(hash, data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memset(hash, 0, CRYPTO_SHA512_SIZE);
|
||||
memcpy(hash, data, length < CRYPTO_SHA512_SIZE ? length : CRYPTO_SHA512_SIZE);
|
||||
#else
|
||||
crypto_hash_sha512(hash, data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void sys_random_bytes(void *obj, uint8_t *bytes, size_t length)
|
||||
{
|
||||
randombytes(bytes, length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static uint32_t sys_random_uniform(void *obj, uint32_t upper_bound)
|
||||
{
|
||||
#ifdef VANILLA_NACL
|
||||
if (upper_bound == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t randnum;
|
||||
sys_random_bytes(obj, (uint8_t *)&randnum, sizeof(randnum));
|
||||
return randnum % upper_bound;
|
||||
#else
|
||||
return randombytes_uniform(upper_bound);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const Random_Funcs system_random_funcs = {
|
||||
sys_random_bytes,
|
||||
sys_random_uniform,
|
||||
};
|
||||
|
||||
static const Random system_random_obj = {&system_random_funcs};
|
||||
|
||||
const Random *system_random(void)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
if ((true)) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
#ifndef VANILLA_NACL
|
||||
// It is safe to call this function more than once and from different
|
||||
// threads -- subsequent calls won't have any effects.
|
||||
if (sodium_init() == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return &system_random_obj;
|
||||
}
|
||||
|
||||
void random_bytes(const Random *rng, uint8_t *bytes, size_t length)
|
||||
{
|
||||
rng->funcs->random_bytes(rng->obj, bytes, length);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Connected {
|
||||
uint32_t conference_number;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_connected_construct(Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
*conference_connected = (Tox_Event_Conference_Connected) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_connected_destruct(Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_connected_set_conference_number(
|
||||
Tox_Event_Conference_Connected *conference_connected, uint32_t conference_number)
|
||||
{
|
||||
assert(conference_connected != nullptr);
|
||||
conference_connected->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_connected_get_conference_number(
|
||||
const Tox_Event_Conference_Connected *conference_connected)
|
||||
{
|
||||
assert(conference_connected != nullptr);
|
||||
return conference_connected->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_connected_pack(
|
||||
const Tox_Event_Conference_Connected *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_CONNECTED)
|
||||
&& bin_pack_u32(bp, event->conference_number);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_connected_unpack(
|
||||
Tox_Event_Conference_Connected *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_unpack_u32(bu, &event->conference_number);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Connected *tox_events_add_conference_connected(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_connected_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_connected_size == events->conference_connected_capacity) {
|
||||
const uint32_t new_conference_connected_capacity = events->conference_connected_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Connected *new_conference_connected = (Tox_Event_Conference_Connected *)realloc(
|
||||
events->conference_connected, new_conference_connected_capacity * sizeof(Tox_Event_Conference_Connected));
|
||||
|
||||
if (new_conference_connected == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_connected = new_conference_connected;
|
||||
events->conference_connected_capacity = new_conference_connected_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Connected *const conference_connected =
|
||||
&events->conference_connected[events->conference_connected_size];
|
||||
tox_event_conference_connected_construct(conference_connected);
|
||||
++events->conference_connected_size;
|
||||
return conference_connected;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_connected(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_connected_size; ++i) {
|
||||
tox_event_conference_connected_destruct(&events->conference_connected[i]);
|
||||
}
|
||||
|
||||
free(events->conference_connected);
|
||||
events->conference_connected = nullptr;
|
||||
events->conference_connected_size = 0;
|
||||
events->conference_connected_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_connected_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_connected_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Connected *tox_events_get_conference_connected(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_connected_size);
|
||||
assert(events->conference_connected != nullptr);
|
||||
return &events->conference_connected[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_connected(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_connected_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_connected_pack(tox_events_get_conference_connected(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_connected(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Connected *event = tox_events_add_conference_connected(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_connected_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_connected(Tox *tox, uint32_t conference_number, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Connected *conference_connected = tox_events_add_conference_connected(state->events);
|
||||
|
||||
if (conference_connected == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_connected_set_conference_number(conference_connected, conference_number);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Invite {
|
||||
uint32_t friend_number;
|
||||
Tox_Conference_Type type;
|
||||
uint8_t *cookie;
|
||||
uint32_t cookie_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_construct(Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
*conference_invite = (Tox_Event_Conference_Invite) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_invite_destruct(Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
free(conference_invite->cookie);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_set_friend_number(Tox_Event_Conference_Invite *conference_invite,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
conference_invite->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_conference_invite_get_friend_number(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_invite_set_type(Tox_Event_Conference_Invite *conference_invite,
|
||||
Tox_Conference_Type type)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
conference_invite->type = type;
|
||||
}
|
||||
Tox_Conference_Type tox_event_conference_invite_get_type(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_set_cookie(Tox_Event_Conference_Invite *conference_invite,
|
||||
const uint8_t *cookie, uint32_t cookie_length)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
|
||||
if (conference_invite->cookie != nullptr) {
|
||||
free(conference_invite->cookie);
|
||||
conference_invite->cookie = nullptr;
|
||||
conference_invite->cookie_length = 0;
|
||||
}
|
||||
|
||||
conference_invite->cookie = (uint8_t *)malloc(cookie_length);
|
||||
|
||||
if (conference_invite->cookie == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_invite->cookie, cookie, cookie_length);
|
||||
conference_invite->cookie_length = cookie_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_invite_get_cookie_length(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->cookie_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_invite_get_cookie(const Tox_Event_Conference_Invite *conference_invite)
|
||||
{
|
||||
assert(conference_invite != nullptr);
|
||||
return conference_invite->cookie;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_pack(
|
||||
const Tox_Event_Conference_Invite *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_INVITE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->cookie, event->cookie_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_invite_unpack(
|
||||
Tox_Event_Conference_Invite *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_conference_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->cookie, &event->cookie_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Invite *tox_events_add_conference_invite(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_invite_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_invite_size == events->conference_invite_capacity) {
|
||||
const uint32_t new_conference_invite_capacity = events->conference_invite_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Invite *new_conference_invite = (Tox_Event_Conference_Invite *)realloc(
|
||||
events->conference_invite, new_conference_invite_capacity * sizeof(Tox_Event_Conference_Invite));
|
||||
|
||||
if (new_conference_invite == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_invite = new_conference_invite;
|
||||
events->conference_invite_capacity = new_conference_invite_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Invite *const conference_invite = &events->conference_invite[events->conference_invite_size];
|
||||
tox_event_conference_invite_construct(conference_invite);
|
||||
++events->conference_invite_size;
|
||||
return conference_invite;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_invite(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_invite_size; ++i) {
|
||||
tox_event_conference_invite_destruct(&events->conference_invite[i]);
|
||||
}
|
||||
|
||||
free(events->conference_invite);
|
||||
events->conference_invite = nullptr;
|
||||
events->conference_invite_size = 0;
|
||||
events->conference_invite_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_invite_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_invite_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Invite *tox_events_get_conference_invite(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_invite_size);
|
||||
assert(events->conference_invite != nullptr);
|
||||
return &events->conference_invite[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_invite(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_invite_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_invite_pack(tox_events_get_conference_invite(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_invite(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Invite *event = tox_events_add_conference_invite(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_invite_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_invite(Tox *tox, uint32_t friend_number, Tox_Conference_Type type,
|
||||
const uint8_t *cookie, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Invite *conference_invite = tox_events_add_conference_invite(state->events);
|
||||
|
||||
if (conference_invite == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_invite_set_friend_number(conference_invite, friend_number);
|
||||
tox_event_conference_invite_set_type(conference_invite, type);
|
||||
tox_event_conference_invite_set_cookie(conference_invite, cookie, length);
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Message {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_construct(Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
*conference_message = (Tox_Event_Conference_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_message_destruct(Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
free(conference_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_conference_number(Tox_Event_Conference_Message *conference_message,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_conference_number(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_peer_number(Tox_Event_Conference_Message *conference_message,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_peer_number(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_message_set_type(Tox_Event_Conference_Message *conference_message,
|
||||
Tox_Message_Type type)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
conference_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_conference_message_get_type(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_set_message(Tox_Event_Conference_Message *conference_message,
|
||||
const uint8_t *message, uint32_t message_length)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
|
||||
if (conference_message->message != nullptr) {
|
||||
free(conference_message->message);
|
||||
conference_message->message = nullptr;
|
||||
conference_message->message_length = 0;
|
||||
}
|
||||
|
||||
conference_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (conference_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_message->message, message, message_length);
|
||||
conference_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_message_get_message_length(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_message_get_message(const Tox_Event_Conference_Message *conference_message)
|
||||
{
|
||||
assert(conference_message != nullptr);
|
||||
return conference_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_pack(
|
||||
const Tox_Event_Conference_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_MESSAGE)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_message_unpack(
|
||||
Tox_Event_Conference_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Message *tox_events_add_conference_message(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_message_size == events->conference_message_capacity) {
|
||||
const uint32_t new_conference_message_capacity = events->conference_message_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Message *new_conference_message = (Tox_Event_Conference_Message *)realloc(
|
||||
events->conference_message, new_conference_message_capacity * sizeof(Tox_Event_Conference_Message));
|
||||
|
||||
if (new_conference_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_message = new_conference_message;
|
||||
events->conference_message_capacity = new_conference_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Message *const conference_message = &events->conference_message[events->conference_message_size];
|
||||
tox_event_conference_message_construct(conference_message);
|
||||
++events->conference_message_size;
|
||||
return conference_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_message_size; ++i) {
|
||||
tox_event_conference_message_destruct(&events->conference_message[i]);
|
||||
}
|
||||
|
||||
free(events->conference_message);
|
||||
events->conference_message = nullptr;
|
||||
events->conference_message_size = 0;
|
||||
events->conference_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Message *tox_events_get_conference_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_message_size);
|
||||
assert(events->conference_message != nullptr);
|
||||
return &events->conference_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_message_pack(tox_events_get_conference_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Message *event = tox_events_add_conference_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_message(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
Tox_Message_Type type, const uint8_t *message, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Message *conference_message = tox_events_add_conference_message(state->events);
|
||||
|
||||
if (conference_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_message_set_conference_number(conference_message, conference_number);
|
||||
tox_event_conference_message_set_peer_number(conference_message, peer_number);
|
||||
tox_event_conference_message_set_type(conference_message, type);
|
||||
tox_event_conference_message_set_message(conference_message, message, length);
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Peer_List_Changed {
|
||||
uint32_t conference_number;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_construct(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
*conference_peer_list_changed = (Tox_Event_Conference_Peer_List_Changed) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_destruct(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_list_changed_set_conference_number(Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed, uint32_t conference_number)
|
||||
{
|
||||
assert(conference_peer_list_changed != nullptr);
|
||||
conference_peer_list_changed->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_list_changed_get_conference_number(const Tox_Event_Conference_Peer_List_Changed
|
||||
*conference_peer_list_changed)
|
||||
{
|
||||
assert(conference_peer_list_changed != nullptr);
|
||||
return conference_peer_list_changed->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_list_changed_pack(
|
||||
const Tox_Event_Conference_Peer_List_Changed *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_PEER_LIST_CHANGED)
|
||||
&& bin_pack_u32(bp, event->conference_number);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_list_changed_unpack(
|
||||
Tox_Event_Conference_Peer_List_Changed *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_unpack_u32(bu, &event->conference_number);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Peer_List_Changed *tox_events_add_conference_peer_list_changed(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_peer_list_changed_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_peer_list_changed_size == events->conference_peer_list_changed_capacity) {
|
||||
const uint32_t new_conference_peer_list_changed_capacity = events->conference_peer_list_changed_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Peer_List_Changed *new_conference_peer_list_changed = (Tox_Event_Conference_Peer_List_Changed *)
|
||||
realloc(
|
||||
events->conference_peer_list_changed,
|
||||
new_conference_peer_list_changed_capacity * sizeof(Tox_Event_Conference_Peer_List_Changed));
|
||||
|
||||
if (new_conference_peer_list_changed == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_peer_list_changed = new_conference_peer_list_changed;
|
||||
events->conference_peer_list_changed_capacity = new_conference_peer_list_changed_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *const conference_peer_list_changed =
|
||||
&events->conference_peer_list_changed[events->conference_peer_list_changed_size];
|
||||
tox_event_conference_peer_list_changed_construct(conference_peer_list_changed);
|
||||
++events->conference_peer_list_changed_size;
|
||||
return conference_peer_list_changed;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_peer_list_changed(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_peer_list_changed_size; ++i) {
|
||||
tox_event_conference_peer_list_changed_destruct(&events->conference_peer_list_changed[i]);
|
||||
}
|
||||
|
||||
free(events->conference_peer_list_changed);
|
||||
events->conference_peer_list_changed = nullptr;
|
||||
events->conference_peer_list_changed_size = 0;
|
||||
events->conference_peer_list_changed_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_peer_list_changed_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_peer_list_changed_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Peer_List_Changed *tox_events_get_conference_peer_list_changed(const Tox_Events *events,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_peer_list_changed_size);
|
||||
assert(events->conference_peer_list_changed != nullptr);
|
||||
return &events->conference_peer_list_changed[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_peer_list_changed(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_peer_list_changed_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_peer_list_changed_pack(tox_events_get_conference_peer_list_changed(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_peer_list_changed(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Peer_List_Changed *event = tox_events_add_conference_peer_list_changed(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_peer_list_changed_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_peer_list_changed(Tox *tox, uint32_t conference_number, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed = tox_events_add_conference_peer_list_changed(
|
||||
state->events);
|
||||
|
||||
if (conference_peer_list_changed == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_peer_list_changed_set_conference_number(conference_peer_list_changed, conference_number);
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Peer_Name {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_construct(Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
*conference_peer_name = (Tox_Event_Conference_Peer_Name) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_destruct(Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
free(conference_peer_name->name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_set_conference_number(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
conference_peer_name->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_conference_number(const Tox_Event_Conference_Peer_Name
|
||||
*conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_peer_name_set_peer_number(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
conference_peer_name->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_peer_number(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_set_name(Tox_Event_Conference_Peer_Name *conference_peer_name,
|
||||
const uint8_t *name, uint32_t name_length)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
|
||||
if (conference_peer_name->name != nullptr) {
|
||||
free(conference_peer_name->name);
|
||||
conference_peer_name->name = nullptr;
|
||||
conference_peer_name->name_length = 0;
|
||||
}
|
||||
|
||||
conference_peer_name->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (conference_peer_name->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_peer_name->name, name, name_length);
|
||||
conference_peer_name->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_peer_name_get_name_length(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_peer_name_get_name(const Tox_Event_Conference_Peer_Name *conference_peer_name)
|
||||
{
|
||||
assert(conference_peer_name != nullptr);
|
||||
return conference_peer_name->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_pack(
|
||||
const Tox_Event_Conference_Peer_Name *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_PEER_NAME)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_peer_name_unpack(
|
||||
Tox_Event_Conference_Peer_Name *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Peer_Name *tox_events_add_conference_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_peer_name_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_peer_name_size == events->conference_peer_name_capacity) {
|
||||
const uint32_t new_conference_peer_name_capacity = events->conference_peer_name_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Peer_Name *new_conference_peer_name = (Tox_Event_Conference_Peer_Name *)realloc(
|
||||
events->conference_peer_name, new_conference_peer_name_capacity * sizeof(Tox_Event_Conference_Peer_Name));
|
||||
|
||||
if (new_conference_peer_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_peer_name = new_conference_peer_name;
|
||||
events->conference_peer_name_capacity = new_conference_peer_name_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_Name *const conference_peer_name =
|
||||
&events->conference_peer_name[events->conference_peer_name_size];
|
||||
tox_event_conference_peer_name_construct(conference_peer_name);
|
||||
++events->conference_peer_name_size;
|
||||
return conference_peer_name;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_peer_name(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_peer_name_size; ++i) {
|
||||
tox_event_conference_peer_name_destruct(&events->conference_peer_name[i]);
|
||||
}
|
||||
|
||||
free(events->conference_peer_name);
|
||||
events->conference_peer_name = nullptr;
|
||||
events->conference_peer_name_size = 0;
|
||||
events->conference_peer_name_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_peer_name_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_peer_name_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Peer_Name *tox_events_get_conference_peer_name(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_peer_name_size);
|
||||
assert(events->conference_peer_name != nullptr);
|
||||
return &events->conference_peer_name[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_peer_name(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_peer_name_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_peer_name_pack(tox_events_get_conference_peer_name(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_peer_name(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Peer_Name *event = tox_events_add_conference_peer_name(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_peer_name_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_peer_name(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
const uint8_t *name, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Peer_Name *conference_peer_name = tox_events_add_conference_peer_name(state->events);
|
||||
|
||||
if (conference_peer_name == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_peer_name_set_conference_number(conference_peer_name, conference_number);
|
||||
tox_event_conference_peer_name_set_peer_number(conference_peer_name, peer_number);
|
||||
tox_event_conference_peer_name_set_name(conference_peer_name, name, length);
|
||||
}
|
||||
248
local_pod_repo/toxcore/toxcore/toxcore/events/conference_title.m
Normal file
248
local_pod_repo/toxcore/toxcore/toxcore/events/conference_title.m
Normal file
@@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Conference_Title {
|
||||
uint32_t conference_number;
|
||||
uint32_t peer_number;
|
||||
uint8_t *title;
|
||||
uint32_t title_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_construct(Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
*conference_title = (Tox_Event_Conference_Title) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_conference_title_destruct(Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
free(conference_title->title);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_set_conference_number(Tox_Event_Conference_Title *conference_title,
|
||||
uint32_t conference_number)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
conference_title->conference_number = conference_number;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_conference_number(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->conference_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_conference_title_set_peer_number(Tox_Event_Conference_Title *conference_title,
|
||||
uint32_t peer_number)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
conference_title->peer_number = peer_number;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_peer_number(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->peer_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_set_title(Tox_Event_Conference_Title *conference_title, const uint8_t *title,
|
||||
uint32_t title_length)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
|
||||
if (conference_title->title != nullptr) {
|
||||
free(conference_title->title);
|
||||
conference_title->title = nullptr;
|
||||
conference_title->title_length = 0;
|
||||
}
|
||||
|
||||
conference_title->title = (uint8_t *)malloc(title_length);
|
||||
|
||||
if (conference_title->title == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(conference_title->title, title, title_length);
|
||||
conference_title->title_length = title_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_conference_title_get_title_length(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->title_length;
|
||||
}
|
||||
const uint8_t *tox_event_conference_title_get_title(const Tox_Event_Conference_Title *conference_title)
|
||||
{
|
||||
assert(conference_title != nullptr);
|
||||
return conference_title->title;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_pack(
|
||||
const Tox_Event_Conference_Title *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_CONFERENCE_TITLE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->conference_number)
|
||||
&& bin_pack_u32(bp, event->peer_number)
|
||||
&& bin_pack_bin(bp, event->title, event->title_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_conference_title_unpack(
|
||||
Tox_Event_Conference_Title *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->conference_number)
|
||||
&& bin_unpack_u32(bu, &event->peer_number)
|
||||
&& bin_unpack_bin(bu, &event->title, &event->title_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Conference_Title *tox_events_add_conference_title(Tox_Events *events)
|
||||
{
|
||||
if (events->conference_title_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->conference_title_size == events->conference_title_capacity) {
|
||||
const uint32_t new_conference_title_capacity = events->conference_title_capacity * 2 + 1;
|
||||
Tox_Event_Conference_Title *new_conference_title = (Tox_Event_Conference_Title *)realloc(
|
||||
events->conference_title, new_conference_title_capacity * sizeof(Tox_Event_Conference_Title));
|
||||
|
||||
if (new_conference_title == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->conference_title = new_conference_title;
|
||||
events->conference_title_capacity = new_conference_title_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Title *const conference_title = &events->conference_title[events->conference_title_size];
|
||||
tox_event_conference_title_construct(conference_title);
|
||||
++events->conference_title_size;
|
||||
return conference_title;
|
||||
}
|
||||
|
||||
void tox_events_clear_conference_title(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->conference_title_size; ++i) {
|
||||
tox_event_conference_title_destruct(&events->conference_title[i]);
|
||||
}
|
||||
|
||||
free(events->conference_title);
|
||||
events->conference_title = nullptr;
|
||||
events->conference_title_size = 0;
|
||||
events->conference_title_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_conference_title_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->conference_title_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Conference_Title *tox_events_get_conference_title(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->conference_title_size);
|
||||
assert(events->conference_title != nullptr);
|
||||
return &events->conference_title[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_conference_title(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_conference_title_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_conference_title_pack(tox_events_get_conference_title(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_conference_title(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Conference_Title *event = tox_events_add_conference_title(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_conference_title_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_conference_title(Tox *tox, uint32_t conference_number, uint32_t peer_number,
|
||||
const uint8_t *title, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Conference_Title *conference_title = tox_events_add_conference_title(state->events);
|
||||
|
||||
if (conference_title == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_conference_title_set_conference_number(conference_title, conference_number);
|
||||
tox_event_conference_title_set_peer_number(conference_title, peer_number);
|
||||
tox_event_conference_title_set_title(conference_title, title, length);
|
||||
}
|
||||
216
local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.h
Normal file
216
local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
||||
#define C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
||||
|
||||
#include "../attributes.h"
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Tox_Events {
|
||||
Tox_Event_Conference_Connected *conference_connected;
|
||||
uint32_t conference_connected_size;
|
||||
uint32_t conference_connected_capacity;
|
||||
|
||||
Tox_Event_Conference_Invite *conference_invite;
|
||||
uint32_t conference_invite_size;
|
||||
uint32_t conference_invite_capacity;
|
||||
|
||||
Tox_Event_Conference_Message *conference_message;
|
||||
uint32_t conference_message_size;
|
||||
uint32_t conference_message_capacity;
|
||||
|
||||
Tox_Event_Conference_Peer_List_Changed *conference_peer_list_changed;
|
||||
uint32_t conference_peer_list_changed_size;
|
||||
uint32_t conference_peer_list_changed_capacity;
|
||||
|
||||
Tox_Event_Conference_Peer_Name *conference_peer_name;
|
||||
uint32_t conference_peer_name_size;
|
||||
uint32_t conference_peer_name_capacity;
|
||||
|
||||
Tox_Event_Conference_Title *conference_title;
|
||||
uint32_t conference_title_size;
|
||||
uint32_t conference_title_capacity;
|
||||
|
||||
Tox_Event_File_Chunk_Request *file_chunk_request;
|
||||
uint32_t file_chunk_request_size;
|
||||
uint32_t file_chunk_request_capacity;
|
||||
|
||||
Tox_Event_File_Recv *file_recv;
|
||||
uint32_t file_recv_size;
|
||||
uint32_t file_recv_capacity;
|
||||
|
||||
Tox_Event_File_Recv_Chunk *file_recv_chunk;
|
||||
uint32_t file_recv_chunk_size;
|
||||
uint32_t file_recv_chunk_capacity;
|
||||
|
||||
Tox_Event_File_Recv_Control *file_recv_control;
|
||||
uint32_t file_recv_control_size;
|
||||
uint32_t file_recv_control_capacity;
|
||||
|
||||
Tox_Event_Friend_Connection_Status *friend_connection_status;
|
||||
uint32_t friend_connection_status_size;
|
||||
uint32_t friend_connection_status_capacity;
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet;
|
||||
uint32_t friend_lossless_packet_size;
|
||||
uint32_t friend_lossless_packet_capacity;
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet;
|
||||
uint32_t friend_lossy_packet_size;
|
||||
uint32_t friend_lossy_packet_capacity;
|
||||
|
||||
Tox_Event_Friend_Message *friend_message;
|
||||
uint32_t friend_message_size;
|
||||
uint32_t friend_message_capacity;
|
||||
|
||||
Tox_Event_Friend_Name *friend_name;
|
||||
uint32_t friend_name_size;
|
||||
uint32_t friend_name_capacity;
|
||||
|
||||
Tox_Event_Friend_Read_Receipt *friend_read_receipt;
|
||||
uint32_t friend_read_receipt_size;
|
||||
uint32_t friend_read_receipt_capacity;
|
||||
|
||||
Tox_Event_Friend_Request *friend_request;
|
||||
uint32_t friend_request_size;
|
||||
uint32_t friend_request_capacity;
|
||||
|
||||
Tox_Event_Friend_Status *friend_status;
|
||||
uint32_t friend_status_size;
|
||||
uint32_t friend_status_capacity;
|
||||
|
||||
Tox_Event_Friend_Status_Message *friend_status_message;
|
||||
uint32_t friend_status_message_size;
|
||||
uint32_t friend_status_message_capacity;
|
||||
|
||||
Tox_Event_Friend_Typing *friend_typing;
|
||||
uint32_t friend_typing_size;
|
||||
uint32_t friend_typing_capacity;
|
||||
|
||||
Tox_Event_Self_Connection_Status *self_connection_status;
|
||||
uint32_t self_connection_status_size;
|
||||
uint32_t self_connection_status_capacity;
|
||||
};
|
||||
|
||||
typedef struct Tox_Events_State {
|
||||
Tox_Err_Events_Iterate error;
|
||||
Tox_Events *events;
|
||||
} Tox_Events_State;
|
||||
|
||||
tox_conference_connected_cb tox_events_handle_conference_connected;
|
||||
tox_conference_invite_cb tox_events_handle_conference_invite;
|
||||
tox_conference_message_cb tox_events_handle_conference_message;
|
||||
tox_conference_peer_list_changed_cb tox_events_handle_conference_peer_list_changed;
|
||||
tox_conference_peer_name_cb tox_events_handle_conference_peer_name;
|
||||
tox_conference_title_cb tox_events_handle_conference_title;
|
||||
tox_file_chunk_request_cb tox_events_handle_file_chunk_request;
|
||||
tox_file_recv_cb tox_events_handle_file_recv;
|
||||
tox_file_recv_chunk_cb tox_events_handle_file_recv_chunk;
|
||||
tox_file_recv_control_cb tox_events_handle_file_recv_control;
|
||||
tox_friend_connection_status_cb tox_events_handle_friend_connection_status;
|
||||
tox_friend_lossless_packet_cb tox_events_handle_friend_lossless_packet;
|
||||
tox_friend_lossy_packet_cb tox_events_handle_friend_lossy_packet;
|
||||
tox_friend_message_cb tox_events_handle_friend_message;
|
||||
tox_friend_name_cb tox_events_handle_friend_name;
|
||||
tox_friend_read_receipt_cb tox_events_handle_friend_read_receipt;
|
||||
tox_friend_request_cb tox_events_handle_friend_request;
|
||||
tox_friend_status_cb tox_events_handle_friend_status;
|
||||
tox_friend_status_message_cb tox_events_handle_friend_status_message;
|
||||
tox_friend_typing_cb tox_events_handle_friend_typing;
|
||||
tox_self_connection_status_cb tox_events_handle_self_connection_status;
|
||||
|
||||
// non_null()
|
||||
typedef void tox_events_clear_cb(Tox_Events *events);
|
||||
|
||||
tox_events_clear_cb tox_events_clear_conference_connected;
|
||||
tox_events_clear_cb tox_events_clear_conference_invite;
|
||||
tox_events_clear_cb tox_events_clear_conference_message;
|
||||
tox_events_clear_cb tox_events_clear_conference_peer_list_changed;
|
||||
tox_events_clear_cb tox_events_clear_conference_peer_name;
|
||||
tox_events_clear_cb tox_events_clear_conference_title;
|
||||
tox_events_clear_cb tox_events_clear_file_chunk_request;
|
||||
tox_events_clear_cb tox_events_clear_file_recv_chunk;
|
||||
tox_events_clear_cb tox_events_clear_file_recv_control;
|
||||
tox_events_clear_cb tox_events_clear_file_recv;
|
||||
tox_events_clear_cb tox_events_clear_friend_connection_status;
|
||||
tox_events_clear_cb tox_events_clear_friend_lossless_packet;
|
||||
tox_events_clear_cb tox_events_clear_friend_lossy_packet;
|
||||
tox_events_clear_cb tox_events_clear_friend_message;
|
||||
tox_events_clear_cb tox_events_clear_friend_name;
|
||||
tox_events_clear_cb tox_events_clear_friend_read_receipt;
|
||||
tox_events_clear_cb tox_events_clear_friend_request;
|
||||
tox_events_clear_cb tox_events_clear_friend_status_message;
|
||||
tox_events_clear_cb tox_events_clear_friend_status;
|
||||
tox_events_clear_cb tox_events_clear_friend_typing;
|
||||
tox_events_clear_cb tox_events_clear_self_connection_status;
|
||||
|
||||
// non_null()
|
||||
typedef bool tox_events_pack_cb(const Tox_Events *events, Bin_Pack *bp);
|
||||
|
||||
tox_events_pack_cb tox_events_pack_conference_connected;
|
||||
tox_events_pack_cb tox_events_pack_conference_invite;
|
||||
tox_events_pack_cb tox_events_pack_conference_message;
|
||||
tox_events_pack_cb tox_events_pack_conference_peer_list_changed;
|
||||
tox_events_pack_cb tox_events_pack_conference_peer_name;
|
||||
tox_events_pack_cb tox_events_pack_conference_title;
|
||||
tox_events_pack_cb tox_events_pack_file_chunk_request;
|
||||
tox_events_pack_cb tox_events_pack_file_recv_chunk;
|
||||
tox_events_pack_cb tox_events_pack_file_recv_control;
|
||||
tox_events_pack_cb tox_events_pack_file_recv;
|
||||
tox_events_pack_cb tox_events_pack_friend_connection_status;
|
||||
tox_events_pack_cb tox_events_pack_friend_lossless_packet;
|
||||
tox_events_pack_cb tox_events_pack_friend_lossy_packet;
|
||||
tox_events_pack_cb tox_events_pack_friend_message;
|
||||
tox_events_pack_cb tox_events_pack_friend_name;
|
||||
tox_events_pack_cb tox_events_pack_friend_read_receipt;
|
||||
tox_events_pack_cb tox_events_pack_friend_request;
|
||||
tox_events_pack_cb tox_events_pack_friend_status_message;
|
||||
tox_events_pack_cb tox_events_pack_friend_status;
|
||||
tox_events_pack_cb tox_events_pack_friend_typing;
|
||||
tox_events_pack_cb tox_events_pack_self_connection_status;
|
||||
|
||||
tox_events_pack_cb tox_events_pack;
|
||||
|
||||
// non_null()
|
||||
typedef bool tox_events_unpack_cb(Tox_Events *events, Bin_Unpack *bu);
|
||||
|
||||
tox_events_unpack_cb tox_events_unpack_conference_connected;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_invite;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_message;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_peer_list_changed;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_peer_name;
|
||||
tox_events_unpack_cb tox_events_unpack_conference_title;
|
||||
tox_events_unpack_cb tox_events_unpack_file_chunk_request;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv_chunk;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv_control;
|
||||
tox_events_unpack_cb tox_events_unpack_file_recv;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_connection_status;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_lossless_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_lossy_packet;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_message;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_name;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_read_receipt;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_request;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_status_message;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_status;
|
||||
tox_events_unpack_cb tox_events_unpack_friend_typing;
|
||||
tox_events_unpack_cb tox_events_unpack_self_connection_status;
|
||||
|
||||
tox_events_unpack_cb tox_events_unpack;
|
||||
|
||||
non_null()
|
||||
Tox_Events_State *tox_events_alloc(void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
|
||||
64
local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.m
Normal file
64
local_pod_repo/toxcore/toxcore/toxcore/events/events_alloc.m
Normal file
@@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../ccompat.h"
|
||||
|
||||
Tox_Events_State *tox_events_alloc(void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = (Tox_Events_State *)user_data;
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events != nullptr) {
|
||||
// Already allocated.
|
||||
return state;
|
||||
}
|
||||
|
||||
state->events = (Tox_Events *)calloc(1, sizeof(Tox_Events));
|
||||
|
||||
if (state->events == nullptr) {
|
||||
// It's still null => allocation failed.
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
} else {
|
||||
*state->events = (Tox_Events) {
|
||||
nullptr
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void tox_events_free(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
tox_events_clear_conference_connected(events);
|
||||
tox_events_clear_conference_invite(events);
|
||||
tox_events_clear_conference_message(events);
|
||||
tox_events_clear_conference_peer_list_changed(events);
|
||||
tox_events_clear_conference_peer_name(events);
|
||||
tox_events_clear_conference_title(events);
|
||||
tox_events_clear_file_chunk_request(events);
|
||||
tox_events_clear_file_recv_chunk(events);
|
||||
tox_events_clear_file_recv_control(events);
|
||||
tox_events_clear_file_recv(events);
|
||||
tox_events_clear_friend_connection_status(events);
|
||||
tox_events_clear_friend_lossless_packet(events);
|
||||
tox_events_clear_friend_lossy_packet(events);
|
||||
tox_events_clear_friend_message(events);
|
||||
tox_events_clear_friend_name(events);
|
||||
tox_events_clear_friend_read_receipt(events);
|
||||
tox_events_clear_friend_request(events);
|
||||
tox_events_clear_friend_status(events);
|
||||
tox_events_clear_friend_status_message(events);
|
||||
tox_events_clear_friend_typing(events);
|
||||
tox_events_clear_self_connection_status(events);
|
||||
free(events);
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Chunk_Request {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint64_t position;
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_construct(Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
*file_chunk_request = (Tox_Event_File_Chunk_Request) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_destruct(Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_friend_number(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_chunk_request_get_friend_number(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_file_number(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_chunk_request_get_file_number(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_position(Tox_Event_File_Chunk_Request *file_chunk_request,
|
||||
uint64_t position)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->position = position;
|
||||
}
|
||||
uint64_t tox_event_file_chunk_request_get_position(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->position;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_chunk_request_set_length(Tox_Event_File_Chunk_Request *file_chunk_request, uint16_t length)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
file_chunk_request->length = length;
|
||||
}
|
||||
uint16_t tox_event_file_chunk_request_get_length(const Tox_Event_File_Chunk_Request *file_chunk_request)
|
||||
{
|
||||
assert(file_chunk_request != nullptr);
|
||||
return file_chunk_request->length;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_chunk_request_pack(
|
||||
const Tox_Event_File_Chunk_Request *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_CHUNK_REQUEST)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u64(bp, event->position)
|
||||
&& bin_pack_u16(bp, event->length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_chunk_request_unpack(
|
||||
Tox_Event_File_Chunk_Request *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u64(bu, &event->position)
|
||||
&& bin_unpack_u16(bu, &event->length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Chunk_Request *tox_events_add_file_chunk_request(Tox_Events *events)
|
||||
{
|
||||
if (events->file_chunk_request_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_chunk_request_size == events->file_chunk_request_capacity) {
|
||||
const uint32_t new_file_chunk_request_capacity = events->file_chunk_request_capacity * 2 + 1;
|
||||
Tox_Event_File_Chunk_Request *new_file_chunk_request = (Tox_Event_File_Chunk_Request *)realloc(
|
||||
events->file_chunk_request, new_file_chunk_request_capacity * sizeof(Tox_Event_File_Chunk_Request));
|
||||
|
||||
if (new_file_chunk_request == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_chunk_request = new_file_chunk_request;
|
||||
events->file_chunk_request_capacity = new_file_chunk_request_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Chunk_Request *const file_chunk_request = &events->file_chunk_request[events->file_chunk_request_size];
|
||||
tox_event_file_chunk_request_construct(file_chunk_request);
|
||||
++events->file_chunk_request_size;
|
||||
return file_chunk_request;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_chunk_request(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_chunk_request_size; ++i) {
|
||||
tox_event_file_chunk_request_destruct(&events->file_chunk_request[i]);
|
||||
}
|
||||
|
||||
free(events->file_chunk_request);
|
||||
events->file_chunk_request = nullptr;
|
||||
events->file_chunk_request_size = 0;
|
||||
events->file_chunk_request_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_chunk_request_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_chunk_request_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Chunk_Request *tox_events_get_file_chunk_request(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_chunk_request_size);
|
||||
assert(events->file_chunk_request != nullptr);
|
||||
return &events->file_chunk_request[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_chunk_request(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_chunk_request_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_chunk_request_pack(tox_events_get_file_chunk_request(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_chunk_request(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Chunk_Request *event = tox_events_add_file_chunk_request(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_chunk_request_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Chunk_Request *file_chunk_request = tox_events_add_file_chunk_request(state->events);
|
||||
|
||||
if (file_chunk_request == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_chunk_request_set_friend_number(file_chunk_request, friend_number);
|
||||
tox_event_file_chunk_request_set_file_number(file_chunk_request, file_number);
|
||||
tox_event_file_chunk_request_set_position(file_chunk_request, position);
|
||||
tox_event_file_chunk_request_set_length(file_chunk_request, length);
|
||||
}
|
||||
282
local_pod_repo/toxcore/toxcore/toxcore/events/file_recv.m
Normal file
282
local_pod_repo/toxcore/toxcore/toxcore/events/file_recv.m
Normal file
@@ -0,0 +1,282 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint32_t kind;
|
||||
uint64_t file_size;
|
||||
uint8_t *filename;
|
||||
uint32_t filename_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_construct(Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
*file_recv = (Tox_Event_File_Recv) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_destruct(Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
free(file_recv->filename);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_friend_number(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_friend_number(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_file_number(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_file_number(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_kind(Tox_Event_File_Recv *file_recv,
|
||||
uint32_t kind)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->kind = kind;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_kind(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->kind;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_set_file_size(Tox_Event_File_Recv *file_recv,
|
||||
uint64_t file_size)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
file_recv->file_size = file_size;
|
||||
}
|
||||
uint64_t tox_event_file_recv_get_file_size(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->file_size;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_set_filename(Tox_Event_File_Recv *file_recv, const uint8_t *filename,
|
||||
uint32_t filename_length)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
|
||||
if (file_recv->filename != nullptr) {
|
||||
free(file_recv->filename);
|
||||
file_recv->filename = nullptr;
|
||||
file_recv->filename_length = 0;
|
||||
}
|
||||
|
||||
file_recv->filename = (uint8_t *)malloc(filename_length);
|
||||
|
||||
if (file_recv->filename == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(file_recv->filename, filename, filename_length);
|
||||
file_recv->filename_length = filename_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_file_recv_get_filename_length(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->filename_length;
|
||||
}
|
||||
const uint8_t *tox_event_file_recv_get_filename(const Tox_Event_File_Recv *file_recv)
|
||||
{
|
||||
assert(file_recv != nullptr);
|
||||
return file_recv->filename;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_pack(
|
||||
const Tox_Event_File_Recv *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV)
|
||||
&& bin_pack_array(bp, 5)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u32(bp, event->kind)
|
||||
&& bin_pack_u64(bp, event->file_size)
|
||||
&& bin_pack_bin(bp, event->filename, event->filename_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_unpack(
|
||||
Tox_Event_File_Recv *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u32(bu, &event->kind)
|
||||
&& bin_unpack_u64(bu, &event->file_size)
|
||||
&& bin_unpack_bin(bu, &event->filename, &event->filename_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv *tox_events_add_file_recv(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_size == events->file_recv_capacity) {
|
||||
const uint32_t new_file_recv_capacity = events->file_recv_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv *new_file_recv = (Tox_Event_File_Recv *)realloc(
|
||||
events->file_recv, new_file_recv_capacity * sizeof(Tox_Event_File_Recv));
|
||||
|
||||
if (new_file_recv == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv = new_file_recv;
|
||||
events->file_recv_capacity = new_file_recv_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv *const file_recv = &events->file_recv[events->file_recv_size];
|
||||
tox_event_file_recv_construct(file_recv);
|
||||
++events->file_recv_size;
|
||||
return file_recv;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_size; ++i) {
|
||||
tox_event_file_recv_destruct(&events->file_recv[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv);
|
||||
events->file_recv = nullptr;
|
||||
events->file_recv_size = 0;
|
||||
events->file_recv_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv *tox_events_get_file_recv(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_size);
|
||||
assert(events->file_recv != nullptr);
|
||||
return &events->file_recv[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_pack(tox_events_get_file_recv(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv *event = tox_events_add_file_recv(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind,
|
||||
uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv *file_recv = tox_events_add_file_recv(state->events);
|
||||
|
||||
if (file_recv == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_set_friend_number(file_recv, friend_number);
|
||||
tox_event_file_recv_set_file_number(file_recv, file_number);
|
||||
tox_event_file_recv_set_kind(file_recv, kind);
|
||||
tox_event_file_recv_set_file_size(file_recv, file_size);
|
||||
tox_event_file_recv_set_filename(file_recv, filename, filename_length);
|
||||
}
|
||||
265
local_pod_repo/toxcore/toxcore/toxcore/events/file_recv_chunk.m
Normal file
265
local_pod_repo/toxcore/toxcore/toxcore/events/file_recv_chunk.m
Normal file
@@ -0,0 +1,265 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv_Chunk {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
uint64_t position;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_construct(Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
*file_recv_chunk = (Tox_Event_File_Recv_Chunk) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_destruct(Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
free(file_recv_chunk->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_friend_number(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_friend_number(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_file_number(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_file_number(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_chunk_set_position(Tox_Event_File_Recv_Chunk *file_recv_chunk,
|
||||
uint64_t position)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
file_recv_chunk->position = position;
|
||||
}
|
||||
uint64_t tox_event_file_recv_chunk_get_position(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->position;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_set_data(Tox_Event_File_Recv_Chunk *file_recv_chunk, const uint8_t *data,
|
||||
uint32_t data_length)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
|
||||
if (file_recv_chunk->data != nullptr) {
|
||||
free(file_recv_chunk->data);
|
||||
file_recv_chunk->data = nullptr;
|
||||
file_recv_chunk->data_length = 0;
|
||||
}
|
||||
|
||||
file_recv_chunk->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (file_recv_chunk->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(file_recv_chunk->data, data, data_length);
|
||||
file_recv_chunk->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_file_recv_chunk_get_length(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_file_recv_chunk_get_data(const Tox_Event_File_Recv_Chunk *file_recv_chunk)
|
||||
{
|
||||
assert(file_recv_chunk != nullptr);
|
||||
return file_recv_chunk->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_pack(
|
||||
const Tox_Event_File_Recv_Chunk *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV_CHUNK)
|
||||
&& bin_pack_array(bp, 4)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u64(bp, event->position)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_chunk_unpack(
|
||||
Tox_Event_File_Recv_Chunk *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& bin_unpack_u64(bu, &event->position)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv_Chunk *tox_events_add_file_recv_chunk(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_chunk_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_chunk_size == events->file_recv_chunk_capacity) {
|
||||
const uint32_t new_file_recv_chunk_capacity = events->file_recv_chunk_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv_Chunk *new_file_recv_chunk = (Tox_Event_File_Recv_Chunk *)realloc(
|
||||
events->file_recv_chunk, new_file_recv_chunk_capacity * sizeof(Tox_Event_File_Recv_Chunk));
|
||||
|
||||
if (new_file_recv_chunk == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv_chunk = new_file_recv_chunk;
|
||||
events->file_recv_chunk_capacity = new_file_recv_chunk_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Chunk *const file_recv_chunk = &events->file_recv_chunk[events->file_recv_chunk_size];
|
||||
tox_event_file_recv_chunk_construct(file_recv_chunk);
|
||||
++events->file_recv_chunk_size;
|
||||
return file_recv_chunk;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv_chunk(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_chunk_size; ++i) {
|
||||
tox_event_file_recv_chunk_destruct(&events->file_recv_chunk[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv_chunk);
|
||||
events->file_recv_chunk = nullptr;
|
||||
events->file_recv_chunk_size = 0;
|
||||
events->file_recv_chunk_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_chunk_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_chunk_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv_Chunk *tox_events_get_file_recv_chunk(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_chunk_size);
|
||||
assert(events->file_recv_chunk != nullptr);
|
||||
return &events->file_recv_chunk[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv_chunk(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_chunk_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_chunk_pack(tox_events_get_file_recv_chunk(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv_chunk(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv_Chunk *event = tox_events_add_file_recv_chunk(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_chunk_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Chunk *file_recv_chunk = tox_events_add_file_recv_chunk(state->events);
|
||||
|
||||
if (file_recv_chunk == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_chunk_set_friend_number(file_recv_chunk, friend_number);
|
||||
tox_event_file_recv_chunk_set_file_number(file_recv_chunk, file_number);
|
||||
tox_event_file_recv_chunk_set_position(file_recv_chunk, position);
|
||||
tox_event_file_recv_chunk_set_data(file_recv_chunk, data, length);
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_File_Recv_Control {
|
||||
uint32_t friend_number;
|
||||
uint32_t file_number;
|
||||
Tox_File_Control control;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_construct(Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
*file_recv_control = (Tox_Event_File_Recv_Control) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_destruct(Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_friend_number(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_control_get_friend_number(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_file_number(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
uint32_t file_number)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->file_number = file_number;
|
||||
}
|
||||
uint32_t tox_event_file_recv_control_get_file_number(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->file_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_file_recv_control_set_control(Tox_Event_File_Recv_Control *file_recv_control,
|
||||
Tox_File_Control control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
file_recv_control->control = control;
|
||||
}
|
||||
Tox_File_Control tox_event_file_recv_control_get_control(const Tox_Event_File_Recv_Control *file_recv_control)
|
||||
{
|
||||
assert(file_recv_control != nullptr);
|
||||
return file_recv_control->control;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_control_pack(
|
||||
const Tox_Event_File_Recv_Control *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FILE_RECV_CONTROL)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->file_number)
|
||||
&& bin_pack_u32(bp, event->control);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_file_recv_control_unpack(
|
||||
Tox_Event_File_Recv_Control *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_u32(bu, &event->file_number)
|
||||
&& tox_unpack_file_control(bu, &event->control);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_File_Recv_Control *tox_events_add_file_recv_control(Tox_Events *events)
|
||||
{
|
||||
if (events->file_recv_control_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->file_recv_control_size == events->file_recv_control_capacity) {
|
||||
const uint32_t new_file_recv_control_capacity = events->file_recv_control_capacity * 2 + 1;
|
||||
Tox_Event_File_Recv_Control *new_file_recv_control = (Tox_Event_File_Recv_Control *)realloc(
|
||||
events->file_recv_control, new_file_recv_control_capacity * sizeof(Tox_Event_File_Recv_Control));
|
||||
|
||||
if (new_file_recv_control == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->file_recv_control = new_file_recv_control;
|
||||
events->file_recv_control_capacity = new_file_recv_control_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Control *const file_recv_control = &events->file_recv_control[events->file_recv_control_size];
|
||||
tox_event_file_recv_control_construct(file_recv_control);
|
||||
++events->file_recv_control_size;
|
||||
return file_recv_control;
|
||||
}
|
||||
|
||||
void tox_events_clear_file_recv_control(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->file_recv_control_size; ++i) {
|
||||
tox_event_file_recv_control_destruct(&events->file_recv_control[i]);
|
||||
}
|
||||
|
||||
free(events->file_recv_control);
|
||||
events->file_recv_control = nullptr;
|
||||
events->file_recv_control_size = 0;
|
||||
events->file_recv_control_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_file_recv_control_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->file_recv_control_size;
|
||||
}
|
||||
|
||||
const Tox_Event_File_Recv_Control *tox_events_get_file_recv_control(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->file_recv_control_size);
|
||||
assert(events->file_recv_control != nullptr);
|
||||
return &events->file_recv_control[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_file_recv_control(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_file_recv_control_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_file_recv_control_pack(tox_events_get_file_recv_control(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_file_recv_control(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_File_Recv_Control *event = tox_events_add_file_recv_control(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_file_recv_control_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_file_recv_control(Tox *tox, uint32_t friend_number, uint32_t file_number,
|
||||
Tox_File_Control control, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_File_Recv_Control *file_recv_control = tox_events_add_file_recv_control(state->events);
|
||||
|
||||
if (file_recv_control == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_file_recv_control_set_friend_number(file_recv_control, friend_number);
|
||||
tox_event_file_recv_control_set_file_number(file_recv_control, file_number);
|
||||
tox_event_file_recv_control_set_control(file_recv_control, control);
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Connection_Status {
|
||||
uint32_t friend_number;
|
||||
Tox_Connection connection_status;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_construct(Tox_Event_Friend_Connection_Status *friend_connection_status)
|
||||
{
|
||||
*friend_connection_status = (Tox_Event_Friend_Connection_Status) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_destruct(Tox_Event_Friend_Connection_Status *friend_connection_status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_set_friend_number(Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status, uint32_t friend_number)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
friend_connection_status->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_connection_status_get_friend_number(const Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
return friend_connection_status->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_connection_status_set_connection_status(Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status, Tox_Connection connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
friend_connection_status->connection_status = connection_status;
|
||||
}
|
||||
Tox_Connection tox_event_friend_connection_status_get_connection_status(const Tox_Event_Friend_Connection_Status
|
||||
*friend_connection_status)
|
||||
{
|
||||
assert(friend_connection_status != nullptr);
|
||||
return friend_connection_status->connection_status;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_connection_status_pack(
|
||||
const Tox_Event_Friend_Connection_Status *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_CONNECTION_STATUS)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->connection_status);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_connection_status_unpack(
|
||||
Tox_Event_Friend_Connection_Status *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_connection(bu, &event->connection_status);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Connection_Status *tox_events_add_friend_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_connection_status_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_connection_status_size == events->friend_connection_status_capacity) {
|
||||
const uint32_t new_friend_connection_status_capacity = events->friend_connection_status_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Connection_Status *new_friend_connection_status = (Tox_Event_Friend_Connection_Status *)realloc(
|
||||
events->friend_connection_status, new_friend_connection_status_capacity * sizeof(Tox_Event_Friend_Connection_Status));
|
||||
|
||||
if (new_friend_connection_status == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_connection_status = new_friend_connection_status;
|
||||
events->friend_connection_status_capacity = new_friend_connection_status_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Connection_Status *const friend_connection_status =
|
||||
&events->friend_connection_status[events->friend_connection_status_size];
|
||||
tox_event_friend_connection_status_construct(friend_connection_status);
|
||||
++events->friend_connection_status_size;
|
||||
return friend_connection_status;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_connection_status(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_connection_status_size; ++i) {
|
||||
tox_event_friend_connection_status_destruct(&events->friend_connection_status[i]);
|
||||
}
|
||||
|
||||
free(events->friend_connection_status);
|
||||
events->friend_connection_status = nullptr;
|
||||
events->friend_connection_status_size = 0;
|
||||
events->friend_connection_status_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_connection_status_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_connection_status_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Connection_Status *tox_events_get_friend_connection_status(const Tox_Events *events,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_connection_status_size);
|
||||
assert(events->friend_connection_status != nullptr);
|
||||
return &events->friend_connection_status[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_connection_status(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_connection_status_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_connection_status_pack(tox_events_get_friend_connection_status(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_connection_status(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Connection_Status *event = tox_events_add_friend_connection_status(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_connection_status_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_connection_status(Tox *tox, uint32_t friend_number, Tox_Connection connection_status,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Connection_Status *friend_connection_status = tox_events_add_friend_connection_status(state->events);
|
||||
|
||||
if (friend_connection_status == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_connection_status_set_friend_number(friend_connection_status, friend_number);
|
||||
tox_event_friend_connection_status_set_connection_status(friend_connection_status, connection_status);
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Lossless_Packet {
|
||||
uint32_t friend_number;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_construct(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
*friend_lossless_packet = (Tox_Event_Friend_Lossless_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_destruct(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
free(friend_lossless_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossless_packet_set_friend_number(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
friend_lossless_packet->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_lossless_packet_get_friend_number(const Tox_Event_Friend_Lossless_Packet
|
||||
*friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_set_data(Tox_Event_Friend_Lossless_Packet *friend_lossless_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
|
||||
if (friend_lossless_packet->data != nullptr) {
|
||||
free(friend_lossless_packet->data);
|
||||
friend_lossless_packet->data = nullptr;
|
||||
friend_lossless_packet->data_length = 0;
|
||||
}
|
||||
|
||||
friend_lossless_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (friend_lossless_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_lossless_packet->data, data, data_length);
|
||||
friend_lossless_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_lossless_packet_get_data_length(const Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_lossless_packet_get_data(const Tox_Event_Friend_Lossless_Packet *friend_lossless_packet)
|
||||
{
|
||||
assert(friend_lossless_packet != nullptr);
|
||||
return friend_lossless_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_pack(
|
||||
const Tox_Event_Friend_Lossless_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_LOSSLESS_PACKET)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossless_packet_unpack(
|
||||
Tox_Event_Friend_Lossless_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Lossless_Packet *tox_events_add_friend_lossless_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_lossless_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_lossless_packet_size == events->friend_lossless_packet_capacity) {
|
||||
const uint32_t new_friend_lossless_packet_capacity = events->friend_lossless_packet_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Lossless_Packet *new_friend_lossless_packet = (Tox_Event_Friend_Lossless_Packet *)realloc(
|
||||
events->friend_lossless_packet, new_friend_lossless_packet_capacity * sizeof(Tox_Event_Friend_Lossless_Packet));
|
||||
|
||||
if (new_friend_lossless_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_lossless_packet = new_friend_lossless_packet;
|
||||
events->friend_lossless_packet_capacity = new_friend_lossless_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *const friend_lossless_packet =
|
||||
&events->friend_lossless_packet[events->friend_lossless_packet_size];
|
||||
tox_event_friend_lossless_packet_construct(friend_lossless_packet);
|
||||
++events->friend_lossless_packet_size;
|
||||
return friend_lossless_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_lossless_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_lossless_packet_size; ++i) {
|
||||
tox_event_friend_lossless_packet_destruct(&events->friend_lossless_packet[i]);
|
||||
}
|
||||
|
||||
free(events->friend_lossless_packet);
|
||||
events->friend_lossless_packet = nullptr;
|
||||
events->friend_lossless_packet_size = 0;
|
||||
events->friend_lossless_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_lossless_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_lossless_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Lossless_Packet *tox_events_get_friend_lossless_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_lossless_packet_size);
|
||||
assert(events->friend_lossless_packet != nullptr);
|
||||
return &events->friend_lossless_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_lossless_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_lossless_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_lossless_packet_pack(tox_events_get_friend_lossless_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_lossless_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Lossless_Packet *event = tox_events_add_friend_lossless_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_lossless_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossless_Packet *friend_lossless_packet = tox_events_add_friend_lossless_packet(state->events);
|
||||
|
||||
if (friend_lossless_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_lossless_packet_set_friend_number(friend_lossless_packet, friend_number);
|
||||
tox_event_friend_lossless_packet_set_data(friend_lossless_packet, data, length);
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Lossy_Packet {
|
||||
uint32_t friend_number;
|
||||
uint8_t *data;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_construct(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
*friend_lossy_packet = (Tox_Event_Friend_Lossy_Packet) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_destruct(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
free(friend_lossy_packet->data);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_lossy_packet_set_friend_number(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
friend_lossy_packet->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_lossy_packet_get_friend_number(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_set_data(Tox_Event_Friend_Lossy_Packet *friend_lossy_packet,
|
||||
const uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
|
||||
if (friend_lossy_packet->data != nullptr) {
|
||||
free(friend_lossy_packet->data);
|
||||
friend_lossy_packet->data = nullptr;
|
||||
friend_lossy_packet->data_length = 0;
|
||||
}
|
||||
|
||||
friend_lossy_packet->data = (uint8_t *)malloc(data_length);
|
||||
|
||||
if (friend_lossy_packet->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_lossy_packet->data, data, data_length);
|
||||
friend_lossy_packet->data_length = data_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_lossy_packet_get_data_length(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->data_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_lossy_packet_get_data(const Tox_Event_Friend_Lossy_Packet *friend_lossy_packet)
|
||||
{
|
||||
assert(friend_lossy_packet != nullptr);
|
||||
return friend_lossy_packet->data;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_pack(
|
||||
const Tox_Event_Friend_Lossy_Packet *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_LOSSY_PACKET)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->data, event->data_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_lossy_packet_unpack(
|
||||
Tox_Event_Friend_Lossy_Packet *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->data, &event->data_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Lossy_Packet *tox_events_add_friend_lossy_packet(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_lossy_packet_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_lossy_packet_size == events->friend_lossy_packet_capacity) {
|
||||
const uint32_t new_friend_lossy_packet_capacity = events->friend_lossy_packet_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Lossy_Packet *new_friend_lossy_packet = (Tox_Event_Friend_Lossy_Packet *)realloc(
|
||||
events->friend_lossy_packet, new_friend_lossy_packet_capacity * sizeof(Tox_Event_Friend_Lossy_Packet));
|
||||
|
||||
if (new_friend_lossy_packet == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_lossy_packet = new_friend_lossy_packet;
|
||||
events->friend_lossy_packet_capacity = new_friend_lossy_packet_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *const friend_lossy_packet =
|
||||
&events->friend_lossy_packet[events->friend_lossy_packet_size];
|
||||
tox_event_friend_lossy_packet_construct(friend_lossy_packet);
|
||||
++events->friend_lossy_packet_size;
|
||||
return friend_lossy_packet;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_lossy_packet(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_lossy_packet_size; ++i) {
|
||||
tox_event_friend_lossy_packet_destruct(&events->friend_lossy_packet[i]);
|
||||
}
|
||||
|
||||
free(events->friend_lossy_packet);
|
||||
events->friend_lossy_packet = nullptr;
|
||||
events->friend_lossy_packet_size = 0;
|
||||
events->friend_lossy_packet_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_lossy_packet_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_lossy_packet_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Lossy_Packet *tox_events_get_friend_lossy_packet(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_lossy_packet_size);
|
||||
assert(events->friend_lossy_packet != nullptr);
|
||||
return &events->friend_lossy_packet[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_lossy_packet(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_lossy_packet_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_lossy_packet_pack(tox_events_get_friend_lossy_packet(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_lossy_packet(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Lossy_Packet *event = tox_events_add_friend_lossy_packet(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_lossy_packet_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Lossy_Packet *friend_lossy_packet = tox_events_add_friend_lossy_packet(state->events);
|
||||
|
||||
if (friend_lossy_packet == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_lossy_packet_set_friend_number(friend_lossy_packet, friend_number);
|
||||
tox_event_friend_lossy_packet_set_data(friend_lossy_packet, data, length);
|
||||
}
|
||||
248
local_pod_repo/toxcore/toxcore/toxcore/events/friend_message.m
Normal file
248
local_pod_repo/toxcore/toxcore/toxcore/events/friend_message.m
Normal file
@@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
#include "../tox_unpack.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Message {
|
||||
uint32_t friend_number;
|
||||
Tox_Message_Type type;
|
||||
uint8_t *message;
|
||||
uint32_t message_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_construct(Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
*friend_message = (Tox_Event_Friend_Message) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_message_destruct(Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
free(friend_message->message);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_set_friend_number(Tox_Event_Friend_Message *friend_message,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
friend_message->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_message_get_friend_number(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_message_set_type(Tox_Event_Friend_Message *friend_message, Tox_Message_Type type)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
friend_message->type = type;
|
||||
}
|
||||
Tox_Message_Type tox_event_friend_message_get_type(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->type;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_set_message(Tox_Event_Friend_Message *friend_message, const uint8_t *message,
|
||||
uint32_t message_length)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
|
||||
if (friend_message->message != nullptr) {
|
||||
free(friend_message->message);
|
||||
friend_message->message = nullptr;
|
||||
friend_message->message_length = 0;
|
||||
}
|
||||
|
||||
friend_message->message = (uint8_t *)malloc(message_length);
|
||||
|
||||
if (friend_message->message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_message->message, message, message_length);
|
||||
friend_message->message_length = message_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_message_get_message_length(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->message_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_message_get_message(const Tox_Event_Friend_Message *friend_message)
|
||||
{
|
||||
assert(friend_message != nullptr);
|
||||
return friend_message->message;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_pack(
|
||||
const Tox_Event_Friend_Message *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_MESSAGE)
|
||||
&& bin_pack_array(bp, 3)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_u32(bp, event->type)
|
||||
&& bin_pack_bin(bp, event->message, event->message_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_message_unpack(
|
||||
Tox_Event_Friend_Message *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& tox_unpack_message_type(bu, &event->type)
|
||||
&& bin_unpack_bin(bu, &event->message, &event->message_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Message *tox_events_add_friend_message(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_message_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_message_size == events->friend_message_capacity) {
|
||||
const uint32_t new_friend_message_capacity = events->friend_message_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Message *new_friend_message = (Tox_Event_Friend_Message *)realloc(
|
||||
events->friend_message, new_friend_message_capacity * sizeof(Tox_Event_Friend_Message));
|
||||
|
||||
if (new_friend_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_message = new_friend_message;
|
||||
events->friend_message_capacity = new_friend_message_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Message *const friend_message = &events->friend_message[events->friend_message_size];
|
||||
tox_event_friend_message_construct(friend_message);
|
||||
++events->friend_message_size;
|
||||
return friend_message;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_message(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_message_size; ++i) {
|
||||
tox_event_friend_message_destruct(&events->friend_message[i]);
|
||||
}
|
||||
|
||||
free(events->friend_message);
|
||||
events->friend_message = nullptr;
|
||||
events->friend_message_size = 0;
|
||||
events->friend_message_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_message_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_message_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Message *tox_events_get_friend_message(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_message_size);
|
||||
assert(events->friend_message != nullptr);
|
||||
return &events->friend_message[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_message(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_message_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_message_pack(tox_events_get_friend_message(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_message(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Message *event = tox_events_add_friend_message(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_message_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message,
|
||||
size_t length, void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Message *friend_message = tox_events_add_friend_message(state->events);
|
||||
|
||||
if (friend_message == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_message_set_friend_number(friend_message, friend_number);
|
||||
tox_event_friend_message_set_type(friend_message, type);
|
||||
tox_event_friend_message_set_message(friend_message, message, length);
|
||||
}
|
||||
231
local_pod_repo/toxcore/toxcore/toxcore/events/friend_name.m
Normal file
231
local_pod_repo/toxcore/toxcore/toxcore/events/friend_name.m
Normal file
@@ -0,0 +1,231 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "events_alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../bin_pack.h"
|
||||
#include "../bin_unpack.h"
|
||||
#include "../ccompat.h"
|
||||
#include "../tox.h"
|
||||
#include "../tox_events.h"
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: struct and accessors
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
struct Tox_Event_Friend_Name {
|
||||
uint32_t friend_number;
|
||||
uint8_t *name;
|
||||
uint32_t name_length;
|
||||
};
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_name_construct(Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
*friend_name = (Tox_Event_Friend_Name) {
|
||||
0
|
||||
};
|
||||
}
|
||||
non_null()
|
||||
static void tox_event_friend_name_destruct(Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
free(friend_name->name);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void tox_event_friend_name_set_friend_number(Tox_Event_Friend_Name *friend_name,
|
||||
uint32_t friend_number)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
friend_name->friend_number = friend_number;
|
||||
}
|
||||
uint32_t tox_event_friend_name_get_friend_number(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->friend_number;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_set_name(Tox_Event_Friend_Name *friend_name, const uint8_t *name,
|
||||
uint32_t name_length)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
|
||||
if (friend_name->name != nullptr) {
|
||||
free(friend_name->name);
|
||||
friend_name->name = nullptr;
|
||||
friend_name->name_length = 0;
|
||||
}
|
||||
|
||||
friend_name->name = (uint8_t *)malloc(name_length);
|
||||
|
||||
if (friend_name->name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(friend_name->name, name, name_length);
|
||||
friend_name->name_length = name_length;
|
||||
return true;
|
||||
}
|
||||
uint32_t tox_event_friend_name_get_name_length(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->name_length;
|
||||
}
|
||||
const uint8_t *tox_event_friend_name_get_name(const Tox_Event_Friend_Name *friend_name)
|
||||
{
|
||||
assert(friend_name != nullptr);
|
||||
return friend_name->name;
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_pack(
|
||||
const Tox_Event_Friend_Name *event, Bin_Pack *bp)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
return bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, TOX_EVENT_FRIEND_NAME)
|
||||
&& bin_pack_array(bp, 2)
|
||||
&& bin_pack_u32(bp, event->friend_number)
|
||||
&& bin_pack_bin(bp, event->name, event->name_length);
|
||||
}
|
||||
|
||||
non_null()
|
||||
static bool tox_event_friend_name_unpack(
|
||||
Tox_Event_Friend_Name *event, Bin_Unpack *bu)
|
||||
{
|
||||
assert(event != nullptr);
|
||||
if (!bin_unpack_array_fixed(bu, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bin_unpack_u32(bu, &event->friend_number)
|
||||
&& bin_unpack_bin(bu, &event->name, &event->name_length);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: add/clear/get
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
non_null()
|
||||
static Tox_Event_Friend_Name *tox_events_add_friend_name(Tox_Events *events)
|
||||
{
|
||||
if (events->friend_name_size == UINT32_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (events->friend_name_size == events->friend_name_capacity) {
|
||||
const uint32_t new_friend_name_capacity = events->friend_name_capacity * 2 + 1;
|
||||
Tox_Event_Friend_Name *new_friend_name = (Tox_Event_Friend_Name *)realloc(
|
||||
events->friend_name, new_friend_name_capacity * sizeof(Tox_Event_Friend_Name));
|
||||
|
||||
if (new_friend_name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
events->friend_name = new_friend_name;
|
||||
events->friend_name_capacity = new_friend_name_capacity;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Name *const friend_name = &events->friend_name[events->friend_name_size];
|
||||
tox_event_friend_name_construct(friend_name);
|
||||
++events->friend_name_size;
|
||||
return friend_name;
|
||||
}
|
||||
|
||||
void tox_events_clear_friend_name(Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < events->friend_name_size; ++i) {
|
||||
tox_event_friend_name_destruct(&events->friend_name[i]);
|
||||
}
|
||||
|
||||
free(events->friend_name);
|
||||
events->friend_name = nullptr;
|
||||
events->friend_name_size = 0;
|
||||
events->friend_name_capacity = 0;
|
||||
}
|
||||
|
||||
uint32_t tox_events_get_friend_name_size(const Tox_Events *events)
|
||||
{
|
||||
if (events == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return events->friend_name_size;
|
||||
}
|
||||
|
||||
const Tox_Event_Friend_Name *tox_events_get_friend_name(const Tox_Events *events, uint32_t index)
|
||||
{
|
||||
assert(index < events->friend_name_size);
|
||||
assert(events->friend_name != nullptr);
|
||||
return &events->friend_name[index];
|
||||
}
|
||||
|
||||
bool tox_events_pack_friend_name(const Tox_Events *events, Bin_Pack *bp)
|
||||
{
|
||||
const uint32_t size = tox_events_get_friend_name_size(events);
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
if (!tox_event_friend_name_pack(tox_events_get_friend_name(events, i), bp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tox_events_unpack_friend_name(Tox_Events *events, Bin_Unpack *bu)
|
||||
{
|
||||
Tox_Event_Friend_Name *event = tox_events_add_friend_name(events);
|
||||
|
||||
if (event == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tox_event_friend_name_unpack(event, bu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
*
|
||||
* :: event handler
|
||||
*
|
||||
*****************************************************/
|
||||
|
||||
|
||||
void tox_events_handle_friend_name(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length,
|
||||
void *user_data)
|
||||
{
|
||||
Tox_Events_State *state = tox_events_alloc(user_data);
|
||||
assert(state != nullptr);
|
||||
|
||||
if (state->events == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Event_Friend_Name *friend_name = tox_events_add_friend_name(state->events);
|
||||
|
||||
if (friend_name == nullptr) {
|
||||
state->error = TOX_ERR_EVENTS_ITERATE_MALLOC;
|
||||
return;
|
||||
}
|
||||
|
||||
tox_event_friend_name_set_friend_number(friend_name, friend_number);
|
||||
tox_event_friend_name_set_name(friend_name, name, length);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user