RTCRtpSynchronizationSource-helper.js (4316B)
1 'use strict'; 2 3 // This file depends on `webrtc/RTCPeerConnection-helper.js` 4 // which should be loaded from the main HTML file. 5 6 var kAbsCaptureTime = 7 'http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time'; 8 9 function addHeaderExtensionToSdp(sdp, uri) { 10 // Find the highest used header extension id by sorting the extension ids used, 11 // eliminating duplicates and adding one. This is not quite correct 12 // but this code will go away with the header extension API. 13 const usedIds = sdp.split('\n') 14 .filter(line => line.startsWith('a=extmap:')) 15 .map(line => parseInt(line.split(' ')[0].substring(9), 10)) 16 .sort((a, b) => a - b) 17 .filter((item, index, array) => array.indexOf(item) === index); 18 const nextId = usedIds[usedIds.length - 1] + 1; 19 const extmapLine = 'a=extmap:' + nextId + ' ' + uri + '\r\n'; 20 21 const sections = sdp.split('\nm=').map((part, index) => { 22 return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; 23 }); 24 const sessionPart = sections.shift(); 25 return sessionPart + sections.map(mediaSection => mediaSection + extmapLine).join(''); 26 } 27 28 // TODO(crbug.com/1051821): Use RTP header extension API instead of munging 29 // when the RTP header extension API is implemented. 30 async function addAbsCaptureTimeAndExchangeOffer(caller, callee) { 31 let offer = await caller.createOffer(); 32 33 // Absolute capture time header extension may not be offered by default, 34 // in such case, munge the SDP. 35 offer.sdp = addHeaderExtensionToSdp(offer.sdp, kAbsCaptureTime); 36 37 await caller.setLocalDescription(offer); 38 return callee.setRemoteDescription(offer); 39 } 40 41 // TODO(crbug.com/1051821): Use RTP header extension API instead of munging 42 // when the RTP header extension API is implemented. 43 async function checkAbsCaptureTimeAndExchangeAnswer(caller, callee, 44 absCaptureTimeAnswered) { 45 let answer = await callee.createAnswer(); 46 47 const extmap = new RegExp('a=extmap:\\d+ ' + kAbsCaptureTime + '\r\n', 'g'); 48 if (answer.sdp.match(extmap) == null) { 49 // We expect that absolute capture time RTP header extension is answered. 50 // But if not, there is no need to proceed with the test. 51 assert_false(absCaptureTimeAnswered, 'Absolute capture time RTP ' + 52 'header extension is not answered'); 53 } else { 54 if (!absCaptureTimeAnswered) { 55 // We expect that absolute capture time RTP header extension is not 56 // answered, but it is, then we munge the answer to remove it. 57 answer.sdp = answer.sdp.replace(extmap, ''); 58 } 59 } 60 61 await callee.setLocalDescription(answer); 62 return caller.setRemoteDescription(answer); 63 } 64 65 async function exchangeOfferAndListenToOntrack(t, caller, callee, 66 absCaptureTimeOffered) { 67 const ontrackPromise = addEventListenerPromise(t, callee, 'track'); 68 // Absolute capture time header extension is expected not offered by default, 69 // and thus munging is needed to enable it. 70 await absCaptureTimeOffered 71 ? addAbsCaptureTimeAndExchangeOffer(caller, callee) 72 : exchangeOffer(caller, callee); 73 return ontrackPromise; 74 } 75 76 async function initiateSingleTrackCall(t, cap, absCaptureTimeOffered, 77 absCaptureTimeAnswered) { 78 const caller = new RTCPeerConnection(); 79 t.add_cleanup(() => caller.close()); 80 const callee = new RTCPeerConnection(); 81 t.add_cleanup(() => callee.close()); 82 83 const stream = await getNoiseStream(cap); 84 stream.getTracks().forEach(track => { 85 caller.addTrack(track, stream); 86 t.add_cleanup(() => track.stop()); 87 }); 88 89 // TODO(crbug.com/988432): `getSynchronizationSources() on the audio side 90 // needs a hardware sink for the returned dictionary entries to get updated. 91 const remoteVideo = document.getElementById('remote'); 92 93 callee.ontrack = e => { 94 remoteVideo.srcObject = e.streams[0]; 95 } 96 97 exchangeIceCandidates(caller, callee); 98 99 await exchangeOfferAndListenToOntrack(t, caller, callee, 100 absCaptureTimeOffered); 101 102 // Exchange answer and check whether the absolute capture time RTP header 103 // extension is answered. 104 await checkAbsCaptureTimeAndExchangeAnswer(caller, callee, 105 absCaptureTimeAnswered); 106 107 return [caller, callee]; 108 }