MKPlayer and React cannot destroy the player on strict mode

MKPlayer and React cannot destroy the player on strict mode

Hello there,

while implementing the MKPlayer on a React application, I found a problem on strict mode, that might lead to unexpected issues when implementing the player on react applications.

To put as context, strict mode simulates an unmount of the each react component (individually) to find possible bugs. Basically, it re-renders each component to find possible "leaks" when the state/data is not properly cleaned up.

That put, it shows that the MKPlayer creates 2 players on an react app (when using strict mode), indicating that destroying the player (cleaning up it's resources) is not 100% effective and it might lead to issues/bugs when running the player on a react application.

Below is the player working how it is supposed to be:
working as it should

and here below is the player bugging because the improper resource clean up:
player bugging with the improper cleanup


The proper code generated:
  1. <div class="mediakind-player" style="max-width: inherit; max-height: inherit;">
  2.     <video id="bitmovinplayer-video-null" src="blob:https://localhost..." webkit-playsinline="" playsinline="" style="display: block !important;"></video>
  3.     <div id="mkplayer-subtitle-container" style="position: absolute; top: 0px; left: 0px; border: 0px; margin: 0px; padding: 0px; width: 100%; height: 100%; pointer-events: none;">
  4.         <div id="mkplayer-subtitle-region" style="position: absolute; top: 5%; left: 5%; width: 90%; height: 90%; margin: 0px; padding: 0px; text-align: center; display: flex; overflow: hidden; visibility: visible; opacity: 1; flex-direction: column; justify-content: flex-end; z-index: auto;">
  5.         </div>
  6.     </div>
  7. </div>
And here is the HTML generated with two video components
  1. <div class="mediakind-player" style="max-width: inherit; max-height: inherit;">
  2.     <video id="bitmovinplayer-video-null" src="blob:http://localhost:8088/..."></video>
  3.     <video id="bitmovinplayer-video-null" src="blob:http://localhost:8088/..." webkit-playsinline="" playsinline=""></video>
  4.     <div id="mkplayer-subtitle-container" style="position: absolute; top: 0px; left: 0px; border: 0px; margin: 0px; padding: 0px; width: 100%; height: 100%; pointer-events: none;">
  5.         <div id="mkplayer-subtitle-region" style="position: absolute; top: 5%; left: 5%; width: 90%; height: 90%; margin: 0px; padding: 0px; text-align: center; display: flex; overflow: hidden; visibility: visible; opacity: 1; flex-direction: column; justify-content: flex-end; z-index: auto;">
  6.         </div>
  7.     </div>
  8.     <div class="bitmovinplayer-poster"></div>
  9. </div>
As you can see,  the video on line 2 shouldn't be there, only the one that is on line 3.

Here below is the simplified component that is being used:
  1. export function MediaPlayer({
  2.     hls,
  3.     dash,
  4.     authorizationToken,
        title, 
        description
  5. }: MediaPlayerProps) {
  6.     const playerElementRef = useRef<HTMLVideoElement>(null);
  7.     const playerRef = useRef<MKPlayer>();

  8.     useEffect(() => {
  9.         const playback = {
  10.             muted: true,
  11.             autoplay: true,
  12.             preferredTech: [{
  13.                 player: 'html5',
  14.                 streaming: 'hls'
  15.             }],
  16.             volume: 0,
  17.         } as MKPlaybackConfig;

  18.         const playerConfig = {
  19.             key: 'my-key',
  20.             playback,
  21.             // Subscribe to player events
  22.             events: {
  23.                 [MKPlayerEvent.Error]: (event) => {
  24.                     console.log('Encountered player error: ', JSON.stringify(event));
  25.                 },
  26.             }
  27.         } as MKPlayerConfig;

  28.         playerRef.current = new MKPlayer(playerElementRef.current!, playerConfig);

  29.         playerRef.current.load({
  30.             title,
  31.             description,
  32.             hls,
  33.             dash,
  34.             drm: {
  35.                 [MKDrmType.ClearKey]: {
  36.                     LA_URL: 'HLS_AES',
  37.                     headers: {
  38.                         Authorization: `Bearer ${authorizationToken}`
  39.                     }
  40.                 } as MKClearKeyDRMServerConfig
  41.             }
  42.         });

  43.         return () => {
  44.             playerRef.current?.destroy(); //<-- here it is being destroyed, but in any case the video is still being visible
  45.         };
  46.     }, []);

  47.     return (<video ref={playerElementRef} />);
  48. }
On line 49 the video player is being destroyed, but it anyway the duplicated html video component exists.

Just to conclude, this is not a critical bug, but it might lead to problems when executing the player on a react application.

    Features & Ideas

    Have an idea for a feature? Request a feature or an idea!