mirror of
https://github.com/onyx-and-iris/vban-cmd-python.git
synced 2025-01-18 18:40:47 +00:00
add some tests, commands and bus class
added a couple of lower tests. add some string tests to higher tests. added bus class add higher commands show, hide, shutdown, restart, version and type
This commit is contained in:
parent
6e40ceb346
commit
364e456c94
@ -1,5 +1,6 @@
|
|||||||
import vban_cmd
|
import vban_cmd
|
||||||
from vban_cmd import kinds
|
from vban_cmd import kinds
|
||||||
|
from vban_cmd.channel import Modes
|
||||||
import socket
|
import socket
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
@ -13,5 +14,7 @@ def setup_package():
|
|||||||
tests.worker = Thread(target=tests._send_register_rt, daemon=True)
|
tests.worker = Thread(target=tests._send_register_rt, daemon=True)
|
||||||
tests.worker.start()
|
tests.worker.start()
|
||||||
|
|
||||||
|
tests._modes = Modes()
|
||||||
|
|
||||||
def teardown_package():
|
def teardown_package():
|
||||||
pass
|
pass
|
||||||
|
42
tests/tests_higher.py
Normal file
42
tests/tests_higher.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from nose.tools import assert_equal, nottest
|
||||||
|
from parameterized import parameterized, parameterized_class
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from tests import tests
|
||||||
|
|
||||||
|
#@nottest
|
||||||
|
@parameterized_class([
|
||||||
|
{ "val": False }, { "val": True }
|
||||||
|
])
|
||||||
|
class TestSetAndGetBoolHigher(unittest.TestCase):
|
||||||
|
""" strip tests, physical and virtual """
|
||||||
|
@parameterized.expand([
|
||||||
|
(0, 'mute'), (2, 'mono'), (3, 'A1'), (3, 'B3')
|
||||||
|
])
|
||||||
|
def test_it_sets_and_gets_strip_bool_params(self, index, param):
|
||||||
|
setattr(tests.strip[index], param, self.val)
|
||||||
|
retval = getattr(tests.strip[index], param)
|
||||||
|
self.assertTrue(isinstance(retval, bool))
|
||||||
|
assert_equal(retval, self.val)
|
||||||
|
|
||||||
|
|
||||||
|
#@nottest
|
||||||
|
@parameterized_class([
|
||||||
|
{ "val": "test0" }, { "val": "test1" }
|
||||||
|
])
|
||||||
|
class TestSetAndGetStringHigher(unittest.TestCase):
|
||||||
|
""" strip tests, physical and virtual """
|
||||||
|
@parameterized.expand([
|
||||||
|
(2, 'label'), (3, 'label')
|
||||||
|
])
|
||||||
|
def test_it_sets_and_gets_strip_string_params(self, index, param):
|
||||||
|
setattr(tests.strip[index], param, self.val)
|
||||||
|
assert_equal(getattr(tests.strip[index], param), self.val)
|
||||||
|
|
||||||
|
""" bus tests, physical and virtual """
|
||||||
|
@parameterized.expand([
|
||||||
|
(0, 'label'), (4, 'label')
|
||||||
|
])
|
||||||
|
def test_it_sets_and_gets_bus_string_params(self, index, param):
|
||||||
|
setattr(tests.bus[index], param, self.val)
|
||||||
|
assert_equal(getattr(tests.bus[index], param), self.val)
|
29
tests/tests_lower.py
Normal file
29
tests/tests_lower.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from nose.tools import assert_equal, nottest
|
||||||
|
from parameterized import parameterized, parameterized_class
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from tests import tests
|
||||||
|
|
||||||
|
#@nottest
|
||||||
|
@parameterized_class([
|
||||||
|
{ "val": 0 }, { "val": 1 },
|
||||||
|
])
|
||||||
|
class TestSetAndGetParamsLower(unittest.TestCase):
|
||||||
|
""" get_rt, set_rt test """
|
||||||
|
@parameterized.expand([
|
||||||
|
(0, 'mute'), (4, 'mute'),
|
||||||
|
])
|
||||||
|
def test_it_sets_and_gets_strip_bool_params(self, index, param):
|
||||||
|
tests.set_rt(f'Strip[{index}]', param, self.val)
|
||||||
|
retval = tests.get_rt()
|
||||||
|
retval = not int.from_bytes(retval.stripstate[index], 'little') & tests._modes._mute == 0
|
||||||
|
assert_equal(retval, self.val)
|
||||||
|
|
||||||
|
@parameterized.expand([
|
||||||
|
(0, 'mono'), (5, 'mono'),
|
||||||
|
])
|
||||||
|
def test_it_sets_and_gets_strip_bool_params(self, index, param):
|
||||||
|
tests.set_rt(f'Strip[{index}]', param, self.val)
|
||||||
|
retval = tests.get_rt()
|
||||||
|
retval = not int.from_bytes(retval.stripstate[index], 'little') & tests._modes._mono == 0
|
||||||
|
assert_equal(retval, self.val)
|
93
vban_cmd/bus.py
Normal file
93
vban_cmd/bus.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
from .errors import VMCMDErrors
|
||||||
|
from . import channel
|
||||||
|
from .channel import Channel
|
||||||
|
from . import kinds
|
||||||
|
from .meta import bus_output_prop
|
||||||
|
|
||||||
|
class OutputBus(Channel):
|
||||||
|
""" Base class for output buses. """
|
||||||
|
@classmethod
|
||||||
|
def make(cls, is_physical, remote, index, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Factory function for output busses.
|
||||||
|
Returns a physical/virtual bus of a kind.
|
||||||
|
"""
|
||||||
|
OutputBus = PhysicalOutputBus if is_physical else VirtualOutputBus
|
||||||
|
OB_cls = type(f'Bus{remote.kind.name}', (OutputBus,), {
|
||||||
|
})
|
||||||
|
return OB_cls(remote, index, *args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
return f'Bus[{self.index}]'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mute(self) -> bool:
|
||||||
|
data = self.getter()
|
||||||
|
return not int.from_bytes(data.busstate[self.index], 'little') & self._modes._mute == 0
|
||||||
|
|
||||||
|
@mute.setter
|
||||||
|
def mute(self, val: bool):
|
||||||
|
if not isinstance(val, bool) and val not in (0,1):
|
||||||
|
raise VMCMDErrors('mute is a boolean parameter')
|
||||||
|
self.setter('mute', 1 if val else 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mono(self) -> bool:
|
||||||
|
data = self.getter()
|
||||||
|
return not int.from_bytes(data.busstate[self.index], 'little') & self._modes._mono == 0
|
||||||
|
|
||||||
|
@mono.setter
|
||||||
|
def mono(self, val: bool):
|
||||||
|
if not isinstance(val, bool) and val not in (0,1):
|
||||||
|
raise VMCMDErrors('mono is a boolean parameter')
|
||||||
|
self.setter('mono', 1 if val else 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def eq(self) -> bool:
|
||||||
|
data = self.getter()
|
||||||
|
return not int.from_bytes(data.busstate[self.index], 'little') & self._modes._eq == 0
|
||||||
|
|
||||||
|
@eq.setter
|
||||||
|
def eq(self, val: bool):
|
||||||
|
if not isinstance(val, bool) and val not in (0,1):
|
||||||
|
raise ('eq is a boolean parameter')
|
||||||
|
self.setter('eq.On', 1 if val else 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def eq_ab(self) -> bool:
|
||||||
|
data = self.getter()
|
||||||
|
return not int.from_bytes(data.busstate[self.index], 'little') & self._modes._eqb == 0
|
||||||
|
|
||||||
|
@eq_ab.setter
|
||||||
|
def eq_ab(self, val: bool):
|
||||||
|
if not isinstance(val, bool) and val not in (0,1):
|
||||||
|
raise VMCMDErrors('eq_ab is a boolean parameter')
|
||||||
|
self.setter('eq.ab', 1 if val else 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def label(self) -> str:
|
||||||
|
data = self.getter()
|
||||||
|
return data.buslabels[self.index]
|
||||||
|
|
||||||
|
@label.setter
|
||||||
|
def label(self, val: str):
|
||||||
|
if not isinstance(val, str):
|
||||||
|
raise VMCMDErrors('label is a string parameter')
|
||||||
|
self.setter('Label', val)
|
||||||
|
|
||||||
|
|
||||||
|
class PhysicalOutputBus(OutputBus):
|
||||||
|
@property
|
||||||
|
def device(self) -> str:
|
||||||
|
data = self.getter()
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sr(self) -> int:
|
||||||
|
data = self.getter()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualOutputBus(OutputBus):
|
||||||
|
pass
|
@ -1,7 +1,7 @@
|
|||||||
from .errors import VMCMDErrors
|
from .errors import VMCMDErrors
|
||||||
|
|
||||||
def strip_output_prop(param):
|
def strip_output_prop(param):
|
||||||
""" A channel prop. """
|
""" A strip output prop. """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
data = self.getter()
|
data = self.getter()
|
||||||
return not int.from_bytes(data.stripstate[self.index], 'little') & getattr(self._modes, f'_bus{param.lower()}') == 0
|
return not int.from_bytes(data.stripstate[self.index], 'little') & getattr(self._modes, f'_bus{param.lower()}') == 0
|
||||||
@ -10,3 +10,14 @@ def strip_output_prop(param):
|
|||||||
raise VMCMDErrors(f'{param} is a boolean parameter')
|
raise VMCMDErrors(f'{param} is a boolean parameter')
|
||||||
self.setter(param, 1 if val else 0)
|
self.setter(param, 1 if val else 0)
|
||||||
return property(fget, fset)
|
return property(fget, fset)
|
||||||
|
|
||||||
|
def bus_output_prop(param):
|
||||||
|
""" A bus output prop. """
|
||||||
|
def fget(self):
|
||||||
|
data = self.getter()
|
||||||
|
return not int.from_bytes(data.busstate[self.index], 'little') & getattr(self._modes, f'_bus{param.lower()}') == 0
|
||||||
|
def fset(self, val):
|
||||||
|
if not isinstance(val, bool) and val not in (0, 1):
|
||||||
|
raise VMCMDErrors(f'{param} is a boolean parameter')
|
||||||
|
self.setter(param, 1 if val else 0)
|
||||||
|
return property(fget, fset)
|
||||||
|
@ -4,19 +4,19 @@ import socket
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
import sys
|
import sys
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple, NoReturn
|
||||||
|
|
||||||
from .errors import VMCMDErrors
|
from .errors import VMCMDErrors
|
||||||
from . import kinds
|
from . import kinds
|
||||||
from .dataclass import (
|
from .dataclass import (
|
||||||
HEADER_SIZE,
|
HEADER_SIZE,
|
||||||
MAX_PACKET_SIZE,
|
|
||||||
VBAN_VMRT_Packet_Data,
|
VBAN_VMRT_Packet_Data,
|
||||||
VBAN_VMRT_Packet_Header,
|
VBAN_VMRT_Packet_Header,
|
||||||
RegisterRTHeader,
|
RegisterRTHeader,
|
||||||
TextRequestHeader
|
TextRequestHeader
|
||||||
)
|
)
|
||||||
from .strip import InputStrip
|
from .strip import InputStrip
|
||||||
|
from .bus import OutputBus
|
||||||
|
|
||||||
class VbanCmd(abc.ABC):
|
class VbanCmd(abc.ABC):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -26,6 +26,7 @@ class VbanCmd(abc.ABC):
|
|||||||
self._bps = kwargs['bps']
|
self._bps = kwargs['bps']
|
||||||
self._channel = kwargs['channel']
|
self._channel = kwargs['channel']
|
||||||
self._delay = kwargs['delay']
|
self._delay = kwargs['delay']
|
||||||
|
self._max_polls = kwargs['max_polls']
|
||||||
self._bps_opts = \
|
self._bps_opts = \
|
||||||
[0, 110, 150, 300, 600, 1200, 2400, 4800, 9600, 14400,19200, 31250,
|
[0, 110, 150, 300, 600, 1200, 2400, 4800, 9600, 14400,19200, 31250,
|
||||||
38400, 57600, 115200, 128000, 230400, 250000, 256000, 460800,921600,
|
38400, 57600, 115200, 128000, 230400, 250000, 256000, 460800,921600,
|
||||||
@ -99,14 +100,13 @@ class VbanCmd(abc.ABC):
|
|||||||
while not data:
|
while not data:
|
||||||
data = self._fetch_rt_packet()
|
data = self._fetch_rt_packet()
|
||||||
return data
|
return data
|
||||||
for i in range(2):
|
for i in range(self._max_polls):
|
||||||
data = fget()
|
data = fget()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def set_rt(self, id_, param, val):
|
def set_rt(self, id_, param, val):
|
||||||
cmd = f'{id_}.{param}={val}'
|
cmd = f'{id_}.{param}={val}'
|
||||||
if self._sendrequest_string_socket in self.ready_to_write:
|
if self._sendrequest_string_socket in self.ready_to_write:
|
||||||
print(f'sending {cmd} to {socket.gethostbyname(self._ip)}:{self._port}')
|
|
||||||
self._sendrequest_string_socket.sendto(
|
self._sendrequest_string_socket.sendto(
|
||||||
self._text_header.header + cmd.encode(), (socket.gethostbyname(self._ip), self._port)
|
self._text_header.header + cmd.encode(), (socket.gethostbyname(self._ip), self._port)
|
||||||
)
|
)
|
||||||
@ -114,6 +114,29 @@ class VbanCmd(abc.ABC):
|
|||||||
self._text_header.framecounter = count.to_bytes(4, 'little')
|
self._text_header.framecounter = count.to_bytes(4, 'little')
|
||||||
sleep(self._delay)
|
sleep(self._delay)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
data = self.get_rt()
|
||||||
|
return data.voicemeetertype
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self):
|
||||||
|
data = self.get_rt()
|
||||||
|
return data.voicemeeterversion
|
||||||
|
|
||||||
|
def show(self) -> NoReturn:
|
||||||
|
""" Shows Voicemeeter if it's hidden. """
|
||||||
|
self.set_rt('Command', 'Show', 1)
|
||||||
|
def hide(self) -> NoReturn:
|
||||||
|
""" Hides Voicemeeter if it's shown. """
|
||||||
|
self.set_rt('Command', 'Show', 0)
|
||||||
|
def shutdown(self) -> NoReturn:
|
||||||
|
""" Closes Voicemeeter. """
|
||||||
|
self.set_rt('Command', 'Shutdown', 1)
|
||||||
|
def restart(self) -> NoReturn:
|
||||||
|
""" Restarts Voicemeeter's audio engine. """
|
||||||
|
self.set_rt('Command', 'Restart', 1)
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||||
self._rt_packet_socket.close()
|
self._rt_packet_socket.close()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
@ -129,7 +152,7 @@ def _make_remote(kind: NamedTuple) -> VbanCmd:
|
|||||||
def init(self, *args, **kwargs):
|
def init(self, *args, **kwargs):
|
||||||
defaultkwargs = {
|
defaultkwargs = {
|
||||||
'ip': None, 'port': 6990, 'streamname': 'Command1', 'bps': 0,
|
'ip': None, 'port': 6990, 'streamname': 'Command1', 'bps': 0,
|
||||||
'channel': 0, 'delay': 0.001,
|
'channel': 0, 'delay': 0.001, 'max_polls': 2
|
||||||
}
|
}
|
||||||
kwargs = defaultkwargs | kwargs
|
kwargs = defaultkwargs | kwargs
|
||||||
VbanCmd.__init__(self, *args, **kwargs)
|
VbanCmd.__init__(self, *args, **kwargs)
|
||||||
@ -139,6 +162,9 @@ def _make_remote(kind: NamedTuple) -> VbanCmd:
|
|||||||
self.strip = \
|
self.strip = \
|
||||||
tuple(InputStrip.make((i < self.phys_in), self, i)
|
tuple(InputStrip.make((i < self.phys_in), self, i)
|
||||||
for i in range(self.phys_in + self.virt_in))
|
for i in range(self.phys_in + self.virt_in))
|
||||||
|
self.bus = \
|
||||||
|
tuple(OutputBus.make((i < self.phys_out), self, i)
|
||||||
|
for i in range(self.phys_out + self.virt_out))
|
||||||
|
|
||||||
return type(f'VbanCmd{kind.name}', (VbanCmd,), {
|
return type(f'VbanCmd{kind.name}', (VbanCmd,), {
|
||||||
'__init__': init,
|
'__init__': init,
|
||||||
|
Loading…
Reference in New Issue
Block a user