mx-remote 8.0.2__tar.gz → 9.0.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.
- {mx_remote-8.0.2 → mx_remote-9.0.0}/PKG-INFO +1 -1
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/api.md +31 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/oneip.md +59 -1
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/Interface.py +151 -13
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/Interface.pyi +45 -1
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/const.py +1 -1
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Constants.py +43 -6
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Constants.pyi +16 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Factory.py +3 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +25 -8
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPOsdSync.py +45 -12
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPOsdSync.pyi +10 -2
- mx_remote-9.0.0/mx_remote/proto/FrameV2IPPrivacy.py +83 -0
- mx_remote-9.0.0/mx_remote/proto/FrameV2IPPrivacy.pyi +22 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Device.py +106 -8
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Device.pyi +14 -2
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/OsdSync.py +1 -11
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Remote.py +14 -3
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Remote.pyi +3 -1
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/handlers.py +1 -0
- mx_remote-9.0.0/tests/osdmessage.py +114 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/osdsync.py +12 -13
- mx_remote-9.0.0/tests/privacy.py +112 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/proto_stamp.py +1 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/run.py +2 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/smoke.py +1 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipsettings.py +59 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/.gitignore +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/AGENTS.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/CLAUDE.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/LICENSE +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/README.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/README.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/_static/brand.css +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/_static/favicon.svg +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/_static/logo-dark.svg +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/_static/logo.svg +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/audio.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/callbacks.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/conf.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/configuration.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/devices-and-bays.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/diagnostics.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/index.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/multiviewer.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/requirements.txt +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/docs/routing.md +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/hatch_build.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/Uid.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/Uid.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/__init__.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/__init__.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/compat.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/compat.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/const.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/deprecated.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/deprecated.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/main.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/main.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/BayConfig.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/BayConfig.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Data.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Data.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Factory.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAudioClip.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAudioClip.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAudioSetRoute.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameAudioSetRoute.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBase.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBase.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayConfig.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayConfig.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayContent.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayContent.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayHide.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayHide.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameBayStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameConnectStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameDebug.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameDebug.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameDiscover.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameDiscover.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameEDID.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameEDID.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameEDIDProfile.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFactoryReset.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFactoryReset.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFilterStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFirmwareVersion.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameFirmwareVersion.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameHeader.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameHeader.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameHello.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameHello.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameLinks.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameLinks.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMeshOperation.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMeshOperation.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMirrorStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMonitoringPulse.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameNetworkStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FramePing.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FramePing.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FramePowerChange.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FramePowerChange.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCAction.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCAction.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCIr.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCIr.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCKey.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCKey.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCSettings.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRCSettings.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameReboot.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameReboot.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRoutingChange.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetInstaller.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetName.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetName.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetRoute.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetRoute.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetupStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSignalStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSignalStatusNew.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSysTemperature.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSystemStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTXRCAction.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTXRCKey.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTime.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTime.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTimeZone.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTimeZone.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTopology.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTopology.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTxIR.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameTxIR.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUnitCommand.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUnitCommand.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUnitStatus.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUnitStatus.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUpgradeFPGA.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPAudio.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPAudio.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPBayMapping.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPDetectBays.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPLink.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPMultiviewer.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPPowerSave.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSetMaster.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSettingsAll.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSettingsAll.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSinkSdp.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSinkSdp.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSourceSwitch.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSources.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPSources.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPStats.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPStats.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPTestcard.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPTestcard.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPTiling.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPVideoWall.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolume.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolume.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeDown.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeSet.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeUp.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/LinkConfig.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/LinkConfig.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Multiviewer.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Multiviewer.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Svd.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/Svd.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/V2IPConfig.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/V2IPConfig.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/V2IPStats.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/V2IPStats.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/__init__.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/__init__.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/proto/svd.csv +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/py.typed +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Bay.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Bay.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/ConnectionAsync.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/ConnectionAsync.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Link.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/Link.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/OsdSync.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/State.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/State.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/V2IP.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/mx_remote/remote/V2IP.pyi +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/pyproject.toml +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/audio_ir.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/audiolock.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/baycontent.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/capture.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/complete.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/deprecated.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/e2e.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/entry.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/handlers_cover.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/hello.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/idempotent.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/lengths.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/merge.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/mesh.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/meshbays.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/newops.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/offline.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/offsets.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/ping.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/protogate.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/rcsettings.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/roundtrip.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/routes.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/sources.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/staterequest.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/stats.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/structs.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/txresult.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/unit.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/unknowns.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipptp.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipscaling.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipsdp.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipsubject.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2iptestcard.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/v2ipvlan.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/vdetails.py +0 -0
- {mx_remote-8.0.2 → mx_remote-9.0.0}/tests/wirefix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mx_remote
|
|
3
|
-
Version:
|
|
3
|
+
Version: 9.0.0
|
|
4
4
|
Summary: Python 3 library for interfacing with MX Remote compatible devices
|
|
5
5
|
Project-URL: Homepage, https://github.com/opdenkamp/mx-remote/
|
|
6
6
|
Project-URL: Documentation, https://opdenkamp.github.io/mx-remote/
|
|
@@ -85,6 +85,23 @@ place, backgrounds and logo images.
|
|
|
85
85
|
.. autodata:: mx_remote.proto.Constants.OSD_SYNC_PERCENT_MAX
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
## Overlay messages
|
|
89
|
+
|
|
90
|
+
The message on a unit's output, which the overlay sync opcode carries too.
|
|
91
|
+
|
|
92
|
+
```{eval-rst}
|
|
93
|
+
.. autoclass:: mx_remote.OsdMessage
|
|
94
|
+
:members:
|
|
95
|
+
|
|
96
|
+
.. autoclass:: mx_remote.proto.Constants.OsdMessageFlag
|
|
97
|
+
:members:
|
|
98
|
+
|
|
99
|
+
.. autoclass:: mx_remote.proto.Constants.OsdMessagePriority
|
|
100
|
+
:members:
|
|
101
|
+
|
|
102
|
+
.. autodata:: mx_remote.proto.Constants.OSD_MESSAGE_TEXT_MAX
|
|
103
|
+
```
|
|
104
|
+
|
|
88
105
|
## Device identity
|
|
89
106
|
|
|
90
107
|
```{eval-rst}
|
|
@@ -180,6 +197,8 @@ state only the device reports.
|
|
|
180
197
|
|
|
181
198
|
.. autodata:: mx_remote.proto.Constants.ONEIP_STREAM_TTL_DEFAULT
|
|
182
199
|
|
|
200
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_SINK_ROTATION_MAX
|
|
201
|
+
|
|
183
202
|
.. autodata:: mx_remote.proto.Constants.ONEIP_PTP_DOMAIN_MAX
|
|
184
203
|
```
|
|
185
204
|
|
|
@@ -240,6 +259,18 @@ What an output plays from a session description, and how it is timed.
|
|
|
240
259
|
.. autodata:: mx_remote.proto.Constants.ONEIP_SDP_MAX
|
|
241
260
|
```
|
|
242
261
|
|
|
262
|
+
## OneIP stream encryption
|
|
263
|
+
|
|
264
|
+
How a source unit encrypts its streams, as it reports it.
|
|
265
|
+
|
|
266
|
+
```{eval-rst}
|
|
267
|
+
.. autoclass:: mx_remote.OneIPPrivacy
|
|
268
|
+
:members:
|
|
269
|
+
|
|
270
|
+
.. autoclass:: mx_remote.OneIPPrivacyStream
|
|
271
|
+
:members:
|
|
272
|
+
```
|
|
273
|
+
|
|
243
274
|
## OneIP test card
|
|
244
275
|
|
|
245
276
|
A sink's test pattern, tone and lip-sync flash, and the ranges it accepts.
|
|
@@ -247,6 +247,10 @@ that takes a power save level switches it off, so a level write, this client's
|
|
|
247
247
|
or another sender's, clears it unless the same frame states it. Firmware
|
|
248
248
|
without the bit never reports it, and the switch is refused there.
|
|
249
249
|
|
|
250
|
+
`OneIPDeviceSetting.CLOUD` is a switch for whether a device connects to the
|
|
251
|
+
cloud service. A device that does not report it connects regardless, and the
|
|
252
|
+
switch is refused there.
|
|
253
|
+
|
|
250
254
|
### PTP
|
|
251
255
|
|
|
252
256
|
A device's PTP mode, domain and grandmaster priority1 are settings like the
|
|
@@ -284,10 +288,23 @@ same block, behind `SAP_EXPIRE` and `SAP_INTERVAL`, and are set the same way;
|
|
|
284
288
|
`SAP_LISTEN` and `SAP_ANNOUNCE` are switches like the other on/off settings.
|
|
285
289
|
A device with an encoder reports its streams' TTL there too, behind
|
|
286
290
|
`STREAM_TTL`; a TTL of 0 is refused, as a device changes nothing for one.
|
|
291
|
+
A device with an HDMI output reports the angle its output is turned by,
|
|
292
|
+
clockwise, behind `SINK_ROTATION`, with the step its video processor turns by.
|
|
293
|
+
It takes 0 or a multiple of that step up to `ONEIP_SINK_ROTATION_MAX`, so any
|
|
294
|
+
other angle is refused before it is sent, and the step is never written.
|
|
295
|
+
`set_all_oneip_device_settings` can only check the range; each device judges
|
|
296
|
+
the step.
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
m = settings.ptp_messages
|
|
300
|
+
print(m.sink_rotation, m.sink_rotation_step) # e.g. 0 and 90
|
|
301
|
+
await device.set_oneip_ptp_messages(OneIPDeviceSetting.SINK_ROTATION,
|
|
302
|
+
OneIPPtpMessages(sink_rotation=180))
|
|
303
|
+
```
|
|
287
304
|
|
|
288
305
|
Only the values behind the bits named are sent. A DSCP above `ONEIP_DSCP_MAX` is
|
|
289
306
|
refused, and not cached from another controller's write. A write carrying one of
|
|
290
|
-
these runs on to 224 bytes, or 232 with the TTL; every other write keeps the 176
|
|
307
|
+
these runs on to 224 bytes, or 232 with the TTL or the rotation; every other write keeps the 176
|
|
291
308
|
every device knows.
|
|
292
309
|
|
|
293
310
|
What the device's clock is actually doing is its PTP state, which only the
|
|
@@ -412,6 +429,47 @@ save then takes this content rather than the controller's. Logo images are
|
|
|
412
429
|
served over HTTP from this client, on `logo_port` or a free port. Content a unit
|
|
413
430
|
would refuse is refused before anything is sent; see `send_osd_sync`.
|
|
414
431
|
|
|
432
|
+
### Overlay messages
|
|
433
|
+
|
|
434
|
+
A unit shows a message on its output, over the picture, until it restarts. The
|
|
435
|
+
text is markup of at most `OSD_MESSAGE_TEXT_MAX` bytes with no control
|
|
436
|
+
character, shown with a logo: 0 the built-in one, -1 none, 1 to 5 a slot. Its
|
|
437
|
+
priority places it against the unit's own messages, such as Locate Device.
|
|
438
|
+
|
|
439
|
+
```python
|
|
440
|
+
from mx_remote.proto.Constants import OsdMessagePriority
|
|
441
|
+
|
|
442
|
+
await sink.show_osd_message('Back at <b>3</b>', logo=-1, priority=OsdMessagePriority.TOP)
|
|
443
|
+
await sink.request_osd_message() # the unit answers with what it shows
|
|
444
|
+
await sink.clear_osd_message()
|
|
445
|
+
|
|
446
|
+
print(sink.osd_message) # None until the unit has answered
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
A unit takes a message only from management, which this client announces
|
|
450
|
+
itself as, and answers every write and request with the message it then has;
|
|
451
|
+
`on_osd_message_changed` reports a change. The answer carries
|
|
452
|
+
`OsdMessageFlag.REFUSED` when the unit did not take the write, as when its
|
|
453
|
+
video processor has no message layer. A text, logo or priority a unit would
|
|
454
|
+
refuse is refused before it is sent, as is a device that is not a OneIP output.
|
|
455
|
+
|
|
456
|
+
### Stream encryption
|
|
457
|
+
|
|
458
|
+
A source unit from protocol 0x30 encrypts its video, audio and ancillary
|
|
459
|
+
streams, and reports what a receiver needs to decrypt them whenever that
|
|
460
|
+
changes and at least once a minute. The key itself never travels: every unit of
|
|
461
|
+
a mesh holds the same one, and this library holds none.
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
await source.request_oneip_privacy() # report now
|
|
465
|
+
await mx.request_all_oneip_privacy() # every source unit of the mesh
|
|
466
|
+
|
|
467
|
+
print(source.oneip_privacy) # None until the unit has reported
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
A request to a unit that is not a source, or that is below protocol 0x30, is
|
|
471
|
+
refused before it is sent.
|
|
472
|
+
|
|
415
473
|
### Every device at once
|
|
416
474
|
|
|
417
475
|
One broadcast changes settings on every OneIP device of the mesh. Each device
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
######################################################
|
|
7
7
|
|
|
8
8
|
from abc import ABC, abstractmethod
|
|
9
|
-
from dataclasses import dataclass
|
|
9
|
+
from dataclasses import dataclass, replace
|
|
10
10
|
from datetime import datetime, timezone
|
|
11
11
|
from enum import IntEnum
|
|
12
12
|
import time
|
|
@@ -2215,8 +2215,8 @@ def _wire_enum(cls:Any, value:int) -> Any:
|
|
|
2215
2215
|
@dataclass(frozen=True)
|
|
2216
2216
|
class OneIPPtpMessages:
|
|
2217
2217
|
"""
|
|
2218
|
-
How a OneIP device paces its PTP messages, its SAP timings
|
|
2219
|
-
TTL, which a frame carries in the same block. Each value is behind its own bit of
|
|
2218
|
+
How a OneIP device paces its PTP messages, its SAP timings, its streams'
|
|
2219
|
+
TTL and its output's rotation, which a frame carries in the same block. Each value is behind its own bit of
|
|
2220
2220
|
OneIPDeviceSettings.valid, one of ONEIP_DEVICE_SETTINGS_BLOCK.
|
|
2221
2221
|
|
|
2222
2222
|
Intervals are base-2 logarithms of seconds, so -3 is 125 ms and 1 is 2 s.
|
|
@@ -2241,6 +2241,19 @@ class OneIPPtpMessages:
|
|
|
2241
2241
|
"""The TTL of the device's streams, 1 to 255, behind STREAM_TTL. A device
|
|
2242
2242
|
whose video processor cannot change it keeps the setting and sends
|
|
2243
2243
|
ONEIP_STREAM_TTL_DEFAULT."""
|
|
2244
|
+
sink_rotation: int = 0
|
|
2245
|
+
"""The degrees the device's HDMI output is turned by, clockwise, at most
|
|
2246
|
+
ONEIP_SINK_ROTATION_MAX, behind SINK_ROTATION."""
|
|
2247
|
+
sink_rotation_step: int = 0
|
|
2248
|
+
"""The step the output turns by: the device takes only an angle that is a
|
|
2249
|
+
multiple of it, and 0 alone when it is 0. Only the device reports it,
|
|
2250
|
+
behind the same bit."""
|
|
2251
|
+
|
|
2252
|
+
def takes_sink_rotation(self, degrees:int) -> bool:
|
|
2253
|
+
"""Whether a device reporting this step takes degrees as its output's
|
|
2254
|
+
rotation."""
|
|
2255
|
+
return (degrees == 0) or ((0 < degrees <= ONEIP_SINK_ROTATION_MAX) and (self.sink_rotation_step != 0)
|
|
2256
|
+
and (degrees % self.sink_rotation_step == 0))
|
|
2244
2257
|
|
|
2245
2258
|
def merge(self, other:'OneIPPtpMessages', which:OneIPDeviceSetting) -> 'OneIPPtpMessages':
|
|
2246
2259
|
"""The values behind the bits of which copied from other, the rest kept."""
|
|
@@ -2253,7 +2266,9 @@ class OneIPPtpMessages:
|
|
|
2253
2266
|
dscp=(other if (S.PTP_DSCP in which) else self).dscp,
|
|
2254
2267
|
sap_expire_min=(other if (S.SAP_EXPIRE in which) else self).sap_expire_min,
|
|
2255
2268
|
sap_interval_s=(other if (S.SAP_INTERVAL in which) else self).sap_interval_s,
|
|
2256
|
-
stream_ttl=(other if (S.STREAM_TTL in which) else self).stream_ttl
|
|
2269
|
+
stream_ttl=(other if (S.STREAM_TTL in which) else self).stream_ttl,
|
|
2270
|
+
sink_rotation=(other if (S.SINK_ROTATION in which) else self).sink_rotation,
|
|
2271
|
+
sink_rotation_step=(other if (S.SINK_ROTATION in which) else self).sink_rotation_step)
|
|
2257
2272
|
|
|
2258
2273
|
def describe(self, valid:OneIPDeviceSetting) -> list[str]:
|
|
2259
2274
|
"""The values behind the bits of valid, one "name=value" each."""
|
|
@@ -2266,7 +2281,8 @@ class OneIPPtpMessages:
|
|
|
2266
2281
|
(S.PTP_DSCP, 'ptp_dscp', self.dscp),
|
|
2267
2282
|
(S.SAP_EXPIRE, 'sap_expire_min', self.sap_expire_min),
|
|
2268
2283
|
(S.SAP_INTERVAL, 'sap_interval_s', self.sap_interval_s),
|
|
2269
|
-
(S.STREAM_TTL, 'stream_ttl', self.stream_ttl)
|
|
2284
|
+
(S.STREAM_TTL, 'stream_ttl', self.stream_ttl),
|
|
2285
|
+
(S.SINK_ROTATION, 'sink_rotation', self.sink_rotation))
|
|
2270
2286
|
if (bit in valid)]
|
|
2271
2287
|
|
|
2272
2288
|
@dataclass(frozen=True)
|
|
@@ -2317,8 +2333,7 @@ class OsdSyncRequest:
|
|
|
2317
2333
|
missing: bytes
|
|
2318
2334
|
"""The settings it lacks, bit i standing for setting i, 16 bytes."""
|
|
2319
2335
|
source: MxrDeviceUid
|
|
2320
|
-
"""Who sent the sync it asks about. Empty when it asks for a new sync
|
|
2321
|
-
from a unit whose module does not name the source."""
|
|
2336
|
+
"""Who sent the sync it asks about. Empty when it asks for a new sync."""
|
|
2322
2337
|
|
|
2323
2338
|
def is_missing(self, index:int) -> bool:
|
|
2324
2339
|
"""Whether the unit lacks setting index."""
|
|
@@ -2394,6 +2409,28 @@ class OsdSyncReport:
|
|
|
2394
2409
|
reason: str
|
|
2395
2410
|
"""Why it failed or refused any."""
|
|
2396
2411
|
|
|
2412
|
+
@dataclass(frozen=True)
|
|
2413
|
+
class OsdMessage:
|
|
2414
|
+
"""
|
|
2415
|
+
The message on a unit's output, as the unit last reported it. The unit
|
|
2416
|
+
holds it until it restarts.
|
|
2417
|
+
"""
|
|
2418
|
+
flags: OsdMessageFlag
|
|
2419
|
+
"""Whether a message is set and shown, whether the unit can show one, and
|
|
2420
|
+
whether it refused the write it answers. Without SET the other fields are
|
|
2421
|
+
empty."""
|
|
2422
|
+
logo: int
|
|
2423
|
+
"""The logo shown with it: 0 the built-in logo, -1 none, 1 to 5 a slot."""
|
|
2424
|
+
priority: OsdMessagePriority|int
|
|
2425
|
+
"""Where it stands against the unit's own messages."""
|
|
2426
|
+
text: str
|
|
2427
|
+
"""Its markup."""
|
|
2428
|
+
|
|
2429
|
+
def __str__(self) -> str:
|
|
2430
|
+
if (OsdMessageFlag.SET not in self.flags):
|
|
2431
|
+
return f"none{' (refused)' if (OsdMessageFlag.REFUSED in self.flags) else ''}"
|
|
2432
|
+
return f"'{self.text}' logo {self.logo} {self.flags!r}"
|
|
2433
|
+
|
|
2397
2434
|
@dataclass(frozen=True)
|
|
2398
2435
|
class OsdSyncEntry:
|
|
2399
2436
|
"""One setting of an overlay sync this client sends."""
|
|
@@ -2471,6 +2508,59 @@ class OneIPSinkSdp:
|
|
|
2471
2508
|
return (f"'{self.name}' {self.group}:{self.port} {encoding} {self.channels}ch {self.rate_hz}Hz"
|
|
2472
2509
|
f"{' audio only' if (OneIPSdpFlag.AUDIO_ONLY in self.flags) else ''}")
|
|
2473
2510
|
|
|
2511
|
+
@dataclass(frozen=True)
|
|
2512
|
+
class OneIPPrivacyStream:
|
|
2513
|
+
"""
|
|
2514
|
+
How one of a OneIP source unit's streams is encrypted, as the unit reports
|
|
2515
|
+
it: the values of the stream's ``a=privacy`` and ``a=extmap`` session
|
|
2516
|
+
description attributes.
|
|
2517
|
+
|
|
2518
|
+
A receiver needs these to decrypt the stream. The key itself never travels:
|
|
2519
|
+
every unit of a mesh holds the same one. This library holds no key and
|
|
2520
|
+
decrypts nothing.
|
|
2521
|
+
"""
|
|
2522
|
+
group: str = '0.0.0.0'
|
|
2523
|
+
"""The stream's destination address."""
|
|
2524
|
+
port: int = 0
|
|
2525
|
+
"""The stream's UDP port."""
|
|
2526
|
+
version: int = 0
|
|
2527
|
+
"""Steps whenever the parameters change."""
|
|
2528
|
+
on: bool = False
|
|
2529
|
+
"""Whether the stream is encrypted. Without it the stream goes out in the
|
|
2530
|
+
clear, and the fields below mean nothing."""
|
|
2531
|
+
full_id: int = 0
|
|
2532
|
+
"""The RTP header extension id of the full IV counter."""
|
|
2533
|
+
short_id: int = 0
|
|
2534
|
+
"""The RTP header extension id of the short IV counter."""
|
|
2535
|
+
iv: bytes = bytes(8)
|
|
2536
|
+
"""The initialisation vector, 8 bytes."""
|
|
2537
|
+
key_generator: bytes = bytes(16)
|
|
2538
|
+
"""The key generator, 16 bytes."""
|
|
2539
|
+
key_id: bytes = bytes(8)
|
|
2540
|
+
"""Names the mesh's key, 8 bytes. A receiver holding another drops the stream."""
|
|
2541
|
+
key_version: int = 0
|
|
2542
|
+
"""The key version."""
|
|
2543
|
+
|
|
2544
|
+
def __str__(self) -> str:
|
|
2545
|
+
if not self.on:
|
|
2546
|
+
return f"{self.group}:{self.port} clear"
|
|
2547
|
+
return f"{self.group}:{self.port} encrypted, key {self.key_id.hex()} v{self.key_version}"
|
|
2548
|
+
|
|
2549
|
+
@dataclass(frozen=True)
|
|
2550
|
+
class OneIPPrivacy:
|
|
2551
|
+
"""
|
|
2552
|
+
How a OneIP source unit's streams are encrypted, as it last reported it. A
|
|
2553
|
+
unit reports this whenever it changes, at least once a minute, and when
|
|
2554
|
+
asked. A unit that is in no mesh sends in the clear.
|
|
2555
|
+
"""
|
|
2556
|
+
video: OneIPPrivacyStream
|
|
2557
|
+
audio: OneIPPrivacyStream
|
|
2558
|
+
anc: OneIPPrivacyStream
|
|
2559
|
+
"""The ancillary data stream."""
|
|
2560
|
+
|
|
2561
|
+
def __str__(self) -> str:
|
|
2562
|
+
return f"video {self.video}, audio {self.audio}, anc {self.anc}"
|
|
2563
|
+
|
|
2474
2564
|
@dataclass(frozen=True)
|
|
2475
2565
|
class OneIPTestTone:
|
|
2476
2566
|
"""A OneIP sink's test tone."""
|
|
@@ -2714,16 +2804,25 @@ class OneIPDeviceSettings:
|
|
|
2714
2804
|
else previous._power_save_level),
|
|
2715
2805
|
ptp_messages=previous._ptp_messages.merge(self._ptp_messages, valid))
|
|
2716
2806
|
|
|
2717
|
-
def as_applied_to(self, reported:OneIPDeviceSetting) -> 'OneIPDeviceSettings':
|
|
2807
|
+
def as_applied_to(self, reported:'OneIPDeviceSettings|OneIPDeviceSetting|None') -> 'OneIPDeviceSettings':
|
|
2718
2808
|
"""
|
|
2719
|
-
This block limited to what a device takes from a
|
|
2809
|
+
This block limited to what a device that reported reported takes from a
|
|
2810
|
+
write about it.
|
|
2720
2811
|
|
|
2721
2812
|
A device applies a setting only if it has it, a profile, PTP mode, PTP
|
|
2722
2813
|
domain, power save level or PTP DSCP only within its range, a stream
|
|
2723
|
-
TTL only when it is not 0,
|
|
2724
|
-
itself.
|
|
2814
|
+
TTL only when it is not 0, a rotation only by its own step, and never
|
|
2815
|
+
what only it can report about itself. The step stays the device's.
|
|
2816
|
+
|
|
2817
|
+
reported may be only the bits the device reported, which says nothing
|
|
2818
|
+
of its step, so a rotation other than 0 is then left out.
|
|
2725
2819
|
"""
|
|
2726
|
-
|
|
2820
|
+
if (reported is None):
|
|
2821
|
+
reported = OneIPDeviceSettings()
|
|
2822
|
+
elif not isinstance(reported, OneIPDeviceSettings):
|
|
2823
|
+
reported = OneIPDeviceSettings(valid=OneIPDeviceSetting(reported))
|
|
2824
|
+
own = reported._ptp_messages
|
|
2825
|
+
valid = (self._valid & reported._valid) & ~ONEIP_DEVICE_SETTINGS_REPORTED_ONLY
|
|
2727
2826
|
if not (0 <= self._ir_profile < ONEIP_IR_PROFILE_MAX):
|
|
2728
2827
|
valid &= ~OneIPDeviceSetting.IR_PROFILE
|
|
2729
2828
|
if not (ONEIP_IR_PROFILE_NOT_SET <= self._ir_profile_sink < ONEIP_IR_PROFILE_MAX):
|
|
@@ -2738,13 +2837,16 @@ class OneIPDeviceSettings:
|
|
|
2738
2837
|
valid &= ~OneIPDeviceSetting.PTP_DSCP
|
|
2739
2838
|
if (self._ptp_messages.stream_ttl == 0):
|
|
2740
2839
|
valid &= ~OneIPDeviceSetting.STREAM_TTL
|
|
2840
|
+
if not own.takes_sink_rotation(self._ptp_messages.sink_rotation):
|
|
2841
|
+
valid &= ~OneIPDeviceSetting.SINK_ROTATION
|
|
2741
2842
|
return OneIPDeviceSettings(valid=valid, flags=self._flags, ir_profiles=self._ir_profiles,
|
|
2742
2843
|
ir_profile=self._ir_profile, ir_profile_sink=self._ir_profile_sink,
|
|
2743
2844
|
auto_power_save=self._auto_power_save, power_save=self._power_save,
|
|
2744
2845
|
ptp_mode=self._ptp_mode, ptp_domain=self._ptp_domain,
|
|
2745
2846
|
ptp_priority1=self._ptp_priority1,
|
|
2746
2847
|
power_save_level=self._power_save_level,
|
|
2747
|
-
ptp_messages=self._ptp_messages
|
|
2848
|
+
ptp_messages=replace(self._ptp_messages,
|
|
2849
|
+
sink_rotation_step=own.sink_rotation_step))
|
|
2748
2850
|
|
|
2749
2851
|
def __eq__(self, other:Any) -> bool:
|
|
2750
2852
|
if not isinstance(other, OneIPDeviceSettings):
|
|
@@ -3452,6 +3554,26 @@ class DeviceBase(ABC):
|
|
|
3452
3554
|
def osd_sync_report(self) -> OsdSyncReport|None:
|
|
3453
3555
|
'''This unit's last report on taking an overlay sync, None until it has.'''
|
|
3454
3556
|
|
|
3557
|
+
@property
|
|
3558
|
+
@abstractmethod
|
|
3559
|
+
def osd_message(self) -> OsdMessage|None:
|
|
3560
|
+
'''The message on this unit's output, as it last reported it to this
|
|
3561
|
+
client, None until it has. A unit reports it only when asked, or when
|
|
3562
|
+
this client writes it.'''
|
|
3563
|
+
|
|
3564
|
+
@abstractmethod
|
|
3565
|
+
async def request_osd_message(self) -> bool:
|
|
3566
|
+
'''ask this unit for the message on its output'''
|
|
3567
|
+
|
|
3568
|
+
@abstractmethod
|
|
3569
|
+
async def show_osd_message(self, text:str, logo:int=-1,
|
|
3570
|
+
priority:OsdMessagePriority=OsdMessagePriority.NORMAL) -> bool:
|
|
3571
|
+
'''show a message on this unit's output, in place of any it has'''
|
|
3572
|
+
|
|
3573
|
+
@abstractmethod
|
|
3574
|
+
async def clear_osd_message(self) -> bool:
|
|
3575
|
+
'''take the message down from this unit's output'''
|
|
3576
|
+
|
|
3455
3577
|
@property
|
|
3456
3578
|
@abstractmethod
|
|
3457
3579
|
def oneip_sink_sdp(self) -> OneIPSinkSdp|None:
|
|
@@ -3459,6 +3581,17 @@ class DeviceBase(ABC):
|
|
|
3459
3581
|
reported it, None until it has. It reports when that changes and at
|
|
3460
3582
|
least once a minute.'''
|
|
3461
3583
|
|
|
3584
|
+
@property
|
|
3585
|
+
@abstractmethod
|
|
3586
|
+
def oneip_privacy(self) -> OneIPPrivacy|None:
|
|
3587
|
+
'''How this OneIP source unit's streams are encrypted, as it last
|
|
3588
|
+
reported it, None until it has. It reports when that changes and at
|
|
3589
|
+
least once a minute.'''
|
|
3590
|
+
|
|
3591
|
+
@abstractmethod
|
|
3592
|
+
async def request_oneip_privacy(self) -> bool:
|
|
3593
|
+
'''ask this OneIP source unit how its streams are encrypted now'''
|
|
3594
|
+
|
|
3462
3595
|
@abstractmethod
|
|
3463
3596
|
async def play_oneip_sdp(self, sdp:str) -> bool:
|
|
3464
3597
|
'''have this OneIP output play the stream a session description describes'''
|
|
@@ -4056,6 +4189,11 @@ class MxrCallbacks:
|
|
|
4056
4189
|
_LOGGER.debug(f"{dev} overlay sync {report.seq}: {report.state!r} {report.reason}")
|
|
4057
4190
|
self.on_device_update(dev)
|
|
4058
4191
|
|
|
4192
|
+
def on_osd_message_changed(self, dev:DeviceBase, message:OsdMessage) -> None:
|
|
4193
|
+
''' called when unit 'dev' reported something different about the message on its output '''
|
|
4194
|
+
_LOGGER.debug(f"{dev} overlay message: {message}")
|
|
4195
|
+
self.on_device_update(dev)
|
|
4196
|
+
|
|
4059
4197
|
def on_osd_sync_requested(self, dev:DeviceBase, request:OsdSyncRequest) -> None:
|
|
4060
4198
|
''' called when 'dev' asked for an overlay sync, or for settings of one '''
|
|
4061
4199
|
pass
|
|
@@ -787,6 +787,9 @@ class OneIPPtpMessages:
|
|
|
787
787
|
sap_expire_min: int = ...
|
|
788
788
|
sap_interval_s: int = ...
|
|
789
789
|
stream_ttl: int = ...
|
|
790
|
+
sink_rotation: int = ...
|
|
791
|
+
sink_rotation_step: int = ...
|
|
792
|
+
def takes_sink_rotation(self, degrees: int) -> bool: ...
|
|
790
793
|
def merge(self, other: OneIPPtpMessages, which: OneIPDeviceSetting) -> OneIPPtpMessages: ...
|
|
791
794
|
def describe(self, valid: OneIPDeviceSetting) -> list[str]: ...
|
|
792
795
|
|
|
@@ -853,6 +856,13 @@ class OsdSyncReport:
|
|
|
853
856
|
refused: int
|
|
854
857
|
reason: str
|
|
855
858
|
|
|
859
|
+
@dataclass(frozen=True)
|
|
860
|
+
class OsdMessage:
|
|
861
|
+
flags: OsdMessageFlag
|
|
862
|
+
logo: int
|
|
863
|
+
priority: OsdMessagePriority | int
|
|
864
|
+
text: str
|
|
865
|
+
|
|
856
866
|
@dataclass(frozen=True)
|
|
857
867
|
class OsdSyncEntry:
|
|
858
868
|
value: OsdSyncValue
|
|
@@ -891,6 +901,25 @@ class OneIPSinkSdp:
|
|
|
891
901
|
@property
|
|
892
902
|
def active(self) -> bool: ...
|
|
893
903
|
|
|
904
|
+
@dataclass(frozen=True)
|
|
905
|
+
class OneIPPrivacyStream:
|
|
906
|
+
group: str = ...
|
|
907
|
+
port: int = ...
|
|
908
|
+
version: int = ...
|
|
909
|
+
on: bool = ...
|
|
910
|
+
full_id: int = ...
|
|
911
|
+
short_id: int = ...
|
|
912
|
+
iv: bytes = ...
|
|
913
|
+
key_generator: bytes = ...
|
|
914
|
+
key_id: bytes = ...
|
|
915
|
+
key_version: int = ...
|
|
916
|
+
|
|
917
|
+
@dataclass(frozen=True)
|
|
918
|
+
class OneIPPrivacy:
|
|
919
|
+
video: OneIPPrivacyStream
|
|
920
|
+
audio: OneIPPrivacyStream
|
|
921
|
+
anc: OneIPPrivacyStream
|
|
922
|
+
|
|
894
923
|
@dataclass(frozen=True)
|
|
895
924
|
class OneIPTestTone:
|
|
896
925
|
mode: OneIPToneMode | int = ...
|
|
@@ -949,7 +978,7 @@ class OneIPDeviceSettings:
|
|
|
949
978
|
@property
|
|
950
979
|
def ptp_messages(self) -> OneIPPtpMessages | None: ...
|
|
951
980
|
def merge(self, previous: OneIPDeviceSettings | None) -> OneIPDeviceSettings: ...
|
|
952
|
-
def as_applied_to(self, reported: OneIPDeviceSetting) -> OneIPDeviceSettings: ...
|
|
981
|
+
def as_applied_to(self, reported: OneIPDeviceSettings | OneIPDeviceSetting | None) -> OneIPDeviceSettings: ...
|
|
953
982
|
def __eq__(self, other: Any) -> bool: ...
|
|
954
983
|
def __ne__(self, other: Any) -> bool: ...
|
|
955
984
|
|
|
@@ -1305,7 +1334,21 @@ class DeviceBase(ABC):
|
|
|
1305
1334
|
def osd_sync_report(self) -> OsdSyncReport | None: ...
|
|
1306
1335
|
@property
|
|
1307
1336
|
@abstractmethod
|
|
1337
|
+
def osd_message(self) -> OsdMessage | None: ...
|
|
1338
|
+
@abstractmethod
|
|
1339
|
+
async def request_osd_message(self) -> bool: ...
|
|
1340
|
+
@abstractmethod
|
|
1341
|
+
async def show_osd_message(self, text: str, logo: int = -1, priority: OsdMessagePriority = ...) -> bool: ...
|
|
1342
|
+
@abstractmethod
|
|
1343
|
+
async def clear_osd_message(self) -> bool: ...
|
|
1344
|
+
@property
|
|
1345
|
+
@abstractmethod
|
|
1308
1346
|
def oneip_sink_sdp(self) -> OneIPSinkSdp | None: ...
|
|
1347
|
+
@property
|
|
1348
|
+
@abstractmethod
|
|
1349
|
+
def oneip_privacy(self) -> OneIPPrivacy | None: ...
|
|
1350
|
+
@abstractmethod
|
|
1351
|
+
async def request_oneip_privacy(self) -> bool: ...
|
|
1309
1352
|
@abstractmethod
|
|
1310
1353
|
async def play_oneip_sdp(self, sdp: str) -> bool: ...
|
|
1311
1354
|
@abstractmethod
|
|
@@ -1537,6 +1580,7 @@ class MxrCallbacks:
|
|
|
1537
1580
|
def on_status_hdbt_connected_changed(self, bay: BayBase, val: bool) -> None: ...
|
|
1538
1581
|
def on_osd_sync(self, dev: DeviceBase, sync: OsdSync) -> None: ...
|
|
1539
1582
|
def on_osd_sync_report(self, dev: DeviceBase, report: OsdSyncReport) -> None: ...
|
|
1583
|
+
def on_osd_message_changed(self, dev: DeviceBase, message: OsdMessage) -> None: ...
|
|
1540
1584
|
def on_osd_sync_requested(self, dev: DeviceBase, request: OsdSyncRequest) -> None: ...
|
|
1541
1585
|
def on_osd_sync_setting(self, dev: DeviceBase, setting: OsdSyncSetting) -> None: ...
|
|
1542
1586
|
def on_bay_content_changed(self, bay: BayBase, content: BayContent) -> None: ...
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
from enum import IntEnum, IntFlag
|
|
11
11
|
from typing import TypeVar
|
|
12
12
|
|
|
13
|
-
MXR_PROTOCOL_VERSION =
|
|
13
|
+
MXR_PROTOCOL_VERSION = 0x30
|
|
14
14
|
"""Highest mx_remote protocol version this library understands.
|
|
15
15
|
|
|
16
16
|
Mirrors the firmware's own protocol version. Bump
|
|
@@ -31,7 +31,8 @@ every 20-30s once every device it knows is on 0x2A.
|
|
|
31
31
|
0x2B.
|
|
32
32
|
|
|
33
33
|
0x2E is the row of V2IP_SINK_SDP, so an output's session description report
|
|
34
|
-
arrives stamped 0x2E,
|
|
34
|
+
arrives stamped 0x2E, 0x2F the row of V2IP_OSD_SYNC and 0x30 the row of
|
|
35
|
+
V2IP_PRIVACY."""
|
|
35
36
|
|
|
36
37
|
MXR_PROTOCOL_VERSION_SLOW_HELLO = 0x2A
|
|
37
38
|
"""First protocol version whose devices may hello only every 20-30s."""
|
|
@@ -121,6 +122,7 @@ MXR_OPCODE_VERSIONS: dict[int, int] = {
|
|
|
121
122
|
0x51: 0x2D, # BAY_CONTENT
|
|
122
123
|
0x52: 0x2E, # V2IP_SINK_SDP
|
|
123
124
|
0x53: 0x2F, # V2IP_OSD_SYNC
|
|
125
|
+
0x54: 0x30, # V2IP_PRIVACY
|
|
124
126
|
}
|
|
125
127
|
"""Per-opcode minimum compatible protocol version, mirroring the firmware's
|
|
126
128
|
own opcode table. Transmitters stamp the
|
|
@@ -374,9 +376,16 @@ class OneIPDeviceSetting(IntFlag):
|
|
|
374
376
|
STREAM_TTL = (1 << 29)
|
|
375
377
|
'''The TTL of the device's streams, video, audio and ancillary alike.
|
|
376
378
|
Reported only by a device with an encoder.'''
|
|
379
|
+
CLOUD = (1 << 30)
|
|
380
|
+
'''Connects to the cloud service. A device that does not report it
|
|
381
|
+
connects regardless.'''
|
|
382
|
+
SINK_ROTATION = (1 << 31)
|
|
383
|
+
'''The angle the device's HDMI output is turned by. Reported only by a
|
|
384
|
+
device with an HDMI output.'''
|
|
377
385
|
|
|
378
386
|
ONEIP_DEVICE_SETTING_SWITCHES = OneIPDeviceSetting(0xFF) | OneIPDeviceSetting.AES67 \
|
|
379
|
-
| OneIPDeviceSetting.SAP_LISTEN | OneIPDeviceSetting.SAP_ANNOUNCE | OneIPDeviceSetting.POWER_SAVE_DISABLED
|
|
387
|
+
| OneIPDeviceSetting.SAP_LISTEN | OneIPDeviceSetting.SAP_ANNOUNCE | OneIPDeviceSetting.POWER_SAVE_DISABLED \
|
|
388
|
+
| OneIPDeviceSetting.CLOUD
|
|
380
389
|
"""The settings that are on or off, as opposed to carrying a value, and that
|
|
381
390
|
can be written."""
|
|
382
391
|
|
|
@@ -392,14 +401,17 @@ ONEIP_DEVICE_SETTINGS_PTP_MESSAGES = OneIPDeviceSetting.PTP_ANNOUNCE | OneIPDevi
|
|
|
392
401
|
"""The PTP message settings."""
|
|
393
402
|
|
|
394
403
|
ONEIP_DEVICE_SETTINGS_BLOCK = ONEIP_DEVICE_SETTINGS_PTP_MESSAGES | OneIPDeviceSetting.SAP_EXPIRE \
|
|
395
|
-
| OneIPDeviceSetting.SAP_INTERVAL | OneIPDeviceSetting.STREAM_TTL
|
|
404
|
+
| OneIPDeviceSetting.SAP_INTERVAL | OneIPDeviceSetting.STREAM_TTL | OneIPDeviceSetting.SINK_ROTATION
|
|
396
405
|
"""The settings whose values a frame carries in a block of their own behind the
|
|
397
|
-
rest, OneIPPtpMessages: the PTP message settings, the two SAP values
|
|
398
|
-
stream TTL."""
|
|
406
|
+
rest, OneIPPtpMessages: the PTP message settings, the two SAP values, the
|
|
407
|
+
stream TTL and the output's rotation."""
|
|
399
408
|
|
|
400
409
|
ONEIP_STREAM_TTL_DEFAULT = 64
|
|
401
410
|
"""The TTL a OneIP device's streams carry until it is set."""
|
|
402
411
|
|
|
412
|
+
ONEIP_SINK_ROTATION_MAX = 359
|
|
413
|
+
"""The largest angle a OneIP device's HDMI output is turned by, in degrees."""
|
|
414
|
+
|
|
403
415
|
class OneIPPtpMode(IntEnum):
|
|
404
416
|
'''How a OneIP device takes part in PTP.'''
|
|
405
417
|
OFF = 0
|
|
@@ -428,6 +440,31 @@ class OsdSyncWhat(IntFlag):
|
|
|
428
440
|
LOGO_SLOTS = (1 << 3)
|
|
429
441
|
'''The logo images in the four slots.'''
|
|
430
442
|
|
|
443
|
+
class OsdMessageFlag(IntFlag):
|
|
444
|
+
'''What a unit says of the message on its output.'''
|
|
445
|
+
SET = (1 << 0)
|
|
446
|
+
'''A message is set. In a write: show it, rather than take it down.'''
|
|
447
|
+
SHOWN = (1 << 1)
|
|
448
|
+
'''The output shows it, rather than another message ahead of it.'''
|
|
449
|
+
SUPPORTED = (1 << 2)
|
|
450
|
+
'''The unit's video processor composes the message layer.'''
|
|
451
|
+
REFUSED = (1 << 3)
|
|
452
|
+
'''The unit did not take the write it answers, and reports the message it
|
|
453
|
+
kept.'''
|
|
454
|
+
|
|
455
|
+
class OsdMessagePriority(IntEnum):
|
|
456
|
+
'''Where a message stands against the unit's own messages: its upgrade,
|
|
457
|
+
Locate Device and encrypted source messages.'''
|
|
458
|
+
LOW = 0
|
|
459
|
+
'''After them.'''
|
|
460
|
+
NORMAL = 1
|
|
461
|
+
'''Between them.'''
|
|
462
|
+
TOP = 2
|
|
463
|
+
'''Before them.'''
|
|
464
|
+
|
|
465
|
+
OSD_MESSAGE_TEXT_MAX = 255
|
|
466
|
+
"""The longest message text a unit takes, in bytes."""
|
|
467
|
+
|
|
431
468
|
class OsdSyncState(IntEnum):
|
|
432
469
|
'''How far a unit has got with taking an overlay sync.'''
|
|
433
470
|
TAKING = 0
|
|
@@ -108,6 +108,8 @@ class OneIPDeviceSetting(IntFlag):
|
|
|
108
108
|
SAP_INTERVAL: Incomplete
|
|
109
109
|
POWER_SAVE_DISABLED: Incomplete
|
|
110
110
|
STREAM_TTL: Incomplete
|
|
111
|
+
CLOUD: Incomplete
|
|
112
|
+
SINK_ROTATION: Incomplete
|
|
111
113
|
|
|
112
114
|
ONEIP_DEVICE_SETTING_SWITCHES: Incomplete
|
|
113
115
|
ONEIP_DEVICE_SETTINGS_REPORTED_ONLY: Incomplete
|
|
@@ -115,6 +117,7 @@ ONEIP_DEVICE_SETTINGS_PTP: Incomplete
|
|
|
115
117
|
ONEIP_DEVICE_SETTINGS_PTP_MESSAGES: Incomplete
|
|
116
118
|
ONEIP_DEVICE_SETTINGS_BLOCK: Incomplete
|
|
117
119
|
ONEIP_STREAM_TTL_DEFAULT: int
|
|
120
|
+
ONEIP_SINK_ROTATION_MAX: int
|
|
118
121
|
|
|
119
122
|
class OneIPPtpMode(IntEnum):
|
|
120
123
|
OFF: int
|
|
@@ -131,6 +134,19 @@ class OsdSyncWhat(IntFlag):
|
|
|
131
134
|
BACKGROUNDS: Incomplete
|
|
132
135
|
LOGO_SLOTS: Incomplete
|
|
133
136
|
|
|
137
|
+
class OsdMessageFlag(IntFlag):
|
|
138
|
+
SET: Incomplete
|
|
139
|
+
SHOWN: Incomplete
|
|
140
|
+
SUPPORTED: Incomplete
|
|
141
|
+
REFUSED: Incomplete
|
|
142
|
+
|
|
143
|
+
class OsdMessagePriority(IntEnum):
|
|
144
|
+
LOW: int
|
|
145
|
+
NORMAL: int
|
|
146
|
+
TOP: int
|
|
147
|
+
|
|
148
|
+
OSD_MESSAGE_TEXT_MAX: int
|
|
149
|
+
|
|
134
150
|
class OsdSyncState(IntEnum):
|
|
135
151
|
TAKING: int
|
|
136
152
|
DONE: int
|
|
@@ -246,6 +246,9 @@ def _mxr_frame_factory(hdr:FrameHeader, timestamp:float) -> FrameBase|None:
|
|
|
246
246
|
if hdr.opcode == 0x53:
|
|
247
247
|
from .FrameV2IPOsdSync import FrameV2IPOsdSync
|
|
248
248
|
return FrameV2IPOsdSync(header=hdr, timestamp=timestamp)
|
|
249
|
+
if hdr.opcode == 0x54:
|
|
250
|
+
from .FrameV2IPPrivacy import FrameV2IPPrivacy
|
|
251
|
+
return FrameV2IPPrivacy(header=hdr, timestamp=timestamp)
|
|
249
252
|
if hdr.opcode == 0x50:
|
|
250
253
|
from .FrameUnitCommand import FrameUnitCommand
|
|
251
254
|
return FrameUnitCommand(header=hdr, timestamp=timestamp)
|