Handheld.PlayFullScreenMovie doesn't always pause unity right away

I have been fighting with a hard to find bug for awhile now. I have an intro cutscene that plays on app startup the first time. You can tap to skip past it.

This has worked great for a long time, but I have always had a couple reports where people were claiming that the game would freeze on startup.

This was only for Android 4.x devices and when I told them to try and tap past it that worked fine but the video never played, it would just load up and stop with a blank screen. These users (being early adoptors of 4.x) were generally using some crazy combination of roms and launchers and other customizations so I just thought it was probably that.

Up until recently my 4.x usage was in the single digits, but we have gone up to about 40% 4.x devices now and I am getting lots more of these reports. I finally got ahold of a nexus 7 so that I could properly test it (I only have a couple devices in house).

It turns out that the problem is that Handheld.PlayFullScreenMovie works exactly like you expect on the older devices (my galaxy tab with 2.x works just fine) once you call Handheld.PlayFullScreenMovie unity pauses immediately and the movie loads and when it is done unity resumes.

However, on newer devices this is not the case. Unity does NOT pause right away, but instead happily runs in the background while the movie is loaded into memory, and only once it starts playing does Unity pause. This can take up to 1.5 seconds (tho it is usually about 0.6ish on my nook and nexus 7.)

So before I had code that ran like this:

        Debug.Log("Movie Starts");
        if (horizontalIntro) Screen.orientation = ScreenOrientation.LandscapeLeft;
 	Handheld.PlayFullScreenMovie (moviePath, Color.black, FullScreenMovieControlMode.CancelOnInput);	
        if (horizontalIntro) Screen.orientation = ScreenOrientation.Portrait;
        Debug.Log("Movie Ends");
 	// now load the main menu
	Instantiate(sceneLoader);

and that worked great. The log would show ’ Movie starts’ an then the movie would play and when it was done the log would show ‘Movie ends’ and everything was dandy.

On newer devices, the log shows ‘Movie starts’, and then ‘movie ends’ and then it happily instantiates my scene loader which does it’s thing and then at some point after that Unity will actually pause, and for some reason the movie would sometimes just hang. It would usually work whenever I did a build and run from unity, but then not work when I ran it from the device by tapping the app. (but sometimes it would work. It sucked)

So I tried this:

        Debug.Log("Movie Starts");
        if (horizontalIntro) Screen.orientation = ScreenOrientation.LandscapeLeft;
 	Handheld.PlayFullScreenMovie (moviePath, Color.black, FullScreenMovieControlMode.CancelOnInput);	
        if (horizontalIntro) Screen.orientation = ScreenOrientation.Portrait;
        Debug.Log("Movie Ends");

        // kill some time
        for (int i = 0; i < 100; i++) {
          Debug.Log ("--> What time do we think it is? " + Time.timeSinceLevelLoad);
          Debug.Log ("--> What time is it really? "+ Time.realtimeSinceStartup);
          yield return new WaitForSeconds(0.1f);
        }
 	// now load the main menu
	Instantiate(sceneLoader);

This will generate some log output like this:

I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time do we think it is? 1
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time is it really? 1.154128
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time do we think it is? 1.188923
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time is it really? 1.180601
I/Unity   ( 2820):  
...
...
... this goes on for a bit
...
...
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time do we think it is? 1.745316
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time is it really? 1.737076
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
W/ActivityManager(  357): Activity pause timeout for ActivityRecord{426adb48 au.com.tinmangames.gamebook1android/com.unity3d.player.UnityPlayerNativeActivity}
I/Unity   ( 2820): --> What time do we think it is? 1.860899
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time is it really? 1.852489
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820):

and then it will finally pause the engine, the video will play. When it is done you will come back with something like this:

I/Unity   ( 2820): --> What time do we think it is? 1.961225
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)
I/Unity   ( 2820): 
I/Unity   ( 2820): --> What time is it really? 31.31148
I/Unity   ( 2820):  
I/Unity   ( 2820): (Filename: ./Runtime/ExportGenerated/AndroidManaged/UnityEngineDebug.cpp Line: 43)

So, it takes the unity engine about 0.7 seconds from when you tell it to start the movie to when it actually starts the movie. This happens on my Nexus 7 with android 4.1.1 as well as my Nook Tablet with whatever the hell OS is on that thing.

So now I have implemented this terrible hack (that seems to give consistent playback on all devices now)

    Debug.Log("---> In Android Loop");

    float currentTime = Time.timeSinceLevelLoad;
    float timeDifference = Time.realtimeSinceStartup - currentTime;

    if (horizontalIntro) Screen.orientation = ScreenOrientation.LandscapeLeft;
    Debug.Log ("--> start movie " + Time.realtimeSinceStartup);
    Handheld.PlayFullScreenMovie (moviePath, Color.black, FullScreenMovieControlMode.CancelOnInput);
    currentTime = Time.timeSinceLevelLoad + timeDifference; // in theory this should be a few seconds off of the real time by now
    Debug.Log ("--> movie ended? " + currentTime + " " + Time.realtimeSinceStartup);
    if (Mathf.Abs (currentTime - Time.realtimeSinceStartup) < 0.3f) {
      // then we didnt actually pause anything.
      // start counting down until Unity is paused
      for (int i = 0; i < 100; i++) {
        currentTime = Time.timeSinceLevelLoad + timeDifference; // if we are not paused then this should be close to the real time
        if (Mathf.Abs(currentTime - Time.realtimeSinceStartup) < 0.3f) {
          yield return new WaitForSeconds(0.1f);
        } else {
          Debug.Log ("--> We did pause!");
          break;
        }
      }
    }
    Debug.Log ("--> Movie Actually Ended.");
    finalizeVideoPlay();

What the hell am I doing here?

I am using the timeSinceLevelLoad and comparing that with the realtimeSinceStartup (with an adjustment to get them to be closer together)

As we can see from the test above, when the Unity engine actually pauses, then the timeSinceLevelLoad will also pause, but the realtimeSinceStartup will not. So in theory, if the video actually pauses the engine, then the two time stamps should be very different. If they are not very different then that means that Unity never got paused and we need to twiddle our thumbs until it actually does get paused at which point we continue on our merry way.

note: this runs from a coroutine, but the not-pausing problem happens no matter where you call the Handheld.PlayFullScreenMovie from.

From this pain I hope one (or more) of three things happens:

  1. that this saves someone else a huge headache of figuring out what the hell is up with your video.

  2. that Unity fixes it and perhaps forces an engine pause as soon as Handheld.PlayFullScreenMovie is called instead of waiting for the OS to tell it to pause.

or 3) that I am completely insane, and this is somehow tied into the screen orientation, or there is a far better way to deal with this or some other thing, and I don’t have to put this horrible horrible code into my project.

Cheers!
-Ben

I would say that you have enough information to email unity support to see if they might be able to help you and bring this up to the developers so that we might get a better solution.

If I recall properly I ran into the same issue when I was developing my game. What I did was that while I found that it would not pause the main execution inside of a method call like it does on iOS. It will pause coroutines properly? Have you tried to put the Handheld.PlayFullScreenMovie inside of a coroutine and then try to play it?

Hey Ferazel,

The code above is running a coroutine.

Also I will definitely send this off to Unity support, I just wanted to put it out to the community to make sure I wasnt doing something silly :slight_smile: Usually whenever I find a bug in the unity engine, it turns out to be something stupid that I have done.

Cheers!
-Ben

It’s been over a year since you posted this Ben, and it seems to still be happening to me (hence me landing here), so no fix for it yet. I’m about to implement your lovely hack. Thanks for that.

-Adsy

It’s been a considerable time since the original post by Ben. I’m experiencing a similar problem. I’m wondering if anyone knows if this was ever resolved. I am on Unity 5.2.2.f1 Personal. I am testing on a Samsung S2 tablet which uses the Android Lollipop operating system. I can play videos, the problem I get is that when they start they flash and then start.
It’s not a very good user experience. If this was not fixed then I will either try the hack, or look for a third party product.

I think that you have a white skybox.
You should try in your Main Camera to change:
Clear flag = Solid Color
Background = BLACK DARN HIGH RESOLUTION BLACK kuch
Culling Mask = Everything
2425660--166117--Screen Shot 2015-12-16 at 09.31.55.png

From the UnityRef:
Calling this function will initiate a transition that fades the screen from your current content to the designated background color of the player. When playback finishes, the player uses another fade effect to transition back to your content.

I too am experiencing the black flashes at beginning and end of the video when using Handheld.PlayFullScreenMovie(). In my case I want it to fade through white, so I set that color in the call, and I also made the suggested changes to the camera, but to no avail. It works fine in iOS. Any other suggestions?

I’m using Unity 5.3.4p6 and testing on a Samsung Galaxy Tab 3 running Android 4.4.2