bmdwire 1.2.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bmdwire-1.2.0/bmdwire.egg-info → bmdwire-1.3.0}/PKG-INFO +2 -2
- {bmdwire-1.2.0 → bmdwire-1.3.0}/README.md +1 -1
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/atem.py +4 -1
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/connection.py +36 -1
- bmdwire-1.3.0/atemwire/docs/SURFACE.md +995 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/_helpers.py +13 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/switching.py +4 -17
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/input_video.py +19 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/upstream_keyer.py +11 -1
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/probe.py +9 -2
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/apply.py +51 -4
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/save.py +11 -4
- {bmdwire-1.2.0 → bmdwire-1.3.0/bmdwire.egg-info}/PKG-INFO +2 -2
- {bmdwire-1.2.0 → bmdwire-1.3.0}/bmdwire.egg-info/SOURCES.txt +1 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/pyproject.toml +1 -1
- {bmdwire-1.2.0 → bmdwire-1.3.0}/LICENSE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/LICENSE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/LICENSE-gpl3.txt +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/NOTICE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/_socketqueue.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/_transfer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/docs/MACRO_FORMAT.md +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/docs/MEDIA_LOCK.md +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/docs/PROFILE_FORMAT.md +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/docs/PROFILE_SAVE_RESTORE.md +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/helpers.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/imaging.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/_io.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/downstream_keyer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/fairlight.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/flow.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/hyperdeck.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/media.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/macrotransfer/upstream_keyer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/mediaconvertmodule.c +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/_dsl.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/audio_legacy.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/camera_control.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/color_generator.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/downstream_keyer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/fade_to_black.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/fairlight.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/file_transfer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/hyperdeck.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/lock.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/macros.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/manual.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/media.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/meters.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/multiviewer.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/recording.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/streaming.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/supersource.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/switching.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/system_info.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/tally.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/messages/transition.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/pool.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/_common.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/_enums.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/_xml.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/profile/options.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/protocol.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/py.typed +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/ready.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/state.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/testing.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/atemwire/transport.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/bmdwire.egg-info/dependency_links.txt +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/bmdwire.egg-info/requires.txt +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/bmdwire.egg-info/top_level.txt +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/hyperdeckwire/LICENSE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/hyperdeckwire/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/hyperdeckwire/client.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/hyperdeckwire/setup.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/hyperdeckwire/upload.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/setup.cfg +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/setup.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/LICENSE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/_preamble.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/_protocol.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/network.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/profile/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/profile/_ranges.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/profile/archive.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/ultimattewire/profile/restore.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/videohubwire/LICENSE +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/videohubwire/__init__.py +0 -0
- {bmdwire-1.2.0 → bmdwire-1.3.0}/videohubwire/client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bmdwire
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Python libraries for Blackmagic Design broadcast devices: ATEM switchers, HyperDeck recorders, Ultimatte keyers and Videohub routers
|
|
5
5
|
Author: Lucas Romanenko, Martijn Braam and the OpenAtem contributors
|
|
6
6
|
License-Expression: LGPL-3.0-only AND MIT
|
|
@@ -49,7 +49,7 @@ pip install bmdwire
|
|
|
49
49
|
| **`ultimattewire`** | Ultimatte 12 keyers: archive and restore over the native TCP protocol, Smart Remote 4 compatible zips | MIT | [ultimattewire/README.md](ultimattewire/README.md) |
|
|
50
50
|
| **`videohubwire`** | Videohub routers: state snapshot, crosspoint routing, labels over TCP 9990 | MIT | [videohubwire/README.md](videohubwire/README.md) |
|
|
51
51
|
|
|
52
|
-
All four are pure standard library except atemwire, whose small C extension ships prebuilt for Linux, macOS and Windows on CPython 3.10 to 3.14, so installing needs no compiler. Pin the version in a requirements file (`bmdwire==1.
|
|
52
|
+
All four are pure standard library except atemwire, whose small C extension ships prebuilt for Linux, macOS and Windows on CPython 3.10 to 3.14, so installing needs no compiler. Pin the version in a requirements file (`bmdwire==1.3.0`) so a later release cannot change your install under you.
|
|
53
53
|
|
|
54
54
|
## atemwire stands on pyatem
|
|
55
55
|
|
|
@@ -15,7 +15,7 @@ pip install bmdwire
|
|
|
15
15
|
| **`ultimattewire`** | Ultimatte 12 keyers: archive and restore over the native TCP protocol, Smart Remote 4 compatible zips | MIT | [ultimattewire/README.md](ultimattewire/README.md) |
|
|
16
16
|
| **`videohubwire`** | Videohub routers: state snapshot, crosspoint routing, labels over TCP 9990 | MIT | [videohubwire/README.md](videohubwire/README.md) |
|
|
17
17
|
|
|
18
|
-
All four are pure standard library except atemwire, whose small C extension ships prebuilt for Linux, macOS and Windows on CPython 3.10 to 3.14, so installing needs no compiler. Pin the version in a requirements file (`bmdwire==1.
|
|
18
|
+
All four are pure standard library except atemwire, whose small C extension ships prebuilt for Linux, macOS and Windows on CPython 3.10 to 3.14, so installing needs no compiler. Pin the version in a requirements file (`bmdwire==1.3.0`) so a later release cannot change your install under you.
|
|
19
19
|
|
|
20
20
|
## atemwire stands on pyatem
|
|
21
21
|
|
|
@@ -221,8 +221,11 @@ class ATEM:
|
|
|
221
221
|
|
|
222
222
|
@property
|
|
223
223
|
def connected(self) -> bool:
|
|
224
|
+
"""True while the session is up AND its state is current — False
|
|
225
|
+
during a transport re-handshake, when the state is empty (see
|
|
226
|
+
``ATEMConnection.is_ready``)."""
|
|
224
227
|
conn = self._conn
|
|
225
|
-
return bool(conn and conn.
|
|
228
|
+
return bool(conn and conn.is_ready)
|
|
226
229
|
|
|
227
230
|
@property
|
|
228
231
|
def video_mode(self) -> str:
|
|
@@ -131,6 +131,12 @@ class ATEMConnection:
|
|
|
131
131
|
# immediately reflects the post-disconnect state.
|
|
132
132
|
self._handshake_done: bool = False
|
|
133
133
|
|
|
134
|
+
# ``_session_ready`` follows the protocol's 'connected' /
|
|
135
|
+
# 'disconnected' events: False from the moment a transport
|
|
136
|
+
# re-handshake empties mixerstate until the new state dump is
|
|
137
|
+
# complete. Read through ``is_ready``.
|
|
138
|
+
self._session_ready: bool = False
|
|
139
|
+
|
|
134
140
|
self._lifecycle_lock = threading.Lock() # serializes connect/disconnect calls
|
|
135
141
|
self._transfer_serial_lock = threading.Lock() # one native transfer at a time
|
|
136
142
|
|
|
@@ -168,6 +174,19 @@ class ATEMConnection:
|
|
|
168
174
|
worker = self._worker
|
|
169
175
|
return worker is not None and worker.is_alive()
|
|
170
176
|
|
|
177
|
+
@property
|
|
178
|
+
def is_ready(self) -> bool:
|
|
179
|
+
"""True iff ``is_connected`` AND the switcher's state is current.
|
|
180
|
+
|
|
181
|
+
After ~5 s without packets the transport re-handshakes on its own:
|
|
182
|
+
the protocol raises 'disconnected' and empties ``mixerstate``, the
|
|
183
|
+
same worker carries on, and 'connected' fires again once the new
|
|
184
|
+
state dump is complete. ``is_connected`` stays True through that
|
|
185
|
+
gap (the worker is alive and recovering, so the pool must not evict
|
|
186
|
+
it); ``is_ready`` is False for its whole length.
|
|
187
|
+
"""
|
|
188
|
+
return self._session_ready and self.is_connected
|
|
189
|
+
|
|
171
190
|
@property
|
|
172
191
|
def mixerstate(self) -> dict:
|
|
173
192
|
"""Live state dict from atemwire. Safe to read from any thread — CPython
|
|
@@ -405,6 +424,7 @@ class ATEMConnection:
|
|
|
405
424
|
self._ready_event.clear()
|
|
406
425
|
self._connect_error = None
|
|
407
426
|
self._handshake_done = False
|
|
427
|
+
self._session_ready = False
|
|
408
428
|
self._died_signalled = False
|
|
409
429
|
self.ip_address = ip_address
|
|
410
430
|
|
|
@@ -478,12 +498,27 @@ class ATEMConnection:
|
|
|
478
498
|
# bare (non-indexed) field so the event name is 'change:macro-play-status'.
|
|
479
499
|
def _on_macro_play(contents):
|
|
480
500
|
running = bool(getattr(contents, 'running', False))
|
|
481
|
-
|
|
501
|
+
# Slot 0 is a real macro; only 0xFFFF (or no index) is idle.
|
|
502
|
+
idx = getattr(contents, 'index', None)
|
|
503
|
+
idx = 0xFFFF if idx is None else int(idx)
|
|
482
504
|
if running and idx != 0xFFFF and idx >= 0:
|
|
483
505
|
self.last_run_macro_index = idx
|
|
484
506
|
|
|
485
507
|
self._protocol.on('change:macro-play-status', _on_macro_play)
|
|
486
508
|
|
|
509
|
+
# Session readiness (``is_ready``): 'disconnected' is raised when
|
|
510
|
+
# the transport gives up on the session and mixerstate is
|
|
511
|
+
# emptied; 'connected' when a state dump is complete, at the
|
|
512
|
+
# first connect and again after every re-handshake.
|
|
513
|
+
def _on_connected():
|
|
514
|
+
self._session_ready = True
|
|
515
|
+
|
|
516
|
+
def _on_disconnected():
|
|
517
|
+
self._session_ready = False
|
|
518
|
+
|
|
519
|
+
self._protocol.on('connected', _on_connected)
|
|
520
|
+
self._protocol.on('disconnected', _on_disconnected)
|
|
521
|
+
|
|
487
522
|
try:
|
|
488
523
|
self._protocol.connect()
|
|
489
524
|
except Exception as e:
|