Compare commits
2 commits
dda2a9147a
...
d9ef18631d
Author | SHA1 | Date | |
---|---|---|---|
|
d9ef18631d | ||
|
76ad2ccd44 |
18 changed files with 211 additions and 133 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,7 +2,6 @@
|
||||||
.pylint.out
|
.pylint.out
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
*.bak
|
|
||||||
|
|
||||||
toxygen/toxcore
|
toxygen/toxcore
|
||||||
tests/tests
|
tests/tests
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
# usually this is installed by your OS package manager and pip may not
|
# usually this is installed by your OS package manager and pip may not
|
||||||
# detect the right version, so we leave these commented
|
# detect the right version, so we leave these commented
|
||||||
# PyQt5 >= 5.15.10
|
# PyQt5 >= 5.15.10
|
||||||
|
# this is not on pypi yet but is required - get it from
|
||||||
|
# https://git.plastiras.org/emdee/toxygen_wrapper
|
||||||
|
# toxygen_wrapper == 1.0.0
|
||||||
QtPy >= 2.4.1
|
QtPy >= 2.4.1
|
||||||
PyAudio >= 0.2.13
|
PyAudio >= 0.2.13
|
||||||
numpy >= 1.26.1
|
numpy >= 1.26.1
|
||||||
|
@ -17,6 +20,7 @@ sounddevice >= 0.3.15
|
||||||
coloredlogs >= 15.0.1
|
coloredlogs >= 15.0.1
|
||||||
# this is optional
|
# this is optional
|
||||||
# qtconsole >= 5.4.3
|
# qtconsole >= 5.4.3
|
||||||
# this is not on pypi yet - get it from
|
# this is not on pypi yet but is optional for qweechat - get it from
|
||||||
# https://git.plastiras.org/emdee/toxygen_wrapper
|
# https://git.plastiras.org/emdee/qweechat
|
||||||
# toxygen_wrapper == 1.0.0
|
# qweechat_wrapper == 0.0.1
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
path = os.path.dirname(os.path.realpath(__file__)) # curr dir
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(path, 'styles'))
|
|
||||||
sys.path.insert(0, os.path.join(path, 'plugins'))
|
|
||||||
sys.path.insert(0, os.path.join(path, 'third_party'))
|
|
||||||
sys.path.insert(0, path)
|
|
||||||
|
|
|
@ -37,6 +37,12 @@ with ts.ignoreStderr():
|
||||||
__maintainer__ = 'Ingvar'
|
__maintainer__ = 'Ingvar'
|
||||||
__version__ = '1.0.0' # was 0.5.0+
|
__version__ = '1.0.0' # was 0.5.0+
|
||||||
|
|
||||||
|
path = os.path.dirname(os.path.realpath(__file__)) # curr dir
|
||||||
|
sys.path.insert(0, os.path.join(path, 'styles'))
|
||||||
|
sys.path.insert(0, os.path.join(path, 'plugins'))
|
||||||
|
sys.path.insert(0, os.path.join(path, 'third_party'))
|
||||||
|
sys.path.insert(0, path)
|
||||||
|
|
||||||
sleep = time.sleep
|
sleep = time.sleep
|
||||||
|
|
||||||
os.environ['QT_API'] = os.environ.get('QT_API', 'pyqt5')
|
os.environ['QT_API'] = os.environ.get('QT_API', 'pyqt5')
|
||||||
|
|
|
@ -839,14 +839,15 @@ class App:
|
||||||
|
|
||||||
def loop(self, n) -> None:
|
def loop(self, n) -> None:
|
||||||
"""
|
"""
|
||||||
Im guessings - there are 3 sleeps - time, tox, and Qt
|
Im guessing - there are 4 sleeps - time, tox, and Qt gevent
|
||||||
"""
|
"""
|
||||||
interval = self._tox.iteration_interval()
|
interval = self._tox.iteration_interval()
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
self._tox.iterate()
|
self._tox.iterate()
|
||||||
QtCore.QThread.msleep(interval)
|
QtCore.QThread.msleep(interval)
|
||||||
# NO QtCore.QCoreApplication.processEvents()
|
# NO?
|
||||||
sleep(interval / 1000.0)
|
QtCore.QCoreApplication.processEvents()
|
||||||
|
# sleep(interval / 1000.0)
|
||||||
|
|
||||||
def _test_tox(self) -> None:
|
def _test_tox(self) -> None:
|
||||||
self.test_net(iMax=8)
|
self.test_net(iMax=8)
|
||||||
|
@ -918,7 +919,6 @@ class App:
|
||||||
LOG.info(f"Connected # {i}" +' : ' +repr(status))
|
LOG.info(f"Connected # {i}" +' : ' +repr(status))
|
||||||
break
|
break
|
||||||
LOG.trace(f"Connected status #{i}: {status}")
|
LOG.trace(f"Connected status #{i}: {status}")
|
||||||
self.loop(2)
|
|
||||||
|
|
||||||
def _test_env(self) -> None:
|
def _test_env(self) -> None:
|
||||||
_settings = self._settings
|
_settings = self._settings
|
||||||
|
|
|
@ -16,7 +16,7 @@ import common.tox_save
|
||||||
from utils import ui as util_ui
|
from utils import ui as util_ui
|
||||||
import toxygen_wrapper.tests.support_testing as ts
|
import toxygen_wrapper.tests.support_testing as ts
|
||||||
from middleware.threads import invoke_in_main_thread
|
from middleware.threads import invoke_in_main_thread
|
||||||
from middleware.threads import BaseThread
|
from middleware.threads import BaseThread, BaseQThread
|
||||||
|
|
||||||
sleep = time.sleep
|
sleep = time.sleep
|
||||||
|
|
||||||
|
@ -25,9 +25,42 @@ import logging
|
||||||
LOG = logging.getLogger('app.'+__name__)
|
LOG = logging.getLogger('app.'+__name__)
|
||||||
|
|
||||||
TIMER_TIMEOUT = 30.0
|
TIMER_TIMEOUT = 30.0
|
||||||
bSTREAM_CALLBACK = False
|
|
||||||
iFPS = 25
|
iFPS = 25
|
||||||
|
|
||||||
|
class AudioThread(BaseQThread):
|
||||||
|
def __init__(self, av, name=''):
|
||||||
|
super().__init__()
|
||||||
|
self.av = av
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def join(self, ito=ts.iTHREAD_TIMEOUT):
|
||||||
|
LOG_DEBUG(f"AudioThread join {self}")
|
||||||
|
# dunno
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
LOG_DEBUG('AudioThread run: ')
|
||||||
|
# maybe not needed
|
||||||
|
while not self._stop_thread:
|
||||||
|
self.av.send_audio()
|
||||||
|
sleep(100.0 / 1000.0)
|
||||||
|
|
||||||
|
class VideoThread(BaseQThread):
|
||||||
|
def __init__(self, av, name=''):
|
||||||
|
super().__init__()
|
||||||
|
self.av = av
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def join(self, ito=ts.iTHREAD_TIMEOUT):
|
||||||
|
LOG_DEBUG(f"VideoThread join {self}")
|
||||||
|
# dunno
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
LOG_DEBUG('VideoThread run: ')
|
||||||
|
# maybe not needed
|
||||||
|
while not self._stop_thread:
|
||||||
|
self.av.send_video()
|
||||||
|
sleep(100.0 / 1000.0)
|
||||||
|
|
||||||
class AV(common.tox_save.ToxAvSave):
|
class AV(common.tox_save.ToxAvSave):
|
||||||
|
|
||||||
def __init__(self, toxav, settings):
|
def __init__(self, toxav, settings):
|
||||||
|
@ -71,10 +104,9 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
# was iOutput = self._settings._args.audio['output']
|
# was iOutput = self._settings._args.audio['output']
|
||||||
iInput = self._settings['audio']['input']
|
iInput = self._settings['audio']['input']
|
||||||
self.lPaSampleratesI = ts.lSdSamplerates(iInput)
|
self.lPaSampleratesI = ts.lSdSamplerates(iInput)
|
||||||
if not self.lPaSampleratesI: LOG.warn(f"empty self.lPaSampleratesI iInput={iInput}")
|
|
||||||
iOutput = self._settings['audio']['output']
|
iOutput = self._settings['audio']['output']
|
||||||
self.lPaSampleratesO = ts.lSdSamplerates(iOutput)
|
self.lPaSampleratesO = ts.lSdSamplerates(iOutput)
|
||||||
if not self.lPaSampleratesO: LOG.warn(f"empty self.lPaSampleratesO iOutput={iOutput}")
|
|
||||||
global oPYA
|
global oPYA
|
||||||
oPYA = self._audio = pyaudio.PyAudio()
|
oPYA = self._audio = pyaudio.PyAudio()
|
||||||
|
|
||||||
|
@ -113,8 +145,9 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
return self.call_accept_call(friend_number, audio_enabled, video_enabled)
|
return self.call_accept_call(friend_number, audio_enabled, video_enabled)
|
||||||
|
|
||||||
def call_accept_call(self, friend_number, audio_enabled, video_enabled):
|
def call_accept_call(self, friend_number, audio_enabled, video_enabled):
|
||||||
LOG.debug(f"call_accept_call from {friend_number} {self._running}" +
|
# called from CM.accept_call in a try:
|
||||||
f"{audio_enabled} {video_enabled}")
|
LOG.debug(f"call_accept_call from F={friend_number} R={self._running}" +
|
||||||
|
f" A={audio_enabled} V={video_enabled}")
|
||||||
# import pdb; pdb.set_trace() - gets into q Qt exec_ problem
|
# import pdb; pdb.set_trace() - gets into q Qt exec_ problem
|
||||||
# ts.trepan_handler()
|
# ts.trepan_handler()
|
||||||
|
|
||||||
|
@ -129,19 +162,18 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
self._audio_krate_tox_audio if audio_enabled else 0,
|
self._audio_krate_tox_audio if audio_enabled else 0,
|
||||||
self._audio_krate_tox_video if video_enabled else 0)
|
self._audio_krate_tox_video if video_enabled else 0)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.debug(f"AV accept_call error from {friend_number} {self._running} {e}")
|
LOG.error(f"AV accept_call error from {friend_number} {self._running} {e}")
|
||||||
raise
|
raise
|
||||||
if audio_enabled:
|
|
||||||
# may raise
|
|
||||||
self.start_audio_thread()
|
|
||||||
if video_enabled:
|
if video_enabled:
|
||||||
# may raise
|
# may raise
|
||||||
self.start_video_thread()
|
self.start_video_thread()
|
||||||
|
if audio_enabled:
|
||||||
|
LOG.debug(f"calls accept_call calling start_audio_thread F={friend_number}")
|
||||||
|
# may raise
|
||||||
|
self.start_audio_thread()
|
||||||
|
|
||||||
def finish_call(self, friend_number, by_friend=False):
|
def finish_call(self, friend_number, by_friend=False):
|
||||||
LOG.debug(f"finish_call {friend_number}")
|
LOG.debug(f"finish_call {friend_number}")
|
||||||
if not by_friend:
|
|
||||||
self._toxav.call_control(friend_number, TOXAV_CALL_CONTROL['CANCEL'])
|
|
||||||
if friend_number in self._calls:
|
if friend_number in self._calls:
|
||||||
del self._calls[friend_number]
|
del self._calls[friend_number]
|
||||||
try:
|
try:
|
||||||
|
@ -155,6 +187,10 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
# dunno
|
# dunno
|
||||||
self.stop_audio_thread()
|
self.stop_audio_thread()
|
||||||
self.stop_video_thread()
|
self.stop_video_thread()
|
||||||
|
if not by_friend:
|
||||||
|
LOG.debug(f"finish_call before call_control {friend_number}")
|
||||||
|
self._toxav.call_control(friend_number, TOXAV_CALL_CONTROL['CANCEL'])
|
||||||
|
LOG.debug(f"finish_call after call_control {friend_number}")
|
||||||
|
|
||||||
def finish_not_started_call(self, friend_number):
|
def finish_not_started_call(self, friend_number):
|
||||||
if friend_number in self:
|
if friend_number in self:
|
||||||
|
@ -184,11 +220,12 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
|
|
||||||
# Threads
|
# Threads
|
||||||
|
|
||||||
def start_audio_thread(self):
|
def start_audio_thread(self, bSTREAM_CALLBACK=False):
|
||||||
"""
|
"""
|
||||||
Start audio sending
|
Start audio sending
|
||||||
from a callback
|
from a callback
|
||||||
"""
|
"""
|
||||||
|
# called from call_accept_call in an try: from CM.accept_call
|
||||||
global oPYA
|
global oPYA
|
||||||
# was iInput = self._settings._args.audio['input']
|
# was iInput = self._settings._args.audio['input']
|
||||||
iInput = self._settings['audio']['input']
|
iInput = self._settings['audio']['input']
|
||||||
|
@ -199,7 +236,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
lPaSamplerates = ts.lSdSamplerates(iInput)
|
lPaSamplerates = ts.lSdSamplerates(iInput)
|
||||||
if not(len(lPaSamplerates)):
|
if not(len(lPaSamplerates)):
|
||||||
e = f"No sample rates for device: audio[input]={iInput}"
|
e = f"No sample rates for device: audio[input]={iInput}"
|
||||||
LOG_ERROR(f"start_audio_thread {e}")
|
LOG_WARN(f"start_audio_thread {e}")
|
||||||
#?? dunno - cancel call? - no let the user do it
|
#?? dunno - cancel call? - no let the user do it
|
||||||
# return
|
# return
|
||||||
# just guessing here in case that's a false negative
|
# just guessing here in case that's a false negative
|
||||||
|
@ -207,26 +244,28 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
if lPaSamplerates and self._audio_rate_pa in lPaSamplerates:
|
if lPaSamplerates and self._audio_rate_pa in lPaSamplerates:
|
||||||
pass
|
pass
|
||||||
elif lPaSamplerates:
|
elif lPaSamplerates:
|
||||||
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates}")
|
|
||||||
self._audio_rate_pa = lPaSamplerates[0]
|
|
||||||
LOG_WARN(f"Setting audio_rate to: {lPaSamplerates[0]}")
|
LOG_WARN(f"Setting audio_rate to: {lPaSamplerates[0]}")
|
||||||
|
self._audio_rate_pa = lPaSamplerates[0]
|
||||||
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iInput):
|
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iInput):
|
||||||
self._audio_rate_pa = oPYA.get_device_info_by_index(iInput)['defaultSampleRate']
|
self._audio_rate_pa = oPYA.get_device_info_by_index(iInput)['defaultSampleRate']
|
||||||
|
LOG_WARN(f"setting to defaultSampleRate")
|
||||||
else:
|
else:
|
||||||
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates}")
|
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates}")
|
||||||
# a float is in here - must it be int?
|
# a float is in here - must it be int?
|
||||||
if type(self._audio_rate_pa) == float:
|
if type(self._audio_rate_pa) == float:
|
||||||
self._audio_rate_pa = round(self._audio_rate_pa)
|
self._audio_rate_pa = round(self._audio_rate_pa)
|
||||||
try:
|
try:
|
||||||
LOG_DEBUG( f"start_audio_thread framerate: {self._audio_rate_pa}" \
|
|
||||||
+f" device: {iInput}"
|
|
||||||
+f" supported: {lPaSamplerates}")
|
|
||||||
if self._audio_rate_pa not in lPaSamplerates:
|
if self._audio_rate_pa not in lPaSamplerates:
|
||||||
LOG_WARN(f"PAudio sampling rate was {self._audio_rate_pa} changed to {lPaSamplerates[0]}")
|
LOG_WARN(f"PAudio sampling rate was {self._audio_rate_pa} changed to {lPaSamplerates[0]}")
|
||||||
LOG_DEBUG(f"lPaSamplerates={lPaSamplerates}")
|
LOG_DEBUG(f"lPaSamplerates={lPaSamplerates}")
|
||||||
self._audio_rate_pa = lPaSamplerates[0]
|
self._audio_rate_pa = lPaSamplerates[0]
|
||||||
|
else:
|
||||||
|
LOG_DEBUG( f"start_audio_thread framerate: {self._audio_rate_pa}" \
|
||||||
|
+f" device: {iInput}"
|
||||||
|
+f" supported: {lPaSamplerates}")
|
||||||
|
|
||||||
if bSTREAM_CALLBACK:
|
if bSTREAM_CALLBACK:
|
||||||
|
# why would you not call a thread?
|
||||||
self._audio_stream = oPYA.open(format=pyaudio.paInt16,
|
self._audio_stream = oPYA.open(format=pyaudio.paInt16,
|
||||||
rate=self._audio_rate_pa,
|
rate=self._audio_rate_pa,
|
||||||
channels=self._audio_channels,
|
channels=self._audio_channels,
|
||||||
|
@ -240,8 +279,8 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
self._audio_stream.stop_stream()
|
self._audio_stream.stop_stream()
|
||||||
self._audio_stream.close()
|
self._audio_stream.close()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
LOG_DEBUG( f"start_audio_thread starting thread {self._audio_rate_pa}")
|
||||||
self._audio_stream = oPYA.open(format=pyaudio.paInt16,
|
self._audio_stream = oPYA.open(format=pyaudio.paInt16,
|
||||||
rate=self._audio_rate_pa,
|
rate=self._audio_rate_pa,
|
||||||
channels=self._audio_channels,
|
channels=self._audio_channels,
|
||||||
|
@ -249,21 +288,24 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
input_device_index=iInput,
|
input_device_index=iInput,
|
||||||
frames_per_buffer=self._audio_sample_count_pa * 10)
|
frames_per_buffer=self._audio_sample_count_pa * 10)
|
||||||
self._audio_running = True
|
self._audio_running = True
|
||||||
self._audio_thread = BaseThread(target=self.send_audio,
|
self._audio_thread = AudioThread(self,
|
||||||
name='_audio_thread')
|
name='_audio_thread')
|
||||||
self._audio_thread.start()
|
self._audio_thread.start()
|
||||||
|
LOG_DEBUG( f"start_audio_thread started thread name='_audio_thread'")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(f"Starting self._audio.open {e}")
|
LOG_ERROR(f"Starting self._audio.open {e}")
|
||||||
LOG.debug(repr(dict(format=pyaudio.paInt16,
|
LOG_DEBUG(repr(dict(format=pyaudio.paInt16,
|
||||||
rate=self._audio_rate_pa,
|
rate=self._audio_rate_pa,
|
||||||
channels=self._audio_channels,
|
channels=self._audio_channels,
|
||||||
input=True,
|
input=True,
|
||||||
input_device_index=iInput,
|
input_device_index=iInput,
|
||||||
frames_per_buffer=self._audio_sample_count_pa * 10)))
|
frames_per_buffer=self._audio_sample_count_pa * 10)))
|
||||||
# catcher in place in calls_manager? not if from a callback
|
# catcher in place in calls_manager? yes accept_call
|
||||||
# calls_manager._call.toxav_call_state_cb(friend_number, mask)
|
# calls_manager._call.toxav_call_state_cb(friend_number, mask)
|
||||||
# raise RuntimeError(e)
|
invoke_in_main_thread(util_ui.message_box,
|
||||||
|
str(e),
|
||||||
|
util_ui.tr("Starting self._audio.open"))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
LOG_DEBUG(f"start_audio_thread {self._audio_stream}")
|
LOG_DEBUG(f"start_audio_thread {self._audio_stream}")
|
||||||
|
@ -274,6 +316,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
if self._audio_thread is None:
|
if self._audio_thread is None:
|
||||||
return
|
return
|
||||||
self._audio_running = False
|
self._audio_running = False
|
||||||
|
self._audio_thread._stop_thread = True
|
||||||
|
|
||||||
self._audio_thread = None
|
self._audio_thread = None
|
||||||
self._audio_stream = None
|
self._audio_stream = None
|
||||||
|
@ -306,8 +349,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
s['video']['width'],
|
s['video']['width'],
|
||||||
s['video']['height'])
|
s['video']['height'])
|
||||||
else:
|
else:
|
||||||
with ts.ignoreStdout():
|
with ts.ignoreStdout(): import cv2
|
||||||
import cv2
|
|
||||||
if s['video']['device'] == 0:
|
if s['video']['device'] == 0:
|
||||||
# webcam
|
# webcam
|
||||||
self._video = cv2.VideoCapture(s['video']['device'], cv2.DSHOW)
|
self._video = cv2.VideoCapture(s['video']['device'], cv2.DSHOW)
|
||||||
|
@ -327,7 +369,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
+f" supported: {s['video']['width']} {s['video']['height']}")
|
+f" supported: {s['video']['width']} {s['video']['height']}")
|
||||||
|
|
||||||
self._video_running = True
|
self._video_running = True
|
||||||
self._video_thread = BaseThread(target=self.send_video,
|
self._video_thread = VideoThread(self,
|
||||||
name='_video_thread')
|
name='_video_thread')
|
||||||
self._video_thread.start()
|
self._video_thread.start()
|
||||||
|
|
||||||
|
@ -336,6 +378,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
if self._video_thread is None:
|
if self._video_thread is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self._video_thread._stop_thread = True
|
||||||
self._video_running = False
|
self._video_running = False
|
||||||
i = 0
|
i = 0
|
||||||
while i < ts.iTHREAD_JOINS:
|
while i < ts.iTHREAD_JOINS:
|
||||||
|
@ -349,31 +392,31 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
LOG.warn("self._video_thread.is_alive BLOCKED")
|
LOG.warn("self._video_thread.is_alive BLOCKED")
|
||||||
self._video_thread = None
|
self._video_thread = None
|
||||||
self._video = None
|
self._video = None
|
||||||
|
|
||||||
# Incoming chunks
|
# Incoming chunks
|
||||||
|
|
||||||
def audio_chunk(self, samples, channels_count, rate) -> None:
|
def audio_chunk(self, samples, channels_count, rate) -> None:
|
||||||
"""
|
"""
|
||||||
Incoming chunk
|
Incoming chunk
|
||||||
"""
|
"""
|
||||||
|
# from callback
|
||||||
if self._out_stream is None:
|
if self._out_stream is None:
|
||||||
# was iOutput = self._settings._args.audio['output']
|
# was iOutput = self._settings._args.audio['output']
|
||||||
iOutput = self._settings['audio']['output']
|
iOutput = self._settings['audio']['output']
|
||||||
if self.lPaSampleratesO and rate in self.lPaSampleratesO:
|
if self.lPaSampleratesO and rate in self.lPaSampleratesO:
|
||||||
pass
|
LOG_DEBUG(f"Using rate {rate} in self.lPaSampleratesO")
|
||||||
elif self.lPaSampleratesO:
|
elif self.lPaSampleratesO:
|
||||||
LOG.warn(f"{rate} not in {self.lPaSampleratesO}")
|
LOG_WARN(f"{rate} not in {self.lPaSampleratesO}")
|
||||||
LOG.warn(f"Setting audio_rate to: {self.lPaSampleratesO[0]}")
|
LOG_WARN(f"Setting audio_rate to: {self.lPaSampleratesO[0]}")
|
||||||
rate = self.lPaSampleratesO[0]
|
rate = self.lPaSampleratesO[0]
|
||||||
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iOutput):
|
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iOutput):
|
||||||
rate = round(oPYA.get_device_info_by_index(iOutput)['defaultSampleRate'])
|
rate = round(oPYA.get_device_info_by_index(iOutput)['defaultSampleRate'])
|
||||||
LOG.warn(f"Setting rate to {rate} empty self.lPaSampleratesO")
|
LOG_WARN(f"Setting rate to {rate} empty self.lPaSampleratesO")
|
||||||
else:
|
else:
|
||||||
LOG.warn(f"Using rate {rate} empty self.lPaSampleratesO")
|
LOG_WARN(f"Using rate {rate} empty self.lPaSampleratesO")
|
||||||
if type(rate) == float:
|
if type(rate) == float:
|
||||||
rate = round(rate)
|
rate = round(rate)
|
||||||
|
# test output device?
|
||||||
|
# [Errno -9985] Device unavailable
|
||||||
try:
|
try:
|
||||||
with ts.ignoreStderr():
|
with ts.ignoreStderr():
|
||||||
self._out_stream = oPYA.open(format=pyaudio.paInt16,
|
self._out_stream = oPYA.open(format=pyaudio.paInt16,
|
||||||
|
@ -382,46 +425,53 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
output_device_index=iOutput,
|
output_device_index=iOutput,
|
||||||
output=True)
|
output=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(f"Error playing audio_chunk creating self._out_stream {e}")
|
LOG_ERROR(f"Error playing audio_chunk creating self._out_stream output_device_index={iOutput} {e}")
|
||||||
invoke_in_main_thread(util_ui.message_box,
|
invoke_in_main_thread(util_ui.message_box,
|
||||||
str(e),
|
str(e),
|
||||||
util_ui.tr("Error Chunking audio"))
|
util_ui.tr("Error Chunking audio"))
|
||||||
# dunno
|
# dunno
|
||||||
self.stop()
|
self.stop()
|
||||||
return
|
return
|
||||||
|
|
||||||
iOutput = self._settings['audio']['output']
|
iOutput = self._settings['audio']['output']
|
||||||
#trace LOG.debug(f"audio_chunk output_device_index={iOutput} rate={rate} channels={channels_count}")
|
#trace LOG_DEBUG(f"audio_chunk output_device_index={iOutput} rate={rate} channels={channels_count}")
|
||||||
self._out_stream.write(samples)
|
try:
|
||||||
|
self._out_stream.write(samples)
|
||||||
|
except Exception as e:
|
||||||
|
# OSError: [Errno -9999] Unanticipated host error
|
||||||
|
LOG_WARN(f"audio_chunk output_device_index={iOutput} {e}")
|
||||||
|
|
||||||
# AV sending
|
# AV sending
|
||||||
|
|
||||||
def send_audio_data(self, data, count, *largs, **kwargs) -> None:
|
def send_audio_data(self, data, count, *largs, **kwargs) -> None:
|
||||||
|
# callback
|
||||||
pcm = data
|
pcm = data
|
||||||
# :param sampling_rate: Audio sampling rate used in this frame.
|
# :param sampling_rate: Audio sampling rate used in this frame.
|
||||||
if self._toxav is None:
|
try:
|
||||||
raise RuntimeError("_toxav not initialized")
|
if self._toxav is None:
|
||||||
if self._audio_rate_tox not in ts.lToxSamplerates:
|
LOG_ERROR("_toxav not initialized")
|
||||||
LOG.warn(f"ToxAudio sampling rate was {self._audio_rate_tox} changed to {ts.lToxSamplerates[0]}")
|
return
|
||||||
self._audio_rate_tox = ts.lToxSamplerates[0]
|
if self._audio_rate_tox not in ts.lToxSamplerates:
|
||||||
|
LOG_WARN(f"ToxAudio sampling rate was {self._audio_rate_tox} changed to {ts.lToxSamplerates[0]}")
|
||||||
|
self._audio_rate_tox = ts.lToxSamplerates[0]
|
||||||
|
|
||||||
for friend_num in self._calls:
|
for friend_num in self._calls:
|
||||||
if self._calls[friend_num].out_audio:
|
if self._calls[friend_num].out_audio:
|
||||||
try:
|
|
||||||
# app.av.calls ERROR Error send_audio audio_send_frame: This client is currently not in a call with the friend.
|
# app.av.calls ERROR Error send_audio audio_send_frame: This client is currently not in a call with the friend.
|
||||||
self._toxav.audio_send_frame(friend_num,
|
self._toxav.audio_send_frame(friend_num,
|
||||||
pcm,
|
pcm,
|
||||||
count,
|
count,
|
||||||
self._audio_channels,
|
self._audio_channels,
|
||||||
self._audio_rate_tox)
|
self._audio_rate_tox)
|
||||||
except Exception as e:
|
ts)
|
||||||
LOG.error(f"Error send_audio audio_send_frame: {e}")
|
except Exception as e:
|
||||||
LOG.debug(f"send_audio self._audio_rate_tox={self._audio_rate_tox} self._audio_channels={self._audio_channels}")
|
LOG.error(f"Error send_audio_data audio_send_frame: {e}")
|
||||||
# invoke_in_main_thread(util_ui.message_box,
|
LOG.debug(f"send_audio_data self._audio_rate_tox={self._audio_rate_tox} self._audio_channels={self._audio_channels}")
|
||||||
# str(e),
|
self.stop_audio_thread()
|
||||||
# util_ui.tr("Error send_audio audio_send_frame"))
|
invoke_in_main_thread(util_ui.message_box,
|
||||||
# raise #? stop ? endcall?
|
str(e),
|
||||||
self.stop_audio_thread()
|
util_ui.tr("Error send_audio_data audio_send_frame"))
|
||||||
|
#? stop ? endcall?
|
||||||
|
|
||||||
def send_audio(self) -> None:
|
def send_audio(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -429,7 +479,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
"""
|
"""
|
||||||
i=0
|
i=0
|
||||||
count = self._audio_sample_count_tox
|
count = self._audio_sample_count_tox
|
||||||
LOG.debug(f"send_audio stream={self._audio_stream}")
|
LOG_DEBUG(f"send_audio stream={self._audio_stream}")
|
||||||
while self._audio_running:
|
while self._audio_running:
|
||||||
try:
|
try:
|
||||||
pcm = self._audio_stream.read(count, exception_on_overflow=False)
|
pcm = self._audio_stream.read(count, exception_on_overflow=False)
|
||||||
|
@ -448,17 +498,17 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
"""
|
"""
|
||||||
This method sends video to friends
|
This method sends video to friends
|
||||||
"""
|
"""
|
||||||
LOG.debug(f"send_video thread={threading.current_thread().name}"
|
# LOG_DEBUG(f"send_video thread={threading.current_thread().name}"
|
||||||
+f" self._video_running={self._video_running}"
|
# +f" self._video_running={self._video_running}"
|
||||||
+f" device: {self._settings['video']['device']}" )
|
# +f" device: {self._settings['video']['device']}" )
|
||||||
while self._video_running:
|
while self._video_running:
|
||||||
try:
|
try:
|
||||||
result, frame = self._video.read()
|
result, frame = self._video.read()
|
||||||
if not result:
|
if not result:
|
||||||
LOG.warn(f"send_video video_send_frame _video.read result={result}")
|
LOG_WARN(f"send_video video_send_frame _video.read result={result}")
|
||||||
break
|
break
|
||||||
if frame is None:
|
if frame is None:
|
||||||
LOG.warn(f"send_video video_send_frame _video.read result={result} frame={frame}")
|
LOG_WARN(f"send_video video_send_frame _video.read result={result} frame={frame}")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
LOG_TRACE(f"send_video video_send_frame _video.read result={result}")
|
LOG_TRACE(f"send_video video_send_frame _video.read result={result}")
|
||||||
|
@ -468,7 +518,7 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
if self._calls[friend_num].out_video:
|
if self._calls[friend_num].out_video:
|
||||||
friends.append(friend_num)
|
friends.append(friend_num)
|
||||||
if len(friends) == 0:
|
if len(friends) == 0:
|
||||||
LOG.warn(f"send_video video_send_frame no friends")
|
LOG_WARN(f"send_video video_send_frame no friends")
|
||||||
else:
|
else:
|
||||||
LOG_TRACE(f"send_video video_send_frame {friends}")
|
LOG_TRACE(f"send_video video_send_frame {friends}")
|
||||||
friend_num = friends[0]
|
friend_num = friends[0]
|
||||||
|
@ -476,11 +526,11 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
y, u, v = self.convert_bgr_to_yuv(frame)
|
y, u, v = self.convert_bgr_to_yuv(frame)
|
||||||
self._toxav.video_send_frame(friend_num, width, height, y, u, v)
|
self._toxav.video_send_frame(friend_num, width, height, y, u, v)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.debug(f"send_video video_send_frame ERROR {e}")
|
LOG_WARN(f"send_video video_send_frame ERROR {e}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(f"send_video video_send_frame {e}")
|
LOG_ERROR(f"send_video video_send_frame {e}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
sleep( 1.0/iFPS)
|
sleep( 1.0/iFPS)
|
||||||
|
@ -524,11 +574,12 @@ class AV(common.tox_save.ToxAvSave):
|
||||||
y = list(itertools.chain.from_iterable(y))
|
y = list(itertools.chain.from_iterable(y))
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
u = np.zeros((self._video_height // 2, self._video_width // 2), dtype=np.int)
|
# was np.int
|
||||||
|
u = np.zeros((self._video_height // 2, self._video_width // 2), dtype=np.int32)
|
||||||
u[::2, :] = frame[self._video_height:self._video_height * 5 // 4, :self._video_width // 2]
|
u[::2, :] = frame[self._video_height:self._video_height * 5 // 4, :self._video_width // 2]
|
||||||
u[1::2, :] = frame[self._video_height:self._video_height * 5 // 4, self._video_width // 2:]
|
u[1::2, :] = frame[self._video_height:self._video_height * 5 // 4, self._video_width // 2:]
|
||||||
u = list(itertools.chain.from_iterable(u))
|
u = list(itertools.chain.from_iterable(u))
|
||||||
v = np.zeros((self._video_height // 2, self._video_width // 2), dtype=np.int)
|
v = np.zeros((self._video_height // 2, self._video_width // 2), dtype=np.int32)
|
||||||
v[::2, :] = frame[self._video_height * 5 // 4:, :self._video_width // 2]
|
v[::2, :] = frame[self._video_height * 5 // 4:, :self._video_width // 2]
|
||||||
v[1::2, :] = frame[self._video_height * 5 // 4:, self._video_width // 2:]
|
v[1::2, :] = frame[self._video_height * 5 // 4:, self._video_width // 2:]
|
||||||
v = list(itertools.chain.from_iterable(v))
|
v = list(itertools.chain.from_iterable(v))
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from qtpy import QtCore
|
||||||
|
|
||||||
import av.calls
|
import av.calls
|
||||||
from messenger.messages import *
|
from messenger.messages import *
|
||||||
|
@ -11,7 +14,6 @@ import common.event as event
|
||||||
import utils.ui as util_ui
|
import utils.ui as util_ui
|
||||||
|
|
||||||
global LOG
|
global LOG
|
||||||
import logging
|
|
||||||
LOG = logging.getLogger('app.'+__name__)
|
LOG = logging.getLogger('app.'+__name__)
|
||||||
|
|
||||||
class CallsManager:
|
class CallsManager:
|
||||||
|
@ -63,7 +65,7 @@ class CallsManager:
|
||||||
"""
|
"""
|
||||||
Incoming call from friend.
|
Incoming call from friend.
|
||||||
"""
|
"""
|
||||||
LOG.debug(__name__ +f" incoming_call {friend_number}")
|
LOG.debug(f"CM incoming_call {friend_number}")
|
||||||
# if not self._settings['audio']['enabled']: return
|
# if not self._settings['audio']['enabled']: return
|
||||||
friend = self._contacts_manager.get_friend_by_number(friend_number)
|
friend = self._contacts_manager.get_friend_by_number(friend_number)
|
||||||
self._call_started_event(friend_number, audio, video, False)
|
self._call_started_event(friend_number, audio, video, False)
|
||||||
|
@ -83,11 +85,17 @@ class CallsManager:
|
||||||
Called from a thread
|
Called from a thread
|
||||||
"""
|
"""
|
||||||
|
|
||||||
LOG.debug(f"CM accept_call from {friend_number} {audio} {video}")
|
LOG.debug(f"CM accept_call from friend_number={friend_number} {audio} {video}")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self._main_screen.active_call()
|
||||||
|
# failsafe added somewhere this was being left up
|
||||||
|
self.close_call(friend_number)
|
||||||
|
QtCore.QCoreApplication.processEvents()
|
||||||
|
|
||||||
self._callav.call_accept_call(friend_number, audio, video)
|
self._callav.call_accept_call(friend_number, audio, video)
|
||||||
|
LOG.debug(f"accept_call _call.accept_call CALLED f={friend_number}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#
|
#
|
||||||
LOG.error(f"accept_call _call.accept_call ERROR for {friend_number} {e}")
|
LOG.error(f"accept_call _call.accept_call ERROR for {friend_number} {e}")
|
||||||
|
@ -112,46 +120,57 @@ class CallsManager:
|
||||||
LOG.warn(f"_settings not in self._main_screen")
|
LOG.warn(f"_settings not in self._main_screen")
|
||||||
util_ui.message_box(str(e),
|
util_ui.message_box(str(e),
|
||||||
util_ui.tr('ERROR Accepting call from {friend_number}'))
|
util_ui.tr('ERROR Accepting call from {friend_number}'))
|
||||||
else:
|
|
||||||
self._main_screen.active_call()
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# does not terminate call - just the av_widget
|
# does not terminate call - just the av_widget
|
||||||
if friend_number in self._incoming_calls:
|
LOG.debug(f"CM.accept_call close av_widget")
|
||||||
self._incoming_calls.remove(friend_number)
|
self.close_call(friend_number)
|
||||||
try:
|
LOG.debug(f" closed self._call_widgets[{friend_number}]")
|
||||||
|
|
||||||
|
def close_call(self, friend_number):
|
||||||
|
# refactored out from above because the accept window not getting
|
||||||
|
# taken down in some accept audio calls
|
||||||
|
LOG.debug(f"close_call {friend_number}")
|
||||||
|
try:
|
||||||
|
if friend_number in self._call_widgets:
|
||||||
self._call_widgets[friend_number].close()
|
self._call_widgets[friend_number].close()
|
||||||
del self._call_widgets[friend_number]
|
del self._call_widgets[friend_number]
|
||||||
except:
|
if friend_number in self._incoming_calls:
|
||||||
# RuntimeError: wrapped C/C++ object of type IncomingCallWidget has been deleted
|
self._incoming_calls.remove(friend_number)
|
||||||
|
except Exception as e:
|
||||||
|
# RuntimeError: wrapped C/C++ object of type IncomingCallWidget has been deleted
|
||||||
|
|
||||||
|
LOG.warn(f" closed self._call_widgets[{friend_number}] {e}")
|
||||||
|
# invoke_in_main_thread(QtCore.QCoreApplication.processEvents)
|
||||||
|
QtCore.QCoreApplication.processEvents()
|
||||||
|
|
||||||
pass
|
|
||||||
LOG.debug(f" closed self._call_widgets[{friend_number}]")
|
|
||||||
|
|
||||||
def stop_call(self, friend_number, by_friend):
|
def stop_call(self, friend_number, by_friend):
|
||||||
"""
|
"""
|
||||||
Stop call with friend
|
Stop call with friend
|
||||||
"""
|
"""
|
||||||
LOG.debug(__name__+f" stop_call {friend_number}")
|
LOG.debug(f"CM.stop_call friend={friend_number}")
|
||||||
if friend_number in self._incoming_calls:
|
if friend_number in self._incoming_calls:
|
||||||
self._incoming_calls.remove(friend_number)
|
self._incoming_calls.remove(friend_number)
|
||||||
is_declined = True
|
is_declined = True
|
||||||
else:
|
else:
|
||||||
is_declined = False
|
is_declined = False
|
||||||
|
if friend_number in self._call_widgets:
|
||||||
|
LOG.debug(f"CM.stop_call _call_widgets close")
|
||||||
|
self.close_call(friend_number)
|
||||||
|
|
||||||
|
LOG.debug(f"CM.stop_call _main_screen.call_finished")
|
||||||
self._main_screen.call_finished()
|
self._main_screen.call_finished()
|
||||||
self._callav.finish_call(friend_number, by_friend) # finish or decline call
|
self._callav.finish_call(friend_number, by_friend) # finish or decline call
|
||||||
if friend_number in self._call_widgets:
|
is_video = self._callav.is_video_call(friend_number)
|
||||||
self._call_widgets[friend_number].close()
|
if is_video:
|
||||||
del self._call_widgets[friend_number]
|
def destroy_window():
|
||||||
|
#??? FixMe
|
||||||
def destroy_window():
|
with ts.ignoreStdout(): import cv2
|
||||||
#??? FixMed
|
|
||||||
is_video = self._callav.is_video_call(friend_number)
|
|
||||||
if is_video:
|
|
||||||
import cv2
|
|
||||||
cv2.destroyWindow(str(friend_number))
|
cv2.destroyWindow(str(friend_number))
|
||||||
|
LOG.debug(f"CM.stop_call destroy_window")
|
||||||
|
threading.Timer(2.0, destroy_window).start()
|
||||||
|
|
||||||
threading.Timer(2.0, destroy_window).start()
|
LOG.debug(f"CM.stop_call _call_finished_event")
|
||||||
self._call_finished_event(friend_number, is_declined)
|
self._call_finished_event(friend_number, is_declined)
|
||||||
|
|
||||||
def friend_exit(self, friend_number):
|
def friend_exit(self, friend_number):
|
||||||
|
|
|
@ -93,6 +93,7 @@ class FileTransfersHandler(ToxSave):
|
||||||
:param file_number: file number
|
:param file_number: file number
|
||||||
:param already_cancelled: was cancelled by friend
|
:param already_cancelled: was cancelled by friend
|
||||||
"""
|
"""
|
||||||
|
# callback
|
||||||
if (friend_number, file_number) in self._file_transfers:
|
if (friend_number, file_number) in self._file_transfers:
|
||||||
tr = self._file_transfers[(friend_number, file_number)]
|
tr = self._file_transfers[(friend_number, file_number)]
|
||||||
if not already_cancelled:
|
if not already_cancelled:
|
||||||
|
|
|
@ -5,7 +5,7 @@ import utils.util as util
|
||||||
|
|
||||||
global LOG
|
global LOG
|
||||||
import logging
|
import logging
|
||||||
LOG = logging.getLogger('app.db')
|
LOG = logging.getLogger('h.database')
|
||||||
|
|
||||||
TIMEOUT = 11
|
TIMEOUT = 11
|
||||||
SAVE_MESSAGES = 500
|
SAVE_MESSAGES = 500
|
||||||
|
@ -86,7 +86,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("dd_friend_to_db " +self._name +' Database exception! ' +str(e))
|
LOG.error("dd_friend_to_db " +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
@ -101,7 +101,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("delete_friend_from_db " +self._name +' Database exception! ' +str(e))
|
LOG.error("delete_friend_from_db " +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
@ -118,7 +118,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
LOG.error("save_messages_to_db" +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
@ -134,7 +134,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
LOG.error("update_messages" +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
@ -149,7 +149,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
LOG.error("delete_message" +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
@ -164,7 +164,7 @@ class Database:
|
||||||
db.commit()
|
db.commit()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("" +self._name +' Database exception! ' +str(e))
|
LOG.error("delete_messages" +self._name +f" Database exception! {e}")
|
||||||
db.rollback()
|
db.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -365,7 +365,7 @@ def callback_audio(calls_manager):
|
||||||
"""
|
"""
|
||||||
New audio chunk
|
New audio chunk
|
||||||
"""
|
"""
|
||||||
LOG_DEBUG(f"callback_audio #{friend_number}")
|
#trace LOG_DEBUG(f"callback_audio #{friend_number}")
|
||||||
# dunno was .call
|
# dunno was .call
|
||||||
calls_manager._call.audio_chunk(
|
calls_manager._call.audio_chunk(
|
||||||
bytes(samples[:audio_samples_per_channel * 2 * audio_channels_count]),
|
bytes(samples[:audio_samples_per_channel * 2 * audio_channels_count]),
|
||||||
|
@ -402,7 +402,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
|
It can be created from initial y, u, v using slices
|
||||||
"""
|
"""
|
||||||
LOG_DEBUG(f"video_receive_frame from toxav_video_receive_frame_cb={friend_number}")
|
LOG_DEBUG(f"video_receive_frame from toxav_video_receive_frame_cb={friend_number}")
|
||||||
import cv2
|
with ts.ignoreStdout(): import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
try:
|
try:
|
||||||
y_size = abs(max(width, abs(ystride)))
|
y_size = abs(max(width, abs(ystride)))
|
||||||
|
@ -426,7 +426,7 @@ def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, u
|
||||||
frame[height * 5 // 4:, width // 2:] = v[1:height // 2:2, :width // 2]
|
frame[height * 5 // 4:, width // 2:] = v[1:height // 2:2, :width // 2]
|
||||||
|
|
||||||
frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
|
frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
|
||||||
|
# imshow
|
||||||
invoke_in_main_thread(cv2.imshow, str(friend_number), frame)
|
invoke_in_main_thread(cv2.imshow, str(friend_number), frame)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
LOG_ERROR(f"video_receive_frame {ex} #{friend_number}")
|
LOG_ERROR(f"video_receive_frame {ex} #{friend_number}")
|
||||||
|
|
|
@ -23,7 +23,7 @@ def LOG_ERROR(l): print('EROR+ '+l)
|
||||||
def LOG_WARN(l): print('WARN+ '+l)
|
def LOG_WARN(l): print('WARN+ '+l)
|
||||||
def LOG_INFO(l): print('INFO+ '+l)
|
def LOG_INFO(l): print('INFO+ '+l)
|
||||||
def LOG_DEBUG(l): print('DBUG+ '+l)
|
def LOG_DEBUG(l): print('DBUG+ '+l)
|
||||||
def LOG_TRACE(l): pass # print('TRACE+ '+l)
|
def LOG_TRACE(l): pass # print('TRAC+ '+l)
|
||||||
|
|
||||||
iLAST_CONN = 0
|
iLAST_CONN = 0
|
||||||
iLAST_DELTA = 60
|
iLAST_DELTA = 60
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -118,7 +118,7 @@ class IncomingCallWidget(widgets.CenteredWidget):
|
||||||
self.thread = None
|
self.thread = None
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
LOG.debug(f"stop from {self._friend_number}")
|
LOG.debug(f"stop from friend_number={self._friend_number}")
|
||||||
if self._processing:
|
if self._processing:
|
||||||
self.close()
|
self.close()
|
||||||
if self.thread is not None:
|
if self.thread is not None:
|
||||||
|
@ -147,7 +147,9 @@ class IncomingCallWidget(widgets.CenteredWidget):
|
||||||
try:
|
try:
|
||||||
self._calls_manager.accept_call(self._friend_number, True, False)
|
self._calls_manager.accept_call(self._friend_number, True, False)
|
||||||
finally:
|
finally:
|
||||||
self.stop()
|
#? self.stop()
|
||||||
|
LOG.debug(f" accept_call_with_audio NOT stop from={self._friend_number}")
|
||||||
|
pass
|
||||||
|
|
||||||
def accept_call_with_video(self):
|
def accept_call_with_video(self):
|
||||||
# ts.trepan_handler()
|
# ts.trepan_handler()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
from qtpy import uic
|
from qtpy import uic
|
||||||
from qtpy import QtCore, QtGui, QtWidgets
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
|
@ -701,10 +702,15 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
if self._we:
|
if self._we:
|
||||||
self._we.show()
|
self._we.show()
|
||||||
return
|
return
|
||||||
LOG.info("Loading WeechatConsole")
|
try:
|
||||||
|
from qweechat import qweechat
|
||||||
|
from qweechat.config import write
|
||||||
|
LOG.info("Loading WeechatConsole")
|
||||||
|
except ImportError as e:
|
||||||
|
LOG.error(f"ImportError Loading import qweechat {e} {sys.path}")
|
||||||
|
LOG.debug(traceback.print_exc())
|
||||||
|
return
|
||||||
|
|
||||||
from third_party.qweechat import qweechat
|
|
||||||
from third_party.qweechat import config
|
|
||||||
try:
|
try:
|
||||||
# WeeChat backported from PySide6 to PyQt5
|
# WeeChat backported from PySide6 to PyQt5
|
||||||
LOG.info("Adding WeechatConsole")
|
LOG.info("Adding WeechatConsole")
|
||||||
|
@ -717,7 +723,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
self.network.disconnect_weechat()
|
self.network.disconnect_weechat()
|
||||||
if self.network.debug_dialog:
|
if self.network.debug_dialog:
|
||||||
self.network.debug_dialog.close()
|
self.network.debug_dialog.close()
|
||||||
qweechat.config.write(self.config)
|
write(self.config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(f"ERROR WeechatConsole {e}")
|
LOG.exception(f"ERROR WeechatConsole {e}")
|
||||||
MainWindow = None
|
MainWindow = None
|
||||||
|
|
|
@ -4,8 +4,7 @@ import urllib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from qtpy import QtCore, QtGui, QtWidgets
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
from PyQt5.QtCore import pyqtSignal
|
from qtpy.QtCore import Signal
|
||||||
Signal = pyqtSignal
|
|
||||||
|
|
||||||
from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit
|
from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit
|
||||||
import utils.util as util
|
import utils.util as util
|
||||||
|
|
|
@ -594,7 +594,7 @@ class VideoSettings(CenteredWidget):
|
||||||
|
|
||||||
def _update_ui(self):
|
def _update_ui(self):
|
||||||
try:
|
try:
|
||||||
import cv2
|
with ts.ignoreStdout(): import cv2
|
||||||
except ImportError:
|
except ImportError:
|
||||||
cv2 = None
|
cv2 = None
|
||||||
self.deviceComboBox.currentIndexChanged.connect(self._device_changed)
|
self.deviceComboBox.currentIndexChanged.connect(self._device_changed)
|
||||||
|
|
|
@ -43,7 +43,7 @@ class WidgetsFactory:
|
||||||
|
|
||||||
def create_video_settings_window(self):
|
def create_video_settings_window(self):
|
||||||
try:
|
try:
|
||||||
import cv2
|
with ts.ignoreStdout(): import cv2
|
||||||
except ImportError:
|
except ImportError:
|
||||||
cv2 = None
|
cv2 = None
|
||||||
if cv2 is None: return None
|
if cv2 is None: return None
|
||||||
|
|
|
@ -10,11 +10,11 @@ import subprocess
|
||||||
global LOG
|
global LOG
|
||||||
import logging
|
import logging
|
||||||
LOG = logging.getLogger('app.'+__name__)
|
LOG = logging.getLogger('app.'+__name__)
|
||||||
log = lambda x: LOG.info(x)
|
|
||||||
|
|
||||||
TIMEOUT=10
|
TIMEOUT=10
|
||||||
|
|
||||||
def connection_available():
|
def connection_available():
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
urllib.request.urlopen('http://216.58.192.142', timeout=TIMEOUT) # google.com
|
urllib.request.urlopen('http://216.58.192.142', timeout=TIMEOUT) # google.com
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in a new issue