@@ -502,9 +502,17 @@ class JamulusConnector:
502502 def __init__ (self , host = "" , port = DEFAULT_PORT , debug = False , log_audio = True ):
503503 self .debug = debug
504504 self .log_audio = log_audio
505- self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
506- self .sock .bind ((host , port ))
507- print ("listening to port {}" .format (port ))
505+ self .host = host
506+ self .port = port
507+ if self .port is not None :
508+ self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
509+ print ("listening to port {}" .format (self .port ))
510+ self .sock .bind ((self .host , self .port ))
511+
512+ def close (self ):
513+ if self .port is not None :
514+ print ("closing socket" )
515+ self .sock .close ()
508516
509517 def calc_crc (self , data ):
510518 """
@@ -559,29 +567,36 @@ def pack(self, format, values, mode="<"):
559567 """
560568 data = b""
561569 for key , format_char in format :
562- if format_char == "A" :
563- # A = 4 bytes / IPv4 address
564- ip = socket .inet_aton (values [key ])
565- data += struct .pack ("{}{}" .format (mode , "L" ), struct .unpack ("!L" , ip )[0 ])
566- elif format_char in ["U" , "V" , "v" ]:
567- # U = 1 byte length n + n bytes UTF-8 string
568- # V = 2 bytes length n + n bytes UTF-8 string
569- # v = 2 bytes length n + n bytes data
570- utf8_enc = True if format_char in ["U" , "V" ] else False
571- value = values [key ].encode () if utf8_enc else values [key ]
572-
573- length_format = "B" if format_char == "U" else "H"
574- length = len (value )
575-
576- data += struct .pack ("{}{}{}{}" .format (mode , length_format , length , "s" ), length , value )
577- elif format_char == "z" :
578- # z = all remaining data
570+ try :
579571 value = values [key ]
580- length = len (value )
581- data += struct .pack ("{}{}" .format (length , "s" ), value )
582- else :
583- # standard format characters
584- data += struct .pack ("{}{}" .format (mode , format_char ), values [key ])
572+ except KeyError as error :
573+ raise ValueError ("error packing '{}': missing key in values" .format (key ))
574+
575+ try :
576+ if format_char == "A" :
577+ # A = 4 bytes / IPv4 address
578+ ip = socket .inet_aton (value )
579+ data += struct .pack ("{}{}" .format (mode , "L" ), struct .unpack ("!L" , ip )[0 ])
580+ elif format_char in ["U" , "V" , "v" ]:
581+ # U = 1 byte length n + n bytes UTF-8 string
582+ # V = 2 bytes length n + n bytes UTF-8 string
583+ # v = 2 bytes length n + n bytes data
584+ if format_char in ["U" , "V" ]:
585+ value = value .encode ()
586+
587+ length_format = "B" if format_char == "U" else "H"
588+ length = len (value )
589+
590+ data += struct .pack ("{}{}{}{}" .format (mode , length_format , length , "s" ), length , value )
591+ elif format_char == "z" :
592+ # z = all remaining data
593+ length = len (value )
594+ data += struct .pack ("{}{}" .format (length , "s" ), value )
595+ else :
596+ # standard format characters
597+ data += struct .pack ("{}{}" .format (mode , format_char ), value )
598+ except struct .error as error :
599+ raise ValueError ("error packing '{}': {}" .format (key , error ))
585600
586601 return data
587602
@@ -608,8 +623,8 @@ def unpack(self, format, data, offset=0, mode="<"):
608623 """
609624 values = {}
610625
611- try :
612- for key , format_char in format :
626+ for key , format_char in format :
627+ try :
613628 if format_char == "A" :
614629 # A = 4 bytes / IPv4 address
615630 ip = struct .pack ("!L" , * struct .unpack_from ("{}{}" .format (mode , "L" ), data , offset ))
@@ -638,8 +653,8 @@ def unpack(self, format, data, offset=0, mode="<"):
638653 (values [key ],) = struct .unpack_from ("{}{}" .format (mode , format_char ), data , offset )
639654 offset += struct .calcsize ("{}{}" .format (mode , format_char ))
640655
641- except struct .error :
642- return {}, 0
656+ except struct .error as error :
657+ raise ValueError ( "error unpacking '{}': {}" . format ( key , error ))
643658
644659 return values , offset
645660
@@ -699,8 +714,7 @@ def prot_unpack(self, format, data, repeat=False):
699714 values , offset = self .unpack (format , data , offset )
700715
701716 if offset != len (data ):
702- print ("invalid message length ({}/{}) {}" .format (offset , len (data ), values ))
703- return None
717+ raise ValueError ("invalid message length ({}/{}) {}" .format (offset , len (data ), values ))
704718
705719 return values
706720
@@ -766,22 +780,19 @@ def main_unpack(self, data):
766780 # calculate crc from data
767781 crc_check = self .calc_crc (data )
768782 if crc_values ["crc" ] != crc_check :
769- print ("invalid message crc ({}/{}) {}" .format (crc_values ["crc" ], crc_check , data ))
770- return "INVALID" , None , None
783+ raise ValueError ("invalid message crc ({}/{})" .format (crc_values ["crc" ], crc_check ))
771784
772785 # unpack main frame
773786 main_values , offset = self .unpack (FORMAT ["MAIN_FRAME" ], data )
774787
775788 # verify there's no data left
776789 if offset != len (data ):
777- print ("invalid message length ({}/{}) {}" .format (offset , len (data ), data ))
778- return "INVALID" , None , None
790+ raise ValueError ("invalid message length ({}/{}) {}" .format (offset , len (data )))
779791
780792 # verify ID is valid
781793 id = main_values ["id" ]
782794 if id not in MSG_KEYS .keys () or id == 0 :
783- print ("invalid message ID ({}) {}" .format (id , data ))
784- return "INVALID" , None , None
795+ raise ValueError ("invalid message ID ({})" .format (id ))
785796
786797 key = MSG_KEYS [id ]
787798 prot = PROT [key ]
@@ -837,7 +848,7 @@ def log_message(self, addr, key, count="-", length="", values=None, recv=True):
837848 True for received / False for sent
838849 """
839850 if key != "AUDIO" or self .log_audio :
840- output = "{} {} #{}: {} ({})" .format (
851+ output = "{} {} #{} {} ({})" .format (
841852 addr ,
842853 " >" if recv else "< " ,
843854 count ,
@@ -912,24 +923,26 @@ def recvfrom(self, timeout=None, ackn=True, bufsize=MAX_SIZE_BYTES_NETW_BUF):
912923 except socket .timeout :
913924 raise TimeoutError
914925
915- # detect protocol messages
916- if len (data ) >= 9 and data [:2 ] == b"\x00 \x00 " :
917- key , count , values = self .main_unpack (data )
918- self .log_message (addr , key , count = count , length = len (data ), values = values , recv = True )
919- if ackn :
920- self .send_ack (addr , key , count )
921-
922- # assume audio messages
923- elif len (data ) >= 1 :
924- key = "AUDIO"
925- count = None
926- values = self .unpack (FORMAT ["AUDIO_FRAME" ], data )
927- self .log_message (addr , key , length = len (data ), values = values , recv = True )
926+ key = "INVALID"
927+ count = None
928+ values = None
928929
929- else :
930- key = "INVALID"
931- count = None
932- values = None
930+ try :
931+ # detect protocol messages
932+ if len (data ) >= 9 and data [:2 ] == b"\x00 \x00 " :
933+ key , count , values = self .main_unpack (data )
934+ self .log_message (addr , key , count = count , length = len (data ), values = values , recv = True )
935+ if ackn :
936+ self .send_ack (addr , key , count )
937+
938+ # assume audio messages
939+ elif len (data ) >= 1 :
940+ key = "AUDIO"
941+ values = self .unpack (FORMAT ["AUDIO_FRAME" ], data )[0 ]
942+ self .log_message (addr , key , length = len (data ), values = values , recv = True )
943+
944+ except ValueError as error :
945+ print ("error decoding message from {}: {} - {}" .format (addr , error , data ))
933946
934947 return (addr , key , count , values )
935948
0 commit comments