176 lines
6.9 KiB
Python
176 lines
6.9 KiB
Python
import threading
|
|
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
import pyaudio
|
|
import wave
|
|
|
|
from ui import widgets
|
|
import utils.util as util
|
|
import wrapper_tests.support_testing as ts
|
|
|
|
global LOG
|
|
import logging
|
|
LOG = logging.getLogger('app.'+__name__)
|
|
|
|
class IncomingCallWidget(widgets.CenteredWidget):
|
|
|
|
def __init__(self, settings, calls_manager, friend_number, text, name):
|
|
super().__init__()
|
|
self._settings = settings
|
|
self._calls_manager = calls_manager
|
|
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint) # | QtCore.Qt.WindowStaysOnTopHint
|
|
self.resize(QtCore.QSize(500, 270))
|
|
self.avatar_label = QtWidgets.QLabel(self)
|
|
self.avatar_label.setGeometry(QtCore.QRect(10, 20, 64, 64))
|
|
self.avatar_label.setScaledContents(False)
|
|
self.name = widgets.DataLabel(self)
|
|
self.name.setGeometry(QtCore.QRect(90, 20, 300, 25))
|
|
self._friend_number = friend_number
|
|
font = QtGui.QFont()
|
|
font.setFamily(settings['font'])
|
|
font.setPointSize(16)
|
|
font.setBold(True)
|
|
self.name.setFont(font)
|
|
self.call_type = widgets.DataLabel(self)
|
|
self.call_type.setGeometry(QtCore.QRect(90, 55, 300, 25))
|
|
self.call_type.setFont(font)
|
|
self.accept_audio = QtWidgets.QPushButton(self)
|
|
self.accept_audio.setGeometry(QtCore.QRect(20, 100, 150, 150))
|
|
self.accept_video = QtWidgets.QPushButton(self)
|
|
self.accept_video.setGeometry(QtCore.QRect(170, 100, 150, 150))
|
|
self.decline = QtWidgets.QPushButton(self)
|
|
self.decline.setGeometry(QtCore.QRect(320, 100, 150, 150))
|
|
pixmap = QtGui.QPixmap(util.join_path(util.get_images_directory(), 'accept_audio.png'))
|
|
icon = QtGui.QIcon(pixmap)
|
|
self.accept_audio.setIcon(icon)
|
|
pixmap = QtGui.QPixmap(util.join_path(util.get_images_directory(), 'accept_video.png'))
|
|
icon = QtGui.QIcon(pixmap)
|
|
self.accept_video.setIcon(icon)
|
|
pixmap = QtGui.QPixmap(util.join_path(util.get_images_directory(), 'decline_call.png'))
|
|
icon = QtGui.QIcon(pixmap)
|
|
self.decline.setIcon(icon)
|
|
self.accept_audio.setIconSize(QtCore.QSize(150, 150))
|
|
self.accept_video.setIconSize(QtCore.QSize(140, 140))
|
|
self.decline.setIconSize(QtCore.QSize(140, 140))
|
|
#self.accept_audio.setStyleSheet("QPushButton { border: none }")
|
|
#self.accept_video.setStyleSheet("QPushButton { border: none }")
|
|
#self.decline.setStyleSheet("QPushButton { border: none }")
|
|
self.setWindowTitle(text)
|
|
self.name.setText(name)
|
|
self.call_type.setText(text)
|
|
self._processing = False
|
|
self.accept_audio.clicked.connect(self.accept_call_with_audio)
|
|
self.accept_video.clicked.connect(self.accept_call_with_video)
|
|
self.decline.clicked.connect(self.decline_call)
|
|
|
|
output_device_index = self._settings._oArgs.audio['output']
|
|
|
|
if False and self._settings['calls_sound']:
|
|
class SoundPlay(QtCore.QThread):
|
|
|
|
def __init__(self):
|
|
QtCore.QThread.__init__(self)
|
|
self.a = None
|
|
|
|
def run(self):
|
|
class AudioFile:
|
|
chunk = 1024
|
|
|
|
def __init__(self, fl):
|
|
self.stop = False
|
|
self.fl = fl
|
|
self.wf = wave.open(self.fl, 'rb')
|
|
self.p = pyaudio.PyAudio()
|
|
self.stream = self.p.open(
|
|
format=self.p.get_format_from_width(self.wf.getsampwidth()),
|
|
channels=self.wf.getnchannels(),
|
|
rate=self.wf.getframerate(),
|
|
# why no device?
|
|
output_device_index=output_device_index,
|
|
output=True)
|
|
|
|
def play(self):
|
|
while not self.stop:
|
|
data = self.wf.readframes(self.chunk)
|
|
# dunno
|
|
if not data: break
|
|
while data and not self.stop:
|
|
self.stream.write(data)
|
|
data = self.wf.readframes(self.chunk)
|
|
self.wf = wave.open(self.fl, 'rb')
|
|
|
|
def close(self):
|
|
try:
|
|
self.stream.close()
|
|
self.p.terminate()
|
|
except Exception as e:
|
|
# malloc_consolidate(): unaligned fastbin chunk detected
|
|
LOG.warn("SoundPlay close exception {e}")
|
|
|
|
self.a = AudioFile(util.join_path(util.get_sounds_directory(), 'call.wav'))
|
|
self.a.play()
|
|
self.a.close()
|
|
|
|
self.thread = SoundPlay()
|
|
self.thread.start()
|
|
else:
|
|
self.thread = None
|
|
|
|
def stop(self):
|
|
if self._processing:
|
|
self.close()
|
|
if self.thread is not None:
|
|
self.thread.a.stop = True
|
|
i = 0
|
|
while i < ts.iTHREAD_JOINS:
|
|
self.thread.wait(ts.iTHREAD_TIMEOUT)
|
|
if not self.thread.isRunning(): break
|
|
i = i + 1
|
|
else:
|
|
LOG.warn(f"SoundPlay {self.thread.a} BLOCKED")
|
|
# Fatal Python error: Segmentation fault
|
|
self.thread.a.stream.close()
|
|
self.thread.a.p.terminate()
|
|
self.thread.a.close()
|
|
# dunno -failsafe
|
|
self.thread.terminate()
|
|
#? dunno
|
|
self._processing = False
|
|
|
|
def accept_call_with_audio(self):
|
|
if self._processing:
|
|
LOG.warn(f" accept_call_with_audio from {self._friend_number}")
|
|
return
|
|
LOG.debug(f" accept_call_with_audio from {self._friend_number}")
|
|
self._processing = True
|
|
try:
|
|
self._calls_manager.accept_call(self._friend_number, True, False)
|
|
finally:
|
|
self.stop()
|
|
|
|
def accept_call_with_video(self):
|
|
# ts.trepan_handler()
|
|
|
|
if self._processing:
|
|
LOG.warn(__name__+f" accept_call_with_video from {self._friend_number}")
|
|
return
|
|
self.setWindowTitle('Answering video call')
|
|
self._processing = True
|
|
LOG.debug(f" accept_call_with_video from {self._friend_number}")
|
|
try:
|
|
self._calls_manager.accept_call(self._friend_number, True, True)
|
|
finally:
|
|
self.stop()
|
|
|
|
def decline_call(self):
|
|
if self._processing:
|
|
return
|
|
self._processing = True
|
|
try:
|
|
self._calls_manager.stop_call(self._friend_number, False)
|
|
finally:
|
|
self.stop()
|
|
|
|
def set_pixmap(self, pixmap):
|
|
self.avatar_label.setPixmap(pixmap)
|