Dev1an / Swift-Atem

Blackmagic Design Atem network protocol implementation in swift 5.1 using NIO 2
MIT License
58 stars 27 forks source link

Getting current Preview / Program Bus index #17

Closed offthegrid-mike closed 3 years ago

offthegrid-mike commented 3 years ago

Hi all, I'm currently developing iOS application to monitor program/preview bus. I've noticed change: ChangePreviewBus and change: ChangeProgramBus can monitor the program/preview bus changes action.

However, may I ask is there anyway to obtain current preview or program bus index so that the UI can response with which bus is currently selecting? To be precise, I am planning to develop a tally iOS application

One more thing, I've noticed there is a while true action in sample PreviewSwitcher. Since iOS can't have such a infinite loop, may I how is there any workaround to retain the controller instance so that it can receive connection.when(change: ChangeXXXBus) action?

Many Thanks

Dev1an commented 3 years ago

Hi Mike, these are some good questions.

Retrieving state

Even though it may be typical for most ATEM client applications to have some kind of switcher state persistency constructs, this library currently does not include them. It is limited to the implementation of the networking protocol. And as far as I know there is no way to send a request to the ATEM to retrieve a specific Bus state. The only thing the ATEM does is to send you all possible state changes whenever they occur. In addition to this, an initial dump of it's entire state is also sent at the beginning of every connection followed by the InitiationComplete message. It is your job to save this state (either in memory or in some kind of database) when it comes in via the network if you want to query it at some later point in time.

Retaining connections

https://github.com/Dev1an/Swift-Atem/blob/b1ab46e3e59353cf18a9093b8fc9ed53917f6e47/Sources/PreviewSwitcher/main.swift#L36-L44 I wrote this while loop because it is plain and simple command line app. When making apps for macOS, iOS or other Apple platforms there is no need to write such while loops, since they already have some kind of RunLoop construct set up for you by default. Having a strong reference to your Atem.Controller (class) instance (in your ViewController for example) is sufficient to keep the connection to your Atem open (see Atem-Simulator for an example).

offthegrid-mike commented 3 years ago

Thanks for the reply! It helps me a lot!

Also, I found that there is a Message.Did::ChangeSourceTallies that may able for me to use as tally. However, I am using AtemSimulator but I can't receive any notification inside Did.ChangeSourceTallies (But received Did.ChangePreviewBus and Did.ChangeProgramBus using AtemSimulator). Is it normal in AtemSimulator can't receive that? Cause I don't have real ATEM device on the hand so I can't test in the real environment.

Dev1an commented 3 years ago

Yeah the simulator is just a toy project to try out the protocol implementation from the other side (the switcher side) and to see if it can trick the black magic clients into thinking it is an actual BMD switcher. It sends a full state dump on initialisation and then responds to bus and slider changes only with ProgramBusChanged, PreviewBusChanged and TransitionPositionChanged. All the rest is not implemented in the simulator.

You can use it to discover and reverse engineer commands sent from the controllers to a switcher. But not the other way around of course. For the other direction you will need a real switcher from BMD.

offthegrid-mike commented 3 years ago

Thanks for the detailed explanation! I may find a way to have a real switcher instead to start my project!

Sorry to bother you more about basic issue. May I ask if there is anyway to check whether the Controller successfully connect to a switcher or not? Since I noticed initializing Controller instance doesn't provide any details of it. Or do I get the info from ConnectionState? And how to use ConnectionState?

Dev1an commented 3 years ago

A Controller is successfully connected when it receives an InitiationComplete message

To handle disconnection and errors use the ControllerConnection's whenDisconnected() and whenError() methods. (You receive a ControllerConnection in the setup handler of the Controller.init)

Dev1an commented 3 years ago

ConnectionState is an internal construct to handle the UDP network messages from the ATEM devices

offthegrid-mike commented 3 years ago

whenDisconnected() and whenError() is in master, not in 1.x version.

Is it stable to use the latest master? (I'm currently using version 1.1.1 to develop)

Dev1an commented 3 years ago

The library is currently in an unfortunate release state... v1.1.1 contains a lot of bug's that are fixed in the master branch. But the master branch is not backwards compatible with v1.x.

So I need to release a v2 but for the moment I have no time to spend time on this project. Hopefully I can work a bit on this in the second half of august.

Your best bet is to work with the current master branch and to make GitHub issues for all problems that you encounter. I will try to fix them and when all current issues are resolved I will bring out a stable V2 release with better docs (probably compiled using DocC instead of jazzy 😉).

offthegrid-mike commented 3 years ago

Hi Mike, these are some good questions.

Retrieving state

Even though it may be typical for most ATEM client applications to have some kind of switcher state persistency constructs, this library currently does not include them. It is limited to the implementation of the networking protocol. And as far as I know there is no way to send a request to the ATEM to retrieve a specific Bus state. The only thing the ATEM does is to send you all possible state changes whenever they occur. In addition to this, an initial dump of it's entire state is also sent at the beginning of every connection followed by the InitiationComplete message. It is your job to save this state (either in memory or in some kind of database) when it comes in via the network if you want to query it at some later point in time.

I've successfully obtain InitiationComplete message, but the class only contain title, dataBytes, and dataBytes. May I ask how to obtain the initial state of it? and does the state contain the controller information like what model of it?