mx-remote 9.0.0__tar.gz → 9.2.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-9.0.0 → mx_remote-9.2.0}/PKG-INFO +1 -1
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/api.md +17 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/oneip.md +46 -12
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/Interface.py +85 -15
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/Interface.pyi +19 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/Uid.py +11 -8
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/const.py +1 -1
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Constants.py +24 -1
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Constants.pyi +11 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +66 -6
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +8 -2
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSources.py +5 -6
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Bay.py +2 -1
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Device.py +73 -9
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Device.pyi +7 -2
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Remote.py +49 -16
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Remote.pyi +1 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/complete.py +12 -0
- mx_remote-9.2.0/tests/downmix.py +124 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/run.py +2 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/staterequest.py +64 -0
- mx_remote-9.2.0/tests/uid.py +50 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipsettings.py +41 -1
- {mx_remote-9.0.0 → mx_remote-9.2.0}/.gitignore +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/AGENTS.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/CLAUDE.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/LICENSE +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/README.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/README.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/_static/brand.css +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/_static/favicon.svg +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/_static/logo-dark.svg +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/_static/logo.svg +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/audio.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/callbacks.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/conf.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/configuration.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/devices-and-bays.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/diagnostics.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/index.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/multiviewer.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/requirements.txt +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/docs/routing.md +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/hatch_build.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/Uid.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/__init__.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/__init__.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/compat.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/compat.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/const.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/deprecated.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/deprecated.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/main.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/main.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/BayConfig.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/BayConfig.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Data.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Data.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Factory.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Factory.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAudioClip.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAudioClip.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAudioSetRoute.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameAudioSetRoute.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBase.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBase.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayConfig.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayConfig.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayContent.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayContent.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayHide.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayHide.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameBayStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameConnectStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameDebug.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameDebug.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameDiscover.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameDiscover.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameEDID.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameEDID.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameEDIDProfile.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFactoryReset.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFactoryReset.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFilterStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFirmwareVersion.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameFirmwareVersion.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameHeader.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameHeader.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameHello.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameHello.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameLinks.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameLinks.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMeshOperation.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMeshOperation.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMirrorStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMonitoringPulse.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameNetworkStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FramePing.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FramePing.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FramePowerChange.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FramePowerChange.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCAction.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCAction.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCIr.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCIr.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCKey.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCKey.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCSettings.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRCSettings.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameReboot.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameReboot.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRoutingChange.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetInstaller.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetName.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetName.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetRoute.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetRoute.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetupStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSignalStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSignalStatusNew.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSysTemperature.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSystemStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTXRCAction.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTXRCKey.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTime.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTime.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTimeZone.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTimeZone.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTopology.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTopology.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTxIR.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameTxIR.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUnitCommand.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUnitCommand.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUnitStatus.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUnitStatus.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUpgradeFPGA.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPAudio.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPAudio.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPBayMapping.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPDetectBays.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPLink.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPMultiviewer.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPOsdSync.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPOsdSync.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPPowerSave.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPPrivacy.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPPrivacy.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSetMaster.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSettingsAll.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSettingsAll.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSinkSdp.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSinkSdp.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSourceSwitch.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPSources.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPStats.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPStats.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPTestcard.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPTestcard.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPTiling.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPVideoWall.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolume.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolume.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeDown.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeSet.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeUp.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/LinkConfig.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/LinkConfig.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Multiviewer.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Multiviewer.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Svd.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/Svd.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/V2IPConfig.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/V2IPConfig.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/V2IPStats.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/V2IPStats.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/__init__.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/__init__.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/proto/svd.csv +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/py.typed +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Bay.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/ConnectionAsync.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/ConnectionAsync.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Link.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/Link.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/OsdSync.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/OsdSync.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/State.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/State.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/V2IP.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/mx_remote/remote/V2IP.pyi +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/pyproject.toml +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/audio_ir.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/audiolock.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/baycontent.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/capture.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/deprecated.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/e2e.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/entry.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/handlers.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/handlers_cover.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/hello.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/idempotent.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/lengths.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/merge.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/mesh.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/meshbays.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/newops.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/offline.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/offsets.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/osdmessage.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/osdsync.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/ping.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/privacy.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/proto_stamp.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/protogate.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/rcsettings.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/roundtrip.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/routes.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/smoke.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/sources.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/stats.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/structs.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/txresult.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/unit.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/unknowns.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipptp.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipscaling.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipsdp.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipsubject.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2iptestcard.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/v2ipvlan.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/vdetails.py +0 -0
- {mx_remote-9.0.0 → mx_remote-9.2.0}/tests/wirefix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mx_remote
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.2.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/
|
|
@@ -168,6 +168,23 @@ bit, and the range of the infrared profiles.
|
|
|
168
168
|
.. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_ID_MAX
|
|
169
169
|
```
|
|
170
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
|
+
|
|
171
188
|
## OneIP PTP
|
|
172
189
|
|
|
173
190
|
A device's PTP settings, which it reports and a controller writes, and the PTP
|
|
@@ -225,27 +225,36 @@ goes out at 176 bytes: a receiver with the schedule ignores the settings of a
|
|
|
225
225
|
shorter frame, and one whose settings end at the idle minutes takes it all the
|
|
226
226
|
same.
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
Power save is switched on or off. Switched on, a device powers down by itself
|
|
229
|
+
to its power save level: reduced, low or off, each powering more down than the
|
|
230
|
+
one before. The device picks the level itself, the one that saves the most
|
|
231
|
+
while its input and display can still wake it, and reports it. Its unit status
|
|
232
|
+
says which levels it supports and what wakes it at each.
|
|
231
233
|
|
|
232
234
|
```python
|
|
233
235
|
from mx_remote import OneIPPowerSaveLevel, UnitPowerSave
|
|
234
236
|
|
|
235
|
-
print(settings.
|
|
237
|
+
print(settings.get(OneIPDeviceSetting.POWER_SAVE_DISABLED)) # False: switched on
|
|
238
|
+
print(settings.power_save_level) # the level it picked
|
|
236
239
|
print(device.unit_status.power_save_level(OneIPPowerSaveLevel.LOW)) # e.g. SUPPORTED|INPUT_WAKE
|
|
237
240
|
|
|
238
|
-
await device.
|
|
241
|
+
await device.set_oneip_power_save(True)
|
|
242
|
+
await mx.set_all_oneip_power_save(False) # every OneIP device of the mesh
|
|
239
243
|
```
|
|
240
244
|
|
|
241
|
-
|
|
242
|
-
|
|
245
|
+
Switched off, `OneIPDeviceSetting.POWER_SAVE_DISABLED` is on: the device does
|
|
246
|
+
not power down by itself, and a power save request still powers it down.
|
|
247
|
+
Switching on is written as a mesh controller writes it, with that switch clear
|
|
248
|
+
and the power save level at 0, so a device whose firmware still takes the level
|
|
249
|
+
as its setting returns to its own default.
|
|
243
250
|
|
|
244
|
-
`
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
251
|
+
`set_oneip_power_save_level()` writes a level, which switches power save on. A
|
|
252
|
+
current device ignores the level; one whose firmware predates picking it takes
|
|
253
|
+
it. A written level is never cached, from this client or another controller:
|
|
254
|
+
`power_save_level` is what the device reports. A level write without the switch
|
|
255
|
+
only clears `POWER_SAVE_DISABLED` on a device that reports it. A level this
|
|
256
|
+
library does not name is refused before it is sent. Firmware without the switch
|
|
257
|
+
never reports it, and switching is refused there.
|
|
249
258
|
|
|
250
259
|
`OneIPDeviceSetting.CLOUD` is a switch for whether a device connects to the
|
|
251
260
|
cloud service. A device that does not report it connects regardless, and the
|
|
@@ -318,6 +327,31 @@ if ptp is not None:
|
|
|
318
327
|
print(ptp.grandmaster) # its clock identity, None while there is none
|
|
319
328
|
```
|
|
320
329
|
|
|
330
|
+
### Stereo downmix
|
|
331
|
+
|
|
332
|
+
A device whose output can mix 5.1 and 7.1 PCM down to stereo reports how,
|
|
333
|
+
once its video processor has answered for it: a mode, a level and the percent
|
|
334
|
+
the LFE channel is mixed in at, which a controller writes, and the state and
|
|
335
|
+
channel count, which only the device reports. A device that reports none has
|
|
336
|
+
no downmix to set, so a write to one is refused, as is a mode, level or LFE
|
|
337
|
+
percent out of range. The write sends the mode, level and LFE together; the
|
|
338
|
+
state and channels are never sent.
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from mx_remote import OneIPDownmix
|
|
342
|
+
from mx_remote.proto.Constants import OneIPDownmixMode, OneIPDownmixLevel
|
|
343
|
+
|
|
344
|
+
downmix = device.oneip_downmix # None: no report yet, or no downmix
|
|
345
|
+
if downmix is not None:
|
|
346
|
+
print(downmix.mode, downmix.level, downmix.lfe) # LFE up to ONEIP_DOWNMIX_LFE_MAX
|
|
347
|
+
print(downmix.state, downmix.channels) # the device's own
|
|
348
|
+
await device.set_oneip_downmix(OneIPDownmix(mode=OneIPDownmixMode.AUTO,
|
|
349
|
+
level=OneIPDownmixLevel.NORMALISED, lfe=50))
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The downmix ends the settings block, behind a second valid word, so the write
|
|
353
|
+
runs on to 248 bytes and carries no other setting.
|
|
354
|
+
|
|
321
355
|
### VLAN
|
|
322
356
|
|
|
323
357
|
A device that announces `DeviceFeature.VLAN` tags its uplink by a VLAN
|
|
@@ -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
|
"""
|
|
@@ -2672,6 +2712,16 @@ class OneIPDeviceSettings:
|
|
|
2672
2712
|
self._power_save_level = int(power_save_level)
|
|
2673
2713
|
self._ptp_messages = ptp_messages if (ptp_messages is not None) else OneIPPtpMessages()
|
|
2674
2714
|
|
|
2715
|
+
@classmethod
|
|
2716
|
+
def power_save_switch(cls, enabled:bool) -> 'OneIPDeviceSettings':
|
|
2717
|
+
"""The settings that switch a device's power save on or off. On is both
|
|
2718
|
+
POWER_SAVE_DISABLED, clear, and POWER_SAVE_LEVEL, at 0."""
|
|
2719
|
+
disabled = OneIPDeviceSetting.POWER_SAVE_DISABLED
|
|
2720
|
+
if enabled:
|
|
2721
|
+
return cls(valid=(disabled | OneIPDeviceSetting.POWER_SAVE_LEVEL),
|
|
2722
|
+
power_save_level=OneIPPowerSaveLevel.NONE)
|
|
2723
|
+
return cls(valid=disabled, flags=disabled)
|
|
2724
|
+
|
|
2675
2725
|
@property
|
|
2676
2726
|
def valid(self) -> OneIPDeviceSetting:
|
|
2677
2727
|
"""The settings reported so far."""
|
|
@@ -2751,8 +2801,9 @@ class OneIPDeviceSettings:
|
|
|
2751
2801
|
|
|
2752
2802
|
@property
|
|
2753
2803
|
def power_save_level(self) -> OneIPPowerSaveLevel|int|None:
|
|
2754
|
-
"""The level the device powers down to in power save,
|
|
2755
|
-
this library does not name, None while it is
|
|
2804
|
+
"""The level the device powers down to in power save, which it picks
|
|
2805
|
+
itself, a raw int for one this library does not name, None while it is
|
|
2806
|
+
not reported."""
|
|
2756
2807
|
if (OneIPDeviceSetting.POWER_SAVE_LEVEL not in self._valid):
|
|
2757
2808
|
return None
|
|
2758
2809
|
return _wire_enum(OneIPPowerSaveLevel, self._power_save_level)
|
|
@@ -2772,18 +2823,14 @@ class OneIPDeviceSettings:
|
|
|
2772
2823
|
|
|
2773
2824
|
Each bit in this block's ``valid`` replaces its own setting and leaves
|
|
2774
2825
|
the others alone, so a write about one setting does not clear what was
|
|
2775
|
-
known about the rest.
|
|
2776
|
-
takes a power save level as switching it off.
|
|
2826
|
+
known about the rest.
|
|
2777
2827
|
"""
|
|
2778
2828
|
if (previous is None):
|
|
2779
2829
|
previous = OneIPDeviceSettings()
|
|
2780
2830
|
valid = self._valid
|
|
2781
|
-
flags = (previous._flags & ~valid) | (self._flags & valid)
|
|
2782
|
-
if (OneIPDeviceSetting.POWER_SAVE_LEVEL in valid) and (OneIPDeviceSetting.POWER_SAVE_DISABLED not in valid):
|
|
2783
|
-
flags &= ~OneIPDeviceSetting.POWER_SAVE_DISABLED
|
|
2784
2831
|
return OneIPDeviceSettings(
|
|
2785
2832
|
valid=(previous._valid | valid),
|
|
2786
|
-
flags=
|
|
2833
|
+
flags=((previous._flags & ~valid) | (self._flags & valid)),
|
|
2787
2834
|
ir_profiles=(self._ir_profiles if (OneIPDeviceSetting.IR_PROFILES in valid)
|
|
2788
2835
|
else previous._ir_profiles),
|
|
2789
2836
|
ir_profile=(self._ir_profile if (OneIPDeviceSetting.IR_PROFILE in valid)
|
|
@@ -2810,9 +2857,11 @@ class OneIPDeviceSettings:
|
|
|
2810
2857
|
write about it.
|
|
2811
2858
|
|
|
2812
2859
|
A device applies a setting only if it has it, a profile, PTP mode, PTP
|
|
2813
|
-
domain
|
|
2814
|
-
|
|
2815
|
-
|
|
2860
|
+
domain or PTP DSCP only within its range, a stream TTL only when it is
|
|
2861
|
+
not 0, a rotation only by its own step, and never what only it can
|
|
2862
|
+
report about itself. The step stays the device's. It picks its power
|
|
2863
|
+
save level itself, and takes a level it is written, without
|
|
2864
|
+
POWER_SAVE_DISABLED, as switching power save on.
|
|
2816
2865
|
|
|
2817
2866
|
reported may be only the bits the device reported, which says nothing
|
|
2818
2867
|
of its step, so a rotation other than 0 is then left out.
|
|
@@ -2831,15 +2880,20 @@ class OneIPDeviceSettings:
|
|
|
2831
2880
|
valid &= ~OneIPDeviceSetting.PTP_MODE
|
|
2832
2881
|
if (self._ptp_domain > ONEIP_PTP_DOMAIN_MAX):
|
|
2833
2882
|
valid &= ~OneIPDeviceSetting.PTP_DOMAIN
|
|
2834
|
-
if (self._power_save_level > OneIPPowerSaveLevel.OFF):
|
|
2835
|
-
valid &= ~OneIPDeviceSetting.POWER_SAVE_LEVEL
|
|
2836
2883
|
if (self._ptp_messages.dscp > ONEIP_DSCP_MAX):
|
|
2837
2884
|
valid &= ~OneIPDeviceSetting.PTP_DSCP
|
|
2838
2885
|
if (self._ptp_messages.stream_ttl == 0):
|
|
2839
2886
|
valid &= ~OneIPDeviceSetting.STREAM_TTL
|
|
2840
2887
|
if not own.takes_sink_rotation(self._ptp_messages.sink_rotation):
|
|
2841
2888
|
valid &= ~OneIPDeviceSetting.SINK_ROTATION
|
|
2842
|
-
|
|
2889
|
+
flags = self._flags
|
|
2890
|
+
if (OneIPDeviceSetting.POWER_SAVE_LEVEL in valid):
|
|
2891
|
+
valid &= ~OneIPDeviceSetting.POWER_SAVE_LEVEL
|
|
2892
|
+
if (OneIPDeviceSetting.POWER_SAVE_DISABLED not in valid) \
|
|
2893
|
+
and (OneIPDeviceSetting.POWER_SAVE_DISABLED in reported._valid):
|
|
2894
|
+
valid |= OneIPDeviceSetting.POWER_SAVE_DISABLED
|
|
2895
|
+
flags &= ~OneIPDeviceSetting.POWER_SAVE_DISABLED
|
|
2896
|
+
return OneIPDeviceSettings(valid=valid, flags=flags, ir_profiles=self._ir_profiles,
|
|
2843
2897
|
ir_profile=self._ir_profile, ir_profile_sink=self._ir_profile_sink,
|
|
2844
2898
|
auto_power_save=self._auto_power_save, power_save=self._power_save,
|
|
2845
2899
|
ptp_mode=self._ptp_mode, ptp_domain=self._ptp_domain,
|
|
@@ -3239,6 +3293,14 @@ class DeviceBase(ABC):
|
|
|
3239
3293
|
async def confirm_unit_network(self) -> bool:
|
|
3240
3294
|
'''keep the unit's pending IP configuration'''
|
|
3241
3295
|
|
|
3296
|
+
@property
|
|
3297
|
+
@abstractmethod
|
|
3298
|
+
def oneip_downmix(self) -> OneIPDownmix|None:
|
|
3299
|
+
'''How this OneIP device's output mixes down to stereo, as it last
|
|
3300
|
+
reported, None while it reports no downmix: until its video processor
|
|
3301
|
+
has answered for it, and always for one whose output cannot mix
|
|
3302
|
+
down.'''
|
|
3303
|
+
|
|
3242
3304
|
@property
|
|
3243
3305
|
@abstractmethod
|
|
3244
3306
|
def oneip_ptp(self) -> OneIPPtpState|None:
|
|
@@ -3524,14 +3586,22 @@ class DeviceBase(ABC):
|
|
|
3524
3586
|
async def set_oneip_ptp_priority1(self, priority1:int) -> bool:
|
|
3525
3587
|
'''set the priority1 the device announces as a PTP grandmaster'''
|
|
3526
3588
|
|
|
3589
|
+
@abstractmethod
|
|
3590
|
+
async def set_oneip_power_save(self, enabled:bool) -> bool:
|
|
3591
|
+
'''switch power save on, so the device powers down by itself to the level it picks, or off'''
|
|
3592
|
+
|
|
3527
3593
|
@abstractmethod
|
|
3528
3594
|
async def set_oneip_power_save_level(self, level:OneIPPowerSaveLevel) -> bool:
|
|
3529
|
-
'''
|
|
3595
|
+
'''write the level the device powers down to in power save, which switches power save on'''
|
|
3530
3596
|
|
|
3531
3597
|
@abstractmethod
|
|
3532
3598
|
async def set_oneip_ptp_messages(self, which:OneIPDeviceSetting, messages:OneIPPtpMessages) -> bool:
|
|
3533
3599
|
'''set how the device paces its PTP messages, its SAP timings and its streams' TTL: the values of messages behind the bits of which'''
|
|
3534
3600
|
|
|
3601
|
+
@abstractmethod
|
|
3602
|
+
async def set_oneip_downmix(self, downmix:OneIPDownmix) -> bool:
|
|
3603
|
+
'''set how the device's output mixes down to stereo'''
|
|
3604
|
+
|
|
3535
3605
|
@abstractmethod
|
|
3536
3606
|
async def set_oneip_vlan(self, vlan:OneIPVlan) -> bool:
|
|
3537
3607
|
'''change the device's VLAN configuration'''
|
|
@@ -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 = ...
|
|
@@ -952,6 +962,8 @@ class OneIPTestcard:
|
|
|
952
962
|
|
|
953
963
|
class OneIPDeviceSettings:
|
|
954
964
|
def __init__(self, valid: OneIPDeviceSetting = ..., flags: OneIPDeviceSetting = ..., ir_profiles: int = 0, ir_profile: int = 0, ir_profile_sink: int = 0, auto_power_save: int = 0, power_save: OneIPPowerSaveSchedule | None = None, ptp_mode: OneIPPtpMode | int = ..., ptp_domain: int = 0, ptp_priority1: int = 0, power_save_level: OneIPPowerSaveLevel | int = ..., ptp_messages: OneIPPtpMessages | None = None) -> None: ...
|
|
965
|
+
@classmethod
|
|
966
|
+
def power_save_switch(cls, enabled: bool) -> OneIPDeviceSettings: ...
|
|
955
967
|
@property
|
|
956
968
|
def valid(self) -> OneIPDeviceSetting: ...
|
|
957
969
|
@property
|
|
@@ -1183,6 +1195,9 @@ class DeviceBase(ABC):
|
|
|
1183
1195
|
async def confirm_unit_network(self) -> bool: ...
|
|
1184
1196
|
@property
|
|
1185
1197
|
@abstractmethod
|
|
1198
|
+
def oneip_downmix(self) -> OneIPDownmix | None: ...
|
|
1199
|
+
@property
|
|
1200
|
+
@abstractmethod
|
|
1186
1201
|
def oneip_ptp(self) -> OneIPPtpState | None: ...
|
|
1187
1202
|
@property
|
|
1188
1203
|
@abstractmethod
|
|
@@ -1317,10 +1332,14 @@ class DeviceBase(ABC):
|
|
|
1317
1332
|
@abstractmethod
|
|
1318
1333
|
async def set_oneip_ptp_priority1(self, priority1: int) -> bool: ...
|
|
1319
1334
|
@abstractmethod
|
|
1335
|
+
async def set_oneip_power_save(self, enabled: bool) -> bool: ...
|
|
1336
|
+
@abstractmethod
|
|
1320
1337
|
async def set_oneip_power_save_level(self, level: OneIPPowerSaveLevel) -> bool: ...
|
|
1321
1338
|
@abstractmethod
|
|
1322
1339
|
async def set_oneip_ptp_messages(self, which: OneIPDeviceSetting, messages: OneIPPtpMessages) -> bool: ...
|
|
1323
1340
|
@abstractmethod
|
|
1341
|
+
async def set_oneip_downmix(self, downmix: OneIPDownmix) -> bool: ...
|
|
1342
|
+
@abstractmethod
|
|
1324
1343
|
async def set_oneip_vlan(self, vlan: OneIPVlan) -> bool: ...
|
|
1325
1344
|
@abstractmethod
|
|
1326
1345
|
async def set_audio_endpoint_locked(self, endpoint: int, locked: bool) -> bool: ...
|
|
@@ -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.'''
|
|
@@ -349,7 +349,11 @@ class OneIPDeviceSetting(IntFlag):
|
|
|
349
349
|
AES67 = (1 << 17)
|
|
350
350
|
'''Sends the source's audio as an AES67 flow, where the source allows.'''
|
|
351
351
|
POWER_SAVE_LEVEL = (1 << 18)
|
|
352
|
-
'''The
|
|
352
|
+
'''The level the device powers down to in power save. A device picks it
|
|
353
|
+
itself: the level that saves the most while its input and display can
|
|
354
|
+
still wake it. Written without POWER_SAVE_DISABLED, it switches power save
|
|
355
|
+
on, and the level written is ignored, except by a device whose firmware
|
|
356
|
+
predates picking it, which takes the level as its setting.'''
|
|
353
357
|
PTP_ANNOUNCE = (1 << 19)
|
|
354
358
|
'''The interval between the device's PTP announce messages.'''
|
|
355
359
|
PTP_SYNC = (1 << 20)
|
|
@@ -609,6 +613,25 @@ class OneIPPowerSaveLevel(IntEnum):
|
|
|
609
613
|
OFF = 3
|
|
610
614
|
'''Everything but the network powers down.'''
|
|
611
615
|
|
|
616
|
+
class OneIPDownmixMode(IntEnum):
|
|
617
|
+
'''When a OneIP output mixes 5.1 and 7.1 PCM down to stereo.'''
|
|
618
|
+
OFF = 0
|
|
619
|
+
'''Never.'''
|
|
620
|
+
AUTO = 1
|
|
621
|
+
'''When the display's EDID lists two PCM channels or fewer.'''
|
|
622
|
+
ALWAYS = 2
|
|
623
|
+
'''Always.'''
|
|
624
|
+
|
|
625
|
+
class OneIPDownmixLevel(IntEnum):
|
|
626
|
+
'''How loud a OneIP output's stereo downmix is.'''
|
|
627
|
+
NORMALISED = 0
|
|
628
|
+
'''Scaled so the mix never clips.'''
|
|
629
|
+
UNSCALED = 1
|
|
630
|
+
'''Unscaled, with dialogue at the level it has in stereo.'''
|
|
631
|
+
|
|
632
|
+
ONEIP_DOWNMIX_LFE_MAX = 100
|
|
633
|
+
"""The largest percent a OneIP output mixes its LFE channel in at."""
|
|
634
|
+
|
|
612
635
|
class UnitPowerSave(IntFlag):
|
|
613
636
|
'''What a unit offers at one power save level.'''
|
|
614
637
|
SUPPORTED = (1 << 0)
|
|
@@ -236,6 +236,17 @@ class OneIPPowerSaveLevel(IntEnum):
|
|
|
236
236
|
LOW: int
|
|
237
237
|
OFF: int
|
|
238
238
|
|
|
239
|
+
class OneIPDownmixMode(IntEnum):
|
|
240
|
+
OFF: int
|
|
241
|
+
AUTO: int
|
|
242
|
+
ALWAYS: int
|
|
243
|
+
|
|
244
|
+
class OneIPDownmixLevel(IntEnum):
|
|
245
|
+
NORMALISED: int
|
|
246
|
+
UNSCALED: int
|
|
247
|
+
|
|
248
|
+
ONEIP_DOWNMIX_LFE_MAX: int
|
|
249
|
+
|
|
239
250
|
class UnitPowerSave(IntFlag):
|
|
240
251
|
SUPPORTED: Incomplete
|
|
241
252
|
INPUT_WAKE: Incomplete
|
|
@@ -14,9 +14,9 @@ from .FrameHeader import FrameHeader
|
|
|
14
14
|
from ..Uid import MxrDeviceUid
|
|
15
15
|
from ..Interface import (DeviceBase, DeviceRegistry, DeviceOneIPDetails, DeviceOneIPScalingSettings,
|
|
16
16
|
DeviceOneIPSink, OneIPAudioFormat, OneIPDeviceSettings, OneIPDscpConfig,
|
|
17
|
-
OneIPPowerSaveSchedule, OneIPPtpMessages, OneIPPtpState,
|
|
18
|
-
OneIPVlan, _wire_enum)
|
|
19
|
-
from .Constants import (ONEIP_DEVICE_SETTINGS_BLOCK, ONEIP_DEVICE_SETTINGS_PTP, OneIPPtpFlag, OneIPPtpLock, OneIPPtpMode, OneIPDeviceSetting, OneIPVideoProcessorFeature, OneIPVlanFlag, MXR_SCALING_FLAG_AUTO_SCALING,
|
|
17
|
+
OneIPDownmix, OneIPPowerSaveSchedule, OneIPPtpMessages, OneIPPtpState,
|
|
18
|
+
OneIPStreamSource, OneIPVlan, _wire_enum)
|
|
19
|
+
from .Constants import (ONEIP_DEVICE_SETTINGS_BLOCK, ONEIP_DEVICE_SETTINGS_PTP, OneIPDownmixLevel, OneIPDownmixMode, OneIPPtpFlag, OneIPPtpLock, OneIPPtpMode, OneIPDeviceSetting, OneIPVideoProcessorFeature, OneIPVlanFlag, MXR_SCALING_FLAG_AUTO_SCALING,
|
|
20
20
|
MXR_SCALING_FLAG_MODE_VALID,
|
|
21
21
|
MXR_SCALING_FLAG_OPTIONS_VALID, MXR_SCALING_FLAG_OPTIONS2_VALID,
|
|
22
22
|
MXR_SCALING_OPTIONS2_SETTINGS, MxrSignalType, oneip_dscp_value,
|
|
@@ -48,13 +48,19 @@ from .V2IPConfig import V2IPStreamSourceImpl, parse_v2ip_av_source
|
|
|
48
48
|
# 216..224 the settings' own block: the PTP announce, sync and delay
|
|
49
49
|
# request intervals as i8, u8 announce timeout, u8 PTP DSCP,
|
|
50
50
|
# u8 SAP expiry in minutes, u16 SAP interval in seconds, and
|
|
51
|
-
# from a device with the stream TTL, u8 TTL
|
|
51
|
+
# from a device with the stream TTL, u8 TTL, a reserved byte,
|
|
52
|
+
# u16 output rotation and u16 rotation step at 224..230, 2
|
|
53
|
+
# reserved
|
|
54
|
+
# 232..248 from a device with the downmix: u32 second valid word, then
|
|
55
|
+
# the downmix's u8 mode, level, LFE percent, state and channels
|
|
56
|
+
# at 236..241, 7 reserved
|
|
52
57
|
#
|
|
53
58
|
# That block is the last of its frame, so it is read by its length: shorter
|
|
54
59
|
# than 8 carries none of its values, and 8, which every device without the TTL
|
|
55
60
|
# sends, carries all but the TTL. A write grows it to 16 only when it carries
|
|
56
|
-
# the TTL
|
|
57
|
-
# predate
|
|
61
|
+
# the TTL or the rotation, and to 32 only for the downmix, so the frames other
|
|
62
|
+
# writes send are unchanged for units that predate them. A block too short to
|
|
63
|
+
# hold the downmix's channels carries no bit of the second valid word.
|
|
58
64
|
#
|
|
59
65
|
# Each of those blocks was appended behind what came before it, leaving every
|
|
60
66
|
# offset ahead of it where it was, so the length is what says whether one is
|
|
@@ -136,6 +142,14 @@ _STREAM_TTL_AT = 8
|
|
|
136
142
|
_SINK_ROTATION_AT = 10
|
|
137
143
|
_SINK_ROTATION_STEP_AT = 12
|
|
138
144
|
_SETTINGS_BLOCK_LONG_SIZE = 16
|
|
145
|
+
_VALID_EXT_OFFSET = SETTINGS_BLOCK_OFFSET + _SETTINGS_BLOCK_LONG_SIZE
|
|
146
|
+
'''The second valid word of the settings, behind the block of their own.'''
|
|
147
|
+
_DOWNMIX_OFFSET = _VALID_EXT_OFFSET + 4
|
|
148
|
+
_DOWNMIX_SIZE = 5
|
|
149
|
+
_WITH_DOWNMIX_SIZE = SETTINGS_BLOCK_OFFSET + 32
|
|
150
|
+
'''The frame a downmix write sends: the settings block run on to 32 bytes.'''
|
|
151
|
+
_SETTING_EXT_DOWNMIX = 1 << 0
|
|
152
|
+
'''The bit of the second valid word that carries the downmix.'''
|
|
139
153
|
|
|
140
154
|
def carries_settings_block(settings:OneIPDeviceSettings) -> bool:
|
|
141
155
|
'''Whether settings carry a value only the block of their own can hold.'''
|
|
@@ -424,6 +438,28 @@ class FrameV2IPDeviceConfiguration(FrameBase):
|
|
|
424
438
|
payload += own_settings_block(settings)
|
|
425
439
|
return FrameBase.construct_base(target=target, mxr=mxr, opcode=_OPCODE, payload=bytes(payload))
|
|
426
440
|
|
|
441
|
+
@staticmethod
|
|
442
|
+
def construct_downmix(mxr:DeviceRegistry, target:Any, target_uid:MxrDeviceUid,
|
|
443
|
+
downmix:OneIPDownmix) -> FrameBase|None:
|
|
444
|
+
'''Build the 0x3C write that changes how a device's output mixes down to
|
|
445
|
+
stereo and nothing else.
|
|
446
|
+
|
|
447
|
+
248 bytes: the frame construct_settings() builds, with a settings block
|
|
448
|
+
that carries no setting, zeroed to 232, then the second valid word
|
|
449
|
+
carrying the downmix and its mode, level and LFE percent at 236..239.
|
|
450
|
+
The state and channels at 239 and 240 are the device's to report, and
|
|
451
|
+
are left 0.
|
|
452
|
+
'''
|
|
453
|
+
frame = FrameV2IPDeviceConfiguration.construct_settings(
|
|
454
|
+
mxr=mxr, target=target, target_uid=target_uid, settings=OneIPDeviceSettings())
|
|
455
|
+
if (frame is None):
|
|
456
|
+
return None
|
|
457
|
+
payload = bytearray(frame.payload or b"")
|
|
458
|
+
payload += bytes(_WITH_DOWNMIX_SIZE - len(payload))
|
|
459
|
+
struct.pack_into('<IBBB', payload, _VALID_EXT_OFFSET, _SETTING_EXT_DOWNMIX,
|
|
460
|
+
int(downmix.mode), int(downmix.level), downmix.lfe)
|
|
461
|
+
return FrameBase.construct_base(target=target, mxr=mxr, opcode=_OPCODE, payload=bytes(payload))
|
|
462
|
+
|
|
427
463
|
@staticmethod
|
|
428
464
|
def construct_vlan(mxr:DeviceRegistry, target:Any, target_uid:MxrDeviceUid,
|
|
429
465
|
vlan:OneIPVlan) -> FrameBase|None:
|
|
@@ -580,6 +616,28 @@ class FrameV2IPDeviceConfiguration(FrameBase):
|
|
|
580
616
|
port_state=port_state, lock=_wire_enum(OneIPPtpLock, lock),
|
|
581
617
|
clock_identity=clock, grandmaster_identity=grandmaster)
|
|
582
618
|
|
|
619
|
+
@property
|
|
620
|
+
def carries_downmix(self) -> bool:
|
|
621
|
+
'''Whether the frame is long enough to say whether it carries a downmix.'''
|
|
622
|
+
return (self.payload is not None) and (len(self.payload) >= (_DOWNMIX_OFFSET + _DOWNMIX_SIZE))
|
|
623
|
+
|
|
624
|
+
@cached_property
|
|
625
|
+
def downmix(self) -> OneIPDownmix|None:
|
|
626
|
+
'''The downmix the frame carries, None when it carries none: in a frame
|
|
627
|
+
too short to hold it, or without its bit of the second valid word.
|
|
628
|
+
|
|
629
|
+
From the subject itself, None reports that it has no downmix; from
|
|
630
|
+
another sender it is a write, of which only the mode, level and LFE
|
|
631
|
+
percent count.'''
|
|
632
|
+
if not self.carries_downmix:
|
|
633
|
+
return None
|
|
634
|
+
p = self.payload or b""
|
|
635
|
+
valid_ext, mode, level, lfe, state, channels = struct.unpack_from('<IBBBBB', p, _VALID_EXT_OFFSET)
|
|
636
|
+
if not (valid_ext & _SETTING_EXT_DOWNMIX):
|
|
637
|
+
return None
|
|
638
|
+
return OneIPDownmix(mode=_wire_enum(OneIPDownmixMode, mode), level=_wire_enum(OneIPDownmixLevel, level),
|
|
639
|
+
lfe=lfe, state=state, channels=channels)
|
|
640
|
+
|
|
583
641
|
def process(self) -> None:
|
|
584
642
|
'''Update the cache of the device this configuration names, not of its sender.'''
|
|
585
643
|
if ((dev := self.subject_device) is None):
|
|
@@ -595,6 +653,8 @@ class FrameV2IPDeviceConfiguration(FrameBase):
|
|
|
595
653
|
dev.on_mxr_update(vlan)
|
|
596
654
|
if ((ptp := self.ptp) is not None):
|
|
597
655
|
dev.on_mxr_update(ptp)
|
|
656
|
+
if self.carries_downmix:
|
|
657
|
+
dev.on_mxr_update(self)
|
|
598
658
|
|
|
599
659
|
def __str__(self) -> str:
|
|
600
660
|
sink_str = f" sink=[{self.sink}]" if (self.sink is not None) else ""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from ..Interface import DeviceBase as DeviceBase, DeviceOneIPDetails as DeviceOneIPDetails, DeviceOneIPScalingSettings as DeviceOneIPScalingSettings, DeviceOneIPSink as DeviceOneIPSink, DeviceRegistry as DeviceRegistry, OneIPAudioFormat as OneIPAudioFormat, OneIPDeviceSettings as OneIPDeviceSettings, OneIPDscpConfig as OneIPDscpConfig, OneIPPowerSaveSchedule as OneIPPowerSaveSchedule, OneIPPtpMessages as OneIPPtpMessages, OneIPPtpState as OneIPPtpState, OneIPStreamSource as OneIPStreamSource, OneIPVlan as OneIPVlan
|
|
1
|
+
from ..Interface import DeviceBase as DeviceBase, DeviceOneIPDetails as DeviceOneIPDetails, DeviceOneIPScalingSettings as DeviceOneIPScalingSettings, DeviceOneIPSink as DeviceOneIPSink, DeviceRegistry as DeviceRegistry, OneIPAudioFormat as OneIPAudioFormat, OneIPDeviceSettings as OneIPDeviceSettings, OneIPDownmix as OneIPDownmix, OneIPDscpConfig as OneIPDscpConfig, OneIPPowerSaveSchedule as OneIPPowerSaveSchedule, OneIPPtpMessages as OneIPPtpMessages, OneIPPtpState as OneIPPtpState, OneIPStreamSource as OneIPStreamSource, OneIPVlan as OneIPVlan
|
|
2
2
|
from ..Uid import MxrDeviceUid as MxrDeviceUid
|
|
3
|
-
from .Constants import MXR_SCALING_FLAG_AUTO_SCALING as MXR_SCALING_FLAG_AUTO_SCALING, MXR_SCALING_FLAG_MODE_VALID as MXR_SCALING_FLAG_MODE_VALID, MXR_SCALING_FLAG_OPTIONS2_VALID as MXR_SCALING_FLAG_OPTIONS2_VALID, MXR_SCALING_FLAG_OPTIONS_VALID as MXR_SCALING_FLAG_OPTIONS_VALID, MXR_SCALING_OPTIONS2_SETTINGS as MXR_SCALING_OPTIONS2_SETTINGS, MxrSignalType as MxrSignalType, ONEIP_DEVICE_SETTINGS_BLOCK as ONEIP_DEVICE_SETTINGS_BLOCK, ONEIP_DEVICE_SETTINGS_PTP as ONEIP_DEVICE_SETTINGS_PTP, OneIPDeviceSetting as OneIPDeviceSetting, OneIPPtpFlag as OneIPPtpFlag, OneIPPtpLock as OneIPPtpLock, OneIPPtpMode as OneIPPtpMode, OneIPVideoProcessorFeature as OneIPVideoProcessorFeature, OneIPVlanFlag as OneIPVlanFlag, oneip_dscp_value as oneip_dscp_value, oneip_rate_valid as oneip_rate_valid
|
|
3
|
+
from .Constants import MXR_SCALING_FLAG_AUTO_SCALING as MXR_SCALING_FLAG_AUTO_SCALING, MXR_SCALING_FLAG_MODE_VALID as MXR_SCALING_FLAG_MODE_VALID, MXR_SCALING_FLAG_OPTIONS2_VALID as MXR_SCALING_FLAG_OPTIONS2_VALID, MXR_SCALING_FLAG_OPTIONS_VALID as MXR_SCALING_FLAG_OPTIONS_VALID, MXR_SCALING_OPTIONS2_SETTINGS as MXR_SCALING_OPTIONS2_SETTINGS, MxrSignalType as MxrSignalType, ONEIP_DEVICE_SETTINGS_BLOCK as ONEIP_DEVICE_SETTINGS_BLOCK, ONEIP_DEVICE_SETTINGS_PTP as ONEIP_DEVICE_SETTINGS_PTP, OneIPDeviceSetting as OneIPDeviceSetting, OneIPDownmixLevel as OneIPDownmixLevel, OneIPDownmixMode as OneIPDownmixMode, OneIPPtpFlag as OneIPPtpFlag, OneIPPtpLock as OneIPPtpLock, OneIPPtpMode as OneIPPtpMode, OneIPVideoProcessorFeature as OneIPVideoProcessorFeature, OneIPVlanFlag as OneIPVlanFlag, oneip_dscp_value as oneip_dscp_value, oneip_rate_valid as oneip_rate_valid
|
|
4
4
|
from .FrameBase import FrameBase as FrameBase
|
|
5
5
|
from .FrameHeader import FrameHeader as FrameHeader
|
|
6
6
|
from .V2IPConfig import V2IPStreamSourceImpl as V2IPStreamSourceImpl, parse_v2ip_av_source as parse_v2ip_av_source
|
|
@@ -48,6 +48,8 @@ class FrameV2IPDeviceConfiguration(FrameBase):
|
|
|
48
48
|
@staticmethod
|
|
49
49
|
def construct_settings(mxr: DeviceRegistry, target: Any, target_uid: MxrDeviceUid, settings: OneIPDeviceSettings) -> FrameBase | None: ...
|
|
50
50
|
@staticmethod
|
|
51
|
+
def construct_downmix(mxr: DeviceRegistry, target: Any, target_uid: MxrDeviceUid, downmix: OneIPDownmix) -> FrameBase | None: ...
|
|
52
|
+
@staticmethod
|
|
51
53
|
def construct_vlan(mxr: DeviceRegistry, target: Any, target_uid: MxrDeviceUid, vlan: OneIPVlan) -> FrameBase | None: ...
|
|
52
54
|
@property
|
|
53
55
|
def target_uid(self) -> MxrDeviceUid | None: ...
|
|
@@ -67,4 +69,8 @@ class FrameV2IPDeviceConfiguration(FrameBase):
|
|
|
67
69
|
def vlan(self) -> OneIPVlan | None: ...
|
|
68
70
|
@cached_property
|
|
69
71
|
def ptp(self) -> OneIPPtpState | None: ...
|
|
72
|
+
@property
|
|
73
|
+
def carries_downmix(self) -> bool: ...
|
|
74
|
+
@cached_property
|
|
75
|
+
def downmix(self) -> OneIPDownmix | None: ...
|
|
70
76
|
def process(self) -> None: ...
|
|
@@ -26,9 +26,10 @@ class FrameV2IPSources(FrameBase):
|
|
|
26
26
|
that list was when the frame was built. None when the payload is neither
|
|
27
27
|
form this opcode carries.
|
|
28
28
|
|
|
29
|
-
A list that fits one frame is sent as bare records from the first byte
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
A list that fits one frame is sent as bare records from the first byte,
|
|
30
|
+
and a unit that knows no source sends it with none. A longer one is
|
|
31
|
+
split into pages, each behind a header. That header is not a whole
|
|
32
|
+
record, so the remainder separates the two forms - and a
|
|
32
33
|
payload that is neither is refused rather than read from byte zero,
|
|
33
34
|
which would shift every record by the header's width and report a full
|
|
34
35
|
set of plausible addresses belonging to no bay.
|
|
@@ -37,9 +38,7 @@ class FrameV2IPSources(FrameBase):
|
|
|
37
38
|
rather than a promise about the set, so it says whether this frame is
|
|
38
39
|
the whole list and nothing more.
|
|
39
40
|
'''
|
|
40
|
-
pl = self.payload
|
|
41
|
-
if (pl is None):
|
|
42
|
-
return None
|
|
41
|
+
pl = self.payload or b''
|
|
43
42
|
rest = (len(pl) % _RECORD_SIZE)
|
|
44
43
|
if (rest == 0):
|
|
45
44
|
return (0, int(len(pl) / _RECORD_SIZE))
|
|
@@ -175,9 +175,10 @@ class Bay(BayBase):
|
|
|
175
175
|
device = self.device
|
|
176
176
|
if (getattr(device, 'local_bay')(self.is_input) is not self):
|
|
177
177
|
return []
|
|
178
|
+
owner = device.remote_id
|
|
178
179
|
return [bay for dev in device.registry.remotes.values() if (dev is not device)
|
|
179
180
|
for bay in dev.bays.values()
|
|
180
|
-
if isinstance(bay, Bay) and (bay.mesh_owner is self)]
|
|
181
|
+
if isinstance(bay, Bay) and (bay._v2ip_uid == owner) and (bay.mesh_owner is self)]
|
|
181
182
|
|
|
182
183
|
def register_callback(self, callback:Callable[[BayBase],None]) -> None:
|
|
183
184
|
'''register a callback, called when the device state changed'''
|