Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # import the library
- from appJar import gui
- from PIL import Image, ImageTk
- import numpy as np
- import cv2
- import socket
- import select
- import threading
- import time
- import json
- import sys
- import queue
- #import winsound
- import os
- from typing import List
- import re
- serverName = 'vega.ii.uam.es'
- serverPort = 8000
- src_port = 8080
- class User():
- filename = 'user.json'
- def __init__(self, name, ip, port: int, creation_timestamp=None, password=None):
- self.name = name
- self.ip = ip
- self.port = port
- self.password = password
- self.creation_timestamp = creation_timestamp
- def __str__(self):
- return "{} {} {} {}".format(self.name, self.ip, self.port, self.creation_timestamp)
- @classmethod
- def load_from_file(cls):
- try:
- with open(cls.filename, "r") as fp:
- raw = json.load(fp)
- return User(raw['name'], raw['ip'], raw['port'], raw['creation_timestamp'], raw['password'])
- except Exception as e:
- print(str(e))
- @classmethod
- def delete_user_file(cls):
- try:
- os.remove(cls.filename)
- except Exception as e:
- print(str(e))
- def save_to_file(self):
- try:
- with open(self.filename, "w") as fp:
- data = {
- 'name': self.name,
- 'ip': self.ip,
- 'port': self.port,
- 'creation_timestamp': self.creation_timestamp,
- 'password': self.password
- }
- json.dump(data, fp, indent=2)
- except Exception as e:
- print(str(e))
- class Control():
- def __init__(self, my_addr, vc, port=8080):
- self.my_addr = my_addr
- self.vc = vc
- self.llamada_actual = None
- self.stop_threads = False
- # Creamos el socket para la conexión de control
- self.socket_in = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket_in.setblocking(False)
- self.inputs = [self.socket_in]
- self.outputs = []
- while port < 65535:
- try:
- self.socket_in.bind((self.my_addr, port))
- self.socket_in.listen(1)
- self.port = port
- break
- except:
- port += 1
- if port == 65536:
- raise Exception(
- "Error reservando puerto para la conexión de control")
- self.port = port
- self.busy = False
- t = threading.Thread(target=self.connection_loop)
- t.start()
- def exit(self):
- self.stop_threads = True
- def connection_loop(self):
- while True:
- # comprobamos si se puede hacer un accept usando un timeout de 0.5 segundos
- rl, wl, _ = select.select(
- self.inputs, self.outputs, self.inputs, 0.5)
- for s in rl:
- conn, addr = s.accept()
- t = threading.Thread(
- target=self.client_thread, args=(conn, addr))
- t.start()
- # si el timeout ha terminado y se ha recibido la señal para parar hilos
- if len(rl) == 0 and self.stop_threads:
- self.socket_in.close()
- break # terminamos thread
- def client_thread(self, conn, addr):
- conn.setblocking(False)
- _in = [conn]
- while True:
- _in = list(filter(lambda x: x._closed == False, _in))
- if not _in:
- return
- rl, _, _ = select.select(_in, [], _in, 0.2)
- for c in rl:
- try:
- data = conn.recv(1024)
- except ConnectionResetError:
- return
- if not data:
- conn.close()
- self.busy = False
- return
- request = data.decode('utf-8')
- w = request.split()
- if request.startswith("CALLING"):
- if self.busy:
- conn.send(b"CALL_BUSY")
- conn.close()
- break
- else:
- self.busy = True
- self.llamada_actual = conn
- self.src_nick = w[1]
- self.src_port = int(w[2])
- self.vc.recibiendo_llamada(self.src_port,addr[0])
- elif request.startswith("CALL_ACEPTED"):
- self.llamada_actual = conn
- self.vc.recibiendo_contestacion(1, int(w[2]), addr[0])
- elif request.startswith("CALL_END"):
- if c is self.llamada_actual:
- self.llamada_actual = None
- c.close()
- self.busy = False
- self.vc.recibiendo_call_end()
- return
- elif request.startswith("CALL_DENIED"):
- self.busy = False
- conn.close()
- self.vc.recibiendo_contestacion(0)
- elif request.startswith("CALL_HOLD"):
- self.vc.recibir_pausar()
- elif request.startswith("CALL_RESUME"):
- self.vc.recibir_resume()
- if not rl and self.stop_threads:
- #parar thread cuando se acctiva el flag stop_threads
- break
- # Funciones para enviar comandos al otro extremo.
- def llamar(self, my_user, dest_user):
- try:
- # Para cuando llammemos nosotros
- self.socket_out = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket_out.connect((dest_user.ip, dest_user.port))
- except ConnectionRefusedError as _:
- return False
- request = "CALLING {} {}".format(
- my_user.name, my_user.udpport)
- self.socket_out.send(request.encode('utf-8'))
- t = threading.Thread(target=self.client_thread,
- args=(self.socket_out, (dest_user.ip,)))
- t.start()
- return True
- def call_accepted(self, my_user):
- request = "CALL_ACEPTED {} {}".format(
- my_user.name, my_user.udpport)
- self.llamada_actual.send(request.encode('utf-8'))
- def call_denied(self):
- request = "CALL_DENIED"
- self.llamada_actual.send(request.encode('utf-8'))
- self.busy = False
- self.llamada_actual.close()
- self.llamada_actual = None
- def call_hold(self):
- request = "CALL_HOLD"
- self.llamada_actual.send(request.encode('utf-8'))
- def call_resume(self):
- request = "CALL_RESUME"
- self.llamada_actual.send(request.encode('utf-8'))
- def call_end(self, nick):
- request = "CALL_END %s" % nick
- self.llamada_actual.send(request.encode('utf-8'))
- #self.llamada_actual.close()
- self.llamada_actual = None
- class Server():
- """
- Clase Server que engloba las funciones que
- se comunican con el servidor y la gestion
- de conexiones con el mismo.
- """
- def __init__(self, my_addr, host, port: int, protocols=[0], debug=False):
- # Conectamos con el servidor
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.my_addr = my_addr
- self.protocols = protocols
- self.debug = debug
- try:
- self.socket.connect((host, port))
- except Exception as e:
- raise Exception("Error connectando con el servidor: %s" % str(e))
- def __del__(self):
- self.quit()
- def register_u(self, user):
- return self.register(user.name, user.port, user.password)
- def register(self, nickname, port: int, password):
- request = "REGISTER {} {} {} {} {}".format(
- nickname,
- self.my_addr,
- port,
- password,
- "#".join(list(map(lambda x: "V"+str(x), self.protocols))))
- if self.debug:
- print("C -> S: " + request)
- self.socket.send(request.encode('utf-8'))
- response = self.socket.recv(1024).decode('utf-8')
- if self.debug:
- print("S -> C: " + response)
- if response.startswith("OK WELCOME"):
- w = response.split()
- return User(w[2], self.my_addr, port, float(w[3]), password)
- elif response.startswith("NOK WRONG_PASS"):
- return None
- else:
- raise Exception("Bad Response from server")
- def query(self, nickname) -> User:
- """
- Solicita la información de un usuario
- """
- request = "QUERY {}".format(nickname)
- if self.debug:
- print("C -> S: " + request)
- self.socket.send(request.encode('utf-8'))
- response = self.socket.recv(1024).decode('utf-8')
- if self.debug:
- print("C -> S: " + response)
- words = response.split()
- if words[0] == 'OK' and words[1] == 'USER_FOUND':
- protocols = words[-1]
- port = int(words[-2])
- ip = words[-3]
- nick = ' '.join(words[2:-3])
- return User(nick, ip, port, 0)
- else:
- return None
- def list_users(self) -> List[User]:
- """
- Obtiene la lista de todos los usuarios
- """
- self.socket.send(b'LIST_USERS')
- # No sabemos cuantos usuarios hay.
- frame1 = self.socket.recv(30)
- words = frame1.split()
- if words[0] == b"OK" and words[1] == b"USERS_LIST":
- num_users = int(words[2])
- data = b' '.join(words[3:])
- # Contamos los usuarios con una expresión regular porque hay gente muy
- # cabrona que pone hashtags en su nombre para que un parseo que podria
- # ser muy simple se convierta en un parseo complicado
- num_users_received = len(re.findall(
- "[0-9]{7,11}.[0-9]{1,8}#", data.decode('utf-8')))
- while num_users_received < num_users:
- data += self.socket.recv(2048)
- num_users_received = len(re.findall(
- "[0-9]{7,11}.[0-9]{1,8}#", data.decode('utf-8')))
- user_lst = []
- separadores = re.findall(
- "[0-9]{7,11}.[0-9]{1,8}#", data.decode('utf-8'))
- last_idx = 0
- data_decoded = data.decode('utf-8')
- for separador in separadores:
- idx_separador = data_decoded.index(separador, last_idx)
- raw_user_data = data_decoded[last_idx:
- idx_separador + len(separador) - 1]
- last_idx = idx_separador + len(separador)
- dat = raw_user_data.split()
- user = User(dat[0], dat[1], dat[2], dat[3]
- if len(dat) == 4 else None)
- user_lst.append(user)
- return user_lst
- def quit(self) -> None:
- sys.exit()
- try:
- self.socket.send("QUIT".encode('utf-8'))
- response = self.socket.revc(1024)
- self.socket.close()
- except:
- pass
- class UDPControl():
- def __init__(self, my_addr):
- self.my_addr = my_addr
- self.udp_port_dest = None
- self.addr_dest = None
- self.socket_in = socket.socket(socket.AF_INET, # Internet
- socket.SOCK_DGRAM) # UDP
- self.socket_in.setblocking(False)
- self.socket_in.settimeout(0.5)
- self.socket_out = socket.socket(socket.AF_INET, # Internet
- socket.SOCK_DGRAM) # UDP
- self.sending_video = False
- self.frame_count = 0
- self.fps = 30
- self.stop_threads = False
- self.queue_in = queue.Queue()
- self.queue_out = queue.Queue()
- def get_src_port(self, port=6000):
- while port < 65535:
- try:
- self.socket_in.bind((self.my_addr, port))
- self.port = port
- break
- except:
- port += 1
- if port == 65536:
- raise Exception(
- "Error reservando puerto para la conexión UDP")
- self.port = port
- return port
- def empezar_videollamada(self):
- t = threading.Thread(target=self.send_videmy_addro)
- t.start()
- t = threading.Thread(target=self.recive_video)
- t.start()
- def send_videmy_addro(self):
- while True:
- try:
- img = self.queue_in.get(timeout=0.1)
- self.frame_count += 1
- timestamp = str(time.time())
- MESSAGE = str(self.frame_count)+"#"+timestamp + "#"+"640x480"+"#"+str(self.fps)+"#"
- MESSAGE = MESSAGE.encode("utf-8") + img
- print(len(MESSAGE))
- self.socket_out.sendto(
- MESSAGE, (self.addr_dest, self.udp_port_dest))
- except:
- pass
- if self.stop_threads:
- return
- def recive_video(self):
- while True:
- try:
- data, _ = self.socket_in.recvfrom(20000)
- num_separadores = 0
- indice = 0
- for byte in data:
- if byte == 35:
- num_separadores+=1
- if num_separadores == 4:
- break
- indice+=1
- indice+=1
- self.queue_out.put(data[indice:])
- print("received message: " + str(data[0:29]))
- except:
- pass
- if self.stop_threads:
- return
- class VideoClient(object):
- def __init__(self, window_size, user_file=None):
- # Creamos una variable que contenga el GUI principal
- self.app = gui("Redes2 - P2P", "340x400", handleArgs=False)
- self.my_addr = get_Host_name_IP()
- self.sending_video = False
- try:
- self.server = Server(
- self.my_addr, 'vega.ii.uam.es', 8000, debug=True)
- except Exception as e:
- self.app.errorBox("Connection Error", str(e))
- self.app.stop()
- sys.exit(-1)
- self.crear_gui()
- # Intentamos cargar la configuración del usuario
- _user = User.load_from_file()
- if _user:
- self.control = Control(self.my_addr, self, _user.port)
- self.udp_control = UDPControl(self.my_addr)
- else:
- self.control = Control(self.my_addr, self)
- self.udp_control = UDPControl(self.my_addr)
- if _user:
- # Intentamos volver a registrar a usuario con los mismos datos
- # Sobre todo para actualizar la ip y el puerto
- _user.port = self.control.port
- self.user = self.server.register_u(_user)
- if self.user:
- # Si todo va bien, iniciamos sesion automaticamente
- self.user.save_to_file()
- self.cambiar_estado("Default")
- self.app.setStatusbar("User: %s" % self.user.name, field=0)
- else:
- # Si no pedimos que el usuario se registre otra vez
- self.cambiar_estado("Registro")
- else:
- # Si no se carga, mostramos el login
- self.cambiar_estado("Registro")
- self.app.setPollTime(33)
- self.app.registerEvent(self.capturaVideo)
- self.sending_video = False
- self.use_webcam=True
- def recibiendo_llamada(self, udp_port_dest=None, addr_dest=None):
- response = self.app.questionBox(
- "LLamada Entrante", "Llamada entrante de {}. Aceptar?".format(self.control.src_nick))
- if response == "yes":
- self.user.udpport = self.udp_control.get_src_port()
- self.control.call_accepted(self.user)
- self.udp_control.udp_port_dest = udp_port_dest
- self.udp_control.addr_dest = addr_dest
- self.udp_control.empezar_videollamada()
- self.cap = cv2.VideoCapture(0)
- self.sending_video = True
- self.app.setPollTime(33)
- else:
- self.control.call_denied()
- def recibiendo_contestacion(self, respuesta, udp_port_dest=None, addr_dest=None):
- if respuesta == 1:
- self.app.hideSubWindow("recibiendo")
- self.app.infoBox("Llamada aceptada", "A conversar!!")
- self.udp_control.udp_port_dest = udp_port_dest
- self.udp_control.addr_dest = addr_dest
- self.sending_video = True
- self.udp_control.empezar_videollamada()
- self.app.setPollTime(33)
- # DONDE EMPIEZA TOH
- else:
- self.app.hideSubWindow("recibiendo")
- self.app.infoBox("Llamada denegada", "Lo siento, no ha podido ser")
- def recibir_pausar(self):
- self.sending_video = False
- self.udp_control.queue_out.queue.clear()
- self.udp_control.queue_in.queue.clear()
- def recibir_resume(self):
- self.sending_video = True
- def crear_gui(self):
- # Pantalla de registro
- self.app.setSticky("nw")
- self.app.setGuiPadding(20, 20)
- self.app.setSticky("nw")
- self.app.startFrame("Registro", row=0, column=3)
- self.app.setPadding([5, 20])
- self.app.addImage("logo", "imgs/logo.png", row=0, column=0, colspan=2)
- self.app.setPadding([3, 7])
- self.app.addLabel("_Usuario", "Usuario", 1, 0)
- self.app.setLabelAlign("_Usuario", "left")
- self.app.addEntry("Username", 1, 1)
- self.app.addLabel("_Contrasena", "Contraseña", 2, 0)
- self.app.addSecretEntry("Password", 2, 1)
- self.app.setEntrySubmitFunction("Username", self.registrarse)
- self.app.setEntrySubmitFunction("Password", self.registrarse)
- self.app.startFrame("_anonBtn1", row=3, column=0, colspan=2)
- self.app.setSticky("we")
- self.app.addNamedButton("Login", "_loginBtn", self.registrarse, 1, 0)
- self.app.addNamedButton("Salir", "_salirBtn", self.app.stop, 1, 1)
- self.app.stopFrame()
- self.app.stopFrame()
- # Fin pantalla de registro
- self.app.setStretch("none")
- self.app.setSticky("ns")
- self.app.startFrame("LEFT", row=0, column=0)
- self.app.setStretch("COLUMN")
- self.app.addLabel("__Usuarios", "Usuarios Registrados")
- self.app.addListBox("users_list")
- self.app.addButton("Actualizar", self.listar)
- self.app.addButton("Logout", self.logout)
- self.app.addButton("Salir", self.app.stop)
- self.app.stopFrame()
- self.app.setFrameWidth("LEFT", 100)
- self.app.setFrameHeight("LEFT", 200)
- self.app.startFrame("RIGHT", row=0, column=1)
- self.app.addLabel("title", "Cliente Multimedia P2P - Redes2 ")
- self.app.addImage("video", "imgs/webcam.gif")
- self.app.startFrame("Botones llmada")
- self.app.addButtons(["Conectar","Conectar con","Pausar","Reanudar","Colgar"], [
- self.conectar,self.conectar_con,self.pausar,self.reanudar, self.colgar])
- self.app.addLabelOptionBox("Fuente Video", ["Webcam", "Fichero"])
- self.app.addNamedButton("SelectVideo", "Seleccionar Video", self.seleccionar_video)
- self.app.setOptionBoxChangeFunction("Fuente Video", self.cambiar_fuente_video);
- self.app.hideButton("Seleccionar Video")
- #self.app.hideButton("Pausar")
- self.app.stopFrame()
- self.app.stopFrame()
- # Ventana llamando
- self.app.startSubWindow("recibiendo")
- self.app.addLabel("popup", "")
- self.app.stopSubWindow()
- self.app.hideSubWindow("recibiendo")
- # Añadir los botones
- self.app.addStatusbar(fields=2)
- self.app.setStopFunction(self.quit)
- def cambiar_estado(self, estado):
- if estado == "Registro":
- self.app.showFrame("Registro")
- self.app.hideFrame("LEFT")
- self.app.hideFrame("RIGHT")
- self.app.setGeom("340x420")
- self.estado = estado
- elif estado == "Default":
- self.app.setGeom("780x530")
- self.listar(None)
- self.app.hideFrame("Registro")
- self.app.showFrame("LEFT")
- self.app.showFrame("RIGHT")
- self.estado = estado
- def registrarse(self, btn=None):
- nick = self.app.getEntry("Username")
- password = self.app.getEntry("Password")
- if len(nick) == 0:
- return self.app.errorBox("Error Validación", "Nick no valido")
- elif len(password) == 0:
- return self.app.errorBox("Error Validación", "Password no valido")
- user = self.server.register(
- nick, self.control.port, password)
- if user:
- user.save_to_file()
- self.cambiar_estado("Default")
- self.user = user
- self.app.setStatusbar("User: %s" % self.user.name, field=0)
- else:
- self.app.errorBox("Error Registro", "Contraseña incorrecta")
- def cambiar_fuente_video(self, obj):
- valor = self.app.getOptionBox(obj)
- if valor == "Webcam":
- self.app.hideButton("Seleccionar Video")
- self.use_webcam=True
- else:
- self.app.showButton("Seleccionar Video")
- self.use_webcam=False
- def seleccionar_video(self, btn=None):
- self.video_path = self.app.openBox("Seleccionar Video", None, fileTypes=[('video', '*.mp4')], asFile=False)
- def logout(self, btn):
- self.cambiar_estado("Registro")
- self.app.setStatusbar("", 0)
- User.delete_user_file()
- def conectar(self, button):
- # Entrada del nick del usuario a conectar
- nick = self.app.textBox("Conexión",
- "Introduce el nick del usuario a buscar")
- if nick == self.user.name:
- self.app.errorBox("¡Error llamada!",
- "No te puedes llamar a ti mismo")
- else:
- user = self.server.query(nick)
- self.user.udpport = self.udp_control.get_src_port()
- if self.use_webcam:
- self.cap = cv2.VideoCapture(0)
- else:
- self.cap = cv2.VideoCapture(self.video_path)
- result = self.control.llamar(self.user, user)
- if result:
- self.app.setLabel("popup", "Llamando a "+nick+"...")
- self.app.showSubWindow("recibiendo")
- #winsound.PlaySound("sounds/Phone_Ringing.wav", winsound.SND_LOOP + winsound.SND_ASYNC)
- else:
- self.app.errorBox("Usuario no conectado",
- "El usuario %s no está conectado" % user.name)
- def conectar_con(self):
- pass
- def pausar(self, btn=None):
- self.control.call_hold()
- self.sending_video = False
- self.udp_control.queue_out.queue.clear()
- self.udp_control.queue_in.queue.clear()
- def reanudar(self, btn=None):
- self.control.call_resume()
- self.sending_video=True
- def colgar(self, btn):
- self.control.call_end(self.user.name)
- self.sending_video = False
- self.cap.release()
- self.udp_control.stop_threads = True
- def recibiendo_call_end(self):
- self.sending_video = False
- self.cap.release()
- self.udp_control.stop_threads = True
- def listar(self, button):
- users = self.server.list_users()
- if users:
- users = sorted(users, key=lambda x: x.name.lower())
- self.user_list = users
- self.app.clearListBox("users_list")
- self.app.addListItems("users_list", list(
- map(lambda x: x.name, users)), select=False)
- else:
- pass
- def quit(self, btn=None):
- self.control.exit()
- return True
- def start(self):
- self.app.go()
- # Función que captura el frame a mostrar en cada momento
- def capturaVideo(self):
- if self.sending_video:
- # Capturamos un frame de la cámara o del vídeo
- ret, frame = self.cap.read()
- frame = cv2.resize(frame, (640, 480))
- cv2_im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
- img_tk = ImageTk.PhotoImage(Image.fromarray(cv2_im))
- # Compresión JPG al 50% de resolución (se puede variar)
- encode_param = [cv2.IMWRITE_JPEG_QUALITY, 50]
- result, encimg = cv2.imencode('.jpg', frame, encode_param)
- if result == False:
- print('Error al codificar imagen')
- encimg = encimg.tobytes()
- self.udp_control.queue_in.put(encimg)
- if not self.udp_control.queue_out.empty():
- img = self.udp_control.queue_out.get()
- # Descompresión de los datos, una vez recibidos
- decimg = cv2.imdecode(np.frombuffer(img,np.uint8), 1)
- # Conversión de formato para su uso en el GUI
- cv2_im = cv2.cvtColor(decimg,cv2.COLOR_BGR2RGB)
- img_tk = ImageTk.PhotoImage(Image.fromarray(cv2_im))
- # Lo mostramos en el GUI
- self.app.setImageData("video", img_tk, fmt='PhotoImage')
- # Establece la resolución de la imagen capturada
- def setImageResolution(self, resolution):
- # Se establece la resolución de captura de la webcam
- # Puede añadirse algún valor superior si la cámara lo permite
- # pero no modificar estos
- if resolution == "LOW":
- self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 160)
- self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 120)
- elif resolution == "MEDIUM":
- self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
- self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
- elif resolution == "HIGH":
- self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
- # Función que gestiona los callbacks de los botones
- def buttonsCallback(self, button):
- if button == "Salir":
- # Salimos de la aplicación
- self.app.stop()
- elif button == "Conectar":
- self.app.showSubWindow("mihai")
- def video_thread():
- UDP_IP = get_Host_name_IP()
- UDP_PORT = 6000
- sock = socket.socket(socket.AF_INET, # Internet
- socket.SOCK_DGRAM) # UDP
- sock.bind((UDP_IP, UDP_PORT))
- while True:
- data, addr = sock.recvfrom(8192) # buffer size is 1024 bytes
- img = data.split("#")
- decimg = cv2.imdecode(np.frombuffer(img[-1], np.uint8), 1)
- # Conversión de formato para su uso en el GUI
- cv2_im = cv2.cvtColor(decimg, cv2.COLOR_BGR2RGB)
- img_tk = ImageTk.PhotoImage(Image.fromarray(cv2_im))
- self.app.setImageData("video", img_tk, fmt='PhotoImage')
- def manage_connection(self):
- print("HEYY there im using wpp")
- while 1:
- conn, addr = self.control_socket.accept()
- data = conn.recv(1024)
- print(data)
- rdata = data.decode("UTF-8").split(" ")
- if rdata[0] == "CALLING":
- f = open("last_user_reg.txt", "r")
- nick = f.read()
- f.close()
- self.port_dest = rdata[2]
- self.ip_dest = str(addr)
- self.sending_video = True
- self.frame_count = 0
- edata = "CALL_ACCEPTED " + nick + " 8080"
- conn.send(edata.encode("utf-8"))
- def get_Host_name_IP():
- #return "127.0.0.1"
- try:
- host_name = socket.gethostname()
- host_ip = socket.gethostbyname(host_name)
- return host_ip
- except:
- raise Exception("Unable to get Hostname and IP")
- if __name__ == '__main__':
- if len(sys.argv) == 2:
- User.filename = sys.argv[1]
- vc = VideoClient("823x504")
- # Crear aquí los threads de lectura, de recepción y,
- # en general, todo el código de inicialización que sea necesario
- # ...
- # Lanza el bucle principal del GUI
- # El control ya NO vuelve de esta función, por lo que todas las
- # acciones deberán ser gestionadas desde callbacks y threads
- vc.start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement