QThread
CI / Python ${{ matrix.python-version }} (3.10) (push) Waiting to run Details
CI / Python ${{ matrix.python-version }} (3.7) (push) Waiting to run Details
CI / Python ${{ matrix.python-version }} (3.8) (push) Waiting to run Details
CI / Python ${{ matrix.python-version }} (3.9) (push) Waiting to run Details

This commit is contained in:
emdee@spm.plastiras.org 2024-02-12 09:21:55 +00:00
parent 76ad2ccd44
commit d9ef18631d
7 changed files with 162 additions and 103 deletions

View File

@ -16,26 +16,51 @@ 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
from qtpy import QtCore
# sleep = time.sleep
def sleep(fSec):
mSec = int(fSec * 1000.0)
QtCore.QThread.msleep(mSec)
# GLib:ERROR:../glib-2.78.4/glib/gmain.c:3428:g_main_dispatch: assertion failed: (source)
# Bail out! GLib:ERROR:../glib-2.78.4/glib/gmain.c:3428:g_main_dispatch: assertion failed: (source)
QtCore.QCoreApplication.processEvents()
global LOG global LOG
import logging 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):
@ -81,6 +106,7 @@ class AV(common.tox_save.ToxAvSave):
self.lPaSampleratesI = ts.lSdSamplerates(iInput) self.lPaSampleratesI = ts.lSdSamplerates(iInput)
iOutput = self._settings['audio']['output'] iOutput = self._settings['audio']['output']
self.lPaSampleratesO = ts.lSdSamplerates(iOutput) self.lPaSampleratesO = ts.lSdSamplerates(iOutput)
global oPYA global oPYA
oPYA = self._audio = pyaudio.PyAudio() oPYA = self._audio = pyaudio.PyAudio()
@ -119,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()
@ -135,14 +162,15 @@ 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}")
@ -192,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']
@ -207,35 +236,37 @@ 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
lPaSamplerates = [round(self._audio.get_device_info_by_index(iInput)['defaultSampleRate'])] lPaSamplerates = [round(oPYA.get_device_info_by_index(iInput)['defaultSampleRate'])]
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]}")
elif 'defaultSampleRate' in self._audio.get_device_info_by_index(iInput): self._audio_rate_pa = lPaSamplerates[0]
self._audio_rate_pa = self._audio.get_device_info_by_index(iInput)['defaultSampleRate'] elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iInput):
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:
self._audio_stream = self._audio.open(format=pyaudio.paInt16, # why would you not call a thread?
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,
input=True, input=True,
@ -248,30 +279,33 @@ 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:
self._audio_stream = self._audio.open(format=pyaudio.paInt16, LOG_DEBUG( f"start_audio_thread starting thread {self._audio_rate_pa}")
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,
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)
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}")
@ -282,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
@ -334,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()
@ -343,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:
@ -356,80 +392,86 @@ 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 self._audio.get_device_info_by_index(iOutput): elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iOutput):
rate = round(self._audio.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? # test output device?
# [Errno -9985] Device unavailable # [Errno -9985] Device unavailable
try: try:
with ts.ignoreStderr(): with ts.ignoreStderr():
self._out_stream = self._audio.open(format=pyaudio.paInt16, self._out_stream = oPYA.open(format=pyaudio.paInt16,
channels=channels_count, channels=channels_count,
rate=rate, rate=rate,
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 output_device_index={iOutput} {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:
""" """
@ -437,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)
@ -456,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}")
@ -476,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]
@ -484,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)
@ -532,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))

View File

@ -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,22 +120,29 @@ 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
LOG.debug(f"CM.accept_call close av_widget") LOG.debug(f"CM.accept_call close av_widget")
try: self.close_call(friend_number)
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]
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)
except Exception as e: except Exception as e:
# RuntimeError: wrapped C/C++ object of type IncomingCallWidget has been deleted # RuntimeError: wrapped C/C++ object of type IncomingCallWidget has been deleted
LOG.warn(f" closed self._call_widgets[{friend_number}] {e}") LOG.warn(f" closed self._call_widgets[{friend_number}] {e}")
# invoke_in_main_thread(QtCore.QCoreApplication.processEvents)
QtCore.QCoreApplication.processEvents()
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):
""" """
@ -141,8 +156,7 @@ class CallsManager:
is_declined = False is_declined = False
if friend_number in self._call_widgets: if friend_number in self._call_widgets:
LOG.debug(f"CM.stop_call _call_widgets close") LOG.debug(f"CM.stop_call _call_widgets close")
self._call_widgets[friend_number].close() self.close_call(friend_number)
del self._call_widgets[friend_number]
LOG.debug(f"CM.stop_call _main_screen.call_finished") LOG.debug(f"CM.stop_call _main_screen.call_finished")
self._main_screen.call_finished() self._main_screen.call_finished()

View File

@ -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:

View File

@ -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:

View File

@ -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}")

View File

@ -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

View File

@ -704,6 +704,7 @@ class MainWindow(QtWidgets.QMainWindow):
return return
try: try:
from qweechat import qweechat from qweechat import qweechat
from qweechat.config import write
LOG.info("Loading WeechatConsole") LOG.info("Loading WeechatConsole")
except ImportError as e: except ImportError as e:
LOG.error(f"ImportError Loading import qweechat {e} {sys.path}") LOG.error(f"ImportError Loading import qweechat {e} {sys.path}")
@ -722,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