Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine how to do session teardown/disconnect/closing #35

Closed
drott opened this issue Dec 18, 2014 · 38 comments
Closed

Refine how to do session teardown/disconnect/closing #35

drott opened this issue Dec 18, 2014 · 38 comments

Comments

@drott
Copy link

drott commented Dec 18, 2014

There are rough edges when it comes to closing the session, resuming it. We need to gain experience from implementations what happens, when the session is disconnected, user-closed, remote-end closed etc.

This section is one aspect of this, but probably the example section needs to shed more light on how expected and unexpected disconnects are handled.

@drott drott added the P1 label Dec 18, 2014
@anssiko anssiko added this to the First Public Working Draft milestone Jan 13, 2015
@drott
Copy link
Author

drott commented Jan 30, 2015

https://lists.w3.org/Archives/Public/public-secondscreen/2015Jan/0012.html (End of the mail "semantics of close"

@mfoltzgoogle
Copy link
Contributor

Copied from #33:

Presumably the user agent will provide the ability for the browser with the initiating page to close the presented document (local or remote). However we may want the user agent to close it on the user's behalf when:

  1. There are no controlling sessions connected for some period of time (e.g., idle timeout)
  2. The presentation is being rendered locally (1-UA) and the media stream has has been terminated permanently.
  3. The presentation is being rendered locally and the user wishes to exit the user-agent.
  4. The presentation wishes to terminate itself.

Some of these scenarios can be implemented by the app developer; if so the behavior of e.g. window.close() should be defined in the presentation context.

@anssiko anssiko removed this from the FPWD milestone Feb 12, 2015
@anssiko anssiko added the F2F label Mar 10, 2015
@schien
Copy link
Contributor

schien commented May 13, 2015

I'd like to put my two cents before the F2F meeting.

Currently PresentationSessionState only support two states: connected and disconnected, which is not enough for both requesting page and presenting page to distinguish between terminating the presentation or presentation display being disconnected accidentally.

This can be solved by introducing additional state terminated. While session.close() (or rename to session.terminate()) being invoked, session.state will enter terminated state. Application can reclaim the resources and terminate itself, e.g. closing the window.

@mfoltzgoogle
Copy link
Contributor

Thanks, that seems reasonable. Other options that I would put forth for consideration:

  1. Adding a disconnectReason property to the statechange event that lets the page know why the PresentationSession was disconnected.
  2. Adding an error event (and handler) to PresentationSession. If the session was terminated accidentally, this would fire. This is similar to RTCDataChannel [1], although the semantics of RTCDataChannel.onerror are not clear from that spec.

[1] http://www.w3.org/TR/webrtc/#rtcdatachannel

@matt-hammond-001
Copy link

Some underlying protocols may not support terminating/closing the 2nd screen content. In DIAL, the ability to "stop" an application is optional [1]. Similarly HbbTV (that builds ontop of DIAL) does not mandate this functionality.

The behaviour is also not always needed. For example: a user browses a catalogue of video on demand on a mobile device and chooses a show. They "cast" it to the TV to watch it there and will continue to watch it, even if they close the webpage on the mobile device or take some other action within that page that moves them onto looking at other content on the primary screen.

I would therefore propose that session.close() or session.terminate() can fail silently if the underlying protocol does not support this action. Alternatively the requirement to support a close/terminate capability could be indicated when checking availability or trying to start a session.

[1] DIAL 1.7.1 spec section 4 or 6.4 at http://www.dial-multiscreen.org/dial-protocol-specification

@tidoust
Copy link
Member

tidoust commented May 19, 2015

PROPOSED RESOLUTION: for #35, add a "terminated" state to the list of connection state and clarify in the spec what happens on the presenting side when "close" is called (in one-to-one scenario, killing the application)

See relevant discussion during first day of Berlin F2F:
http://www.w3.org/2015/05/19-webscreens-minutes.html#item10

@sicking
Copy link

sicking commented Aug 11, 2015

I like the idea of "terminated". Though it doesn't really answer the question of when the page on the TV is closed, does it?

I was first thinking that we could make the statechange event when we transition to "terminated" be cancelable, and make the default behavior be to close the page on the TV. I.e. we'd close the page by default, but the page can override by calling .preventDefault().

However that's somewhat awkward for a couple of reasons.

First of all it's only when the last PresentationSession object is terminated that we would want to close the page.

Second, it's a bit weird to cancel a statechange event since no matter what, the state does change. It's the closing of the page as a result of it that may or may not happen.

So maybe we should fire a "lastsessionterminated" (please come up with a better name) event on the navigator.presentation object when the last session is terminated. The default action of this event would be to kill the page. If the event is cancelled the page stays open.

Either way, I think the page can at any time call window.close() to close the application on the TV.

@schien
Copy link
Contributor

schien commented Aug 11, 2015

The timing of closing window varies from application to application, e.g. multi-player game might wait for more incoming session and remote video play might want to close the window immediately. The question here would be: should we default close the window or not?

If window is not closed by default, adding "terminated" state should be enough because applications can monitor the session state by themselves.

If window is closed by default, we'll have to use the preventDefault() technique mentioned by @sicking in comment 3.

@sicking
Copy link

sicking commented Aug 11, 2015

I think closing the presentation page is a good default when the last device-side page calls .close().

Which is why I'm proposing that calling .close() should transition the PresentationSession to a "terminated" state, and that once the last PresentationSession transitions to "terminated" then we'd fire the "lastsessionterminated" and, by default, close the presentation page.

@schien, I don't quite understand if you are saying that there are things about that solutions that you don't like?

There's also the question of what to do if the user closes the tab with the controlling page, or navigates to a different page. I don't know what a good default behavior is there.

@mfoltzgoogle
Copy link
Contributor

First, let's assume we adopt the both a terminated and closed states per the resolution in #35 (comment). I walked through some scenarios in how the current API could behave.

  • Controlling page calls session.close():
    • session transitions to terminated
    • Presentation is closed
    • Other controlling sessions connected to the presentation also transition to terminated or closed. This depends on whether there was a definitive signal from the presentation that it was intentionally closed, or if it abruptly disconnects sessions at the network level.
  • Presented page is closed (by itself, by user agent, by user)
    • All controlling sessions transition to terminated
  • Controlling session is disconnected from presentation accidentally (e.g. user changes WiFi networks away from TV)
    • Controlling session transitions to closed
    • Corresponding session on the presentation also transitions to closed
    • Presentation continues to run
    • Controlling page may want to offer "reconnect" as an option to the user to resume connection via join().
  • Last controlling session disconnects from presentation
    • Presentation will see that all sessions are in the closed state. It can close itself with window.close() it if wants to, or wait for new connections.
  • Controlling session wishes to leave the presentation (without terminating it).
    • This case is not handled by the API.
    • The controlling page could discard the session, which could cause the corresponding session on the presenting page to transition to closed. This would need to be spelled out.
    • Or we could add a specific session.disconnect() method.

We are overloading the meaning of the state a little bit. It can mean the state of the presentation (terminated or running). It can also mean the state of a single connection between a controlling page and the presentation (closed or not). I don't think these are inconsistent according to the cases above however.

@mfoltzgoogle
Copy link
Contributor

If the scenarios above make sense, it seems like we don't need an explicit event to tell the presentation that all sessions are disconnected. And the controlling session should only call close() when it wants to terminate the presentation (so we don't need to define the meaning of preventDefault for the state change).

@schien
Copy link
Contributor

schien commented Aug 20, 2015

@sicking , the major concern for me is that we need to overload the meaning of preventDefault for onstatechange in order to make closing window as default behavior. I think it make the API more complicate to web developer to understand the lifecycle of session/window with no extra gain.

@sicking
Copy link

sicking commented Aug 21, 2015

  • Controlling session wishes to leave the presentation (without terminating it).
    • This case is not handled by the API.
    • The controlling page could discard the session, which could cause the corresponding session on the presenting page to transition to closed. This would need to be spelled out.
    • Or we could add a specific session.disconnect() method.

I think we need to support this scenario. And I don't think that relying on GC is a good solution for how to support it. Generally speaking, relying on GC to clean up "heavy" resources, like open sockets, is not a good idea since in the world of modern generational GCs it can take a very long time before an object is GCed. This is why we've added .close() on Blob for example.

I would also somewhat argue that in the scenario where multiple parties are connected to the same TV, it feels somewhat strange that the "default action" is that when one of those connections are explicitly (rather than accidentally) ended, that the application on the TV is terminated, even though other people are still connected.

But I think that I might be biased here because my mental model is that a PresentationSession is more of a "connection" rather than a "session". So this is probably coloring my judgement here.

Anyhow, "default" behavior aside, I think there are two ways that we can address the use case of allowing explicitly disconnecting without closing the application running on the TV:

  • Have separate functions on the PresentationSesssion interface for disconnect-and-close-presentation and disconnect-but-don't-close-presentation.
  • Add API on the presentation side which allows the presentation to decide if it should be closed when a connection is explicitly disconnected.

Technically we could even do both solutions above, though that seems somewhat unnecessary.

I can live with either (or both) of these solutions since I think they effectively have the same capability-set.

However I'm somewhat in favor of the latter. Basically I think the presentation has access to more of the state needed to make a decision about if the presentation should be closed or not. For example it has awareness of other connections, or if the application might be in a state where the user might experience data-loss if the application is closed right now.

I.e. it looks nicer to me to let the application on the TV make the ultimate decision about if it should be closed or not when a connection is explicitly terminated.

This is why I propose that we add an event like "lastsessionterminated". This event would be fired when all active sessions has transitioned into the "terminated" state. The default action of this event would be to close the application on the TV. This has several nice properties.

  • The default behavior of calling .close() when there is only one controller attached to the TV is unchanged. Calling .close() in that scenario will close the application.
  • The default behavior when multiple parties are connected is that the application is closed when the last controller calls .close()
  • The application on the TV gets to make the ultimate decision about when the application is closed. (Unless the user overrides by closing the application through other means of course.)
  • The PresentationSession API continues to match WebSocket and RTCDataChannel, i.e. we still have just .send()/onmessage/.close() and with those functions behaving the same across all three interfaces.

But I could also live with any of:

  • Adding a PresentationSession.disconnect()
  • Having PresentationSession.close() just close the connection and PresentationSession.end() also closing the application on the TV.
  • Adding a "sessionterminated" event which is fired any time a session is explicitly ended and whose default behavior is to close the application on the TV.
  • Probably others :)

@avayvod
Copy link
Contributor

avayvod commented Aug 24, 2015

I think adding a .disconnect() is the best forward compatible way. WDYT?
"sessionterminated" could be implemented via window.onbeforeunload for the presentation page?

@mfoltzgoogle
Copy link
Contributor

I actually think we can come to a good solution here by adjusting the semantics I proposed earlier, and without any API facing changes. Let's assume we redefine close() to mean disconnect() as discussed above.

Below "controlling session" means a PresentationSession in the controlling page and "presentation session" means one in the presented page.

  1. Controlling page calls session.close():
    • Controlling session transitions to terminated
    • Corresponding presentation session also transitions to terminated
  2. Presentation is closed (by itself, by user agent, by user)
    • All controlling sessions transition to terminated
  3. Controlling session is disconnected from presentation without any call to close() (e.g. user changes WiFi networks away from TV, navigates away, etc.)
    • Controlling session (if it exists) transitions to closed
    • Corresponding presentation session on the presentation also transitions to closed
    • Presentation continues to run
    • Controlling page may want to offer "reconnect" as an option to the user to resume connection via join().
  4. Presentation wishes to "kick out" a controller (idle timeout, etc.)
    • Calls session.close() which causes the corresponding controlling session to transition to terminated.
  5. Last connected session to the presentation transitions to closed or terminated .
    • Presentation will see that all sessions are in the non-connected state. It can close itself with window.close() it if wants to, or wait for new connections.

To simplify case 5, we can add a boolean connected property to the change event fired at a session's onstatechange. The property would be true if there are any sessions held by that browsing context that remain connected to the presentation, false otherwise.

Here is a bit of sample code for the presenting page under this proposal:

// Assume that the page already is adding the following handler to
// incoming connected sessions.
session.onstatechange = function(e) {
  if (e.state == 'closed' || e.state == 'terminated') {
    // Show a message that a player/controller left the presentation.
  }
  if (!e.connected) {
    // The last controller disconnected.  Close ourselves.  We could also
    // set a timer to await new connections.
   window.close();
 }

This proposal does not give a single controlling session the ability to terminate the entire presentation. This may actually be desirable; a single player should not be able to kill the whole game, and as @sicking argues above the presentation may be in a better position to know when to quit.

I still prefer using window.close() as an explicit mechanism for terminating the presentation page, rather than relying on a new event's default behavior. If there is a good reason to create the default-close behavior, is there a way to do it without adding a new event?

@avayvod
Copy link
Contributor

avayvod commented Sep 1, 2015

I'd think user would prefer being in control - imagine a presentation that
misbehaves intentionally or not and doesn't shut itself down. There must be
a way to explicitly stop the presentation that doesn't involve rebooting
the second screen.
On 1 Sep 2015 4:23 a.m., "Mark Foltz" notifications@github.com wrote:

I actually think we can come to a good solution here by adjusting the
semantics I proposed earlier, and without any API facing changes. Let's
assume we redefine close() to mean disconnect() as discussed above.

Below "controlling session" means a PresentationSession in the controlling
page and "presentation session" means one in the presented page.

  1. Controlling page calls session.close():
    • Controlling session transitions to terminated
    • Corresponding presentation session also transitions to terminated
  2. Presentation is closed (by itself, by user agent, by user)
    • All controlling sessions transition to terminated
  3. Controlling session is disconnected from presentation without any
    call to close() (e.g. user changes WiFi networks away from TV,
    navigates away, etc.)
    • Controlling session (if it exists) transitions to closed
    • Corresponding presentation session on the presentation also
      transitions to closed
    • Presentation continues to run
    • Controlling page may want to offer "reconnect" as an option to
      the user to resume connection via join().
  4. Presentation wishes to "kick out" a controller (idle timeout, etc.)
    • Calls session.close() which causes the corresponding controlling
      session to transition to terminated.
  5. Last connected session to the presentation transitions to closed or
    terminated .
    • Presentation will see that all sessions are in the non-connected
      state. It can close itself with window.close() it if wants to, or
      wait for new connections.

To simplify case 5, we can add a boolean connected property to the change
event fired at a session's onstatechange. The property would be true if
there are any sessions held by that browsing context that remain connected
to the presentation, false otherwise.

Here is a bit of sample code for the presenting page under this proposal:

// Assume that the page already is adding the following handler to
// incoming connected sessions.
session.onstatechange = function(e) {
if (e.state == 'closed' || e.state == 'terminated') {
// Show a message that a player/controller left the presentation.
}
if (!e.connected) {
// The last controller disconnected. Close ourselves. We could also
// set a timer to await new connections.
window.close();
}

This proposal does not give a single controlling session the ability to
terminate the entire presentation. This may actually be desirable; a single
player should not be able to kill the whole game, and as @sicking
https://github.com/sicking argues above the presentation may be in a
better position to know when to quit.

I still prefer using window.close() as an explicit mechanism for
terminating the presentation page, rather than relying on a new event's
default behavior. If there is a good reason to create the default-close
behavior, is there a way to do it without adding a new event?


Reply to this email directly or view it on GitHub
#35 (comment)
.

@mounirlamouri
Copy link
Member

Maybe we can add terminate() and only introduce a slight change to Mark's proposal? Instead of close() transitioning state to terminated, it would transition to closed and terminate() would transition to terminated if the client was the last client connected to the session?

@sicking
Copy link

sicking commented Sep 1, 2015

I don't think that we should worry about intentionally misbehaving pages.

The most common case is likely going to be a website opening itself on the TV. In that scenario neither side is really more "user controlled".

I think this also holds true even if website A opens website B on the TV. It's not obvious to me why we should consider website A as more trusted?

So I don't think any of the options here give the user more or less control. But I also don't think that's a problem. The TV/dongle will most likely have a remote control which enables turning off whatever application is running on the TV.

In theory the browser could also contain some browser-provided UI for turning off the TV application. But I suspect that an ill-willing application running on the TV is a rare enough problem that browser won't want to sacrifice screen realestate to address that?

So I think that what we should optimize for here is developer ergonomics and reducing the risk of bugs.

I'm fine with @mfoltzgoogle proposal. I.e. to make the default behavior to leave the presentation running and then leave it up to the presentation code to close the application as appropriate.

I don't think we'd need a .connected property though. It doesn't seem like it'll simplify webpage logic in any significant way, and it's about as much complexity to implement as a lastsessionterminated event. Compare the code above to:

// Assume that the page already is adding the following handler to
// incoming connected sessions.
session.onstatechange = function(e) {
  if (e.state == 'closed' || e.state == 'terminated') {
    // Show a message that a player/controller left the presentation.
  }
  if (e.state == 'terminated') {
    // opensessions would be a page-maintained Set
    opensessions.delete(session);
    if (opensessions.size == 0) {
      // The last controller disconnected.  Close ourselves.  We could also
     // set a timer to await new connections.
     window.close();
   }
 }

It's just two lines of code more, plus keeping a Set of open connections. But that's likely something that you'd want to do anyway in order to do operations on connected controllers.

Ultimately I think the main question here is what default behavior we want to have. I really don't think that either @mfoltzgoogle proposal or mine is hard to implement.

I don't have strong opinions on having a .terminate() function or not. As mentioned above, I don't think it provides more user control, but it is likely also easy to implement. It does add more requirements on the protocol though, so it might require a more complex protocol once we get around to defining that.

@mounirlamouri
Copy link
Member

I don't really mind either way but I share Anton's concerns. So, just to be a bit more concrete here. What should happen if Chrome starts Netflix on ChromeCast then the Chrome application on the user's phone gets killed by Android? Should Netflix stops because there are no more clients and continue running? I wonder how we could handle this without close() and terminate().

@sicking
Copy link

sicking commented Sep 2, 2015

If I understand correctly, in all of the current proposals, if the Chrome application is killed, the PresentationSession would transition to a closed state and the application running on the TV would be notified about this, but nothing else would automatically happen.

Obviously the application could write whatever application logic to handle this, such as immediately pausing any running video, or immediately closing the application. Or doing either of those things after a timeout.

I don't see how adding separate .close() and .terminate() functions would change this?

@mounirlamouri
Copy link
Member

I guess I should have added more details.

I agree with your description of the expected behaviour and that's probably what a user would expect. However, if a user does the exact same thing (starts Netflix on their ChromeCast from thei Chrome Android) and then wants to stop casting Netflix as in it shouldn't be showing on the ChromeCast anymore. If Netflix were to provide a "Close" button that would call close(), my understanding is that it would behave exactly like the other scenario, right? Exception obviously is that no movie would be running and the app might have a timeout to kill itself at that point.

@anssiko anssiko removed the F2F label Sep 2, 2015
@mfoltzgoogle
Copy link
Contributor

@avayvod The expectation is that the controlling user agent will provide a way to terminate the presentation (not just a specific connection) without requiring a loaded page to have a connected session. It seems like this is a necessary part of any usable implementation since there's no guarantee that the user will be able to navigate to a page and then get that page to reconnect to the presentation, just to be able to call .terminate(). Meanwhile, the user agent itself (if it can connect to the display) should be able to offer the remote-kill capability (and all protocols I am aware of support it). However, it seems like it may be difficult to require this user-agent level feature via the spec.

@sicking Yes that's what I'm proposing here. Another thought is that as long as there is a controlling session connected to the page, the controller can send a command to the presentation asking it to close itself. Adding .terminate() just provides an alternative implementation of this function at the presentation network protocol level, versus the application protocol level.

@sicking
Copy link

sicking commented Sep 2, 2015

@mounirlamouri if the netflix website calls .close(), then the PresentationSession would transition to a terminated state. If we have the lastsessionterminated event, then that would automatically close the application on the TV. If we don't have the lastsessionterminated event, then the presumption is that the application would have code similar to what @mfoltzgoogle provided which would cause the application to close.

Either way, the result would be that if the netflix website calls .close(), that the netflix application on the TV would be closed.

I think @mfoltzgoogle and I are largely in agreement. That we'd have just a .close() function on PresentationSession which would cause the connection to transition to the terminated state. And we'd have no .terminate() function.

The only point of difference in our proposals is whether we have a lastsessionterminated event which by default would close the page. I think whether we do that or not is a function of what default behavior we want to have, and how much work it would be to implement such an event.

I can definitely live with or without the lastsessionterminated event. But I kind'a like the default behavior of closing the application when the last controller goes away, and I don't think implementing the event would be very hard (though I could be wrong about that). So the event gets my vote.

But I can really live with either solution.

@mfoltzgoogle
Copy link
Contributor

I'm relaying some internal discussion for the benefit of the group (paraphrased). The following arguments were put forth in favor of adding an explicit API that would allow any controller to request ending the presentation (versus .close(), which disconnects an individual controller).

  1. It would simplify the life of Web developers who expect a way to terminate a presentation directly through the API, instead of implementing some application level mechanism. In particular the Cast SDK exposes this functionality [1].
  2. It provides the user an additional control over the state of the display and makes it more likely that the state of the controller and the presentation are in sync. I.e. if the presentation should always go away when the controller does, the controller can put session.close() in window.onbeforeunload or the equivalent.
  3. The user may have two different intents, and the API should have a way to express each of them.
    • Disconnect my controller from the presentation, but leave it running (if it wants to)
    • Terminate the presentation
  4. Every display protocol (whether 1-UA or 2-UA) almost certainly have a way to terminate the presentation. Instead of having two ways to terminate, one from the controller's browser, and another via application messaging or connection status, it seems cleaner to share the implementation via the API.

Overall I'm fairly persuaded by these arguments.

@sicking I'll reply about lastsessionterminated when I have a bit more time, and draft an API change that summarizes my current position.

@sicking
Copy link

sicking commented Sep 4, 2015

I take it that in point 2 above, you mean session.terminate() rather than session.close()?

I don't really buy arguments 2 and 3. You can accomplish the same thing in application logic by simply doing session.send("kthxbai"); session.close().

But I can live with having both a .terminate() and a .close(). At worst it will be some amount of code that doesn't get used a lot.

I do think that we should clearly document that .terminate() is not the only way to shut down applications though, and that window.close() works as well.

@mfoltzgoogle
Copy link
Contributor

@sicking Yes, in point 2, I intended session.terminate() - good catch.

Integrating the above, here is the API I would propose for session lifecycle.

enum PresentationSessionState {
    "connected",
    "disconnected",
    "closed",
    "terminated" 
};

partial interface PresentationSession {
    readonly attribute PresentationSessionState state;

    // Both sides transition to "closed."  Presenting context remains running.
    void close(); 

    // All connected sessions transition to "terminated."  Presenting context is closed.
    void terminate();

    // Fired on change to .state
    attribute EventHandler onstatechange;
}; 

partial interface PresentationReceiver : EventTarget {
    // Fired when all sessions have transitioned to a terminal state.  Default behavior
    // is to close the presenting context.
    attribute EventHandler onsessionsclosed;
};

The following diagram summarizes the state transitions for PresentationSession.state. Both closed and terminated are terminal states.

presentation session state diagram 2

I've retained disconnected to signal a break in the connection that was not initiated by either side (i.e. network disconnection); whether or not that is terminal may depend on #149. If we decide that it's a terminal state as well, we can just use closed for it.

Finally, the proposal above includes an event, onsessionsclosed to notify the presenting context that all sessions have transitioned to a terminal state, defaulting to close the presentation. It's likely the common scenario is to have one site running in one user agent controlling the presentation, and the presentation exits when the user browses away from the site. In this proposal, the author of the presentation does nothing to cause it to exit when the user browses away.

However, there are at least two cases we need to make sure are handled properly to not close the presentation:

  1. The controller browses to another page in the same site that automatically reconnects to the presentation
  2. The user has a network glitch that breaks the connection between UAs temporarily.

If nothing above sounds objectionable, I can author a PR based on this proposal.

@avayvod
Copy link
Contributor

avayvod commented Sep 9, 2015

I think we should avoid adding more states and events than we have to. We can always add them later if the developers complain.

We discussed the disconnection case before, for example, and always agreed that the UA would try to reconnect and if it fails, there's nothing for the web page to try anymore. So distinguishing between accidental and intended disconnection doesn't seem valuable to me so far.

The onsessionsclosed is only useful if we have the default behavior of shutting down the presentation when all the sessions are in terminated state. This might make life easier for the web developers who want this behavior, however I suspect many of them would actually prefer the presentation not to be closed immediately:

  • the presentation might be doing something on its own (e.g. playing some media on the TV) and will want to stay on and expect the user to reconnect if needed
  • the sender might want to reconnect to the presentation during navigations and shutting down the presentation on disconnect would be bad in this case too

I believe both cases above would be more popular than shutting down the presentation if anything goes wrong. That's why the default behavior on the receiving side should be not to shut down the presentation and give it an option of shutting down itself using window.close().

The ability for the user to stop the presentation vs. just detaching the sender from the receiver is important though so a method on PresentationSession is needed to stop the presentation.

I still think we should go forward with three states for the PresentationSession: 'connected', 'disconnected' and 'terminated' - and two methods: disconnect() and terminate().

@mfoltzgoogle
Copy link
Contributor

@avayvod All good points. I am in favor of landing a smaller change now, and using feedback to add the additional features discussed in this thread.

In particular, it seems like the question of the default behavior for the presentation when all sessions are disconnected will be difficult to answer without additional real world experience. I can say that for Google Cast applications, the default behavior is to leave the presentation running; it's suggested that the presentation close itself when the last sender disconnects [1], but many implement some timeout before doing that.

Here is a simplified version of the proposal in #35 (comment):

enum PresentationSessionState {
    "connected",
    "closed",
    "terminated" 
};

partial interface PresentationSession {
    readonly attribute PresentationSessionState state;

    // Both sides transition to "closed."  Presenting context remains
    // running.
    void close(); 

    // All connected sessions transition to "terminated."  Presenting
    // context is closed.
    void terminate();

    // Fired on change to .state
    attribute EventHandler onstatechange;
};

presentation session state diagram v2 1

[1] https://developers.google.com/cast/docs/custom_receiver#session-management

I plan to prepare a PR to implement this,

@schien
Copy link
Contributor

schien commented Sep 11, 2015

For user agents that implement 2-UA mode will require a signaling protocol to inform remote endpoint about which state (disconnected/terminated) should be entered, if we take the latest proposal. We might need to address it in the spec as well.

@mfoltzgoogle
Copy link
Contributor

Unless there are further comments, I plan to merge #190 later today.

I'll file a separate feature request to consider defining a behavior when all sessions are disconnected from the presentation (paraphrasing the discussion here).

@mfoltzgoogle
Copy link
Contributor

Regarding @schien's comment #35 (comment) for behavior of terminate() in 2-UA mode:

If the controlling context calls terminate(), the assumption is that the controlling UA has some way of terminating the receiving browsing context, and thus knows that the presentation sessions in the controlling context should transition to terminated.

If the receiving browsing context terminates itself, there may be signaling required to tell the controlling presentation sessions that this was an explicit termination of the presentation (and not, e.g., by a network disconnection or by powering off the display). This is addressed in L771-792 of the PR as an optional (MAY) requirement for the presenting UA.

I think the PR should be updated to handle the case where the receiving context calls window.close() instead of terminate(). The two functions would seem to function identically for the receiving context.

@tidoust
Copy link
Member

tidoust commented Sep 16, 2015

I note some feedback from the TAG on the lifetime of a presentation:

[[
3.The concept of connecting to a shared session object had parallels to the SharedWorker object. The SharedWorker is established by the first party making a connection to it, then it becomes available to any requesting parties, provided they are within the same-origin. It's lifetime terminates when the last document connected to it terminates. In the Presentation API, the spawned presentation browsing context has a lifetime that is potentially longer-lived than the SharedWorker meaning that if no existing connection calls the session's stop() API it could potentially live indefinately. This could become a problem as it leaves the lifetime of a presentation explicitly up to well-behaved JavaScript management. In the web platform, we'd generally like to avoid these type of mananagement problems, espeically when the "second screen" may not have a user-interaction input modality.
]]
https://github.com/w3ctag/spec-reviews/blob/master/2015/presentation-api.md

@sicking
Copy link

sicking commented Sep 25, 2015

(Sorry for absence here, got swamped with other things).

I'm generally fine with the change here.

What surprises me a little is that there now is no ability to detect when a connection is disconnected? It seems useful for for example a game to automatically pause if connection is lost?

Was removing this ability intentional?

@anssiko
Copy link
Member

anssiko commented Sep 29, 2015

@sicking Thanks for getting back to us. @mfoltzgoogle suggested we should gather additional real world experience from implementations before introducing new PresentationSessionStates, such as disconnected.

@mfoltzgoogle I suggest we track the disconnected state feature as a separate issue to keep us focused. Please feel free to open a new issue for it.

@mfoltzgoogle
Copy link
Contributor

@sicking At the TPAC F2F we adopted a proposed resolution for #149 that will fire an error event on the connection in case message sending failed. With this implemented, the two sides could implement a ping-pong protocol to detect accidental disconnection, if that is important for the application.

@sicking
Copy link

sicking commented Nov 6, 2015

(I think we might start to drift offtopic for this issue, let me know if you want me to raise this as a separate issue).

If an implementation has the ability to detect that a message failed to be sent correctly, why wouldn't it transition the connection to a disconnected state?

@mfoltzgoogle
Copy link
Contributor

On failure to send, it will transition the connection to a closed state. The error event could be used to distinguish an application/user request to close, versus an accidental disconnection.

I'm not inherently opposed to adding more states, but would like to see a demonstrated developer need that can't be addressed through the existing API. I can file this as a separate issue to clean up the discussion thread.

@mfoltzgoogle
Copy link
Contributor

Opened #217, let's continue discussion there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants