gapu / google-cast-sdk

Automatically exported from code.google.com/p/google-cast-sdk
0 stars 0 forks source link

problem with video element ended event #431

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. user of android app I am developing selects video to be cast
2. android sender sends load media command to chromecast
3. custom receiver onLoad() override method clears screen, initializes video 
element, calls media manager setMediaElement() method
4. video element starts to buffer video, triggers canPlay event
5. receiver calls video element play() method and video plays
6. video play completes, video element triggers ended event
7. custom receiver onEnded() override method, sends ended indication to sender 
on custom channel (it does NOT call resetMediaElement() method!)
8. sender enables play button on UI, user touches it, sender sends play command 
to receiver
9. receiver library rejects command, saying player state is IDLE

What is the expected output? What do you see instead?

the play command after the ended event should cause the video element's play() 
method to be called and the video should play again

instead, the play command is rejected, and the sender's error handling code 
resets the receiver

What version of the product are you using? On what operating system?

latest sender SDK and receiver library; sender is Android app

Please provide any additional information below.

receiver and sender log files are attached

It seems to me there are two issues here:
- the media manager player has transitioned to the IDLE state when it should 
have stayed in the PLAYING state
- the receiver library did not inform the sender of the transition to the IDLE 
state (the last status update from the receiver indicated that the player was 
in the PLAYING state)

Original issue reported on code.google.com by jim.ren...@gmail.com on 13 Nov 2014 at 11:36

Attachments:

GoogleCodeExporter commented 9 years ago
If you're trying to replay videos, I suggest you check out 
https://github.com/googlecast/CastVideosPlaylist-chrome/blob/master/player_playl
ist_receiver.html

Similar logic can be used to play the same video over and over.

Original comment by jonathan...@google.com on 15 Nov 2014 at 12:38

GoogleCodeExporter commented 9 years ago
jonathan: thank you for the suggestion.

In looking at that code, it appears that the play list is maintained in the 
receiver and the sender has only very limited control over it.

In my application, the play list is maintained in the sender and the sender and 
its user have complete control over it.

In particular, one of the required functionalities is that when a play list 
item completes playing, the user may either stop that item from playing further 
and move on to the next playlist item, or replay the item either from the 
beginning by simply hitting a play button or from a specific point by 
repositioning a progress bar before touching the play button.

All of the required replay functionality is already implemented and working for 
the initial play of the play list item (play, pause, reposition, stop, etc.), 
it's just that when the playback ends the receiver needs to remain in the 
PLAYING state so that it can continue to respond to player commands from the 
sender. If that were the case, the implementation of replay would be a 
no-brainer.

I can see how using the some the techniques from the example to which you 
pointed me, or other techniques that I have though of, I can achieve the 
desired effects, but it would take additional development work in both the 
sender and the custom receiver.

I am hoping to avoid that by taking advantage of what seems to me to be the 
intended way of doing this: when the video (or audio) ends playing, a call to 
the video element's play() method restarts it from the beginning; if the video 
element playback position has been changed before play() is called, playback 
would start from that point.

Original comment by jim.ren...@gmail.com on 17 Nov 2014 at 6:00

GoogleCodeExporter commented 9 years ago
Perhaps you could check if the video finished by seeing if the status is 
cast.receiver.media.IdleReason.FINISHED, make sure the media is not null (i.e. 
the source is still present and can replay the video), and programmatically set 
the status to PLAYING as a workaround.
We highly recommend that the playlist is maintained in the receiver or on a 
server in the cloud. Cast supports multiple devices and also needs to handle 
various network and device stability issues.  Having the playlist in the 
receiver is the only way to maintain a good user experience.

Original comment by jonathan...@google.com on 17 Nov 2014 at 11:02

GoogleCodeExporter commented 9 years ago
Jonathan:

I added code to log the src property of the video element in the onEnded() 
override method, and it is the valid URL that I expected.

In looking at the doc for the receiver MediaManager, I don't see any properties 
or methods that allow you to get the idle reason. The only way I see to know 
this is to override the customizedStatusCallback() method, and extract it, log 
it, and save it there. I had already overridden that method (to get the player 
status; it too does not seem to be available via property or method) so I added 
logging for the idle reason there.

The problem is that the receiver is not reporting a status transition to the 
sender when it transitions to the IDLE state in this situation, so the override 
does not get called. So I can't provide any information to help you there.

Is there some other way that the player's status and idle reason can be 
obtained. If not, maybe there should be getters for these?

You suggest programmatically setting the status to PLAYING as a workaround, but 
again I don't see a property that can be set or a method that can be called to 
do this. Am I missing something?

The only thing I could think to try to achieve this is to dispatch a playing 
event to the media manager in the onEnded() override method. I did this and it 
had no effect.

BTW, it occurred to me that we don't want the player to be in the PLAYING state 
after the ended event, we want it to be in the PAUSED state, because, well, the 
video element's paused property is true. I tried dispatching a pause event to 
the media manager in the onEnded() override method in stead of a playing event, 
but it too had no effect.

It would really help here if the receiver library had an even more verbose 
level of logging than that given by setting the logging level to DEBUG. In 
particular, I would like to see a log of all events that the receiver receives 
from media elements.

I will modify my custom receiver to add event listeners for all events that 
media elements can dispatch, and log them as they occur. Hopefully, this will 
give us some insight as to what's going on here.

Thank you for your attention to this.

Original comment by jim.ren...@gmail.com on 19 Nov 2014 at 5:44

GoogleCodeExporter commented 9 years ago
See 
http://developer.android.com/reference/com/google/android/gms/cast/package-summa
ry.html, in particular the MediaStatus and RemoteMediaPlayer classes.  Just as 
a note, I believe resetMediaElement() should do what you're trying to 
accomplish if you override it to provide the desired IDLE reason and use either 
RemoteMediaPlayer.load() or RemoteMediaPlayer.play() if the user decides to 
replay the video.

I recommend you refer to https://github.com/googlecast/Cast-Player-Sample and 
the other sample apps in the Google Cast project folder to address any future 
development questions.

Original comment by jonathan...@google.com on 19 Nov 2014 at 7:43

GoogleCodeExporter commented 9 years ago
Very disappointed that this has been marked done without the bug of the 
receiver not reporting the state change to the sender being addressed. Or has 
this been addressed?

I can understand that the handling of the video ended event is not a priority, 
but it seems to me that the receiver and sender being out of sync w.r.t. their 
state is pretty serious.

Original comment by jim.ren...@gmail.com on 24 Nov 2014 at 5:21

GoogleCodeExporter commented 9 years ago
I tested this with the CastVideos-android sample app and checking the debugging 
logs showed that the receiver sent an IPC message to the sender indicating that 
the playerstate changed to IDLE.  You might not be seeing this message because 
you overrode OnEnded().

Original comment by jonathan...@google.com on 25 Nov 2014 at 6:54

GoogleCodeExporter commented 9 years ago
Yes, before I overrode the onEnded() method that was the behavior I saw.

Also, with my app the user has the option to pause after the video plays or 
not. If that option is not chosen, my onEnded() method calls 
resetMediaElement() like the default method, and in that case, everything is 
OK: receiver library transitions to IDLE and reports it to the sender.

The problem that I am seeing is that if my onEnded() method does NOT call 
resetMediaElement(), the receiver library is still transitioning to the IDLE 
state, but is not informing the sender.

Like I said, i believe the receiver library transitioning to the IDLE state in 
this circumstance is a bug, but the bigger bug is that it is transitioning to 
IDLE without informing the sender.

If it does it in this circumstance, I am suspicious that it also may do that in 
other, as yet undiscovered circumstances.

BTW, I have a work-around for this, but it is big and kludgy: about 50 lines of 
code in the receiver and about 100 lines of code in the sender.

It works acceptably except in the case of the user repositioning the video with 
the progress bar before starting (re)play. Because I have to recreate the video 
element via a loadMedia() call in the sender, I can't set the position of the 
video until the video element dispatches a "loaded" event. But by then, the 
video element has displayed the first frame of the video, and then displays the 
correct frame after it is positioned, whereas when the original video element 
is repositioned after the ended event it should go directly to the correct 
frame without displaying the first frame. At least that was the behavior I saw 
when I tested this in a browser before implementing it in my app.

Going to the first frame and then the correct frame also introduces a delay: in 
effect the video element has done a double seek, instead of a single one. 
Depending on the size of the video and the responsive of the server that it 
serving it up, this may or may not be objectionable.

If and when either or both of these bugs is fixed, please let me know so that I 
can remove all or some of the kludgy work-around from my app.

Thank you for your help with this, and I hope you have happy holidays.

Original comment by jim.ren...@gmail.com on 25 Nov 2014 at 9:39