I am writing a VideoPlayer() class that has a start() and stop() function to initiate playback for a given video. Each instance of VideoPlayer() manages a single video
The start() and stop() functions are asynchronous and I get notified via a delegate of success/failure. This delegation is done by a third party SDK.
class VideoPlayer {
func start() {
// Async call
}
func stop() {
// Async call
}
// Callback from third party library with status
func videoDidStart(view: UIView) {
// Notify clients
}
func videoDidStop(stopped: Bool) {
// Notify clients
}
}
I have clients calling the start() and stop() function but sometimes it so happens that they are calling start/stop in quick successions. This leads to unexpected behavior.
For example, if the clients call start() before a previous call to stop() has finished, the video won't play.
Ideally, the clients would wait till I send success/failure notification that I receive via the delegates.
But of course, that's not happening and I am tasked with making the VideoPlayer() class manage the imbalance's between start() and stop() and queue all the calls so everything executes in order.
I would like the VideoPlayer() class to ensure that every time there is an imbalance between start() and stop(), every start() is matched with a stop() and the rogue calls are put in a queue and execute them after the imbalance has been sorted out.
How do I manage such a thing? I believe I need to use Operations with a dependency between start() and stop(). Should I make start()/stop() a single operation and queue the rogue calls until the operation finishes.
Are there other approaches I could use? I have looked dispatch_groups and dispatch_barriers but I am not sure if they fit my use case.
Any help would be greatly appreciated. Thank you
I don't see why an operation is needed. As a crude example of the sort of thing you are describing, I made a small dispatcher architecture:
The
startcalls are queued up, and we don't actually start one until we have received sufficientstopcalls to bring it to the front of the queue.I personally don't like this at all, because we are making three very strong assumptions about contract-keeping:
we assume that everyone who calls
startwill also callstop,and we are assuming that someone who calls
startwill not callstopuntil after being called back from thestartcall,and we are assuming that no one who did not call
startwill ever callstop.Nevertheless, if everyone does keep to the contract, then everyone's
stopwill be called back corresponding to that person'sstart. Here's a rough test bed, using random delays throughout to simulate asynchronicity:Try it, and you'll see that, whatever order and with whatever timing these things run, the start-stop pairs are all maintained by the dispatcher.
As I say, I don't like it. I would prefer to assume that callers might not adhere to the contract and be prepared to do something about it. But there it is, for what it's worth.