1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121

content / test / data / gpu / webcodecs / webrtc-peer-connection.html [blame]

<!DOCTYPE html>
<!--
Take frames coming from OffscreenCanvas and send them over an RTCPeerConnection.
-->
<html>
<head>
  <title>RTCPeerConnection test</title>
  <script src="webcodecs_common.js"></script>
  <script type="text/javascript">
    'use strict';
    async function main(arg) {
      const use_worker = arg.use_worker;

      const canvas = document.getElementById('display');
      const ctx = canvas.getContext('2d');

      const mst_generator = new MediaStreamTrackGenerator({kind: 'video'});

      let stopSource = () => {};
      if (use_worker) {
        const worker = new Worker('webrtc-peer-connection-worker.js');
        const writable = mst_generator.writable;
        worker.postMessage(
            {writable, width: canvas.width, height: canvas.height}, [writable]);
        stopSource = () => {
          worker.terminate();
        };
      } else {
        const source = new CanvasSource(canvas.width, canvas.height);

        const writer = mst_generator.writable.getWriter();
        // write frames continuously until test is completed
        const intervalId = setInterval(async () => {
          await writer.write(await source.getNextFrame());
        }, 100);
        stopSource = () => {
          clearInterval(intervalId);
          source.close();
          writer.close();
        };
      }

      const pc_track = await startPeerConnectionPipe(mst_generator);

      const mst_processor = new MediaStreamTrackProcessor({
        track: pc_track,
      });
      const reader = mst_processor.readable.getReader();

      // WebRTC starts with limited bandwidth, so the frames have large encoding
      // artifacts. By 30 frames we expect the diff to be more reasonable,
      // although the tolerance is still quite liberal.
      const high_tolerance_frames_to_read = 30;
      const low_tolerance_frames_to_read = 5;
      for (let i = 0;
           i < high_tolerance_frames_to_read + low_tolerance_frames_to_read;
           i++) {
        const {value: frame, done} = await reader.read();
        if (done) {
          TEST.reportFailure('stream ended unexpectedly');
        }
        ctx.drawImage(frame, 0, 0);

        // TODO(crbug.com/40216940): These tolerances are very high.
        // Colour space issue, or just an expected network encoding diff?
        const tolerance = i < high_tolerance_frames_to_read ? 50 : 40;
        checkFourColorsFrame(ctx, canvas.width, canvas.height, tolerance);

        frame.close();
      }
      reader.cancel();
      pc_track.stop();
    }

    /**
     * Send a track over an RTCPeerConnection. In this case, both ends of the
     * connection are local.
     * @param {!MediaStreamTrack} inputTrack
     * @return {!Promise<!MediaStreamTrack>}
     */
    async function startPeerConnectionPipe(inputTrack) {
      // Disable scaling to obtain stable results.
      const caller = new RTCPeerConnection(null, {
        optional: [
          {
            googCpuOveruseDetection: false,
          },
        ],
      });
      const callee = new RTCPeerConnection(null);
      caller.onicecandidate = (/** !RTCPeerConnectionIceEvent*/ event) => {
        if (event.candidate) callee.addIceCandidate(event.candidate);
      };
      callee.onicecandidate = (/** !RTCPeerConnectionIceEvent */ event) => {
        if (event.candidate) caller.addIceCandidate(event.candidate);
      };
      const outputTrackPromise = new Promise((resolve) => {
        callee.ontrack = (/** !RTCTrackEvent */ event) => {
          resolve(event.track);
        };
      });
      caller.addTransceiver(inputTrack, {
        direction: 'sendonly',
      });
      await caller.setLocalDescription();
      await callee.setRemoteDescription(caller.localDescription);
      await callee.setLocalDescription();
      await caller.setRemoteDescription(callee.localDescription);

      return await outputTrackPromise;
    }
  </script>
</head>

<body>
  <div>
    <canvas id='display' width="640" height="480"></canvas>
  </div>
</body>

</html>