mx-remote 8.1.0__tar.gz → 9.1.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.1.0 → mx_remote-9.1.0}/PKG-INFO +1 -1
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/api.md +36 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/oneip.md +64 -5
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/Interface.py +139 -13
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/Interface.pyi +36 -1
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/Uid.py +11 -8
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/const.py +1 -1
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Constants.py +53 -3
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Constants.pyi +26 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +91 -14
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +8 -2
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPOsdSync.py +45 -12
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPOsdSync.pyi +10 -2
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSources.py +5 -6
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Bay.py +2 -1
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Device.py +131 -8
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Device.pyi +13 -2
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/OsdSync.py +1 -11
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Remote.py +51 -23
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Remote.pyi +1 -1
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/complete.py +12 -0
- mx_remote-9.1.0/tests/downmix.py +124 -0
- mx_remote-9.1.0/tests/osdmessage.py +114 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/osdsync.py +12 -13
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/run.py +3 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/staterequest.py +64 -0
- mx_remote-9.1.0/tests/uid.py +50 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipsettings.py +49 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/.gitignore +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/AGENTS.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/CLAUDE.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/LICENSE +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/README.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/README.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/_static/brand.css +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/_static/favicon.svg +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/_static/logo-dark.svg +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/_static/logo.svg +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/audio.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/callbacks.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/conf.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/configuration.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/devices-and-bays.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/diagnostics.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/index.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/multiviewer.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/requirements.txt +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/docs/routing.md +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/hatch_build.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/Uid.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/__init__.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/__init__.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/compat.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/compat.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/const.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/deprecated.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/deprecated.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/main.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/main.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/BayConfig.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/BayConfig.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Data.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Data.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Factory.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Factory.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAudioClip.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAudioClip.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAudioSetRoute.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameAudioSetRoute.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBase.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBase.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayConfig.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayConfig.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayContent.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayContent.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayHide.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayHide.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameBayStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameConnectStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameDebug.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameDebug.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameDiscover.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameDiscover.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameEDID.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameEDID.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameEDIDProfile.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFactoryReset.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFactoryReset.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFilterStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFirmwareVersion.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameFirmwareVersion.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameHeader.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameHeader.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameHello.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameHello.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameLinks.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameLinks.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMeshOperation.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMeshOperation.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMirrorStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMonitoringPulse.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameNetworkStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FramePing.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FramePing.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FramePowerChange.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FramePowerChange.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCAction.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCAction.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCIr.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCIr.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCKey.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCKey.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCSettings.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRCSettings.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameReboot.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameReboot.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRoutingChange.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetInstaller.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetName.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetName.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetRoute.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetRoute.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetupStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSignalStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSignalStatusNew.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSysTemperature.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSystemStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTXRCAction.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTXRCKey.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTime.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTime.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTimeZone.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTimeZone.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTopology.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTopology.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTxIR.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameTxIR.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUnitCommand.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUnitCommand.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUnitStatus.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUnitStatus.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUpgradeFPGA.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPAudio.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPAudio.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPBayMapping.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPDetectBays.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPLink.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPMultiviewer.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPPowerSave.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPPrivacy.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPPrivacy.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSetMaster.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSettingsAll.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSettingsAll.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSinkSdp.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSinkSdp.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSourceSwitch.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPSources.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPStats.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPStats.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPTestcard.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPTestcard.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPTiling.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPVideoWall.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolume.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolume.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeDown.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeSet.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeUp.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/LinkConfig.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/LinkConfig.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Multiviewer.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Multiviewer.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Svd.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/Svd.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/V2IPConfig.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/V2IPConfig.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/V2IPStats.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/V2IPStats.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/__init__.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/__init__.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/proto/svd.csv +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/py.typed +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Bay.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/ConnectionAsync.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/ConnectionAsync.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Link.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/Link.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/OsdSync.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/State.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/State.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/V2IP.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/mx_remote/remote/V2IP.pyi +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/pyproject.toml +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/audio_ir.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/audiolock.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/baycontent.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/capture.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/deprecated.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/e2e.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/entry.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/handlers.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/handlers_cover.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/hello.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/idempotent.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/lengths.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/merge.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/mesh.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/meshbays.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/newops.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/offline.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/offsets.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/ping.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/privacy.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/proto_stamp.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/protogate.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/rcsettings.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/roundtrip.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/routes.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/smoke.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/sources.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/stats.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/structs.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/txresult.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/unit.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/unknowns.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipptp.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipscaling.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipsdp.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipsubject.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2iptestcard.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/v2ipvlan.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.0}/tests/vdetails.py +0 -0
- {mx_remote-8.1.0 → mx_remote-9.1.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.1.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}
|
|
@@ -151,6 +168,23 @@ bit, and the range of the infrared profiles.
|
|
|
151
168
|
.. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_ID_MAX
|
|
152
169
|
```
|
|
153
170
|
|
|
171
|
+
## OneIP stereo downmix
|
|
172
|
+
|
|
173
|
+
How a device's output mixes 5.1 and 7.1 PCM down to stereo.
|
|
174
|
+
|
|
175
|
+
```{eval-rst}
|
|
176
|
+
.. autoclass:: mx_remote.OneIPDownmix
|
|
177
|
+
:members:
|
|
178
|
+
|
|
179
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPDownmixMode
|
|
180
|
+
:members:
|
|
181
|
+
|
|
182
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPDownmixLevel
|
|
183
|
+
:members:
|
|
184
|
+
|
|
185
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_DOWNMIX_LFE_MAX
|
|
186
|
+
```
|
|
187
|
+
|
|
154
188
|
## OneIP PTP
|
|
155
189
|
|
|
156
190
|
A device's PTP settings, which it reports and a controller writes, and the PTP
|
|
@@ -180,6 +214,8 @@ state only the device reports.
|
|
|
180
214
|
|
|
181
215
|
.. autodata:: mx_remote.proto.Constants.ONEIP_STREAM_TTL_DEFAULT
|
|
182
216
|
|
|
217
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_SINK_ROTATION_MAX
|
|
218
|
+
|
|
183
219
|
.. autodata:: mx_remote.proto.Constants.ONEIP_PTP_DOMAIN_MAX
|
|
184
220
|
```
|
|
185
221
|
|
|
@@ -288,10 +288,23 @@ same block, behind `SAP_EXPIRE` and `SAP_INTERVAL`, and are set the same way;
|
|
|
288
288
|
`SAP_LISTEN` and `SAP_ANNOUNCE` are switches like the other on/off settings.
|
|
289
289
|
A device with an encoder reports its streams' TTL there too, behind
|
|
290
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
|
+
```
|
|
291
304
|
|
|
292
305
|
Only the values behind the bits named are sent. A DSCP above `ONEIP_DSCP_MAX` is
|
|
293
306
|
refused, and not cached from another controller's write. A write carrying one of
|
|
294
|
-
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
|
|
295
308
|
every device knows.
|
|
296
309
|
|
|
297
310
|
What the device's clock is actually doing is its PTP state, which only the
|
|
@@ -305,6 +318,31 @@ if ptp is not None:
|
|
|
305
318
|
print(ptp.grandmaster) # its clock identity, None while there is none
|
|
306
319
|
```
|
|
307
320
|
|
|
321
|
+
### Stereo downmix
|
|
322
|
+
|
|
323
|
+
A device whose output can mix 5.1 and 7.1 PCM down to stereo reports how,
|
|
324
|
+
once its video processor has answered for it: a mode, a level and the percent
|
|
325
|
+
the LFE channel is mixed in at, which a controller writes, and the state and
|
|
326
|
+
channel count, which only the device reports. A device that reports none has
|
|
327
|
+
no downmix to set, so a write to one is refused, as is a mode, level or LFE
|
|
328
|
+
percent out of range. The write sends the mode, level and LFE together; the
|
|
329
|
+
state and channels are never sent.
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from mx_remote import OneIPDownmix
|
|
333
|
+
from mx_remote.proto.Constants import OneIPDownmixMode, OneIPDownmixLevel
|
|
334
|
+
|
|
335
|
+
downmix = device.oneip_downmix # None: no report yet, or no downmix
|
|
336
|
+
if downmix is not None:
|
|
337
|
+
print(downmix.mode, downmix.level, downmix.lfe) # LFE up to ONEIP_DOWNMIX_LFE_MAX
|
|
338
|
+
print(downmix.state, downmix.channels) # the device's own
|
|
339
|
+
await device.set_oneip_downmix(OneIPDownmix(mode=OneIPDownmixMode.AUTO,
|
|
340
|
+
level=OneIPDownmixLevel.NORMALISED, lfe=50))
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The downmix ends the settings block, behind a second valid word, so the write
|
|
344
|
+
runs on to 248 bytes and carries no other setting.
|
|
345
|
+
|
|
308
346
|
### VLAN
|
|
309
347
|
|
|
310
348
|
A device that announces `DeviceFeature.VLAN` tags its uplink by a VLAN
|
|
@@ -412,13 +450,34 @@ await mx.clear_osd_sync() # stop answering for it
|
|
|
412
450
|
Each unit asks for the settings it lacks and takes only those, so this client
|
|
413
451
|
holds the content and answers until it is replaced or cleared, announcing
|
|
414
452
|
itself meanwhile as the mesh's overlay sync manager: a unit waking from power
|
|
415
|
-
save then takes this content rather than the controller's.
|
|
416
|
-
still answers a unit that asks for settings without naming whose sync they are
|
|
417
|
-
from, as an older overlay module does, with its own sync, which replaces this
|
|
418
|
-
client's on that unit. Logo images are
|
|
453
|
+
save then takes this content rather than the controller's. Logo images are
|
|
419
454
|
served over HTTP from this client, on `logo_port` or a free port. Content a unit
|
|
420
455
|
would refuse is refused before anything is sent; see `send_osd_sync`.
|
|
421
456
|
|
|
457
|
+
### Overlay messages
|
|
458
|
+
|
|
459
|
+
A unit shows a message on its output, over the picture, until it restarts. The
|
|
460
|
+
text is markup of at most `OSD_MESSAGE_TEXT_MAX` bytes with no control
|
|
461
|
+
character, shown with a logo: 0 the built-in one, -1 none, 1 to 5 a slot. Its
|
|
462
|
+
priority places it against the unit's own messages, such as Locate Device.
|
|
463
|
+
|
|
464
|
+
```python
|
|
465
|
+
from mx_remote.proto.Constants import OsdMessagePriority
|
|
466
|
+
|
|
467
|
+
await sink.show_osd_message('Back at <b>3</b>', logo=-1, priority=OsdMessagePriority.TOP)
|
|
468
|
+
await sink.request_osd_message() # the unit answers with what it shows
|
|
469
|
+
await sink.clear_osd_message()
|
|
470
|
+
|
|
471
|
+
print(sink.osd_message) # None until the unit has answered
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
A unit takes a message only from management, which this client announces
|
|
475
|
+
itself as, and answers every write and request with the message it then has;
|
|
476
|
+
`on_osd_message_changed` reports a change. The answer carries
|
|
477
|
+
`OsdMessageFlag.REFUSED` when the unit did not take the write, as when its
|
|
478
|
+
video processor has no message layer. A text, logo or priority a unit would
|
|
479
|
+
refuse is refused before it is sent, as is a device that is not a OneIP output.
|
|
480
|
+
|
|
422
481
|
### Stream encryption
|
|
423
482
|
|
|
424
483
|
A source unit from protocol 0x30 encrypts its video, audio and ancillary
|
|
@@ -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
|
|
@@ -2135,6 +2135,46 @@ class OneIPPtpState:
|
|
|
2135
2135
|
return (f"{mode} domain {self.domain} port state {self.port_state} {lock}"
|
|
2136
2136
|
f"{' followed' if self.followed else ''} clock {self.clock_identity.hex(':')} grandmaster {gm}")
|
|
2137
2137
|
|
|
2138
|
+
@dataclass(frozen=True)
|
|
2139
|
+
class OneIPDownmix:
|
|
2140
|
+
"""
|
|
2141
|
+
How a OneIP output mixes 5.1 and 7.1 PCM down to stereo, and whether it
|
|
2142
|
+
does now.
|
|
2143
|
+
|
|
2144
|
+
A device reports it once its video processor has answered for it, so never
|
|
2145
|
+
one whose output cannot mix down.
|
|
2146
|
+
"""
|
|
2147
|
+
mode: OneIPDownmixMode|int = OneIPDownmixMode.OFF
|
|
2148
|
+
"""When the output mixes down; a raw int for a mode this library does not
|
|
2149
|
+
name."""
|
|
2150
|
+
level: OneIPDownmixLevel|int = OneIPDownmixLevel.NORMALISED
|
|
2151
|
+
"""How loud the mix is; a raw int for a level this library does not name."""
|
|
2152
|
+
lfe: int = 0
|
|
2153
|
+
"""The percent the LFE channel is mixed in at, at most
|
|
2154
|
+
ONEIP_DOWNMIX_LFE_MAX; 0 leaves it out."""
|
|
2155
|
+
state: int = 0
|
|
2156
|
+
"""Why the stream is or is not mixed down, as the device's own code. Only
|
|
2157
|
+
the device reports it."""
|
|
2158
|
+
channels: int = 0
|
|
2159
|
+
"""The stream's channels while it is mixed down, else 0. Only the device
|
|
2160
|
+
reports it."""
|
|
2161
|
+
|
|
2162
|
+
def is_valid(self) -> bool:
|
|
2163
|
+
"""Whether the settings a write carries are in range."""
|
|
2164
|
+
return ((OneIPDownmixMode.OFF <= self.mode <= OneIPDownmixMode.ALWAYS)
|
|
2165
|
+
and (OneIPDownmixLevel.NORMALISED <= self.level <= OneIPDownmixLevel.UNSCALED)
|
|
2166
|
+
and (0 <= self.lfe <= ONEIP_DOWNMIX_LFE_MAX))
|
|
2167
|
+
|
|
2168
|
+
def written(self, write:'OneIPDownmix') -> 'OneIPDownmix':
|
|
2169
|
+
"""The settings of write applied to this report, which keeps what only
|
|
2170
|
+
the device reports."""
|
|
2171
|
+
return replace(self, mode=write.mode, level=write.level, lfe=write.lfe)
|
|
2172
|
+
|
|
2173
|
+
def __str__(self) -> str:
|
|
2174
|
+
mode = self.mode.name.lower() if isinstance(self.mode, OneIPDownmixMode) else self.mode
|
|
2175
|
+
level = self.level.name.lower() if isinstance(self.level, OneIPDownmixLevel) else self.level
|
|
2176
|
+
return f"{mode} {level} lfe {self.lfe}% state {self.state} channels {self.channels}"
|
|
2177
|
+
|
|
2138
2178
|
@dataclass(frozen=True)
|
|
2139
2179
|
class OneIPVlan:
|
|
2140
2180
|
"""
|
|
@@ -2215,8 +2255,8 @@ def _wire_enum(cls:Any, value:int) -> Any:
|
|
|
2215
2255
|
@dataclass(frozen=True)
|
|
2216
2256
|
class OneIPPtpMessages:
|
|
2217
2257
|
"""
|
|
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
|
|
2258
|
+
How a OneIP device paces its PTP messages, its SAP timings, its streams'
|
|
2259
|
+
TTL and its output's rotation, which a frame carries in the same block. Each value is behind its own bit of
|
|
2220
2260
|
OneIPDeviceSettings.valid, one of ONEIP_DEVICE_SETTINGS_BLOCK.
|
|
2221
2261
|
|
|
2222
2262
|
Intervals are base-2 logarithms of seconds, so -3 is 125 ms and 1 is 2 s.
|
|
@@ -2241,6 +2281,19 @@ class OneIPPtpMessages:
|
|
|
2241
2281
|
"""The TTL of the device's streams, 1 to 255, behind STREAM_TTL. A device
|
|
2242
2282
|
whose video processor cannot change it keeps the setting and sends
|
|
2243
2283
|
ONEIP_STREAM_TTL_DEFAULT."""
|
|
2284
|
+
sink_rotation: int = 0
|
|
2285
|
+
"""The degrees the device's HDMI output is turned by, clockwise, at most
|
|
2286
|
+
ONEIP_SINK_ROTATION_MAX, behind SINK_ROTATION."""
|
|
2287
|
+
sink_rotation_step: int = 0
|
|
2288
|
+
"""The step the output turns by: the device takes only an angle that is a
|
|
2289
|
+
multiple of it, and 0 alone when it is 0. Only the device reports it,
|
|
2290
|
+
behind the same bit."""
|
|
2291
|
+
|
|
2292
|
+
def takes_sink_rotation(self, degrees:int) -> bool:
|
|
2293
|
+
"""Whether a device reporting this step takes degrees as its output's
|
|
2294
|
+
rotation."""
|
|
2295
|
+
return (degrees == 0) or ((0 < degrees <= ONEIP_SINK_ROTATION_MAX) and (self.sink_rotation_step != 0)
|
|
2296
|
+
and (degrees % self.sink_rotation_step == 0))
|
|
2244
2297
|
|
|
2245
2298
|
def merge(self, other:'OneIPPtpMessages', which:OneIPDeviceSetting) -> 'OneIPPtpMessages':
|
|
2246
2299
|
"""The values behind the bits of which copied from other, the rest kept."""
|
|
@@ -2253,7 +2306,9 @@ class OneIPPtpMessages:
|
|
|
2253
2306
|
dscp=(other if (S.PTP_DSCP in which) else self).dscp,
|
|
2254
2307
|
sap_expire_min=(other if (S.SAP_EXPIRE in which) else self).sap_expire_min,
|
|
2255
2308
|
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
|
|
2309
|
+
stream_ttl=(other if (S.STREAM_TTL in which) else self).stream_ttl,
|
|
2310
|
+
sink_rotation=(other if (S.SINK_ROTATION in which) else self).sink_rotation,
|
|
2311
|
+
sink_rotation_step=(other if (S.SINK_ROTATION in which) else self).sink_rotation_step)
|
|
2257
2312
|
|
|
2258
2313
|
def describe(self, valid:OneIPDeviceSetting) -> list[str]:
|
|
2259
2314
|
"""The values behind the bits of valid, one "name=value" each."""
|
|
@@ -2266,7 +2321,8 @@ class OneIPPtpMessages:
|
|
|
2266
2321
|
(S.PTP_DSCP, 'ptp_dscp', self.dscp),
|
|
2267
2322
|
(S.SAP_EXPIRE, 'sap_expire_min', self.sap_expire_min),
|
|
2268
2323
|
(S.SAP_INTERVAL, 'sap_interval_s', self.sap_interval_s),
|
|
2269
|
-
(S.STREAM_TTL, 'stream_ttl', self.stream_ttl)
|
|
2324
|
+
(S.STREAM_TTL, 'stream_ttl', self.stream_ttl),
|
|
2325
|
+
(S.SINK_ROTATION, 'sink_rotation', self.sink_rotation))
|
|
2270
2326
|
if (bit in valid)]
|
|
2271
2327
|
|
|
2272
2328
|
@dataclass(frozen=True)
|
|
@@ -2317,8 +2373,7 @@ class OsdSyncRequest:
|
|
|
2317
2373
|
missing: bytes
|
|
2318
2374
|
"""The settings it lacks, bit i standing for setting i, 16 bytes."""
|
|
2319
2375
|
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."""
|
|
2376
|
+
"""Who sent the sync it asks about. Empty when it asks for a new sync."""
|
|
2322
2377
|
|
|
2323
2378
|
def is_missing(self, index:int) -> bool:
|
|
2324
2379
|
"""Whether the unit lacks setting index."""
|
|
@@ -2394,6 +2449,28 @@ class OsdSyncReport:
|
|
|
2394
2449
|
reason: str
|
|
2395
2450
|
"""Why it failed or refused any."""
|
|
2396
2451
|
|
|
2452
|
+
@dataclass(frozen=True)
|
|
2453
|
+
class OsdMessage:
|
|
2454
|
+
"""
|
|
2455
|
+
The message on a unit's output, as the unit last reported it. The unit
|
|
2456
|
+
holds it until it restarts.
|
|
2457
|
+
"""
|
|
2458
|
+
flags: OsdMessageFlag
|
|
2459
|
+
"""Whether a message is set and shown, whether the unit can show one, and
|
|
2460
|
+
whether it refused the write it answers. Without SET the other fields are
|
|
2461
|
+
empty."""
|
|
2462
|
+
logo: int
|
|
2463
|
+
"""The logo shown with it: 0 the built-in logo, -1 none, 1 to 5 a slot."""
|
|
2464
|
+
priority: OsdMessagePriority|int
|
|
2465
|
+
"""Where it stands against the unit's own messages."""
|
|
2466
|
+
text: str
|
|
2467
|
+
"""Its markup."""
|
|
2468
|
+
|
|
2469
|
+
def __str__(self) -> str:
|
|
2470
|
+
if (OsdMessageFlag.SET not in self.flags):
|
|
2471
|
+
return f"none{' (refused)' if (OsdMessageFlag.REFUSED in self.flags) else ''}"
|
|
2472
|
+
return f"'{self.text}' logo {self.logo} {self.flags!r}"
|
|
2473
|
+
|
|
2397
2474
|
@dataclass(frozen=True)
|
|
2398
2475
|
class OsdSyncEntry:
|
|
2399
2476
|
"""One setting of an overlay sync this client sends."""
|
|
@@ -2767,16 +2844,25 @@ class OneIPDeviceSettings:
|
|
|
2767
2844
|
else previous._power_save_level),
|
|
2768
2845
|
ptp_messages=previous._ptp_messages.merge(self._ptp_messages, valid))
|
|
2769
2846
|
|
|
2770
|
-
def as_applied_to(self, reported:OneIPDeviceSetting) -> 'OneIPDeviceSettings':
|
|
2847
|
+
def as_applied_to(self, reported:'OneIPDeviceSettings|OneIPDeviceSetting|None') -> 'OneIPDeviceSettings':
|
|
2771
2848
|
"""
|
|
2772
|
-
This block limited to what a device takes from a
|
|
2849
|
+
This block limited to what a device that reported reported takes from a
|
|
2850
|
+
write about it.
|
|
2773
2851
|
|
|
2774
2852
|
A device applies a setting only if it has it, a profile, PTP mode, PTP
|
|
2775
2853
|
domain, power save level or PTP DSCP only within its range, a stream
|
|
2776
|
-
TTL only when it is not 0,
|
|
2777
|
-
itself.
|
|
2854
|
+
TTL only when it is not 0, a rotation only by its own step, and never
|
|
2855
|
+
what only it can report about itself. The step stays the device's.
|
|
2856
|
+
|
|
2857
|
+
reported may be only the bits the device reported, which says nothing
|
|
2858
|
+
of its step, so a rotation other than 0 is then left out.
|
|
2778
2859
|
"""
|
|
2779
|
-
|
|
2860
|
+
if (reported is None):
|
|
2861
|
+
reported = OneIPDeviceSettings()
|
|
2862
|
+
elif not isinstance(reported, OneIPDeviceSettings):
|
|
2863
|
+
reported = OneIPDeviceSettings(valid=OneIPDeviceSetting(reported))
|
|
2864
|
+
own = reported._ptp_messages
|
|
2865
|
+
valid = (self._valid & reported._valid) & ~ONEIP_DEVICE_SETTINGS_REPORTED_ONLY
|
|
2780
2866
|
if not (0 <= self._ir_profile < ONEIP_IR_PROFILE_MAX):
|
|
2781
2867
|
valid &= ~OneIPDeviceSetting.IR_PROFILE
|
|
2782
2868
|
if not (ONEIP_IR_PROFILE_NOT_SET <= self._ir_profile_sink < ONEIP_IR_PROFILE_MAX):
|
|
@@ -2791,13 +2877,16 @@ class OneIPDeviceSettings:
|
|
|
2791
2877
|
valid &= ~OneIPDeviceSetting.PTP_DSCP
|
|
2792
2878
|
if (self._ptp_messages.stream_ttl == 0):
|
|
2793
2879
|
valid &= ~OneIPDeviceSetting.STREAM_TTL
|
|
2880
|
+
if not own.takes_sink_rotation(self._ptp_messages.sink_rotation):
|
|
2881
|
+
valid &= ~OneIPDeviceSetting.SINK_ROTATION
|
|
2794
2882
|
return OneIPDeviceSettings(valid=valid, flags=self._flags, ir_profiles=self._ir_profiles,
|
|
2795
2883
|
ir_profile=self._ir_profile, ir_profile_sink=self._ir_profile_sink,
|
|
2796
2884
|
auto_power_save=self._auto_power_save, power_save=self._power_save,
|
|
2797
2885
|
ptp_mode=self._ptp_mode, ptp_domain=self._ptp_domain,
|
|
2798
2886
|
ptp_priority1=self._ptp_priority1,
|
|
2799
2887
|
power_save_level=self._power_save_level,
|
|
2800
|
-
ptp_messages=self._ptp_messages
|
|
2888
|
+
ptp_messages=replace(self._ptp_messages,
|
|
2889
|
+
sink_rotation_step=own.sink_rotation_step))
|
|
2801
2890
|
|
|
2802
2891
|
def __eq__(self, other:Any) -> bool:
|
|
2803
2892
|
if not isinstance(other, OneIPDeviceSettings):
|
|
@@ -3190,6 +3279,14 @@ class DeviceBase(ABC):
|
|
|
3190
3279
|
async def confirm_unit_network(self) -> bool:
|
|
3191
3280
|
'''keep the unit's pending IP configuration'''
|
|
3192
3281
|
|
|
3282
|
+
@property
|
|
3283
|
+
@abstractmethod
|
|
3284
|
+
def oneip_downmix(self) -> OneIPDownmix|None:
|
|
3285
|
+
'''How this OneIP device's output mixes down to stereo, as it last
|
|
3286
|
+
reported, None while it reports no downmix: until its video processor
|
|
3287
|
+
has answered for it, and always for one whose output cannot mix
|
|
3288
|
+
down.'''
|
|
3289
|
+
|
|
3193
3290
|
@property
|
|
3194
3291
|
@abstractmethod
|
|
3195
3292
|
def oneip_ptp(self) -> OneIPPtpState|None:
|
|
@@ -3483,6 +3580,10 @@ class DeviceBase(ABC):
|
|
|
3483
3580
|
async def set_oneip_ptp_messages(self, which:OneIPDeviceSetting, messages:OneIPPtpMessages) -> bool:
|
|
3484
3581
|
'''set how the device paces its PTP messages, its SAP timings and its streams' TTL: the values of messages behind the bits of which'''
|
|
3485
3582
|
|
|
3583
|
+
@abstractmethod
|
|
3584
|
+
async def set_oneip_downmix(self, downmix:OneIPDownmix) -> bool:
|
|
3585
|
+
'''set how the device's output mixes down to stereo'''
|
|
3586
|
+
|
|
3486
3587
|
@abstractmethod
|
|
3487
3588
|
async def set_oneip_vlan(self, vlan:OneIPVlan) -> bool:
|
|
3488
3589
|
'''change the device's VLAN configuration'''
|
|
@@ -3505,6 +3606,26 @@ class DeviceBase(ABC):
|
|
|
3505
3606
|
def osd_sync_report(self) -> OsdSyncReport|None:
|
|
3506
3607
|
'''This unit's last report on taking an overlay sync, None until it has.'''
|
|
3507
3608
|
|
|
3609
|
+
@property
|
|
3610
|
+
@abstractmethod
|
|
3611
|
+
def osd_message(self) -> OsdMessage|None:
|
|
3612
|
+
'''The message on this unit's output, as it last reported it to this
|
|
3613
|
+
client, None until it has. A unit reports it only when asked, or when
|
|
3614
|
+
this client writes it.'''
|
|
3615
|
+
|
|
3616
|
+
@abstractmethod
|
|
3617
|
+
async def request_osd_message(self) -> bool:
|
|
3618
|
+
'''ask this unit for the message on its output'''
|
|
3619
|
+
|
|
3620
|
+
@abstractmethod
|
|
3621
|
+
async def show_osd_message(self, text:str, logo:int=-1,
|
|
3622
|
+
priority:OsdMessagePriority=OsdMessagePriority.NORMAL) -> bool:
|
|
3623
|
+
'''show a message on this unit's output, in place of any it has'''
|
|
3624
|
+
|
|
3625
|
+
@abstractmethod
|
|
3626
|
+
async def clear_osd_message(self) -> bool:
|
|
3627
|
+
'''take the message down from this unit's output'''
|
|
3628
|
+
|
|
3508
3629
|
@property
|
|
3509
3630
|
@abstractmethod
|
|
3510
3631
|
def oneip_sink_sdp(self) -> OneIPSinkSdp|None:
|
|
@@ -4120,6 +4241,11 @@ class MxrCallbacks:
|
|
|
4120
4241
|
_LOGGER.debug(f"{dev} overlay sync {report.seq}: {report.state!r} {report.reason}")
|
|
4121
4242
|
self.on_device_update(dev)
|
|
4122
4243
|
|
|
4244
|
+
def on_osd_message_changed(self, dev:DeviceBase, message:OsdMessage) -> None:
|
|
4245
|
+
''' called when unit 'dev' reported something different about the message on its output '''
|
|
4246
|
+
_LOGGER.debug(f"{dev} overlay message: {message}")
|
|
4247
|
+
self.on_device_update(dev)
|
|
4248
|
+
|
|
4123
4249
|
def on_osd_sync_requested(self, dev:DeviceBase, request:OsdSyncRequest) -> None:
|
|
4124
4250
|
''' called when 'dev' asked for an overlay sync, or for settings of one '''
|
|
4125
4251
|
pass
|
|
@@ -757,6 +757,16 @@ class OneIPPtpState:
|
|
|
757
757
|
@property
|
|
758
758
|
def grandmaster(self) -> bytes | None: ...
|
|
759
759
|
|
|
760
|
+
@dataclass(frozen=True)
|
|
761
|
+
class OneIPDownmix:
|
|
762
|
+
mode: OneIPDownmixMode | int = ...
|
|
763
|
+
level: OneIPDownmixLevel | int = ...
|
|
764
|
+
lfe: int = ...
|
|
765
|
+
state: int = ...
|
|
766
|
+
channels: int = ...
|
|
767
|
+
def is_valid(self) -> bool: ...
|
|
768
|
+
def written(self, write: OneIPDownmix) -> OneIPDownmix: ...
|
|
769
|
+
|
|
760
770
|
@dataclass(frozen=True)
|
|
761
771
|
class OneIPVlan:
|
|
762
772
|
flags: OneIPVlanFlag = ...
|
|
@@ -787,6 +797,9 @@ class OneIPPtpMessages:
|
|
|
787
797
|
sap_expire_min: int = ...
|
|
788
798
|
sap_interval_s: int = ...
|
|
789
799
|
stream_ttl: int = ...
|
|
800
|
+
sink_rotation: int = ...
|
|
801
|
+
sink_rotation_step: int = ...
|
|
802
|
+
def takes_sink_rotation(self, degrees: int) -> bool: ...
|
|
790
803
|
def merge(self, other: OneIPPtpMessages, which: OneIPDeviceSetting) -> OneIPPtpMessages: ...
|
|
791
804
|
def describe(self, valid: OneIPDeviceSetting) -> list[str]: ...
|
|
792
805
|
|
|
@@ -853,6 +866,13 @@ class OsdSyncReport:
|
|
|
853
866
|
refused: int
|
|
854
867
|
reason: str
|
|
855
868
|
|
|
869
|
+
@dataclass(frozen=True)
|
|
870
|
+
class OsdMessage:
|
|
871
|
+
flags: OsdMessageFlag
|
|
872
|
+
logo: int
|
|
873
|
+
priority: OsdMessagePriority | int
|
|
874
|
+
text: str
|
|
875
|
+
|
|
856
876
|
@dataclass(frozen=True)
|
|
857
877
|
class OsdSyncEntry:
|
|
858
878
|
value: OsdSyncValue
|
|
@@ -968,7 +988,7 @@ class OneIPDeviceSettings:
|
|
|
968
988
|
@property
|
|
969
989
|
def ptp_messages(self) -> OneIPPtpMessages | None: ...
|
|
970
990
|
def merge(self, previous: OneIPDeviceSettings | None) -> OneIPDeviceSettings: ...
|
|
971
|
-
def as_applied_to(self, reported: OneIPDeviceSetting) -> OneIPDeviceSettings: ...
|
|
991
|
+
def as_applied_to(self, reported: OneIPDeviceSettings | OneIPDeviceSetting | None) -> OneIPDeviceSettings: ...
|
|
972
992
|
def __eq__(self, other: Any) -> bool: ...
|
|
973
993
|
def __ne__(self, other: Any) -> bool: ...
|
|
974
994
|
|
|
@@ -1173,6 +1193,9 @@ class DeviceBase(ABC):
|
|
|
1173
1193
|
async def confirm_unit_network(self) -> bool: ...
|
|
1174
1194
|
@property
|
|
1175
1195
|
@abstractmethod
|
|
1196
|
+
def oneip_downmix(self) -> OneIPDownmix | None: ...
|
|
1197
|
+
@property
|
|
1198
|
+
@abstractmethod
|
|
1176
1199
|
def oneip_ptp(self) -> OneIPPtpState | None: ...
|
|
1177
1200
|
@property
|
|
1178
1201
|
@abstractmethod
|
|
@@ -1311,6 +1334,8 @@ class DeviceBase(ABC):
|
|
|
1311
1334
|
@abstractmethod
|
|
1312
1335
|
async def set_oneip_ptp_messages(self, which: OneIPDeviceSetting, messages: OneIPPtpMessages) -> bool: ...
|
|
1313
1336
|
@abstractmethod
|
|
1337
|
+
async def set_oneip_downmix(self, downmix: OneIPDownmix) -> bool: ...
|
|
1338
|
+
@abstractmethod
|
|
1314
1339
|
async def set_oneip_vlan(self, vlan: OneIPVlan) -> bool: ...
|
|
1315
1340
|
@abstractmethod
|
|
1316
1341
|
async def set_audio_endpoint_locked(self, endpoint: int, locked: bool) -> bool: ...
|
|
@@ -1324,6 +1349,15 @@ class DeviceBase(ABC):
|
|
|
1324
1349
|
def osd_sync_report(self) -> OsdSyncReport | None: ...
|
|
1325
1350
|
@property
|
|
1326
1351
|
@abstractmethod
|
|
1352
|
+
def osd_message(self) -> OsdMessage | None: ...
|
|
1353
|
+
@abstractmethod
|
|
1354
|
+
async def request_osd_message(self) -> bool: ...
|
|
1355
|
+
@abstractmethod
|
|
1356
|
+
async def show_osd_message(self, text: str, logo: int = -1, priority: OsdMessagePriority = ...) -> bool: ...
|
|
1357
|
+
@abstractmethod
|
|
1358
|
+
async def clear_osd_message(self) -> bool: ...
|
|
1359
|
+
@property
|
|
1360
|
+
@abstractmethod
|
|
1327
1361
|
def oneip_sink_sdp(self) -> OneIPSinkSdp | None: ...
|
|
1328
1362
|
@property
|
|
1329
1363
|
@abstractmethod
|
|
@@ -1561,6 +1595,7 @@ class MxrCallbacks:
|
|
|
1561
1595
|
def on_status_hdbt_connected_changed(self, bay: BayBase, val: bool) -> None: ...
|
|
1562
1596
|
def on_osd_sync(self, dev: DeviceBase, sync: OsdSync) -> None: ...
|
|
1563
1597
|
def on_osd_sync_report(self, dev: DeviceBase, report: OsdSyncReport) -> None: ...
|
|
1598
|
+
def on_osd_message_changed(self, dev: DeviceBase, message: OsdMessage) -> None: ...
|
|
1564
1599
|
def on_osd_sync_requested(self, dev: DeviceBase, request: OsdSyncRequest) -> None: ...
|
|
1565
1600
|
def on_osd_sync_setting(self, dev: DeviceBase, setting: OsdSyncSetting) -> None: ...
|
|
1566
1601
|
def on_bay_content_changed(self, bay: BayBase, content: BayContent) -> None: ...
|
|
@@ -14,6 +14,7 @@ class MxrDeviceUid:
|
|
|
14
14
|
|
|
15
15
|
def __init__(self, value: object) -> None:
|
|
16
16
|
self._value:bytes
|
|
17
|
+
self._str:str|None = None
|
|
17
18
|
|
|
18
19
|
if value is None:
|
|
19
20
|
self._value = bytes([ 0 for _ in range(16)])
|
|
@@ -44,11 +45,11 @@ class MxrDeviceUid:
|
|
|
44
45
|
|
|
45
46
|
@property
|
|
46
47
|
def value(self) -> str:
|
|
47
|
-
''' value as human
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
''.join(
|
|
51
|
-
|
|
48
|
+
''' value as human readable string, formatted once, as every hash and
|
|
49
|
+
comparison reads it '''
|
|
50
|
+
if (self._str is None):
|
|
51
|
+
self._str = '.'.join(self._value[i:i + 4][::-1].hex() for i in (0, 4, 8, 12))
|
|
52
|
+
return self._str
|
|
52
53
|
|
|
53
54
|
@property
|
|
54
55
|
def empty(self) -> bool:
|
|
@@ -70,12 +71,14 @@ class MxrDeviceUid:
|
|
|
70
71
|
return str(self)
|
|
71
72
|
|
|
72
73
|
def __eq__(self, value: object) -> bool:
|
|
73
|
-
if isinstance(value,
|
|
74
|
-
return
|
|
74
|
+
if isinstance(value, MxrDeviceUid):
|
|
75
|
+
return self.value == value.value
|
|
76
|
+
if isinstance(value, str):
|
|
77
|
+
return self.value == value
|
|
75
78
|
return False
|
|
76
79
|
|
|
77
80
|
def __hash__(self) -> int:
|
|
78
|
-
return hash(
|
|
81
|
+
return hash(self.value)
|
|
79
82
|
|
|
80
83
|
class MxrBayUidOld:
|
|
81
84
|
'''Legacy bay identifier using serial number and port name.'''
|
|
@@ -379,6 +379,9 @@ class OneIPDeviceSetting(IntFlag):
|
|
|
379
379
|
CLOUD = (1 << 30)
|
|
380
380
|
'''Connects to the cloud service. A device that does not report it
|
|
381
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.'''
|
|
382
385
|
|
|
383
386
|
ONEIP_DEVICE_SETTING_SWITCHES = OneIPDeviceSetting(0xFF) | OneIPDeviceSetting.AES67 \
|
|
384
387
|
| OneIPDeviceSetting.SAP_LISTEN | OneIPDeviceSetting.SAP_ANNOUNCE | OneIPDeviceSetting.POWER_SAVE_DISABLED \
|
|
@@ -398,14 +401,17 @@ ONEIP_DEVICE_SETTINGS_PTP_MESSAGES = OneIPDeviceSetting.PTP_ANNOUNCE | OneIPDevi
|
|
|
398
401
|
"""The PTP message settings."""
|
|
399
402
|
|
|
400
403
|
ONEIP_DEVICE_SETTINGS_BLOCK = ONEIP_DEVICE_SETTINGS_PTP_MESSAGES | OneIPDeviceSetting.SAP_EXPIRE \
|
|
401
|
-
| OneIPDeviceSetting.SAP_INTERVAL | OneIPDeviceSetting.STREAM_TTL
|
|
404
|
+
| OneIPDeviceSetting.SAP_INTERVAL | OneIPDeviceSetting.STREAM_TTL | OneIPDeviceSetting.SINK_ROTATION
|
|
402
405
|
"""The settings whose values a frame carries in a block of their own behind the
|
|
403
|
-
rest, OneIPPtpMessages: the PTP message settings, the two SAP values
|
|
404
|
-
stream TTL."""
|
|
406
|
+
rest, OneIPPtpMessages: the PTP message settings, the two SAP values, the
|
|
407
|
+
stream TTL and the output's rotation."""
|
|
405
408
|
|
|
406
409
|
ONEIP_STREAM_TTL_DEFAULT = 64
|
|
407
410
|
"""The TTL a OneIP device's streams carry until it is set."""
|
|
408
411
|
|
|
412
|
+
ONEIP_SINK_ROTATION_MAX = 359
|
|
413
|
+
"""The largest angle a OneIP device's HDMI output is turned by, in degrees."""
|
|
414
|
+
|
|
409
415
|
class OneIPPtpMode(IntEnum):
|
|
410
416
|
'''How a OneIP device takes part in PTP.'''
|
|
411
417
|
OFF = 0
|
|
@@ -434,6 +440,31 @@ class OsdSyncWhat(IntFlag):
|
|
|
434
440
|
LOGO_SLOTS = (1 << 3)
|
|
435
441
|
'''The logo images in the four slots.'''
|
|
436
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
|
+
|
|
437
468
|
class OsdSyncState(IntEnum):
|
|
438
469
|
'''How far a unit has got with taking an overlay sync.'''
|
|
439
470
|
TAKING = 0
|
|
@@ -578,6 +609,25 @@ class OneIPPowerSaveLevel(IntEnum):
|
|
|
578
609
|
OFF = 3
|
|
579
610
|
'''Everything but the network powers down.'''
|
|
580
611
|
|
|
612
|
+
class OneIPDownmixMode(IntEnum):
|
|
613
|
+
'''When a OneIP output mixes 5.1 and 7.1 PCM down to stereo.'''
|
|
614
|
+
OFF = 0
|
|
615
|
+
'''Never.'''
|
|
616
|
+
AUTO = 1
|
|
617
|
+
'''When the display's EDID lists two PCM channels or fewer.'''
|
|
618
|
+
ALWAYS = 2
|
|
619
|
+
'''Always.'''
|
|
620
|
+
|
|
621
|
+
class OneIPDownmixLevel(IntEnum):
|
|
622
|
+
'''How loud a OneIP output's stereo downmix is.'''
|
|
623
|
+
NORMALISED = 0
|
|
624
|
+
'''Scaled so the mix never clips.'''
|
|
625
|
+
UNSCALED = 1
|
|
626
|
+
'''Unscaled, with dialogue at the level it has in stereo.'''
|
|
627
|
+
|
|
628
|
+
ONEIP_DOWNMIX_LFE_MAX = 100
|
|
629
|
+
"""The largest percent a OneIP output mixes its LFE channel in at."""
|
|
630
|
+
|
|
581
631
|
class UnitPowerSave(IntFlag):
|
|
582
632
|
'''What a unit offers at one power save level.'''
|
|
583
633
|
SUPPORTED = (1 << 0)
|