Novage / p2p-media-loader

An open-source engine for P2P streaming of live and on demand video directly in a web browser HTML page
https://novage.com.ua/p2p-media-loader/demo.html
Apache License 2.0
1.45k stars 314 forks source link

Clappr not load config engine HlsJsP2PEngine. #405

Closed stevenking888 closed 3 months ago

stevenking888 commented 3 months ago

Refer to issue #388 with Clappr example code. I found that other player can assign P2P config but not Clappr in this code

const engine = new HlsJsP2PEngine({
        p2p: {
          core: {
                    swarmId: "xxx",
                    simultaneousHttpDownloads: 5,
                    simultaneousP2PDownloads: 5,
                    httpErrorRetries: 5,
                    p2pErrorRetries: 5,
                    announceTrackers: [
                          "wss://xxx.xxx,
                    ]
                },
            },
      });

Player dont' use this config

DimaDemchenko commented 3 months ago

@stevenking888 Thank you for submitting your issue. To ensure your P2P configuration is correctly integrated with Clappr, try using this configuration:

const engine = new HlsJsP2PEngine({
      core: {
        swarmId: "xxx",
        simultaneousHttpDownloads: 5,
        simultaneousP2PDownloads: 5,
        httpErrorRetries: 5,
        p2pErrorRetries: 5,
        announceTrackers: ["wss://xxx.xxx"],
      },
    });

https://novage.github.io/p2p-media-loader/docs/latest/#md:integrating-p2p-with-clappr-and-hlsjs

stevenking888 commented 3 months ago

I confirm this code is work. configuration must be outside p2p{}

but I think onHlsJsCreated: (hls) => {} after "core' seem to not work. for example

const engine = new HlsJsP2PEngine({
          core: {
            swarmId: "xxx",
            simultaneousHttpDownloads: 5,
            simultaneousP2PDownloads: 5,
            httpErrorRetries: 5,
            p2pErrorRetries: 5,
            announceTrackers: ["wss://xxx.yy"],
          },
          onHlsJsCreated: (hls) => {
              // Subscribe to P2P engine and Hls.js events here
              hls.p2pEngine.addEventListener("onPeerConnect", (details) => {
                console.log(`Connected to peer ${details.peerId})`);
              });
              hls.p2pEngine.addEventListener('onChunkDownloaded', (bytesLength, downloadSource, peerId) => {
                console.log(`Downloaded ${bytesLength} bytes from ${downloadSource} ${peerId ? 'from peer ' + peerId : 'from server'}`);
                if (peerId) {
                  downloaded += bytesLength;
                }
                downloaded_total += bytesLength;
              });
              hls.p2pEngine.addEventListener("onChunkUploaded", (bytesLength, peerId) => {
                console.log(`Uploaded ${bytesLength} bytes to peer ${peerId}`);
              });
            }
        });

From above config in "core" is works but the rest is not.

DimaDemchenko commented 3 months ago

@stevenking888 it doesn't work because you need to configure P2PEngine directly in this type of integration.

https://novage.github.io/p2p-media-loader/docs/latest/classes/p2p_media_loader_hlsjs.HlsJsP2PEngine.html

<script type="module">
  import { HlsJsP2PEngine } from "p2p-media-loader-hlsjs";

  const engine = new HlsJsP2PEngine({
    core: {
      swarmId: "Optional custom swarm ID for stream",
      // Other core config parameters go here
    },
  });

  engine.addEventListener("onPeerConnect", (details) => {
                console.log(`Connected to peer ${details.peerId})`);
              });

  const player = new Clappr.Player({
    source: streamUrl,
    plugins: [LevelSelector], 
    height: "100%",
    width: "100%",
    parentId: `#player`,
    playback: {
      hlsjsConfig: {
        ...engine.getConfigForHlsJs(),
        // 
        // Here you can config Hlsjs 
        //
      },
    },
  });

  engine.bindHls(() => clapprPlayer.core.getCurrentPlayback()?._hls);
</script>
stevenking888 commented 3 months ago

I'm not sure why it's not works. I use this code

 const engine = new HlsJsP2PEngine({
    core: {
      swarmId: "Optional custom swarm ID for stream",
      // Other core config parameters go here
    },
  });

  //correct the closing parenthesis ) at the end
  engine.addEventListener("onPeerConnect", (details) => {
    console.log(`Connected to peer ${details.peerId}`);
});

      engine.addEventListener('onChunkDownloaded', (bytesLength, downloadSource, peerId) => {
                console.log(`Downloaded ${bytesLength} bytes from ${downloadSource} ${peerId ? 'from peer ' + peerId : 'from server'}`);
                if (peerId) {
                  downloaded += bytesLength;
                }
                downloaded_total += bytesLength;
              });

I found that console log 'onChunkDownloaded' display but hls can not play (chunks downloaded but not play). when I remove all eninge.addEventListener() hls play as well.

DimaDemchenko commented 3 months ago

@stevenking888

The code below works fine. Try it out

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clappr with P2P HLS.js</title>

    <script type="importmap">
      {
        "imports": {
          "p2p-media-loader-core": "https://cdn.jsdelivr.net/npm/p2p-media-loader-core@^1/dist/p2p-media-loader-core.es.min.js",
          "p2p-media-loader-hlsjs": "https://cdn.jsdelivr.net/npm/p2p-media-loader-hlsjs@^1/dist/p2p-media-loader-hlsjs.es.min.js"
        }
      }
    </script>

    <script src="https://cdn.jsdelivr.net/npm/@clappr/player@~0/dist/clappr.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/clappr/clappr-level-selector-plugin@~0/dist/level-selector.min.js"></script>
  </head>
  <body>
    <div id="player" style="width: 640px; height: 360px"></div>
    <script type="module">
      import { HlsJsP2PEngine } from "p2p-media-loader-hlsjs";

      const engine = new HlsJsP2PEngine({
        core: {
          swarmId: "xxx",
        },
      });

      engine.addEventListener("onPeerConnect", (details) => {
        console.log(`Connected to peer ${details.peerId}`);
      });

      engine.addEventListener(
        "onChunkDownloaded",
        (bytesLength, downloadSource, peerId) => {
          console.log(
            `Downloaded ${bytesLength} bytes from ${downloadSource} ${
              peerId ? "from peer " + peerId : "from server"
            }`
          );
        }
      );

      engine.addEventListener("onSegmentLoaded", (details) => {
        console.log(`Loaded segment ${details.segmentUrl}`);
      });

      engine.addEventListener("onChunkUploaded", (bytesLength, peerId) => {
        console.log(`Uploaded ${bytesLength} bytes to peer ${peerId}`);
      });

      const streamUrl =
        "https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8";

      const clapprPlayer = new Clappr.Player({
        source: streamUrl,
        plugins: [LevelSelector],
        height: "100%",
        width: "100%",
        parentId: "#player",
        playback: {
          hlsjsConfig: {
            ...engine.getConfigForHlsJs(),
          },
        },
      });

      engine.bindHls(() => clapprPlayer.core.getCurrentPlayback()?._hls);
    </script>
  </body>
</html>
stevenking888 commented 3 months ago

engine.addEventListener("onPeerConnect", (details) => { console.log(Connected to peer ${details.peerId}); });

  engine.addEventListener(
    "onChunkDownloaded",
    (bytesLength, downloadSource, peerId) => {
      console.log(
        `Downloaded ${bytesLength} bytes from ${downloadSource} ${
          peerId ? "from peer " + peerId : "from server"
        }`
      );
    }
  );

  engine.addEventListener("onSegmentLoaded", (details) => {
    console.log(`Loaded segment ${details.segmentUrl}`);
  });

  engine.addEventListener("onChunkUploaded", (bytesLength, peerId) => {
    console.log(`Uploaded ${bytesLength} bytes to peer ${peerId}`);
  });

Work like charm.

stevenking888 commented 3 months ago

I found some problem. I'm not sure there are someone found this. I found that if stream url (HLS) has token paramter in URL for the first time load playlist it can request with correct parameters but after a while it seem that hls.js request without parameter then error. I found this problem only on "Safari" browser.

I tried to find answer I found that hls.js able to add this parameter

const hls = new Hls({
  xhrSetup: xhr => {
    xhr.setRequestHeader('id', 1)
    xhr.setRequestHeader('token', 456)
  }
})

Could you please give me an example of add config value for hls.js in Clappr example code ?

DimaDemchenko commented 2 months ago
const clapprPlayer = new Clappr.Player({
        source: streamUrl,
        plugins: [LevelSelector],
        height: "100%",
        width: "100%",
        parentId: "#player",
        playback: {
          hlsjsConfig: {
            ...engine.getConfigForHlsJs(),
            // Additional HLS.js configuration
            xhrSetup: xhr => {
               xhr.setRequestHeader('id', 1)
               xhr.setRequestHeader('token', 456)
             },
          },
        },
      });

@stevenking888, this is how you can specify the hlsjsConfig parameter in your Clappr integration. Please test it to ensure it works as expected according to your specific needs.