summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/tests/mochitests/test_peerConnection_videoCodecs.html
blob: 7a245b5d8cc0025621c4f803048f9b5cdbc2a6ae (plain)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!DOCTYPE HTML>
<html>
<head>
  <script type="application/javascript" src="pc.js"></script>
  <script type="application/javascript" src="stats.js"></script>
  <script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
  createHTML({
    bug: "1395853",
    title: "Verify video content over WebRTC for every video codec",
  });

  async function testVideoCodec(options = {}, codec) {
    const test = new PeerConnectionTest(options);
    test.setMediaConstraints([{video: true}], []);

    let payloadType;
    test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [
      function PC_LOCAL_FILTER_OUT_CODECS() {
        const otherCodec = codecs.find(c => c != codec);
        const otherId = sdputils.findCodecId(test.originalOffer.sdp, otherCodec.name, otherCodec.offset);
        const otherRtpmapMatcher = new RegExp(`a=rtpmap:${otherId}.*\\r\\n`, "gi");

        const id = sdputils.findCodecId(test.originalOffer.sdp, codec.name, codec.offset);
        payloadType = Number(id);
        if (codec.offset) {
          isnot(id, sdputils.findCodecId(test.originalOffer.sdp, codec.name, 0),
            "Different offsets should return different payload types");
        }
        test.originalOffer.sdp =
          sdputils.removeAllButPayloadType(test.originalOffer.sdp, id);

        ok(!test.originalOffer.sdp.match(new RegExp(`m=.*UDP/TLS/RTP/SAVPF.* ${otherId}[^0-9]`, "gi")),
          `Other codec ${otherId} should be removed after filtering`);
        ok(test.originalOffer.sdp.match(new RegExp(`m=.*UDP/TLS/RTP/SAVPF.* ${id}[^0-9]`, "gi")),
          `Tested codec ${id} should remain after filtering`);

        // We only set it now, or the framework would remove non-H264 codecs
        // for us.
        options.h264 = codec.name == "H264";
      },
    ]);

    test.chain.insertAfter("PC_LOCAL_WAIT_FOR_MEDIA_FLOW",
      [PC_LOCAL_TEST_LOCAL_STATS]);

    test.chain.insertAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW",
      [PC_REMOTE_TEST_REMOTE_STATS]);

    test.chain.append([
      async function PC_LOCAL_TEST_CODEC() {
        const stats = await test.pcLocal._pc.getStats();
        let codecCount = 0;
        stats.forEach(stat => {
          if (stat.type == "codec") {
            is(codecCount++, 0, "expected only one encode codec stat");
            is(stat.payloadType, payloadType, "payloadType as expected");
            is(stat.mimeType, `video/${codec.name}`, "mimeType as expected");
            is(stat.codecType, "encode", "codecType as expected");
          }
        });
      },
      async function PC_REMOTE_TEST_CODEC() {
        const stats = await test.pcRemote._pc.getStats();
        let codecCount = 0;
        stats.forEach(stat => {
          if (stat.type == "codec") {
            is(codecCount++, 0, "expected only one decode codec stat");
            is(stat.payloadType, payloadType, "payloadType as expected");
            is(stat.mimeType, `video/${codec.name}`, "mimeType as expected");
            is(stat.codecType, "decode", "codecType as expected");
          }
        });
      },
      async function CHECK_VIDEO_FLOW() {
        try {
          const h = new VideoStreamHelper();
          await h.checkVideoPlaying(
              test.pcRemote.remoteMediaElements[0],
              10, 10, 128);
          ok(true, `Got video flow for codec ${codec.name}, offset ${codec.offset}`);
        } catch(e) {
          ok(false, `No video flow for codec ${codec.name}, offset ${codec.offset}: ${e}`);
        }
      },
    ]);

    await test.run();
  }

  // We match the name against the sdp to figure out the payload type,
  // so all other present codecs can be removed.
  // Use `offset` when there are multiple instances of a codec expected in an sdp.
  const codecs = [
    { name: "VP8" },
    { name: "VP9" },
    { name: "H264" },
    { name: "H264", offset: 1 },
  ];

  runNetworkTest(async (options) => {
    // This test expects the video being captured will change color. Use fake
    // video device as loopback does not currently change.
    await pushPrefs(
      ['media.video_loopback_dev', ''],
      ['media.navigator.streams.fake', true]);
    for (let codec of codecs) {
      info(`Testing video for codec ${codec.name} offset ${codec.offset}`);
      try {
        let enc = SpecialPowers.getBoolPref('media.webrtc.platformencoder');
        let dec = SpecialPowers.getBoolPref('media.navigator.mediadatadecoder_h264_enabled');
        if (codec.name == "H264") {
          await matchPlatformH264CodecPrefs();
          if (codec.offset == 1) {
            // Force fake GMP codec for H.264 mode 0 because not all platforms
            // support slice size control. Re-enable it after
            // a. SW encoder fallback support (bug 1726617), and
            // b. returning valid bitstream from fake GMP encoder (bug 1509012).
            await pushPrefs(
              ['media.webrtc.platformencoder', false],
              ['media.navigator.mediadatadecoder_h264_enabled', false],
            );
          }
        }
        await testVideoCodec(options, codec);
        await pushPrefs(
          ['media.webrtc.platformencoder', enc],
          ['media.navigator.mediadatadecoder_h264_enabled', dec],
        );
      } catch(e) {
        ok(false, `Error in test for codec ${codec.name}: ${e}\n${e.stack}`);
      }
      info(`Tested video for codec ${codec.name}`);
    }
  });
</script>
</pre>
</body>
</html>