2022-09-27 15:51:50 +02:00
|
|
|
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
|
|
|
|
|
|
|
import sys
|
2022-09-27 14:38:39 +02:00
|
|
|
import threading
|
2024-02-11 00:52:50 +01:00
|
|
|
import traceback
|
2022-09-27 15:51:50 +02:00
|
|
|
|
2022-09-27 14:38:39 +02:00
|
|
|
import av.calls
|
2022-11-17 16:26:55 +01:00
|
|
|
from messenger.messages import *
|
|
|
|
from ui import av_widgets
|
2022-11-20 02:11:51 +01:00
|
|
|
import common.event as event
|
|
|
|
import utils.ui as util_ui
|
2022-09-27 14:38:39 +02:00
|
|
|
|
2022-09-27 15:51:50 +02:00
|
|
|
global LOG
|
|
|
|
import logging
|
|
|
|
LOG = logging.getLogger('app.'+__name__)
|
2022-09-27 14:38:39 +02:00
|
|
|
|
|
|
|
class CallsManager:
|
|
|
|
|
2022-09-27 15:51:50 +02:00
|
|
|
def __init__(self, toxav, settings, main_screen, contacts_manager, app=None):
|
2022-10-11 18:36:09 +02:00
|
|
|
self._callav = av.calls.AV(toxav, settings) # object with data about calls
|
|
|
|
self._call = self._callav
|
2022-09-27 14:38:39 +02:00
|
|
|
self._call_widgets = {} # dict of incoming call widgets
|
|
|
|
self._incoming_calls = set()
|
|
|
|
self._settings = settings
|
2022-09-27 15:51:50 +02:00
|
|
|
self._main_screen = main_screen
|
2022-09-27 14:38:39 +02:00
|
|
|
self._contacts_manager = contacts_manager
|
|
|
|
self._call_started_event = event.Event() # friend_number, audio, video, is_outgoing
|
|
|
|
self._call_finished_event = event.Event() # friend_number, is_declined
|
2022-09-27 15:51:50 +02:00
|
|
|
self._app = app
|
2022-09-27 14:38:39 +02:00
|
|
|
|
|
|
|
def set_toxav(self, toxav):
|
2022-10-11 18:36:09 +02:00
|
|
|
self._callav.set_toxav(toxav)
|
2022-09-27 14:38:39 +02:00
|
|
|
|
|
|
|
# Events
|
|
|
|
|
|
|
|
def get_call_started_event(self):
|
|
|
|
return self._call_started_event
|
|
|
|
|
|
|
|
call_started_event = property(get_call_started_event)
|
|
|
|
|
|
|
|
def get_call_finished_event(self):
|
|
|
|
return self._call_finished_event
|
|
|
|
|
|
|
|
call_finished_event = property(get_call_finished_event)
|
|
|
|
|
|
|
|
# AV support
|
|
|
|
|
|
|
|
def call_click(self, audio=True, video=False):
|
|
|
|
"""User clicked audio button in main window"""
|
|
|
|
num = self._contacts_manager.get_active_number()
|
|
|
|
if not self._contacts_manager.is_active_a_friend():
|
|
|
|
return
|
2022-10-11 18:36:09 +02:00
|
|
|
if num not in self._callav and self._contacts_manager.is_active_online(): # start call
|
2022-09-27 15:51:50 +02:00
|
|
|
if not self._settings['audio']['enabled']:
|
2022-09-27 14:38:39 +02:00
|
|
|
return
|
2022-10-11 18:36:09 +02:00
|
|
|
self._callav(num, audio, video)
|
2022-09-27 15:51:50 +02:00
|
|
|
self._main_screen.active_call()
|
2022-09-27 14:38:39 +02:00
|
|
|
self._call_started_event(num, audio, video, True)
|
2022-10-11 18:36:09 +02:00
|
|
|
elif num in self._callav: # finish or cancel call if you call with active friend
|
2022-09-27 14:38:39 +02:00
|
|
|
self.stop_call(num, False)
|
|
|
|
|
|
|
|
def incoming_call(self, audio, video, friend_number):
|
|
|
|
"""
|
|
|
|
Incoming call from friend.
|
|
|
|
"""
|
2022-09-27 15:51:50 +02:00
|
|
|
LOG.debug(__name__ +f" incoming_call {friend_number}")
|
|
|
|
# if not self._settings['audio']['enabled']: return
|
2022-09-27 14:38:39 +02:00
|
|
|
friend = self._contacts_manager.get_friend_by_number(friend_number)
|
|
|
|
self._call_started_event(friend_number, audio, video, False)
|
|
|
|
self._incoming_calls.add(friend_number)
|
|
|
|
if friend_number == self._contacts_manager.get_active_number():
|
2022-09-27 15:51:50 +02:00
|
|
|
self._main_screen.incoming_call()
|
2022-09-27 14:38:39 +02:00
|
|
|
else:
|
|
|
|
friend.actions = True
|
|
|
|
text = util_ui.tr("Incoming video call") if video else util_ui.tr("Incoming audio call")
|
|
|
|
self._call_widgets[friend_number] = self._get_incoming_call_widget(friend_number, text, friend.name)
|
|
|
|
self._call_widgets[friend_number].set_pixmap(friend.get_pixmap())
|
|
|
|
self._call_widgets[friend_number].show()
|
|
|
|
|
|
|
|
def accept_call(self, friend_number, audio, video):
|
|
|
|
"""
|
|
|
|
Accept incoming call with audio or video
|
2022-09-27 15:51:50 +02:00
|
|
|
Called from a thread
|
2022-09-27 14:38:39 +02:00
|
|
|
"""
|
|
|
|
|
2022-09-27 15:51:50 +02:00
|
|
|
LOG.debug(f"CM accept_call from {friend_number} {audio} {video}")
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
|
|
|
try:
|
2022-10-11 18:36:09 +02:00
|
|
|
self._callav.call_accept_call(friend_number, audio, video)
|
2022-09-27 15:51:50 +02:00
|
|
|
except Exception as e:
|
2024-02-11 00:52:50 +01:00
|
|
|
#
|
2022-09-27 15:51:50 +02:00
|
|
|
LOG.error(f"accept_call _call.accept_call ERROR for {friend_number} {e}")
|
2024-02-11 00:52:50 +01:00
|
|
|
LOG.debug(traceback.print_exc())
|
2022-09-27 15:51:50 +02:00
|
|
|
self._main_screen.call_finished()
|
|
|
|
if hasattr(self._main_screen, '_settings') and \
|
|
|
|
'audio' in self._main_screen._settings and \
|
|
|
|
'input' in self._main_screen._settings['audio']:
|
|
|
|
iInput = self._settings['audio']['input']
|
|
|
|
iOutput = self._settings['audio']['output']
|
|
|
|
iVideo = self._settings['video']['device']
|
|
|
|
LOG.debug(f"iInput={iInput} iOutput={iOutput} iVideo={iVideo}")
|
|
|
|
elif hasattr(self._main_screen, '_settings') and \
|
|
|
|
hasattr(self._main_screen._settings, 'audio') and \
|
|
|
|
'input' not in self._main_screen._settings['audio']:
|
2024-02-11 00:52:50 +01:00
|
|
|
LOG.warn(f"'audio' not in {self._main_screen._settings}")
|
2022-09-27 15:51:50 +02:00
|
|
|
elif hasattr(self._main_screen, '_settings') and \
|
|
|
|
hasattr(self._main_screen._settings, 'audio') and \
|
|
|
|
'input' not in self._main_screen._settings['audio']:
|
2024-02-11 00:52:50 +01:00
|
|
|
LOG.warn(f"'audio' not in {self._main_screen._settings}")
|
2022-09-27 15:51:50 +02:00
|
|
|
else:
|
|
|
|
LOG.warn(f"_settings not in self._main_screen")
|
|
|
|
util_ui.message_box(str(e),
|
|
|
|
util_ui.tr('ERROR Accepting call from {friend_number}'))
|
|
|
|
else:
|
|
|
|
self._main_screen.active_call()
|
2022-10-08 04:46:23 +02:00
|
|
|
|
2022-09-27 15:51:50 +02:00
|
|
|
finally:
|
|
|
|
# does not terminate call - just the av_widget
|
|
|
|
if friend_number in self._incoming_calls:
|
|
|
|
self._incoming_calls.remove(friend_number)
|
|
|
|
try:
|
|
|
|
self._call_widgets[friend_number].close()
|
|
|
|
del self._call_widgets[friend_number]
|
|
|
|
except:
|
|
|
|
# RuntimeError: wrapped C/C++ object of type IncomingCallWidget has been deleted
|
|
|
|
|
|
|
|
pass
|
|
|
|
LOG.debug(f" closed self._call_widgets[{friend_number}]")
|
2022-10-08 04:46:23 +02:00
|
|
|
|
2022-09-27 14:38:39 +02:00
|
|
|
def stop_call(self, friend_number, by_friend):
|
|
|
|
"""
|
|
|
|
Stop call with friend
|
|
|
|
"""
|
2022-09-27 15:51:50 +02:00
|
|
|
LOG.debug(__name__+f" stop_call {friend_number}")
|
2022-09-27 14:38:39 +02:00
|
|
|
if friend_number in self._incoming_calls:
|
|
|
|
self._incoming_calls.remove(friend_number)
|
|
|
|
is_declined = True
|
|
|
|
else:
|
|
|
|
is_declined = False
|
2022-09-27 15:51:50 +02:00
|
|
|
self._main_screen.call_finished()
|
2022-10-11 18:36:09 +02:00
|
|
|
self._callav.finish_call(friend_number, by_friend) # finish or decline call
|
2022-09-27 14:38:39 +02:00
|
|
|
if friend_number in self._call_widgets:
|
|
|
|
self._call_widgets[friend_number].close()
|
|
|
|
del self._call_widgets[friend_number]
|
|
|
|
|
|
|
|
def destroy_window():
|
2022-09-27 15:51:50 +02:00
|
|
|
#??? FixMed
|
2022-10-11 18:36:09 +02:00
|
|
|
is_video = self._callav.is_video_call(friend_number)
|
2022-09-27 14:38:39 +02:00
|
|
|
if is_video:
|
2022-09-27 15:51:50 +02:00
|
|
|
import cv2
|
2022-09-27 14:38:39 +02:00
|
|
|
cv2.destroyWindow(str(friend_number))
|
|
|
|
|
|
|
|
threading.Timer(2.0, destroy_window).start()
|
|
|
|
self._call_finished_event(friend_number, is_declined)
|
|
|
|
|
|
|
|
def friend_exit(self, friend_number):
|
2022-10-11 18:36:09 +02:00
|
|
|
if friend_number in self._callav:
|
|
|
|
self._callav.finish_call(friend_number, True)
|
2022-09-27 14:38:39 +02:00
|
|
|
|
|
|
|
# Private methods
|
|
|
|
|
|
|
|
def _get_incoming_call_widget(self, friend_number, text, friend_name):
|
|
|
|
return av_widgets.IncomingCallWidget(self._settings, self, friend_number, text, friend_name)
|