- From: Adam Bergkvist <adam.bergkvist@ericsson.com>
- Date: Thu, 20 Jun 2013 10:48:26 +0200
- To: Jan-Ivar Bruaroey <jib@mozilla.com>
- CC: "public-webrtc@w3.org" <public-webrtc@w3.org>
On 2013-06-19 18:19, Jan-Ivar Bruaroey wrote:
> On 6/19/13 2:47 AM, Adam Bergkvist wrote:
>> On 2013-06-18 23:02, Jan-Ivar Bruaroey wrote:
>>> I can think of no cases, thankfully. My understanding is that the queue
>>> is there to make the API deterministic, rather than encourage enqueuing.
>>> E.g.:
>>
>> Thank you for clarifying this. But is this new approach any easier
>> than classical states?
>
> We may disagree on the classifications "new" and "classical" here. We
> have a state machine affected by operations that may fail. The classical
> approach, to me, is to transition state not until operational steps
> succeed, to preserve a sane state transition diagram. [1] - This means
> that, since our operations are asynchronous, state must transition at
> the completion of our async calls, not at the beginning.
>
> Introducing additional state(s) at the beginning (lets call it "the time
> of intention"), as you're suggesting, I would call new.
I fully agree with your description of the classical approach with
states; the transition to the "target state" happens when the operation
succeeds. But "transition states", used when an async operation needs to
complete before the "target state" can be set, isn't a new thing. See
WebSocket's CONNECTING and CLOSING states and EventSource's CONNECTING
state.
>>> // Bad code. state=have_local_offer
>>> pc.setRemoteDescription(answer1, success, mayfail);
>>> pc.setRemoteDescription(answer2, success, mayfail);
>>>
>>> Without a queue, the second call could succeed or fail based on whether
>>> the first call has completed. With a queue in place it becomes
>>> deterministic: If call 1 succeeds, then call 2 always fails
>>> (state=stable). If call 1 fails, then call 2 has the same starting point
>>> (state=have_local_offer), always.
>>>
>>> Why care? Non-deterministic behavior would be bad for
>>> documentation-reasons alone (having to mention useless edge-cases like
>>> this).
>>>
>>
>> With a processing state, the second call would always fail. That's
>> deterministic and observable from JS (compared to a queue in the
>> background).
>>
>>>> Wouldn't it be simpler to have a model where the PeerConnection enters
>>>> a "processing" state when, for example, setLocalDescription() is
>>>> called, and the state is updated in the task that fires the methods
>>>> success or error callback? The "single operation at a time" rule would
>>>> then be enforced by the PeerConnection signaling state.
>>>
>>> Yes, we could have done that. It would let you throw on bad state, but
>>> at the cost of doubling the number of states in the state machine. I'm
>>> not sure it is simpler.
>>>
>>
>> A single processing state would be enough to start with, and it could
>> be expanded if developers asked for more.
>
> You want to do this for every operation, right? Then I think you mean a
> flag, i.e. a doubling of states effectively. Otherwise, please draw me
> the new state transition diagram.
>
> If you change state at the "time of intention", then you have to handle
> backing out to the previous state if/when the operation fails. With only
> a single "processing" state there's not enough info in the state model
> itself to know the previous state, so that's not a state. And
> signalingstatechange returning "processing" isn't very informative.
>
> I believe you effectively have this in your suggestion:
>
> enum RTCSignalingState {
> "processing-stable",
> "stable",
> "processing-have-local-offer",
> "have-local-offer",
> "processing-have-remote-offer",
> "have-remote-offer",
> "processing-have-local-pranswer",
> "have-local-pranswer",
> "processing-have-remote-pranswer",
> "have-remote-pranswer",
> "processing-closed",
> "closed"
> };
>
> That doesn't seem simpler to me.
>
The full state machine would look something like you describe. I would
remove the "have" from the transition states though
("processing-have-local-offer" -> "processing-local-offer"). I don't
think it gets more complicated; it gets more complete. The transition
states sits nicely between our current states in the diagram.
I think this discloses what really happens instead of the PeerConnection
being in "stable" state and having some operations on a queue that
possibly might change the state and the target state is dependent on
which operations that are on the queue and the outcome of these.
/Adam
> [1] Our diagram
> http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcpeerstate-enum
Received on Thursday, 20 June 2013 08:48:54 UTC