A gtk_switcher/ui/preferences.ui~ => gtk_switcher/ui/preferences.ui~ +731 -0
@@ 0,0 1,731 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <requires lib="libhandy" version="0.0"/>
+ <object class="HdyApplicationWindow" id="window">
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes">Preferences</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyHeaderBar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes">Preferences</property>
+ <property name="show-close-button">True</property>
+ <child type="title">
+ <object class="HdyViewSwitcher">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="stack">mainstack</property>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="mainstack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkBox" id="settings_switcher">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStackSwitcher">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">8</property>
+ <property name="margin-end">8</property>
+ <property name="margin-top">8</property>
+ <property name="margin-bottom">8</property>
+ <property name="stack">settingsstack</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="HdyClamp">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkStack" id="settingsstack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkBox" id="page_general">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin-bottom">4</property>
+ <property name="label" translatable="yes">Video</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">8</property>
+ <property name="column-spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Video standard</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Multiview video standard</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Down convert as</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">SDI output standard</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin-bottom">4</property>
+ <property name="label" translatable="yes">Media pool</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">8</property>
+ <property name="column-spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Clip 1 length</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Clip 2 length</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin-bottom">4</property>
+ <property name="label" translatable="yes">Camera Control</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">8</property>
+ <property name="column-spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Camera control monitoring output</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">general</property>
+ <property name="title" translatable="yes">General</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="page_audio">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">audio</property>
+ <property name="title" translatable="yes">Audio</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="page_multiview">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">16</property>
+ <child>
+ <!-- n-columns=6 n-rows=2 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">4</property>
+ <property name="column-spacing">4</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Multiview layout</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="width">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Audio meters</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">4</property>
+ <property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="label" translatable="yes">1</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="label" translatable="yes">2</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="label" translatable="yes">3</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="label" translatable="yes">4</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=4 n-rows=4 -->
+ <object class="GtkGrid" id="multiview_layout">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">4</property>
+ <property name="column-spacing">4</property>
+ <property name="row-homogeneous">True</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <style>
+ <class name="multiview"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">multiview</property>
+ <property name="title" translatable="yes">Multiview</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="page_labels">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">labels</property>
+ <property name="title" translatable="yes">Labels</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="page_hyperdeck">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">hyperdeck</property>
+ <property name="title" translatable="yes">HyperDeck</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="page_remote">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin-bottom">4</property>
+ <property name="label" translatable="yes">Remote</property>
+ <style>
+ <class name="heading"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-bottom">16</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">8</property>
+ <property name="column-spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">Use RS-422 port for</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">remote</property>
+ <property name="title" translatable="yes">Remote</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">switcher</property>
+ <property name="title" translatable="yes">Switcher</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="settings_app">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">app</property>
+ <property name="title" translatable="yes">Control app</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
M openswitcher_proxy/__main__.py => openswitcher_proxy/__main__.py +8 -1
@@ 8,6 8,7 @@ from openswitcher_proxy.frontend_httpapi import HttpApiFrontendThread
from openswitcher_proxy.frontend_status import StatusFrontendThread
from openswitcher_proxy.frontend_tcp import TcpFrontendThread
from openswitcher_proxy.hardware import HardwareThread
+from openswitcher_proxy.hardware_merge_me import HardwareMergeMEThread
logging.basicConfig(
format="%(asctime)s [%(levelname)-8s %(threadName)-15s] %(message)s",
@@ 26,7 27,13 @@ def run(config_path):
nthreads['hardware'] = {}
for hardware in config['hardware']:
logging.info(f' hardware: {hardware["id"]} ({hardware["label"]})')
- t = HardwareThread(hardware)
+ htype = "atem"
+ if 'type' in hardware:
+ htype = hardware['type']
+ if htype == "atem":
+ t = HardwareThread(hardware)
+ elif htype == "merge-me":
+ t = HardwareMergeMEThread(hardware, nthreads)
t.daemon = True
threads.append(t)
nthreads['hardware'][hardware['id']] = t
M openswitcher_proxy/frontend_status.py => openswitcher_proxy/frontend_status.py +2 -1
@@ 33,10 33,11 @@ class StatusRequestHandler(AuthRequestHandler):
'<table border="1"><tr><th>id</th><th>label</th><th>address</th><th>status</th></tr>'.encode())
for hwid in self.threadpool['hardware']:
hardware = self.threadpool['hardware'][hwid]
+ address = hardware.config['address'] if 'address' in hardware.config else ''
self.wfile.write('<tr>'.encode())
self.wfile.write(f'<td>{hwid}</td>'.encode())
self.wfile.write(f'<td>{hardware.config["label"]}</td>'.encode())
- self.wfile.write(f'<td>{hardware.config["address"]}</td>'.encode())
+ self.wfile.write(f'<td>{address}</td>'.encode())
self.wfile.write(f'<td>{hardware.get_status()}</td>'.encode())
self.wfile.write('</tr>'.encode())
self.wfile.write('</table>'.encode())
A openswitcher_proxy/hardware_merge_me.py => openswitcher_proxy/hardware_merge_me.py +113 -0
@@ 0,0 1,113 @@
+import threading
+import logging
+import time
+from functools import partial
+
+from pyatem.protocol import AtemProtocol
+
+
+class SwitcherDummy:
+ def __init__(self):
+ self.mixerstate = {}
+ self.me_map = []
+
+
+class HardwareMergeMEThread(threading.Thread):
+ def __init__(self, config, namedthreads):
+ self.namedthreads = namedthreads
+ threading.Thread.__init__(self)
+ self.name = 'hw.' + str(config['id'])
+ self.switcher = SwitcherDummy()
+ self.config = config
+ self.stop = False
+ self.status = 'init'
+ self.downstreams = config['hardware'].split(',')
+ self.state = {}
+
+ def run(self):
+ self.status = 'waiting for downstream device sync...'
+ logging.info('Waiting for downstream device sync')
+ for ds in self.downstreams:
+ self.state[ds] = False
+ self.namedthreads['hardware'][ds].switcher.on('connected', partial(self.on_connected, ds))
+ self.namedthreads['hardware'][ds].switcher.on('change', partial(self.on_change, ds))
+ self.namedthreads['hardware'][ds].switcher.on('disconnected', partial(self.on_disconnected, ds))
+
+ while not self.stop:
+ time.sleep(1)
+
+ def get_status(self):
+ return self.status
+
+ def on_connected(self, subdev):
+ self.state[subdev] = True
+ connected = 0
+ for ds in self.state:
+ if self.state[ds]:
+ connected += 1
+ if connected != len(self.state):
+ self.status = 'connecting [{}/{}]'.format(connected, len(self.state))
+ else:
+ self.status = 'connected'
+ logging.info("connected to all downstreams, building initial state")
+ self.build_initial_state()
+
+ def on_disconnected(self, subdev):
+ self.state[subdev] = False
+ self.status = 'lost connection'
+ logging.error('Lost connection with subdevice ' + subdev)
+
+ def on_change(self, subdev, key, value):
+ if key == 'mixer-effect-config':
+ self.switcher.me_map
+
+ def build_initial_state(self):
+ count_mediaplayers = 0
+ count_aux = 0
+ count_multiviewers = 0
+ count_hyperdecks = 0
+ count_dve = 0
+ count_stingers = 0
+ count_supersources = 0
+ count_rs485 = 0
+
+ for ds in self.downstreams:
+ topology = self.namedthreads['hardware'][ds].switcher.mixerstate['topology']
+ me_count = topology.me_units
+ for i in range(0, me_count):
+ self.switcher.me_map.append((ds, i))
+ count_mediaplayers += topology.mediaplayers
+ count_multiviewers += topology.multiviewers
+ count_hyperdecks += topology.hyperdecks
+ count_dve += topology.dve
+ count_stingers += topology.stingers
+ count_supersources += topology.supersources
+ count_rs485 += topology.rs485
+ count_aux += topology.aux_outputs
+
+ self.switcher.mixerstate['topology'] = self.namedthreads['hardware'][self.downstreams[0]].switcher.mixerstate[
+ 'topology']
+ self.switcher.mixerstate['topology'].me_units = len(self.switcher.me_map)
+ self.switcher.mixerstate['topology'].aux_outputs = count_aux
+ self.switcher.mixerstate['topology'].mediaplayers = count_mediaplayers
+ self.switcher.mixerstate['topology'].multiviewers = count_multiviewers
+ self.switcher.mixerstate['topology'].rs485 = count_rs485
+ self.switcher.mixerstate['topology'].hyperdecks = count_hyperdecks
+ self.switcher.mixerstate['topology'].dve = count_dve
+ self.switcher.mixerstate['topology'].stingers = count_stingers
+ self.switcher.mixerstate['topology'].supersources = count_supersources
+ self.switcher.mixerstate['topology'].update()
+
+ for ds in self.downstreams:
+ ds_mixerstate = self.namedthreads['hardware'][ds].switcher.mixerstate
+ for key in ds_mixerstate:
+ if key in ['topology']:
+ continue
+ if isinstance(ds_mixerstate[key], dict):
+ for field in self.ds_mixerstate[key]:
+ if isinstance(ds_mixerstate[key][field], dict):
+ self.switcher.mixerstate[key][field] = ds_mixerstate[key][field]
+ elif hasattr(ds_mixerstate[key][field].__class__, 'ME'):
+
+ if key not in self.switcher.mixerstate:
+ self.switcher.mixerstate[key] = {}
M proxy.toml => proxy.toml +15 -3
@@ 3,11 3,23 @@ id = "mini"
label = "Atem Mini"
address = "192.168.2.84"
+[[hardware]]
+id = "mini2"
+label = "Testdevice"
+address = "192.168.2.17"
+
+[[hardware]]
+id = "merged"
+label = "Mini 2M/E"
+hardware = "mini,mini2"
+type = "merge-me"
+me-input = 4
+
[[frontend]]
type = "http-api"
bind = ":8080"
auth = false
-hardware = "mini"
+hardware = "mini,mini2,merged"
[[frontend]]
type = "websocket"
@@ 15,7 27,7 @@ bind = ":8081"
auth = true
username = "admin"
password = "admin"
-hardware = "mini"
+hardware = "mini,mini2"
static-files = "/var/www/mywebapp"
[[frontend]]
@@ 29,4 41,4 @@ bind = ":8083"
auth = true
username = "admin"
password = "password"
-hardware = "mini">
\ No newline at end of file
+hardware = "mini,mini2"<
\ No newline at end of file
M pyatem/field.py => pyatem/field.py +27 -0
@@ 88,6 88,7 @@ class MixerEffectConfigField(FieldBase):
"""
CODE = "_MeC"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 348,6 349,7 @@ class ProgramBusInputField(FieldBase):
"""
CODE = "PrgI"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 381,6 383,7 @@ class PreviewBusInputField(FieldBase):
"""
CODE = "PrvI"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 852,6 855,22 @@ class TopologyField(FieldBase):
self.stingers = field[10]
self.supersources = field[11]
+ def update(self):
+ field = list(struct.unpack('>28B', self.raw))
+ field[0] = self.me_units
+ field[1] = self.sources
+ field[2] = self.downstream_keyers
+ field[3] = self.aux_outputs
+ field[4] = self.mixminus_outputs
+ field[5] = self.mediaplayers
+ field[6] = self.multiviewers
+ field[7] = self.rs485
+ field[8] = self.hyperdecks
+ field[9] = self.dve
+ field[10] = self.stingers
+ field[11] = self.supersources
+ self.raw = struct.pack('>28B', *field)
+
def __repr__(self):
return '<topology, me={} sources={} aux={}>'.format(self.me_units, self.sources, self.aux_outputs)
@@ 1002,6 1021,7 @@ class TransitionMixField(FieldBase):
"""
CODE = "TMxP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1030,6 1050,7 @@ class FadeToBlackField(FieldBase):
"""
CODE = "FtbP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1059,6 1080,7 @@ class TransitionDipField(FieldBase):
"""
CODE = "TDpP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1097,6 1119,7 @@ class TransitionWipeField(FieldBase):
"""
CODE = "TWpP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1156,6 1179,7 @@ class TransitionDveField(FieldBase):
"""
CODE = "TDvP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1534,6 1558,7 @@ class KeyPropertiesBaseField(FieldBase):
"""
CODE = "KeBP"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1562,6 1587,7 @@ class KeyPropertiesDveField(FieldBase):
"""
CODE = "KeDV"
+ ME = "index"
def __init__(self, raw):
self.raw = raw
@@ 1614,6 1640,7 @@ class KeyPropertiesLumaField(FieldBase):
"""
CODE = "KeLm"
+ ME = "index"
def __init__(self, raw):
self.raw = raw