DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (f1a26f022ec7)

VCS Links

Line Code
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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
<!doctype html>
<meta charset=utf-8>
<title>Change of msid in remote description should trigger related track events</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
const sdpBase =`v=0
o=- 5511237691691746 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=ice-options:trickle
a=ice-lite
a=msid-semantic:WMS *
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 102 0 8 105 13 110 113 126
c=IN IP6 ::
a=rtcp:9 IN IP6 ::
a=rtcp-mux
a=mid:0
a=sendrecv
a=ice-ufrag:z0i8R3C9C4hPRWls
a=ice-pwd:O7bPpOFAqasqoidV4yxnFVbc
a=ice-lite
a=fingerprint:sha-256 B7:9C:0D:C9:D1:42:57:97:82:4D:F9:B7:93:75:49:C3:42:21:5A:DD:9C:B5:ED:53:53:F0:B4:C8:AE:88:7A:E7
a=setup:actpass
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=rtpmap:0 PCMU/8000`;

const sdp0 = sdpBase + `
`;

const sdp1 = sdpBase + `
a=msid:1 2
a=ssrc:3 cname:4
a=ssrc:3 msid:1 2
`;

const sdp2 = sdpBase + `
a=ssrc:3 cname:4
a=ssrc:3 msid:1 2
`;

const sdp3 = sdpBase + `
a=msid:1 2
a=ssrc:3 cname:4
a=ssrc:3 msid:3 2
`;

const sdp4 = sdp1.replace('msid-semantic', 'unknownattr');

const sdp5 = sdpBase + `
a=msid:-
`;

const sdp6 = sdpBase + `
a=msid:1 2
a=msid:1 2
`;

async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
{
    const testTrackPromise = new Promise(resolve  => {
        pc.ontrack = (event) => { resolve([event.track, event.streams]); };
    });
    await pc.setRemoteDescription({type: 'offer', sdp: sdp});
    return testTrackPromise;
}

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
    assert_equals(streams.length, 1, "track event has a stream");
}, "When a=msid is absent, the track should still be associated with a stream");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
    assert_equals(streams.length, 1, "track event has a stream");
    assert_equals(streams[0].id, "1", "msid should match");
}, "Source-level msid should be ignored if media-level msid is present");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp2);
    assert_equals(streams.length, 1, "track event has a stream");
    assert_equals(streams[0].id, "1", "msid should match");
}, "Source-level msid should be parsed if media-level msid is absent");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    let track;
    let streams;
    try {
      [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp3);
    } catch (e) {
      return;
    }
    assert_equals(streams.length, 1, "track event has a stream");
    assert_equals(streams[0].id, "1", "msid should match");
}, "Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp4);
    assert_equals(streams.length, 1, "track event has a stream");
    assert_equals(streams[0].id, "1", "msid should match");
}, "stream ids should be found even if msid-semantic is absent");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp5);
    assert_equals(streams.length, 0, "track event has no stream");
}, "a=msid:- should result in a track event with no streams");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp6);
    assert_equals(streams.length, 1, "track event has one stream");
}, "Duplicate a=msid should result in a track event with one stream");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
    assert_equals(streams.length, 1, "track event has a stream");
    assert_equals(streams[0].id, "1", "msid should match");
    const stream = streams[0];

    await pc.setLocalDescription(await pc.createAnswer());

    const testTrackPromise = new Promise((resolve) => { stream.onremovetrack = resolve; });
    await pc.setRemoteDescription({type: 'offer', 'sdp': sdp0});
    await testTrackPromise;

    assert_equals(stream.getAudioTracks().length, 0, "stream should be empty");
}, "Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream");

promise_test(async test => {
    const pc = new RTCPeerConnection();
    test.add_cleanup(() => pc.close());

    let [track0, streams0] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);

    await pc.setLocalDescription(await pc.createAnswer());

    let [track1, streams1] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);

    assert_equals(streams1.length, 1, "track event has a stream");
    assert_equals(streams1[0].id, "1", "msid should match");
    assert_equals(streams1[0].getTracks()[0], track0, "track should match");
}, "Applying a remote description with a new msid should trigger firing an event with populated streams");
</script>