clean up class names in packet module.

add __init__ to vbanrtpacket class.

patch bump
This commit is contained in:
onyx-and-iris 2022-08-10 17:49:21 +01:00
parent 3e7bd14ba3
commit aea2be624e
4 changed files with 84 additions and 120 deletions

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "vban-cmd"
version = "1.3.2"
version = "1.3.3"
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT"

View File

@ -1,17 +1,17 @@
import socket
import time
from abc import ABCMeta, abstractmethod
from typing import Iterable, NoReturn, Optional, Union
from typing import Iterable, Optional, Union
from .misc import Event
from .packet import TextRequestHeader
from .packet import RequestHeader
from .subject import Subject
from .util import Socket, comp, script
from .worker import Subscriber, Updater
class VbanCmd(metaclass=ABCMeta):
"""Base class responsible for communicating over VBAN RT Service"""
"""Base class responsible for communicating with the VBAN RT Packet Service"""
DELAY = 0.001
# fmt: off
@ -26,7 +26,7 @@ class VbanCmd(metaclass=ABCMeta):
for attr, val in kwargs.items():
setattr(self, attr, val)
self.text_header = TextRequestHeader(
self.packet_request = RequestHeader(
name=self.streamname,
bps_index=self.BPS_OPTS.index(self.bps),
channel=self.channel,
@ -66,11 +66,11 @@ class VbanCmd(metaclass=ABCMeta):
"""Sends a string request command over a network."""
cmd = id_ if not param else f"{id_}.{param}={val}"
self.socks[Socket.request].sendto(
self.text_header.header + cmd.encode(),
self.packet_request.header + cmd.encode(),
(socket.gethostbyname(self.ip), self.port),
)
count = int.from_bytes(self.text_header.framecounter, "little") + 1
self.text_header.framecounter = count.to_bytes(4, "little")
count = int.from_bytes(self.packet_request.framecounter, "little") + 1
self.packet_request.framecounter = count.to_bytes(4, "little")
if param:
self.cache[f"{id_}.{param}"] = val
if self.sync:

View File

@ -8,31 +8,32 @@ HEADER_SIZE = 4 + 1 + 1 + 1 + 1 + 16 + 4
@dataclass
class VBAN_VMRT_Packet_Data:
"""Represents the structure of a VMRT data packet"""
class VbanRtPacket:
"""Represents the body of a VBAN RT data packet"""
_voicemeeterType: bytes
_reserved: bytes
_buffersize: bytes
_voicemeeterVersion: bytes
_optionBits: bytes
_samplerate: bytes
_inputLeveldB100: bytes
_outputLeveldB100: bytes
_TransportBit: bytes
_stripState: bytes
_busState: bytes
_stripGaindB100Layer1: bytes
_stripGaindB100Layer2: bytes
_stripGaindB100Layer3: bytes
_stripGaindB100Layer4: bytes
_stripGaindB100Layer5: bytes
_stripGaindB100Layer6: bytes
_stripGaindB100Layer7: bytes
_stripGaindB100Layer8: bytes
_busGaindB100: bytes
_stripLabelUTF8c60: bytes
_busLabelUTF8c60: bytes
def __init__(self, data):
self._voicemeeterType: bytes = data[28:29]
self._reserved: bytes = data[29:30]
self._buffersize: bytes = data[30:32]
self._voicemeeterVersion: bytes = data[32:36]
self._optionBits: bytes = data[36:40]
self._samplerate: bytes = data[40:44]
self._inputLeveldB100: bytes = data[44:112]
self._outputLeveldB100: bytes = data[112:240]
self._TransportBit: bytes = data[240:244]
self._stripState: bytes = data[244:276]
self._busState: bytes = data[276:308]
self._stripGaindB100Layer1: bytes = data[308:324]
self._stripGaindB100Layer2: bytes = data[324:340]
self._stripGaindB100Layer3: bytes = data[340:356]
self._stripGaindB100Layer4: bytes = data[356:372]
self._stripGaindB100Layer5: bytes = data[372:388]
self._stripGaindB100Layer6: bytes = data[388:404]
self._stripGaindB100Layer7: bytes = data[404:420]
self._stripGaindB100Layer8: bytes = data[420:436]
self._busGaindB100: bytes = data[436:452]
self._stripLabelUTF8c60: bytes = data[452:932]
self._busLabelUTF8c60: bytes = data[932:1412]
def pdirty(self, other):
"""True iff any defined parameter has changed"""
@ -201,8 +202,8 @@ class VBAN_VMRT_Packet_Data:
@dataclass
class VBAN_VMRT_Packet_Header:
"""Represents a RESPONSE RT PACKET header"""
class VbanRtPacketHeader:
"""Represents the header of VBAN RT data packet"""
name = "Voicemeeter-RTP"
vban: bytes = "VBAN".encode()
@ -225,7 +226,7 @@ class VBAN_VMRT_Packet_Header:
@dataclass
class TextRequestHeader:
class RequestHeader:
"""Represents a REQUEST RT PACKET header"""
name: str
@ -262,8 +263,8 @@ class TextRequestHeader:
@dataclass
class RegisterRTHeader:
"""Represents a REGISTER RT PACKET header"""
class SubscribeHeader:
"""Represents a packet used to subscribe to the RT Packet Service"""
name = "Register RTP"
timeout = 15

View File

@ -1,15 +1,8 @@
import socket
import threading
import time
from enum import IntEnum
from typing import Optional
from .packet import (
HEADER_SIZE,
RegisterRTHeader,
VBAN_VMRT_Packet_Data,
VBAN_VMRT_Packet_Header,
)
from .packet import HEADER_SIZE, SubscribeHeader, VbanRtPacket, VbanRtPacketHeader
from .util import Socket
@ -17,23 +10,23 @@ class Subscriber(threading.Thread):
"""fire a subscription packet every 10 seconds"""
def __init__(self, remote):
super().__init__(name="subscriber", target=self.register, daemon=True)
self._rem = remote
self.register_header = RegisterRTHeader()
super().__init__(name="subscriber", target=self.subscribe, daemon=True)
self._remote = remote
self.packet = SubscribeHeader()
def register(self):
while self._rem.running:
def subscribe(self):
while self._remote.running:
try:
self._rem.socks[Socket.register].sendto(
self.register_header.header,
(socket.gethostbyname(self._rem.ip), self._rem.port),
self._remote.socks[Socket.register].sendto(
self.packet.header,
(socket.gethostbyname(self._remote.ip), self._remote.port),
)
count = int.from_bytes(self.register_header.framecounter, "little") + 1
self.register_header.framecounter = count.to_bytes(4, "little")
count = int.from_bytes(self.packet.framecounter, "little") + 1
self.packet.framecounter = count.to_bytes(4, "little")
time.sleep(10)
except socket.gaierror as e:
print(f"Unable to resolve hostname {self._rem.ip}")
self._rem.socks[Socket.register].close()
print(f"Unable to resolve hostname {self._remote.ip}")
self._remote.socks[Socket.register].close()
raise e
@ -46,78 +39,48 @@ class Updater(threading.Thread):
def __init__(self, remote):
super().__init__(name="updater", target=self.update, daemon=True)
self._rem = remote
self._rem.socks[Socket.response].bind(
(socket.gethostbyname(socket.gethostname()), self._rem.port)
self._remote = remote
self._remote.socks[Socket.response].bind(
(socket.gethostbyname(socket.gethostname()), self._remote.port)
)
self.expected_packet = VBAN_VMRT_Packet_Header()
self._rem._public_packet = self._get_rt()
self.packet_expected = VbanRtPacketHeader()
self._remote._public_packet = self._get_rt()
def _fetch_rt_packet(self) -> Optional[VBAN_VMRT_Packet_Data]:
"""Returns a valid RT Data Packet or None"""
data, _ = self._rem.socks[Socket.response].recvfrom(2048)
# check for packet data
if len(data) > HEADER_SIZE:
# check if packet is of type VBAN
if self.expected_packet.header == data[: HEADER_SIZE - 4]:
return VBAN_VMRT_Packet_Data(
_voicemeeterType=data[28:29],
_reserved=data[29:30],
_buffersize=data[30:32],
_voicemeeterVersion=data[32:36],
_optionBits=data[36:40],
_samplerate=data[40:44],
_inputLeveldB100=data[44:112],
_outputLeveldB100=data[112:240],
_TransportBit=data[240:244],
_stripState=data[244:276],
_busState=data[276:308],
_stripGaindB100Layer1=data[308:324],
_stripGaindB100Layer2=data[324:340],
_stripGaindB100Layer3=data[340:356],
_stripGaindB100Layer4=data[356:372],
_stripGaindB100Layer5=data[372:388],
_stripGaindB100Layer6=data[388:404],
_stripGaindB100Layer7=data[404:420],
_stripGaindB100Layer8=data[420:436],
_busGaindB100=data[436:452],
_stripLabelUTF8c60=data[452:932],
_busLabelUTF8c60=data[932:1412],
)
def _get_rt(self) -> VBAN_VMRT_Packet_Data:
def _get_rt(self) -> VbanRtPacket:
"""Attempt to fetch data packet until a valid one found"""
def fget():
data = False
while not data:
data = self._fetch_rt_packet()
time.sleep(self._rem.DELAY)
return data
return fget()
while True:
data, _ = self._remote.socks[Socket.response].recvfrom(2048)
# check for packet data
if len(data) > HEADER_SIZE:
# check if packet is of type rt packet response
if self.packet_expected.header == data[: HEADER_SIZE - 4]:
return VbanRtPacket(data)
time.sleep(self._remote.DELAY)
def update(self):
print(f"Listening for {', '.join(self._rem.event.get())} events")
print(f"Listening for {', '.join(self._remote.event.get())} events")
(
self._rem.cache["strip_level"],
self._rem.cache["bus_level"],
) = self._rem._get_levels(self._rem.public_packet)
self._remote.cache["strip_level"],
self._remote.cache["bus_level"],
) = self._remote._get_levels(self._remote.public_packet)
while self._rem.running:
while self._remote.running:
start = time.time()
_pp = self._get_rt()
self._rem._strip_buf, self._rem._bus_buf = self._rem._get_levels(_pp)
self._rem._pdirty = _pp.pdirty(self._rem.public_packet)
self._remote._strip_buf, self._remote._bus_buf = self._remote._get_levels(
_pp
)
self._remote._pdirty = _pp.pdirty(self._remote.public_packet)
if self._rem.event.ldirty and self._rem.ldirty:
self._rem.cache["strip_level"] = self._rem._strip_buf
self._rem.cache["bus_level"] = self._rem._bus_buf
self._rem.subject.notify("ldirty")
if self._rem.public_packet != _pp:
self._rem._public_packet = _pp
if self._rem.event.pdirty and self._rem.pdirty:
self._rem.subject.notify("pdirty")
if self._remote.event.ldirty and self._remote.ldirty:
self._remote.cache["strip_level"] = self._remote._strip_buf
self._remote.cache["bus_level"] = self._remote._bus_buf
self._remote.subject.notify("ldirty")
if self._remote.public_packet != _pp:
self._remote._public_packet = _pp
if self._remote.event.pdirty and self._remote.pdirty:
self._remote.subject.notify("pdirty")
elapsed = time.time() - start
if self._rem.ratelimit - elapsed > 0:
time.sleep(self._rem.ratelimit - elapsed)
if self._remote.ratelimit - elapsed > 0:
time.sleep(self._remote.ratelimit - elapsed)