Initial commit of py

This commit is contained in:
emdee 2022-09-24 04:00:32 +00:00
parent 849f6072f4
commit cc40380488
8 changed files with 4908 additions and 0 deletions

164
.gitignore vendored Normal file
View File

@ -0,0 +1,164 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.pylint.err
.pylint.log

82
wrapper/libtox.py Normal file
View File

@ -0,0 +1,82 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import os
import sys
from ctypes import CDLL
# You need a libs directory beside this directory
# and you need to link your libtoxcore.so and libtoxav.so
# and libtoxencryptsave.so into ../libs/
# Link all 3 to libtoxcore.so if you have only libtoxcore.so
try:
import utils.util as util
sLIBS_DIR = util.get_libs_directory()
except ImportError:
sLIBS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'libs')
class LibToxCore:
def __init__(self):
platform = sys.platform
if platform == 'win32':
libtoxcore = 'libtox.dll'
elif platform == 'darwin':
libtoxcore = 'libtoxcore.dylib'
else:
libtoxcore = 'libtoxcore.so'
# libtoxcore and libsodium may be installed in your os
# give libs/ precedence
libFile = os.path.join(sLIBS_DIR, libtoxcore)
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._libtoxcore = CDLL(libFile)
else:
self._libtoxcore = CDLL(libtoxcore)
def __getattr__(self, item):
return self._libtoxcore.__getattr__(item)
class LibToxAV:
def __init__(self):
platform = sys.platform
if platform == 'win32':
# on Windows av api is in libtox.dll
self._libtoxav = CDLL(os.path.join(sLIBS_DIR, 'libtox.dll'))
elif platform == 'darwin':
self._libtoxav = CDLL('libtoxcore.dylib')
else:
libFile = os.path.join(sLIBS_DIR, 'libtoxav.so')
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._libtoxav = CDLL(libFile)
else:
self._libtoxav = CDLL('libtoxav.so')
def __getattr__(self, item):
return self._libtoxav.__getattr__(item)
# figure out how to see if we have a combined library
class LibToxEncryptSave:
def __init__(self):
platform = sys.platform
if platform == 'win32':
# on Windows profile encryption api is in libtox.dll
self._lib_tox_encrypt_save = CDLL(os.path.join(sLIBS_DIR, 'libtox.dll'))
elif platform == 'darwin':
self._lib_tox_encrypt_save = CDLL('libtoxcore.dylib')
else:
libFile = os.path.join(sLIBS_DIR, 'libtoxencryptsave.so')
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._lib_tox_encrypt_save = CDLL(libFile)
else:
self._lib_tox_encrypt_save = CDLL('libtoxencryptsave.so')
def __getattr__(self, item):
return self._lib_tox_encrypt_save.__getattr__(item)
# figure out how to see if we have a combined library

3065
wrapper/tox.py Normal file

File diff suppressed because it is too large Load Diff

403
wrapper/toxav.py Normal file
View File

@ -0,0 +1,403 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import logging
from ctypes import c_int, POINTER, c_void_p, byref, ArgumentError, c_uint32, CFUNCTYPE, c_size_t, c_uint8, c_uint16
from ctypes import c_char_p, c_int32, c_bool, cast
from wrapper.libtox import LibToxAV
from wrapper.toxav_enums import *
LOG = logging.getLogger('app.'+__name__)
def LOG_ERROR(a): print('EROR> '+a)
def LOG_WARN(a): print('WARN> '+a)
def LOG_INFO(a): print('INFO> '+a)
def LOG_DEBUG(a): print('DBUG> '+a)
def LOG_TRACE(a): pass # print('DEBUGx: '+a)
class ToxAV:
"""
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.
"""
# -----------------------------------------------------------------------------------------------------------------
# Creation and destruction
# -----------------------------------------------------------------------------------------------------------------
def __init__(self, tox_pointer):
"""
Start new A/V session. There can only be only one session per Tox instance.
:param tox_pointer: pointer to Tox instance
"""
self.libtoxav = LibToxAV()
toxav_err_new = c_int()
f = self.libtoxav.toxav_new
f.restype = POINTER(c_void_p)
self._toxav_pointer = f(tox_pointer, byref(toxav_err_new))
toxav_err_new = toxav_err_new.value
if toxav_err_new == TOXAV_ERR_NEW['NULL']:
raise ArgumentError('One of the arguments to the function was NULL when it was not expected.')
elif toxav_err_new == TOXAV_ERR_NEW['MALLOC']:
raise MemoryError('Memory allocation failure while trying to allocate structures required for the A/V '
'session.')
elif toxav_err_new == TOXAV_ERR_NEW['MULTIPLE']:
raise RuntimeError('Attempted to create a second session for the same Tox instance.')
self.call_state_cb = None
self.audio_receive_frame_cb = None
self.video_receive_frame_cb = None
self.call_cb = None
def kill(self):
"""
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.
"""
self.libtoxav.toxav_kill(self._toxav_pointer)
def get_tox_pointer(self):
"""
Returns the Tox instance the A/V object was created for.
:return: pointer to the Tox instance
"""
self.libtoxav.toxav_get_tox.restype = POINTER(c_void_p)
return self.libtoxav.toxav_get_tox(self._toxav_pointer)
# -----------------------------------------------------------------------------------------------------------------
# A/V event loop
# -----------------------------------------------------------------------------------------------------------------
def iteration_interval(self):
"""
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.
:return: interval in milliseconds
"""
return self.libtoxav.toxav_iteration_interval(self._toxav_pointer)
def iterate(self):
"""
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.
"""
self.libtoxav.toxav_iterate(self._toxav_pointer)
# -----------------------------------------------------------------------------------------------------------------
# Call setup
# -----------------------------------------------------------------------------------------------------------------
def call(self, friend_number, audio_bit_rate, video_bit_rate):
"""
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.
:return: True on success.
"""
toxav_err_call = c_int()
LOG_DEBUG(f"toxav_call")
result = self.libtoxav.toxav_call(self._toxav_pointer, c_uint32(friend_number), c_uint32(audio_bit_rate),
c_uint32(video_bit_rate), byref(toxav_err_call))
toxav_err_call = toxav_err_call.value
if toxav_err_call == TOXAV_ERR_CALL['OK']:
return bool(result)
elif toxav_err_call == TOXAV_ERR_CALL['MALLOC']:
raise MemoryError('A resource allocation error occurred while trying to create the structures required for '
'the call.')
elif toxav_err_call == TOXAV_ERR_CALL['SYNC']:
raise RuntimeError('Synchronization error occurred.')
elif toxav_err_call == TOXAV_ERR_CALL['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend number did not designate a valid friend.')
elif toxav_err_call == TOXAV_ERR_CALL['FRIEND_NOT_CONNECTED']:
raise ArgumentError('The friend was valid, but not currently connected.')
elif toxav_err_call == TOXAV_ERR_CALL['FRIEND_ALREADY_IN_CALL']:
raise ArgumentError('Attempted to call a friend while already in an audio or video call with them.')
elif toxav_err_call == TOXAV_ERR_CALL['INVALID_BIT_RATE']:
raise ArgumentError('Audio or video bit rate is invalid.')
def callback_call(self, callback, user_data):
"""
Set the callback for the `call` event. Pass None to unset.
:param callback: The function for the call callback.
Should take pointer (c_void_p) to ToxAV object,
The friend number (c_uint32) from which the call is incoming.
True (c_bool) if friend is sending audio.
True (c_bool) if friend is sending video.
pointer (c_void_p) to user_data
:param user_data: pointer (c_void_p) to user data
"""
if callback is None:
self.libtoxav.toxav_callback_call(self._toxav_pointer, POINTER(None)(), user_data)
self.call_cb = None
return
LOG_DEBUG(f"toxav_callback_call")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_bool, c_bool, c_void_p)
self.call_cb = c_callback(callback)
self.libtoxav.toxav_callback_call(self._toxav_pointer, self.call_cb, user_data)
def answer(self, friend_number, audio_bit_rate, video_bit_rate):
"""
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.
:return: True on success.
"""
toxav_err_answer = c_int()
LOG_DEBUG(f"toxav_answer")
result = self.libtoxav.toxav_answer(self._toxav_pointer, c_uint32(friend_number), c_uint32(audio_bit_rate),
c_uint32(video_bit_rate), byref(toxav_err_answer))
toxav_err_answer = toxav_err_answer.value
if toxav_err_answer == TOXAV_ERR_ANSWER['OK']:
return bool(result)
elif toxav_err_answer == TOXAV_ERR_ANSWER['SYNC']:
raise RuntimeError('Synchronization error occurred.')
elif toxav_err_answer == TOXAV_ERR_ANSWER['CODEC_INITIALIZATION']:
raise RuntimeError('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.')
elif toxav_err_answer == TOXAV_ERR_ANSWER['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend number did not designate a valid friend.')
elif toxav_err_answer == TOXAV_ERR_ANSWER['FRIEND_NOT_CALLING']:
raise ArgumentError('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.')
elif toxav_err_answer == TOXAV_ERR_ANSWER['INVALID_BIT_RATE']:
raise ArgumentError('Audio or video bit rate is invalid.')
# -----------------------------------------------------------------------------------------------------------------
# Call state graph
# -----------------------------------------------------------------------------------------------------------------
def callback_call_state(self, callback, user_data):
"""
Set the callback for the `call_state` event. Pass None to unset.
:param callback: Python function.
The function for the call_state callback.
Should take pointer (c_void_p) to ToxAV object,
The friend number (c_uint32) for which the call state changed.
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.
pointer (c_void_p) to user_data
:param user_data: pointer (c_void_p) to user data
"""
if callback is None:
self.libtoxav.toxav_callback_call_state(self._toxav_pointer, POINTER(None)(), user_data)
self.call_state_cb = None
return
LOG_DEBUG(f"callback_call_state")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_void_p)
self.call_state_cb = c_callback(callback)
self.libtoxav.toxav_callback_call_state(self._toxav_pointer, self.call_state_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Call control
# -----------------------------------------------------------------------------------------------------------------
def call_control(self, friend_number, 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.
"""
toxav_err_call_control = c_int()
LOG_DEBUG(f"call_control")
result = self.libtoxav.toxav_call_control(self._toxav_pointer, c_uint32(friend_number), c_int(control),
byref(toxav_err_call_control))
toxav_err_call_control = toxav_err_call_control.value
if toxav_err_call_control == TOXAV_ERR_CALL_CONTROL['OK']:
return bool(result)
elif toxav_err_call_control == TOXAV_ERR_CALL_CONTROL['SYNC']:
raise RuntimeError('Synchronization error occurred.')
elif toxav_err_call_control == TOXAV_ERR_CALL_CONTROL['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number passed did not designate a valid friend.')
elif toxav_err_call_control == TOXAV_ERR_CALL_CONTROL['FRIEND_NOT_IN_CALL']:
raise RuntimeError('This client is currently not in a call with the friend. Before the call is answered, '
'only CANCEL is a valid control.')
elif toxav_err_call_control == TOXAV_ERR_CALL_CONTROL['INVALID_TRANSITION']:
raise RuntimeError('Happens if user tried to pause an already paused call or if trying to resume a call '
'that is not paused.')
# -----------------------------------------------------------------------------------------------------------------
# TODO Controlling bit rates
# -----------------------------------------------------------------------------------------------------------------
# -----------------------------------------------------------------------------------------------------------------
# A/V sending
# -----------------------------------------------------------------------------------------------------------------
def audio_send_frame(self, friend_number, pcm, sample_count, channels, sampling_rate):
"""
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 milliseconds.
:param channels: Number of audio channels. Sulpported 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.
"""
toxav_err_send_frame = c_int()
LOG_DEBUG(f"toxav_audio_send_frame")
assert sampling_rate in [8000, 12000, 16000, 24000, 48000]
result = self.libtoxav.toxav_audio_send_frame(self._toxav_pointer,
c_uint32(friend_number),
cast(pcm, c_void_p),
c_size_t(sample_count), c_uint8(channels),
c_uint32(sampling_rate), byref(toxav_err_send_frame))
toxav_err_send_frame = toxav_err_send_frame.value
if toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['OK']:
return bool(result)
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['NULL']:
raise ArgumentError('The samples data pointer was NULL.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number passed did not designate a valid friend.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['FRIEND_NOT_IN_CALL']:
raise RuntimeError('This client is currently not in a call with the friend.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['SYNC']:
raise RuntimeError('Synchronization error occurred.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['INVALID']:
raise ArgumentError('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.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['PAYLOAD_TYPE_DISABLED']:
raise RuntimeError('Either friend turned off audio or video receiving or we turned off sending for the said'
'payload.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['RTP_FAILED']:
RuntimeError('Failed to push frame through rtp interface.')
def video_send_frame(self, friend_number, width, height, y, u, v):
"""
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.
"""
toxav_err_send_frame = c_int()
LOG_DEBUG(f"toxav_video_send_frame")
result = self.libtoxav.toxav_video_send_frame(self._toxav_pointer, c_uint32(friend_number), c_uint16(width),
c_uint16(height), c_char_p(y), c_char_p(u), c_char_p(v),
byref(toxav_err_send_frame))
toxav_err_send_frame = toxav_err_send_frame.value
if toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['OK']:
return bool(result)
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['NULL']:
raise ArgumentError('One of Y, U, or V was NULL.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number passed did not designate a valid friend.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['FRIEND_NOT_IN_CALL']:
raise RuntimeError('This client is currently not in a call with the friend.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['SYNC']:
raise RuntimeError('Synchronization error occurred.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['INVALID']:
raise ArgumentError('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.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['PAYLOAD_TYPE_DISABLED']:
raise RuntimeError('Either friend turned off audio or video receiving or we turned off sending for the said'
'payload.')
elif toxav_err_send_frame == TOXAV_ERR_SEND_FRAME['RTP_FAILED']:
RuntimeError('Failed to push frame through rtp interface.')
# -----------------------------------------------------------------------------------------------------------------
# A/V receiving
# -----------------------------------------------------------------------------------------------------------------
def callback_audio_receive_frame(self, callback, user_data):
"""
Set the callback for the `audio_receive_frame` event. Pass None to unset.
:param callback: Python function.
Function 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.
Should take pointer (c_void_p) to ToxAV object,
The friend number (c_uint32) of the friend who sent an audio frame.
An array (c_uint8) of audio samples (sample_count * channels elements).
The number (c_size_t) of audio samples per channel in the PCM array.
Number (c_uint8) of audio channels.
Sampling rate (c_uint32) used in this frame.
pointer (c_void_p) to user_data
:param user_data: pointer (c_void_p) to user data
"""
if callback is None:
self.libtoxav.toxav_callback_audio_receive_frame(self._toxav_pointer, POINTER(None)(), user_data)
self.audio_receive_frame_cb = None
return
LOG_DEBUG(f"toxav_callback_audio_receive_frame")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t, c_uint8, c_uint32, c_void_p)
self.audio_receive_frame_cb = c_callback(callback)
self.libtoxav.toxav_callback_audio_receive_frame(self._toxav_pointer, self.audio_receive_frame_cb, user_data)
def callback_video_receive_frame(self, callback, user_data):
"""
Set the callback for the `video_receive_frame` event. Pass None to unset.
:param callback: Python function.
The function type for the video_receive_frame callback.
Should take
toxAV pointer (c_void_p) to ToxAV object,
friend_number The friend number (c_uint32) of the friend who sent a video frame.
width Width (c_uint16) of the frame in pixels.
height Height (c_uint16) of the frame in pixels.
y
u
v Plane data (POINTER(c_uint8)).
The size of plane data is derived from width and height where
Y = MAX(width, abs(ystride)) * height,
U = MAX(width/2, abs(ustride)) * (height/2) and
V = MAX(width/2, abs(vstride)) * (height/2).
ystride
ustride
vstride Strides data (c_int32). 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.
user_data pointer (c_void_p) to user_data
:param user_data: pointer (c_void_p) to user data
"""
if callback is None:
self.libtoxav.toxav_callback_video_receive_frame(self._toxav_pointer, POINTER(None)(), user_data)
self.video_receive_frame_cb = None
return
LOG_DEBUG(f"toxav_callback_video_receive_frame")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint16, c_uint16,
POINTER(c_uint8), POINTER(c_uint8), POINTER(c_uint8),
c_int32, c_int32, c_int32,
c_void_p)
self.video_receive_frame_cb = c_callback(callback)
self.libtoxav.toxav_callback_video_receive_frame(self._toxav_pointer, self.video_receive_frame_cb, user_data)

133
wrapper/toxav_enums.py Normal file
View File

@ -0,0 +1,133 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
TOXAV_ERR_NEW = {
# The function returned successfully.
'OK': 0,
# One of the arguments to the function was NULL when it was not expected.
'NULL': 1,
# Memory allocation failure while trying to allocate structures required for the A/V session.
'MALLOC': 2,
# Attempted to create a second session for the same Tox instance.
'MULTIPLE': 3,
}
TOXAV_ERR_CALL = {
# The function returned successfully.
'OK': 0,
# A resource allocation error occurred while trying to create the structures required for the call.
'MALLOC': 1,
# Synchronization error occurred.
'SYNC': 2,
# The friend number did not designate a valid friend.
'FRIEND_NOT_FOUND': 3,
# The friend was valid, but not currently connected.
'FRIEND_NOT_CONNECTED': 4,
# Attempted to call a friend while already in an audio or video call with them.
'FRIEND_ALREADY_IN_CALL': 5,
# Audio or video bit rate is invalid.
'INVALID_BIT_RATE': 6,
}
TOXAV_ERR_ANSWER = {
# The function returned successfully.
'OK': 0,
# Synchronization error occurred.
'SYNC': 1,
# 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.
'CODEC_INITIALIZATION': 2,
# The friend number did not designate a valid friend.
'FRIEND_NOT_FOUND': 3,
# 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.
'FRIEND_NOT_CALLING': 4,
# Audio or video bit rate is invalid.
'INVALID_BIT_RATE': 5,
}
TOXAV_FRIEND_CALL_STATE = {
# 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.
'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.
'FINISHED': 2,
# The flag that marks that friend is sending audio.
'SENDING_A': 4,
# The flag that marks that friend is sending video.
'SENDING_V': 8,
# The flag that marks that friend is receiving audio.
'ACCEPTING_A': 16,
# The flag that marks that friend is receiving video.
'ACCEPTING_V': 32,
}
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.
'RESUME': 0,
# Put a call on hold. Not valid before the call is accepted.
'PAUSE': 1,
# Reject a call if it was not answered, yet. Cancel a call after it was answered.
'CANCEL': 2,
# 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.
'MUTE_AUDIO': 3,
# Calling this control will notify client to start sending audio again.
'UNMUTE_AUDIO': 4,
# 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.
'HIDE_VIDEO': 5,
# Calling this control will notify client to start sending video again.
'SHOW_VIDEO': 6,
}
TOXAV_ERR_CALL_CONTROL = {
# The function returned successfully.
'OK': 0,
# Synchronization error occurred.
'SYNC': 1,
# The friend_number passed did not designate a valid friend.
'FRIEND_NOT_FOUND': 2,
# This client is currently not in a call with the friend. Before the call is answered, only CANCEL is a valid
# control.
'FRIEND_NOT_IN_CALL': 3,
# Happens if user tried to pause an already paused call or if trying to resume a call that is not paused.
'INVALID_TRANSITION': 4,
}
TOXAV_ERR_BIT_RATE_SET = {
# The function returned successfully.
'OK': 0,
# Synchronization error occurred.
'SYNC': 1,
# The audio bit rate passed was not one of the supported values.
'INVALID_AUDIO_BIT_RATE': 2,
# The video bit rate passed was not one of the supported values.
'INVALID_VIDEO_BIT_RATE': 3,
# The friend_number passed did not designate a valid friend.
'FRIEND_NOT_FOUND': 4,
# This client is currently not in a call with the friend.
'FRIEND_NOT_IN_CALL': 5,
}
TOXAV_ERR_SEND_FRAME = {
# The function returned successfully.
'OK': 0,
# In case of video, one of Y, U, or V was NULL. In case of audio, the samples data pointer was NULL.
'NULL': 1,
# The friend_number passed did not designate a valid friend.
'FRIEND_NOT_FOUND': 2,
# This client is currently not in a call with the friend.
'FRIEND_NOT_IN_CALL': 3,
# Synchronization error occurred.
'SYNC': 4,
# 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.
'INVALID': 5,
# Either friend turned off audio or video receiving or we turned off sending for the said payload.
'PAYLOAD_TYPE_DISABLED': 6,
# Failed to push frame through rtp interface.
'RTP_FAILED': 7,
}

View File

@ -0,0 +1,957 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
TOX_USER_STATUS = {
'NONE': 0,
'AWAY': 1,
'BUSY': 2,
}
TOX_MESSAGE_TYPE = {
'NORMAL': 0,
'ACTION': 1,
}
TOX_PROXY_TYPE = {
'NONE': 0,
'HTTP': 1,
'SOCKS5': 2,
}
TOX_SAVEDATA_TYPE = {
'NONE': 0,
'TOX_SAVE': 1,
'SECRET_KEY': 2,
}
TOX_ERR_OPTIONS_NEW = {
'OK': 0,
'MALLOC': 1,
}
TOX_ERR_NEW = {
'OK': 0,
'NULL': 1,
'MALLOC': 2,
'PORT_ALLOC': 3,
'PROXY_BAD_TYPE': 4,
'PROXY_BAD_HOST': 5,
'PROXY_BAD_PORT': 6,
'PROXY_NOT_FOUND': 7,
'LOAD_ENCRYPTED': 8,
'LOAD_BAD_FORMAT': 9,
'TCP_SERVER_ALLOC': 10,
}
TOX_ERR_BOOTSTRAP = {
'OK': 0,
'NULL': 1,
'BAD_HOST': 2,
'BAD_PORT': 3,
}
TOX_CONNECTION = {
'NONE': 0,
'TCP': 1,
'UDP': 2,
}
TOX_ERR_SET_INFO = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
}
TOX_ERR_FRIEND_ADD = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
'NO_MESSAGE': 3,
'OWN_KEY': 4,
'ALREADY_SENT': 5,
'BAD_CHECKSUM': 6,
'SET_NEW_NOSPAM': 7,
'MALLOC': 8,
}
TOX_ERR_FRIEND_DELETE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_BY_PUBLIC_KEY = {
'OK': 0,
'NULL': 1,
'NOT_FOUND': 2,
}
TOX_ERR_FRIEND_GET_PUBLIC_KEY = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_GET_LAST_ONLINE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_QUERY = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
}
TOX_ERR_SET_TYPING = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_SEND_MESSAGE = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'SENDQ': 4,
'TOO_LONG': 5,
'EMPTY': 6,
}
TOX_FILE_KIND = {
'DATA': 0,
'AVATAR': 1,
}
TOX_FILE_CONTROL = {
'RESUME': 0,
'PAUSE': 1,
'CANCEL': 2,
}
TOX_ERR_FILE_CONTROL = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'NOT_PAUSED': 4,
'DENIED': 5,
'ALREADY_PAUSED': 6,
'SENDQ': 7,
}
TOX_ERR_FILE_SEEK = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'DENIED': 4,
'INVALID_POSITION': 5,
'SENDQ': 6,
}
TOX_ERR_FILE_GET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'NOT_FOUND': 3,
}
TOX_ERR_FILE_SEND = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NAME_TOO_LONG': 4,
'TOO_MANY': 5,
}
TOX_ERR_FILE_SEND_CHUNK = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NOT_FOUND': 4,
'NOT_TRANSFERRING': 5,
'INVALID_LENGTH': 6,
'SENDQ': 7,
'WRONG_POSITION': 8,
}
TOX_ERR_FRIEND_CUSTOM_PACKET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'INVALID': 4,
'EMPTY': 5,
'TOO_LONG': 6,
'SENDQ': 7,
}
TOX_ERR_GET_PORT = {
'OK': 0,
'NOT_BOUND': 1,
}
TOX_GROUP_PRIVACY_STATE = {
#
# The group is considered to be public. Anyone may join the group using the Chat ID.
#
# If the group is in this state, even if the Chat ID is never explicitly shared
# with someone outside of the group, information including the Chat ID, IP addresses,
# and peer ID's (but not Tox ID's) is visible to anyone with access to a node
# storing a DHT entry for the given group.
#
'PUBLIC': 0,
#
# The group is considered to be private. The only way to join the group is by having
# someone in your contact list send you an invite.
#
# If the group is in this state, no group information (mentioned above) is present in the DHT;
# the DHT is not used for any purpose at all. If a public group is set to private,
# all DHT information related to the group will expire shortly.
#
'PRIVATE': 1
}
TOX_GROUP_ROLE = {
#
# May kick and ban all other peers as well as set their role to anything (except founder).
# Founders may also set the group password, toggle the privacy state, and set the peer limit.
#
'FOUNDER': 0,
#
# May kick, ban and set the user and observer roles for peers below this role.
# May also set the group topic.
#
'MODERATOR': 1,
#
# May communicate with other peers normally.
#
'USER': 2,
#
# May observe the group and ignore peers; may not communicate with other peers or with the group.
#
'OBSERVER': 3
}
TOX_ERR_GROUP_NEW = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_NEW_OK': 0,
#
# The group name exceeded TOX_GROUP_MAX_GROUP_NAME_LENGTH.
#
'TOX_ERR_GROUP_NEW_TOO_LONG': 1,
#
# group_name is NULL or length is zero.
#
'TOX_ERR_GROUP_NEW_EMPTY': 2,
#
# TOX_GROUP_PRIVACY_STATE is an invalid type.
#
'TOX_ERR_GROUP_NEW_PRIVACY': 3,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_NEW_INIT': 4,
#
# The group state failed to initialize. This usually indicates that something went wrong
# related to cryptographic signing.
#
'TOX_ERR_GROUP_NEW_STATE': 5,
#
# The group failed to announce to the DHT. This indicates a network related error.
#
'TOX_ERR_GROUP_NEW_ANNOUNCE': 6,
}
TOX_ERR_GROUP_JOIN = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_JOIN_OK': 0,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_JOIN_INIT': 1,
#
# The chat_id pointer is set to NULL or a group with chat_id already exists. This usually
# happens if the client attempts to create multiple sessions for the same group.
#
'TOX_ERR_GROUP_JOIN_BAD_CHAT_ID': 2,
#
# Password length exceeded TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_JOIN_TOO_LONG': 3,
}
TOX_ERR_GROUP_RECONNECT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_RECONNECT_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND': 1,
}
TOX_ERR_GROUP_LEAVE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_LEAVE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_GROUP_MAX_PART_LENGTH.
#
'TOX_ERR_GROUP_LEAVE_TOO_LONG': 2,
#
# The parting packet failed to send.
#
'TOX_ERR_GROUP_LEAVE_FAIL_SEND': 3,
#
# The group chat instance failed to be deleted. This may occur due to memory related errors.
#
'TOX_ERR_GROUP_LEAVE_DELETE_FAIL': 4,
}
TOX_ERR_GROUP_SELF_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND': 1,
}
TOX_ERR_GROUP_SELF_NAME_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_NAME_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND': 1,
#
# Name length exceeded 'TOX_MAX_NAME_LENGTH.
#
'TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG': 2,
#
# The length given to the set function is zero or name is a NULL pointer.
#
'TOX_ERR_GROUP_SELF_NAME_SET_INVALID': 3,
#
# The name is already taken by another peer in the group.
#
'TOX_ERR_GROUP_SELF_NAME_SET_TAKEN': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND': 5
}
TOX_ERR_GROUP_SELF_STATUS_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND': 1,
#
# An invalid type was passed to the set function.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_INVALID': 2,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND': 3
}
TOX_ERR_GROUP_PEER_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_PEER_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND': 2
}
TOX_ERR_GROUP_STATE_QUERIES = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_STATE_QUERIES_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_STATE_QUERIES_GROUP_NOT_FOUND': 1
}
TOX_ERR_GROUP_TOPIC_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_TOPIC_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND': 1,
#
# Topic length exceeded 'TOX_GROUP_MAX_TOPIC_LENGTH.
#
'TOX_ERR_GROUP_TOPIC_SET_TOO_LONG': 2,
#
# The caller does not have the required permissions to set the topic.
#
'TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS': 3,
#
# The packet could not be created. This error is usually related to cryptographic signing.
#
'TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND': 5
}
TOX_ERR_GROUP_SEND_MESSAGE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_MESSAGE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG': 2,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_MESSAGE_EMPTY': 3,
#
# The message type is invalid.
#
'TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE': 4,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS': 5,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND': 6
}
TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND': 2,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG': 3,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY': 4,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS': 5,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND': 6
}
TOX_ERR_GROUP_SEND_CUSTOM_PACKET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG': 2,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY': 3,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_PERMISSIONS': 4
}
TOX_ERR_GROUP_INVITE_FRIEND = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_INVITE_FRIEND_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND': 1,
#
# The friend number passed did not designate a valid friend.
#
'TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND': 2,
#
# Creation of the invite packet failed. This indicates a network related error.
#
'TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL': 3,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND': 4
}
TOX_ERR_GROUP_INVITE_ACCEPT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_OK': 0,
#
# The invite data is not in the expected format.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE': 1,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED': 2,
#
# Password length exceeded 'TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG': 3
}
TOX_GROUP_JOIN_FAIL = {
#
# You are using the same nickname as someone who is already in the group.
#
'TOX_GROUP_JOIN_FAIL_NAME_TAKEN': 0,
#
# The group peer limit has been reached.
#
'TOX_GROUP_JOIN_FAIL_PEER_LIMIT': 1,
#
# You have supplied an invalid password.
#
'TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD': 2,
#
# The join attempt failed due to an unspecified error. This often occurs when the group is
# not found in the DHT.
#
'TOX_GROUP_JOIN_FAIL_UNKNOWN': 3
}
TOX_ERR_GROUP_FOUNDER_SET_PASSWORD = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions to set the password.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS': 2,
#
# Password length exceeded 'TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_FAIL_SEND': 4
}
TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_GROUP_NOT_FOUND': 1,
#
# 'TOX_GROUP_PRIVACY_STATE is an invalid type.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_INVALID': 2,
#
# The caller does not have the required permissions to set the privacy state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS': 3,
#
# The privacy state could not be set. This may occur due to an error related to
# cryptographic signing of the new shared state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SET': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SEND': 5
}
TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions to set the peer limit.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS': 2,
#
# The peer limit could not be set. This may occur due to an error related to
# cryptographic signing of the new shared state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SET': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SEND': 4
}
TOX_ERR_GROUP_TOGGLE_IGNORE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_PEER_NOT_FOUND': 2
}
TOX_ERR_GROUP_MOD_SET_ROLE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer. Note: you cannot set your own role.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND': 2,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS': 3,
#
# The role assignment is invalid. This will occur if you try to set a peer's role to
# the role they already have.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT': 4,
#
# The role was not successfully set. This may occur if something goes wrong with role setting': ,
# or if the packet fails to send.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_FAIL_ACTION': 5
}
TOX_ERR_GROUP_MOD_REMOVE_PEER = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_PEER_NOT_FOUND': 2,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS': 3,
#
# The peer could not be removed from the group.
#
# If a ban was set': , this error indicates that the ban entry could not be created.
# This is usually due to the peer's IP address already occurring in the ban list. It may also
# be due to the entry containing invalid peer information': , or a failure to cryptographically
# authenticate the entry.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_FAIL_ACTION': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_FAIL_SEND': 5
}
TOX_ERR_GROUP_MOD_REMOVE_BAN = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS': 2,
#
# The ban entry could not be removed. This may occur if ban_id does not designate
# a valid ban entry.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_SEND': 4
}
TOX_GROUP_MOD_EVENT = {
#
# A peer has been kicked from the group.
#
'KICK': 0,
#
# A peer has been banned from the group.
#
'BAN': 1,
#
# A peer as been given the observer role.
#
'OBSERVER': 2,
#
# A peer has been given the user role.
#
'USER': 3,
#
# A peer has been given the moderator role.
#
'MODERATOR': 4,
}
TOX_ERR_GROUP_BAN_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_BAN_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_BAN_QUERY_GROUP_NOT_FOUND': 1,
#
# The ban_id does not designate a valid ban list entry.
#
'TOX_ERR_GROUP_BAN_QUERY_BAD_ID': 2,
}
TOX_GROUP_BAN_TYPE = {
'IP_PORT': 0,
'PUBLIC_KEY': 1,
'NICK': 2
}
TOX_PUBLIC_KEY_SIZE = 32
TOX_ADDRESS_SIZE = TOX_PUBLIC_KEY_SIZE + 6
TOX_MAX_FRIEND_REQUEST_LENGTH = 1016
TOX_MAX_MESSAGE_LENGTH = 1372
TOX_GROUP_MAX_TOPIC_LENGTH = 512
TOX_GROUP_MAX_PART_LENGTH = 128
TOX_GROUP_MAX_GROUP_NAME_LENGTH = 48
TOX_GROUP_MAX_PASSWORD_SIZE = 32
TOX_GROUP_CHAT_ID_SIZE = 32
TOX_GROUP_PEER_PUBLIC_KEY_SIZE = 32
TOX_MAX_NAME_LENGTH = 128
TOX_MAX_STATUS_MESSAGE_LENGTH = 1007
TOX_SECRET_KEY_SIZE = 32
TOX_FILE_ID_LENGTH = 32
TOX_HASH_LENGTH = 32
TOX_MAX_CUSTOM_PACKET_SIZE = 1373

75
wrapper/toxencryptsave.py Normal file
View File

@ -0,0 +1,75 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from ctypes import c_size_t, create_string_buffer, byref, c_int, ArgumentError, c_char_p, c_bool
from wrapper import libtox
from wrapper.toxencryptsave_enums_and_consts import *
class ToxEncryptSave:
def __init__(self):
self.libtoxencryptsave = libtox.LibToxEncryptSave()
def is_data_encrypted(self, data):
"""
Checks if given data is encrypted
"""
func = self.libtoxencryptsave.tox_is_data_encrypted
func.restype = c_bool
result = func(c_char_p(bytes(data)))
return result
def pass_encrypt(self, data, password):
"""
Encrypts the given data with the given password.
:return: output array
"""
out = create_string_buffer(len(data) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH)
tox_err_encryption = c_int()
self.libtoxencryptsave.tox_pass_encrypt(c_char_p(data),
c_size_t(len(data)),
c_char_p(bytes(password, 'utf-8')),
c_size_t(len(password)),
out,
byref(tox_err_encryption))
tox_err_encryption = tox_err_encryption.value
if tox_err_encryption == TOX_ERR_ENCRYPTION['OK']:
return out[:]
elif tox_err_encryption == TOX_ERR_ENCRYPTION['NULL']:
raise ArgumentError('Some input data, or maybe the output pointer, was null.')
elif tox_err_encryption == TOX_ERR_ENCRYPTION['KEY_DERIVATION_FAILED']:
raise RuntimeError('The crypto lib was unable to derive a key from the given passphrase, which is usually a'
' lack of memory issue. The functions accepting keys do not produce this error.')
elif tox_err_encryption == TOX_ERR_ENCRYPTION['FAILED']:
raise RuntimeError('The encryption itself failed.')
def pass_decrypt(self, data, password):
"""
Decrypts the given data with the given password.
:return: output array
"""
out = create_string_buffer(len(data) - TOX_PASS_ENCRYPTION_EXTRA_LENGTH)
tox_err_decryption = c_int()
self.libtoxencryptsave.tox_pass_decrypt(c_char_p(bytes(data)),
c_size_t(len(data)),
c_char_p(bytes(password, 'utf-8')),
c_size_t(len(password)),
out,
byref(tox_err_decryption))
tox_err_decryption = tox_err_decryption.value
if tox_err_decryption == TOX_ERR_DECRYPTION['OK']:
return out[:]
elif tox_err_decryption == TOX_ERR_DECRYPTION['NULL']:
raise ArgumentError('Some input data, or maybe the output pointer, was null.')
elif tox_err_decryption == TOX_ERR_DECRYPTION['INVALID_LENGTH']:
raise ArgumentError('The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes')
elif tox_err_decryption == TOX_ERR_DECRYPTION['BAD_FORMAT']:
raise ArgumentError('The input data is missing the magic number (i.e. wasn\'t created by this module, or is'
' corrupted)')
elif tox_err_decryption == TOX_ERR_DECRYPTION['KEY_DERIVATION_FAILED']:
raise RuntimeError('The crypto lib was unable to derive a key from the given passphrase, which is usually a'
' lack of memory issue. The functions accepting keys do not produce this error.')
elif tox_err_decryption == TOX_ERR_DECRYPTION['FAILED']:
raise RuntimeError('The encrypted byte array could not be decrypted. Either the data was corrupt or the '
'password/key was incorrect.')

View File

@ -0,0 +1,29 @@
TOX_ERR_ENCRYPTION = {
# The function returned successfully.
'OK': 0,
# Some input data, or maybe the output pointer, was null.
'NULL': 1,
# The crypto lib was unable to derive a key from the given passphrase, which is usually a lack of memory issue. The
# functions accepting keys do not produce this error.
'KEY_DERIVATION_FAILED': 2,
# The encryption itself failed.
'FAILED': 3
}
TOX_ERR_DECRYPTION = {
# The function returned successfully.
'OK': 0,
# Some input data, or maybe the output pointer, was null.
'NULL': 1,
# The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes
'INVALID_LENGTH': 2,
# The input data is missing the magic number (i.e. wasn't created by this module, or is corrupted)
'BAD_FORMAT': 3,
# The crypto lib was unable to derive a key from the given passphrase, which is usually a lack of memory issue. The
# functions accepting keys do not produce this error.
'KEY_DERIVATION_FAILED': 4,
# The encrypted byte array could not be decrypted. Either the data was corrupt or the password/key was incorrect.
'FAILED': 5,
}
TOX_PASS_ENCRYPTION_EXTRA_LENGTH = 80