diff --git a/client.py b/client.py index 96d8627..611289c 100755 --- a/client.py +++ b/client.py @@ -5,9 +5,12 @@ Inspired by the PixelFlut beamer on eth0:winter 2016 and code from https://github.com/defnull/pixelflut/ """ -__version__ = 0.1 +__version__ = 0.2 __author__ = "Jan Klopper " +MAX_PROTOCOL_VERSION = 1; +PROTOCOL_PREAMBLE = 'pixelvloed' + import socket import struct import random @@ -65,15 +68,48 @@ def SendPacket(ipaddress, port, message): socket.SOCK_DGRAM) # UDP sock.sendto(message, (ipaddress, port)) -def main(): - """Sends some random pixels untill we break with ctrl+c""" - ipaddress = "127.0.0.1" - port = 5005 +def DiscoverServers(discoveryport, timeout=5): + """Discover servers that send out the pixelfvloed preample""" + DiscoverySock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + DiscoverySock.bind(('', discoveryport)) + starttime = time.time() + servers = [] + foundhash = {} + while (time.time() - timeout) < starttime: + data, addr = DiscoverySock.recvfrom(1024) + try: + if data.startswith(PROTOCOL_PREAMBLE): + dataset = data.split(' ') + if float(dataset[0].split(':')[1]) <= MAX_PROTOCOL_VERSION: + ip = dataset[1].split(':')[0] + port = int(dataset[1].split(':')[1]) + width = int(dataset[2].split('*')[0]) + height = int(dataset[2].split('*')[1]) + if data not in foundhash: + newserver = {'ip': ip, + 'port': port, + 'width': width, + 'height': height} + foundhash[data] = True + print 'New pixelvloed screen found: %r' % newserver + servers.append(newserver) + except: + pass + if servers: + return servers + return False +def main(): + """Discover the servers and start sending to the first one""" + discoveryport = 5006 + servers = False + while servers == False: + servers = DiscoverServers(discoveryport) + print 'displaying on %(ip)s:%(port)d, %(width)d*%(height)dpx' % servers[0] while True: - for packet in RandomFill(): + for packet in RandomFill(servers[0]['width'], servers[0]['height']): time.sleep(0.01) - SendPacket(ipaddress, port, packet) + SendPacket(servers[0]['ip'], servers[0]['port'], packet) if __name__ == '__main__': main() diff --git a/vloed.py b/vloed.py index 4209857..070ddb0 100755 --- a/vloed.py +++ b/vloed.py @@ -19,6 +19,8 @@ from gevent.queue import Queue monkey.patch_all() UDP_IP = "127.0.0.1" UDP_PORT= 5005 +PROTOCOL_VERSION = 1 +PROTOCOL_PREAMBLE = "pixelvloed" def main(): """Runs a pixelvloed server""" @@ -27,7 +29,7 @@ def main(): class Canvas(object): """PixelVloed server class""" - def __init__(self, queue, debug=False): + def __init__(self, queue, width=1366, height=768, debug=True): """Init the pixelVloed server""" self.debug = debug self.pixeloffset = 2 @@ -35,10 +37,15 @@ class Canvas(object): self.screen = None self.udp_ip = UDP_IP self.udp_port = UDP_PORT + self.width = width + self.height = height self.canvas() self.set_title() self.queue = queue self.limit = 140 + self.broadcastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + self.broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @staticmethod def set_title(text=None): @@ -48,12 +55,12 @@ class Canvas(object): title += ' ' + text pygame.display.set_caption(title) - def canvas(self, width=1366, height=768): + def canvas(self): """Init the pygame canvas""" pygame.init() pygame.mixer.quit() flags = DOUBLEBUF - self.screen = pygame.display.set_mode((width, height), flags) + self.screen = pygame.display.set_mode((self.width, self.height), flags) def clear(self, r=0, g=0, b=0): # pylint: disable=C0103 """ Fill the entire screen with a solid colour (default: black)""" @@ -69,9 +76,14 @@ class Canvas(object): def CanvasUpdate(self): """Updates the screen according to self.fps""" lasttime = time.time() + lastbroadcast = time.time() changed = False while True: changed = self.Draw() or changed + if time.time() - lastbroadcast > 2: + lastbroadcast = time.time() + self.SendDiscoveryPacket() + if time.time() - lasttime >= 1.0 / self.fps and changed: self.pixels = None # release the lock on these pixels so we can flip pygame.display.flip() @@ -99,10 +111,10 @@ class Canvas(object): if preamble else 7 #xx,yy,r,g,b ) - pixelcount = (len(data)-1) / pixellength + pixelcount = min(((len(data)-1) / pixellength), + self.limit) if self.debug: - print '%d pixels received, protocol V %d ' % ( - min(pixelcount, self.limit), protocol) + print '%d pixels received, protocol V %d ' % (pixelcount, protocol) for i in xrange(0, pixelcount): pixel = struct.unpack_from( packetformat, @@ -114,6 +126,20 @@ class Canvas(object): # indicate that we have been drawing stuff return True + def SendDiscoveryPacket(self): + """Lets send out our ip/port/resolution to any listening clients""" + self.broadcastSocket.sendto( + '%s:%f %s:%d %d*%d' % (PROTOCOL_PREAMBLE, PROTOCOL_VERSION, + UDP_IP, UDP_PORT, + self.width, self.height), + ('', UDP_PORT+1)) + if self.debug: + print 'sending discovery packet' + + def __del__(self): + """Clean up any sockets we created""" + self.broadcastSocket.close() + class PixelVloed(DatagramServer): """PixelVloed server class""" queue = Queue()