This commit is contained in:
emdee 2022-09-27 16:02:36 +00:00
parent 870e3125ad
commit a365b7d54c
9 changed files with 166 additions and 123 deletions

View File

@ -21,6 +21,7 @@ LOG = logging.getLogger('app.'+__name__)
TIMER_TIMEOUT = 30.0
bSTREAM_CALLBACK = False
iFPS = 25
class AV(common.tox_save.ToxAvSave):
@ -56,7 +57,7 @@ class AV(common.tox_save.ToxAvSave):
self._video = None
self._video_thread = None
self._video_running = False
self._video_running = None
self._video_width = 320
self._video_height = 240
@ -278,12 +279,7 @@ class AV(common.tox_save.ToxAvSave):
self._video_width = s['video']['width']
self._video_height = s['video']['height']
LOG.info("start_video_thread " \
+f" device: {s['video']['device']}" \
+f" supported: {s['video']['width']} {s['video']['height']}")
s['video']['device'] = -1
if s['video']['device'] == -1:
if True or s['video']['device'] == -1:
self._video = screen_sharing.DesktopGrabber(s['video']['x'],
s['video']['y'],
s['video']['width'],
@ -291,11 +287,24 @@ class AV(common.tox_save.ToxAvSave):
else:
with ts.ignoreStdout():
import cv2
if s['video']['device'] == 0:
# webcam
self._video = cv2.VideoCapture(s['video']['device'], cv2.DSHOW)
else:
self._video = cv2.VideoCapture(s['video']['device'])
self._video.set(cv2.CAP_PROP_FPS, 25)
self._video.set(cv2.CAP_PROP_FRAME_WIDTH, self._video_width)
self._video.set(cv2.CAP_PROP_FRAME_HEIGHT, self._video_height)
self._video.set(cv2.CAP_PROP_FPS, iFPS)
self._video.set(cv2.CAP_PROP_FRAME_WIDTH, self._video_width)
self._video.set(cv2.CAP_PROP_FRAME_HEIGHT, self._video_height)
# self._video.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
if self._video is None:
LOG.error("start_video_thread " \
+f" device: {s['video']['device']}" \
+f" supported: {s['video']['width']} {s['video']['height']}")
return
LOG.info("start_video_thread " \
+f" device: {s['video']['device']}" \
+f" supported: {s['video']['width']} {s['video']['height']}")
self._video_running = True
self._video_thread = BaseThread(target=self.send_video,
name='_video_thread')
@ -345,15 +354,15 @@ class AV(common.tox_save.ToxAvSave):
output_device_index=iOutput,
output=True)
except Exception as e:
LOG.error(f"Error playing audio_chunk creating self._out_stream {e}")
LOG.debug(f"audio_chunk output_device_index={self._settings._args.audio['input']} rate={rate} channels={channels_count}")
invoke_in_main_thread(util_ui.message_box,
LOG.error(f"Error playing audio_chunk creating self._out_stream {e}")
invoke_in_main_thread(util_ui.message_box,
str(e),
util_ui.tr("Error Chunking audio"))
# dunno
self.stop()
return
# dunno
self.stop()
return
LOG.debug(f"audio_chunk output_device_index={self._settings._args.audio['input']} rate={rate} channels={channels_count}")
self._out_stream.write(samples)
# -----------------------------------------------------------------------------------------------------------------
@ -410,29 +419,42 @@ class AV(common.tox_save.ToxAvSave):
"""
This method sends video to friends
"""
LOG.debug(f"send_video thread={threading.current_thread()}"
LOG.debug(f"send_video thread={threading.current_thread().name}"
+f" self._video_running={self._video_running}"
+f" device: {self._settings['video']['device']}" )
while self._video_running:
try:
result, frame = self._video.read()
if result:
LOG.warn(f"send_video video_send_frame _video.read")
if not result:
LOG.warn(f"send_video video_send_frame _video.read result={result}")
break
if frame is None:
LOG.warn(f"send_video video_send_frame _video.read result={result} frame={frame}")
continue
else:
LOG.debug(f"send_video video_send_frame _video.read result={result}")
height, width, channels = frame.shape
friends = []
for friend_num in self._calls:
if self._calls[friend_num].out_video:
try:
y, u, v = self.convert_bgr_to_yuv(frame)
self._toxav.video_send_frame(friend_num, width, height, y, u, v)
except Exception as e:
LOG.debug(f"send_video video_send_frame ERROR {e}")
pass
friends.append(friend_num)
if len(friends) == 0:
LOG.warn(f"send_video video_send_frame no friends")
else:
LOG.debug(f"send_video video_send_frame {friends}")
friend_num = friends[0]
try:
y, u, v = self.convert_bgr_to_yuv(frame)
self._toxav.video_send_frame(friend_num, width, height, y, u, v)
except Exception as e:
LOG.debug(f"send_video video_send_frame ERROR {e}")
pass
except:
except Exception as e:
LOG.error(f"send_video video_send_frame {e}")
pass
sleep(0.1)
sleep( 1.0/iFPS)
def convert_bgr_to_yuv(self, frame):
"""

View File

@ -1,4 +1,7 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import traceback
from contacts.friend import Friend
from contacts.group_chat import GroupChat
from messenger.messages import *
@ -11,6 +14,8 @@ import logging
LOG = logging.getLogger('app.'+__name__)
log = lambda x: LOG.info(x)
UINT32_MAX = 2 ** 32 -1
class ContactsManager(ToxSave):
"""
Represents contacts list.
@ -21,6 +26,7 @@ class ContactsManager(ToxSave):
super().__init__(tox)
self._settings = settings
self._screen = screen
self._ms = screen
self._profile_manager = profile_manager
self._contact_provider = contact_provider
self._tox_dns = tox_dns
@ -34,6 +40,8 @@ class ContactsManager(ToxSave):
self._history = history
self._load_contacts()
def _log(self, s): self._ms(s)
def get_contact(self, num):
if num < 0 or num >= len(self._contacts):
return None
@ -106,6 +114,7 @@ class ContactsManager(ToxSave):
current_contact.curr_text = self._screen.messageEdit.toPlainText()
except:
pass
# IndexError: list index out of range
contact = self._contacts[value]
self._subscribe_to_events(contact)
contact.remove_invalid_unsent_files()
@ -137,7 +146,7 @@ class ContactsManager(ToxSave):
except Exception as ex: # no friend found. ignore
LOG.warn(f"no friend found. Friend value: {value!s}")
LOG.error('in set active: ' + str(ex))
raise
# gulp raise
active_contact = property(get_active, set_active)
@ -322,7 +331,7 @@ class ContactsManager(ToxSave):
Block user with specified tox id (or public key) - delete from friends list and ignore friend requests
"""
tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2]
if tox_id == self._tox.self_get_address[:TOX_PUBLIC_KEY_SIZE * 2]:
if tox_id == self._tox.self_get_address()[:TOX_PUBLIC_KEY_SIZE * 2]:
return
if tox_id not in self._settings['blocked']:
self._settings['blocked'].append(tox_id)
@ -424,26 +433,36 @@ class ContactsManager(ToxSave):
"""
try:
message = message or 'Hello! Add me to your contact list please'
if '@' in tox_id: # value like groupbot@toxme.io
tox_id = self._tox_dns.lookup(tox_id)
if tox_id is None:
raise Exception('TOX DNS lookup failed')
if len(tox_id) == TOX_PUBLIC_KEY_SIZE * 2: # public key
self.add_friend(tox_id)
title = util_ui.tr('Friend added')
text = util_ui.tr('Friend added without sending friend request')
util_ui.message_box(text, title)
title = 'Friend added'
text = 'Friend added without sending friend request'
else:
self._tox.friend_add(tox_id, message.encode('utf-8'))
tox_id = tox_id[:TOX_PUBLIC_KEY_SIZE * 2]
self._add_friend(tox_id)
self.update_filtration()
self.save_profile()
return True
num = self._tox.friend_add(tox_id, message.encode('utf-8'))
if num < UINT32_MAX:
tox_pk = tox_id[:TOX_PUBLIC_KEY_SIZE * 2]
self._add_friend(tox_pk)
self.update_filtration()
title = 'Friend added'
text = 'Friend added by sending friend request'
self.save_profile()
retval = True
else:
title = 'Friend failed'
text = 'Friend failed sending friend request'
retval = text
except Exception as ex: # wrong data
LOG.error('Friend request failed with ' + str(ex))
return str(ex)
title = 'Friend add exception'
text = 'Friend request exception with ' + str(ex)
self._log(text)
LOG.error(traceback.format_exc())
retval = str(ex)
title = util_ui.tr(title)
text = util_ui.tr(text)
util_ui.message_box(text, title)
return retval
def process_friend_request(self, tox_id, message):
"""
Accept or ignore friend request

BIN
toxygen/images/icon.xcf Normal file

Binary file not shown.

View File

@ -29,7 +29,6 @@ from user_data.settings import *
from user_data.settings import Settings
from user_data import settings
import utils.util as util
from tests import omain
with ts.ignoreStderr():
import pyaudio
@ -95,7 +94,7 @@ def setup_audio(oArgs):
global oPYA
audio = setup_default_audio()
for k,v in audio['input_devices'].items():
if v == 'default' and 'input' not in audio :
if v == 'default' and 'input' not in audio:
audio['input'] = k
if v == getattr(oArgs, 'audio_input'):
audio['input'] = k
@ -272,7 +271,7 @@ def main_parser():
parser.add_argument('--download_nodes_url', type=str,
default='https://nodes.tox.chat/json')
parser.add_argument('--network', type=str,
choices=['main', 'new', 'local', 'newlocal'],
choices=['old', 'new', 'local', 'newlocal'],
default='new')
parser.add_argument('--video_input', type=str,
default=-1,
@ -303,43 +302,34 @@ def main_parser():
# clean out the unchanged settings so these can override the profile
lKEEP_SETTINGS = ['uri',
'profile',
'loglevel',
'logfile',
'mode',
'audio',
'video',
'ipv6_enabled',
'udp_enabled',
'local_discovery_enabled',
'theme',
'network',
'message_font_size',
'font',
'save_history',
'language',
'update',
'proxy_host',
'proxy_type',
'proxy_port',
'core_logging',
'audio',
'video'
] # , 'nodes_json'
lBOOLEANS = [
'local_discovery_enabled',
'udp_enabled',
'ipv6_enabled',
'compact_mode',
'allow_inline',
'notifications',
'sound_notifications',
'hole_punching_enabled',
'dht_announcements_enabled',
'save_history',
'download_nodes_list'
'core_logging',
]
'profile',
'loglevel',
'logfile',
'mode',
# dunno
'audio_input',
'audio_output',
'audio',
'video',
'ipv6_enabled',
'udp_enabled',
'local_discovery_enabled',
'theme',
'network',
'message_font_size',
'font',
'save_history',
'language',
'update',
'proxy_host',
'proxy_type',
'proxy_port',
'core_logging',
'audio',
'video'
] # , 'nodes_json'
class A(): pass
@ -373,7 +363,7 @@ def main(lArgs):
if getattr(default_ns, key) == getattr(oArgs, key):
delattr(oArgs, key)
for key in lBOOLEANS:
for key in ts.lBOOLEANS:
if not hasattr(oArgs, key): continue
val = getattr(oArgs, key)
if type(val) == bool: continue
@ -385,15 +375,15 @@ def main(lArgs):
aArgs = A()
for key in oArgs.__dict__.keys():
setattr(aArgs, key, getattr(oArgs, key))
setattr(aArgs, 'video', setup_video(oArgs))
#setattr(aArgs, 'video', setup_video(oArgs))
aArgs.video = setup_video(oArgs)
assert 'video' in aArgs.__dict__
setattr(aArgs, 'audio', setup_audio(oArgs))
#setattr(aArgs, 'audio', setup_audio(oArgs))
aArgs.audio = setup_audio(oArgs)
assert 'audio' in aArgs.__dict__
oArgs = aArgs
toxygen = app.App(__version__, oArgs)
global oAPP
oAPP = toxygen

View File

@ -1,4 +1,5 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import sys
import os
import threading
from PyQt5 import QtGui
@ -13,10 +14,10 @@ from notifications.sound import *
from datetime import datetime
iMAX_INT32 = 4294967295
def LOG_ERROR(l): print('ERRORc: '+l)
def LOG_WARN(l): print('WARNc: '+l)
def LOG_INFO(l): print('INFOc: '+l)
def LOG_DEBUG(l): print('DEBUGc: '+l)
def LOG_ERROR(l): print('EROR< '+l)
def LOG_WARN(l): print('WARN< '+l)
def LOG_INFO(l): print('INFO< '+l)
def LOG_DEBUG(l): print('DBUG< '+l)
def LOG_TRACE(l): pass # print('TRACE+ '+l)
global aTIMES
@ -45,6 +46,7 @@ def bTooSoon(key, sSlot, fSec=10.0):
global iBYTES
iBYTES=0
def sProcBytes(sFile=None):
if sys.platform == 'win32': return ''
global iBYTES
if sFile is None:
pid = os.getpid()
@ -69,13 +71,11 @@ def self_connection_status(tox, profile):
"""
Current user changed connection status (offline, TCP, UDP)
"""
pid = os.getpid()
sFile = '/proc/'+str(pid) +'/net/softnet_stat'
sSlot = 'self connection status'
def wrapped(tox_link, connection, user_data):
key = f"connection {connection}"
if bTooSoon(key, sSlot, 10): return
s = sProcBytes(sFile)
s = sProcBytes()
try:
status = tox.self_get_status() if connection != TOX_CONNECTION['NONE'] else None
if status:
@ -148,10 +148,10 @@ def friend_name(contacts_provider, messenger):
"""
key = f"friend_number={friend_number}"
if bTooSoon(key, sSlot, 60): return
LOG_DEBUG(f'New name friend #' + str(friend_number))
friend = contacts_provider.get_friend_by_number(friend_number)
old_name = friend.name
new_name = str(name, 'utf-8')
LOG_DEBUG(f"get_friend_by_number #{friend_number} {new_name}")
invoke_in_main_thread(friend.set_name, new_name)
invoke_in_main_thread(messenger.new_friend_name, friend, old_name, new_name)
@ -364,7 +364,7 @@ def callback_audio(calls_manager):
New audio chunk
"""
LOG_DEBUG(f"callback_audio #{friend_number}")
# guessing was .call
# dunno was .call
calls_manager._call.audio_chunk(
bytes(samples[:audio_samples_per_channel * 2 * audio_channels_count]),
audio_channels_count,
@ -401,7 +401,7 @@ def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, u
It can be created from initial y, u, v using slices
"""
LOG_DEBUG(f"video_receive_frame from {friend_number}")
LOG_DEBUG(f"video_receive_frame from toxav_video_receive_frame_cb={friend_number}")
import cv2
import numpy as np
try:
@ -480,7 +480,8 @@ def group_private_message(window, tray, tox, messenger, settings, profile):
if settings['sound_notifications'] and bl and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
icon = util.join_path(util.get_images_directory(), 'icon_new_messages.png')
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
if tray and hasattr(tray, 'setIcon'):
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
return wrapped
@ -507,7 +508,10 @@ def group_invite(window, settings, tray, profile, groups_service, contacts_provi
def group_self_join(contacts_provider, contacts_manager, groups_service):
sSlot = 'group_self_join'
def wrapped(tox, group_number, user_data):
key = f"group_number {group_number}"
if bTooSoon(key, sSlot, 10): return
LOG_DEBUG(f"group_self_join #{group_number}")
group = contacts_provider.get_group_by_number(group_number)
invoke_in_main_thread(group.set_status, TOX_USER_STATUS['NONE'])
@ -535,11 +539,18 @@ def group_peer_join(contacts_provider, groups_service):
def group_peer_exit(contacts_provider, groups_service, contacts_manager):
def wrapped(tox, group_number, peer_id, message, length, user_data):
LOG_DEBUG(f"group_peer_exit #{group_number} peer_id={peer_id}")
def wrapped(tox,
group_number, peer_id,
exit_type, name, name_length,
message, length,
user_data):
group = contacts_provider.get_group_by_number(group_number)
group.remove_peer(peer_id)
invoke_in_main_thread(groups_service.generate_peers_list)
if group:
LOG_DEBUG(f"group_peer_exit #{group_number} peer_id={peer_id} exit_type={exit_type}")
group.remove_peer(peer_id)
invoke_in_main_thread(groups_service.generate_peers_list)
else:
LOG_WARN(f"group_peer_exit group not found #{group_number} peer_id={peer_id}")
return wrapped
@ -700,9 +711,6 @@ def init_callbacks(tox, profile, settings, plugin_loader, contacts_manager,
:param groups_service: GroupsService instance
:param contacts_provider: ContactsProvider instance
"""
global LOG
import logging
LOG = logging.getLogger('app.'+__name__)
# self callbacks
tox.callback_self_connection_status(self_connection_status(tox, profile))

View File

@ -30,10 +30,10 @@ import logging
LOG = logging.getLogger('app.'+'threads')
# log = lambda x: LOG.info(x)
def LOG_ERROR(l): print('ERRORt: '+l)
def LOG_WARN(l): print('WARNt: '+l)
def LOG_INFO(l): print('INFOt: '+l)
def LOG_DEBUG(l): print('DEBUGt: '+l)
def LOG_ERROR(l): print('EROR+ '+l)
def LOG_WARN(l): print('WARN+ '+l)
def LOG_INFO(l): print('INFO+ '+l)
def LOG_DEBUG(l): print('DBUG+ '+l)
def LOG_TRACE(l): pass # print('TRACE+ '+l)
# -----------------------------------------------------------------------------------------------------------------
@ -148,8 +148,9 @@ class ToxIterateThread(BaseQThread):
self._tox.iterate()
except Exception as e:
# Fatal Python error: Segmentation fault
LOG_ERROR('ToxIterateThread run: {e}')
sleep(iMsec / 1000)
LOG_ERROR(f"ToxIterateThread run: {e}")
else:
sleep(iMsec / 1000)
class ToxAVIterateThread(BaseQThread):

View File

@ -9,8 +9,9 @@ import os
global LOG
import logging
LOG = logging.getLogger('app.'+'tox_factory')
def LOG_DEBUG(l): print('DEBUGf: '+l)
def LOG_LOG(l): print('TRACf: '+l)
def LOG_INFO(l): print('DBUG> '+l)
def LOG_DEBUG(l): print('DBUG> '+l)
def LOG_LOG(l): print('TRAC> '+l)
from ctypes import *
from utils import util
@ -32,8 +33,7 @@ def tox_log_cb(iTox, level, file, line, func, message, *args):
# root WARNING 3network.c#944:b'send_packet'attempted to send message with network family 10 (probably IPv6) on IPv4 socket
if file == 'network.c' and line == 944: return
message = f"{file}#{line}:{func} {message}"
LOG_LOG(# 'TRAC: ' +
message)
LOG_LOG(message)
def tox_factory(data=None, settings=None, args=None, app=None):
"""

View File

@ -12,7 +12,7 @@ from user_data.settings import Settings
iMAX = 70
global LOG
LOG = logging.getLogger('app.'+__name__)
LOG = logging.getLogger('app.'+'mains')
class QTextEditLogger(logging.Handler):
def __init__(self, parent, app):
@ -190,7 +190,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.menuSettings.addAction(self.actionNetwork)
self.menuSettings.addAction(self.audioSettings)
self.menuSettings.addAction(self.videoSettings)
self.menuSettings.addAction(self.updateSettings)
## self.menuSettings.addAction(self.updateSettings)
self.menuPlugins.addAction(self.pluginData)
self.menuPlugins.addAction(self.importPlugin)
self.menuPlugins.addAction(self.reloadPlugins)
@ -221,7 +221,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.actionNotifications.triggered.connect(self.notification_settings)
self.audioSettings.triggered.connect(self.audio_settings)
self.videoSettings.triggered.connect(self.video_settings)
self.updateSettings.triggered.connect(self.update_settings)
## self.updateSettings.triggered.connect(self.update_settings)
self.pluginData.triggered.connect(self.plugins_menu)
self.lockApp.triggered.connect(self.lock_app)
self.importPlugin.triggered.connect(self.import_plugin)
@ -514,7 +514,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.peers_list.setGeometry(width * 3 // 4, 0, width - width * 3 // 4, self.height() - 155)
invites_button_visible = self.groupInvitesPushButton.isVisible()
LOG.debug(f"invites_button_visible={invites_button_visible}")
# LOG.debug(f"invites_button_visible={invites_button_visible}")
self.friends_list.setGeometry(0, 125 if invites_button_visible else 100,
270, self.height() - 150 if invites_button_visible else self.height() - 125)

View File

@ -400,6 +400,9 @@ class Settings(dict):
if key not in aArgs.__dict__: continue
val = aArgs.__dict__[key]
if val in ['0.0.0.0']: continue
if key in aArgs.__dict__ and key not in info:
# dunno = network
continue
if key in aArgs.__dict__ and info[key] != val:
aRet[key] = val
return aRet